summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/compiler-core/slang-dxc-compiler.cpp112
-rw-r--r--source/slang/slang-capabilities.capdef2
-rw-r--r--source/slang/slang-compiler-tu.cpp115
-rw-r--r--source/slang/slang-compiler.cpp59
-rwxr-xr-xsource/slang/slang-compiler.h14
-rw-r--r--source/slang/slang-diagnostic-defs.h3
-rw-r--r--source/slang/slang-ir-inst-defs.h4
-rw-r--r--source/slang/slang-ir-insts.h3
-rw-r--r--source/slang/slang-ir.cpp46
-rw-r--r--source/slang/slang-ir.h8
-rw-r--r--source/slang/slang-module-library.cpp9
-rw-r--r--source/slang/slang-options.cpp35
-rw-r--r--source/slang/slang-serialize-container.cpp7
-rw-r--r--source/slang/slang-serialize-ir.cpp9
-rw-r--r--source/slang/slang.cpp28
15 files changed, 398 insertions, 56 deletions
diff --git a/source/compiler-core/slang-dxc-compiler.cpp b/source/compiler-core/slang-dxc-compiler.cpp
index aa005d47f..0ecfd0b30 100644
--- a/source/compiler-core/slang-dxc-compiler.cpp
+++ b/source/compiler-core/slang-dxc-compiler.cpp
@@ -381,18 +381,24 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& inOptions, IArt
CompileOptions options = getCompatibleVersion(&inOptions);
- // This compiler can only deal with a single artifact
- if (options.sourceArtifacts.count != 1)
+ // This compiler can only deal at most, a single source code artifact
+ // Should be okay to link together multiple libraries without any source artifacts (assuming that means source code)
+ if (options.sourceArtifacts.count > 1)
{
return SLANG_FAIL;
}
- IArtifact* sourceArtifact = options.sourceArtifacts[0];
+ bool hasSource = options.sourceArtifacts.count > 0;
- if (options.sourceLanguage != SLANG_SOURCE_LANGUAGE_HLSL || options.targetType != SLANG_DXIL)
+ IArtifact* sourceArtifact = hasSource ? options.sourceArtifacts[0] : nullptr;
+
+ if (hasSource)
{
- SLANG_ASSERT(!"Can only compile HLSL to DXIL");
- return SLANG_FAIL;
+ if (options.sourceLanguage != SLANG_SOURCE_LANGUAGE_HLSL || options.targetType != SLANG_DXIL)
+ {
+ SLANG_ASSERT(!"Can only compile HLSL to DXIL");
+ return SLANG_FAIL;
+ }
}
// Find all of the libraries
@@ -416,16 +422,19 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& inOptions, IArt
ComPtr<IDxcLibrary> dxcLibrary;
SLANG_RETURN_ON_FAIL(m_createInstance(CLSID_DxcLibrary, __uuidof(dxcLibrary), (LPVOID*)dxcLibrary.writeRef()));
+ ComPtr<IDxcBlobEncoding> dxcSourceBlob = nullptr;
ComPtr<ISlangBlob> sourceBlob;
- SLANG_RETURN_ON_FAIL(sourceArtifact->loadBlob(ArtifactKeep::Yes, sourceBlob.writeRef()));
+ if (hasSource)
+ {
+ SLANG_RETURN_ON_FAIL(sourceArtifact->loadBlob(ArtifactKeep::Yes, sourceBlob.writeRef()));
- // Create blob from the string
- ComPtr<IDxcBlobEncoding> dxcSourceBlob;
- SLANG_RETURN_ON_FAIL(dxcLibrary->CreateBlobWithEncodingFromPinned(
- (LPBYTE)sourceBlob->getBufferPointer(),
- (UINT32)sourceBlob->getBufferSize(),
- 0,
- dxcSourceBlob.writeRef()));
+ // Create blob from the string
+ SLANG_RETURN_ON_FAIL(dxcLibrary->CreateBlobWithEncodingFromPinned(
+ (LPBYTE)sourceBlob->getBufferPointer(),
+ (UINT32)sourceBlob->getBufferSize(),
+ 0,
+ dxcSourceBlob.writeRef()));
+ }
List<const WCHAR*> args;
@@ -508,7 +517,7 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& inOptions, IArt
String profileName = asString(options.profileName);
// If we are going to link we have to compile in the lib profile style
- if (libraries.getCount())
+ if (libraries.getCount() && hasSource)
{
if (!profileName.startsWith("lib"))
{
@@ -561,28 +570,33 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& inOptions, IArt
}
#endif
- String sourcePath = ArtifactUtil::findPath(sourceArtifact);
- OSString wideSourcePath = sourcePath.toWString();
+ String sourcePath;
+ ComPtr<IDxcBlob> dxcResultBlob = nullptr;
+ auto diagnostics = ArtifactDiagnostics::create();
+ ComPtr<IDxcOperationResult> dxcOperationResult = nullptr;
+ if (hasSource)
+ {
+ sourcePath = ArtifactUtil::findPath(sourceArtifact);
+ OSString wideSourcePath = sourcePath.toWString();
- DxcIncludeHandler includeHandler(&searchDirectories, options.fileSystemExt, options.sourceManager);
+ DxcIncludeHandler includeHandler(&searchDirectories, options.fileSystemExt, options.sourceManager);
- ComPtr<IDxcOperationResult> dxcOperationResult;
- SLANG_RETURN_ON_FAIL(dxcCompiler->Compile(dxcSourceBlob,
- wideSourcePath.begin(),
- wideEntryPointName.begin(),
- wideProfileName.begin(),
- args.getBuffer(),
- UINT32(args.getCount()),
- nullptr, // `#define`s
- 0, // `#define` count
- &includeHandler, // `#include` handler
- dxcOperationResult.writeRef()));
+ SLANG_RETURN_ON_FAIL(dxcCompiler->Compile(dxcSourceBlob,
+ wideSourcePath.begin(),
+ wideEntryPointName.begin(),
+ wideProfileName.begin(),
+ args.getBuffer(),
+ UINT32(args.getCount()),
+ nullptr, // `#define`s
+ 0, // `#define` count
+ &includeHandler, // `#include` handler
+ dxcOperationResult.writeRef()));
- auto diagnostics = ArtifactDiagnostics::create();
-
- ComPtr<IDxcBlob> dxcResultBlob;
+ SLANG_RETURN_ON_FAIL(_handleOperationResult(dxcOperationResult, diagnostics, dxcResultBlob));
- SLANG_RETURN_ON_FAIL(_handleOperationResult(dxcOperationResult, diagnostics, dxcResultBlob));
+ ComPtr<IDxcBlobEncoding> dxcResultBlob2 = nullptr;
+ dxcCompiler->Disassemble(dxcResultBlob, dxcResultBlob2.writeRef());
+ }
// If we have libraries then we need to link...
if (libraries.getCount())
@@ -604,26 +618,30 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& inOptions, IArt
libraryNames.add(String(_addName(library, pool)).toWString());
}
- // Add the compiled blob name
- String name;
- if (options.modulePath.count)
- {
- name = Path::getFileNameWithoutExt(asString(options.modulePath));
- }
- else if (sourcePath.getLength())
+ if (hasSource)
{
- name = Path::getFileNameWithoutExt(sourcePath);
- }
+ // Add the compiled blob name
+ String name;
+ if (options.modulePath.count)
+ {
+ name = Path::getFileNameWithoutExt(asString(options.modulePath));
+ }
+ else if (sourcePath.getLength())
+ {
+ name = Path::getFileNameWithoutExt(sourcePath);
+ }
- // Add the blob with name
- {
- auto blob = (ISlangBlob*)dxcResultBlob.get();
- libraryBlobs.add(ComPtr<ISlangBlob>(blob));
- libraryNames.add(String(_addName(name.getUnownedSlice(), pool)).toWString());
+ // Add the blob with name
+ {
+ auto blob = (ISlangBlob*)dxcResultBlob.get();
+ libraryBlobs.add(ComPtr<ISlangBlob>(blob));
+ libraryNames.add(String(_addName(name.getUnownedSlice(), pool)).toWString());
+ }
}
const Index librariesCount = libraryNames.getCount();
SLANG_ASSERT(libraryBlobs.getCount() == librariesCount);
+ SLANG_ASSERT(libraryNames.getCount() == librariesCount);
List<const wchar_t*> linkLibraryNames;
diff --git a/source/slang/slang-capabilities.capdef b/source/slang/slang-capabilities.capdef
index 264748738..220e4a424 100644
--- a/source/slang/slang-capabilities.capdef
+++ b/source/slang/slang-capabilities.capdef
@@ -119,6 +119,8 @@ def _sm_6_7 : _sm_6_6;
def hlsl_nvapi : hlsl;
+alias dxil_lib = _sm_6_3;
+
// cuda versions
def _cuda_sm_1_0 : cuda;
def _cuda_sm_2_0 : _cuda_sm_1_0;
diff --git a/source/slang/slang-compiler-tu.cpp b/source/slang/slang-compiler-tu.cpp
new file mode 100644
index 000000000..b007e7b71
--- /dev/null
+++ b/source/slang/slang-compiler-tu.cpp
@@ -0,0 +1,115 @@
+// slang-compiler-tu.cpp: Compiles translation units to target language
+// and emit precompiled blobs into IR
+
+#include "../core/slang-basic.h"
+#include "slang-compiler.h"
+#include "slang-ir-insts.h"
+#include "slang-capability.h"
+
+namespace Slang
+{
+ SLANG_NO_THROW SlangResult SLANG_MCALL Module::precompileForTargets(
+ DiagnosticSink* sink,
+ EndToEndCompileRequest* endToEndReq,
+ TargetRequest* targetReq)
+ {
+ auto module = getIRModule();
+ Slang::Session* session = endToEndReq->getSession();
+ Slang::ASTBuilder* astBuilder = session->getGlobalASTBuilder();
+ Slang::Linkage* builtinLinkage = session->getBuiltinLinkage();
+ Slang::Linkage linkage(session, astBuilder, builtinLinkage);
+
+ CapabilityName precompileRequirement = CapabilityName::Invalid;
+ switch (targetReq->getTarget())
+ {
+ case CodeGenTarget::DXIL:
+ linkage.addTarget(Slang::CodeGenTarget::DXIL);
+ precompileRequirement = CapabilityName::dxil_lib;
+ break;
+ default:
+ assert(!"Unhandled target");
+ break;
+ }
+ SLANG_ASSERT(precompileRequirement != CapabilityName::Invalid);
+
+ // Ensure precompilation capability requirements are met.
+ auto targetCaps = targetReq->getTargetCaps();
+ auto precompileRequirementsCapabilitySet = CapabilitySet(precompileRequirement);
+ if (targetCaps.atLeastOneSetImpliedInOther(precompileRequirementsCapabilitySet) == CapabilitySet::ImpliesReturnFlags::NotImplied)
+ {
+ // If `RestrictiveCapabilityCheck` is true we will error, else we will warn.
+ // error ...: dxil libraries require $0, entry point compiled with $1.
+ // warn ...: dxil libraries require $0, entry point compiled with $1, implicitly upgrading capabilities.
+ maybeDiagnoseWarningOrError(
+ sink,
+ targetReq->getOptionSet(),
+ DiagnosticCategory::Capability,
+ SourceLoc(),
+ Diagnostics::incompatibleWithPrecompileLib,
+ Diagnostics::incompatibleWithPrecompileLibRestrictive,
+ precompileRequirementsCapabilitySet,
+ targetCaps);
+
+ // add precompile requirements to the cooked targetCaps
+ targetCaps.join(precompileRequirementsCapabilitySet);
+ if (targetCaps.isInvalid())
+ {
+ sink->diagnose(SourceLoc(), Diagnostics::unknownCapability, targetCaps);
+ return SLANG_FAIL;
+ }
+ else
+ {
+ targetReq->setTargetCaps(targetCaps);
+ }
+ }
+
+ List<RefPtr<ComponentType>> allComponentTypes;
+ allComponentTypes.add(this); // Add Module as a component type
+
+ for (auto entryPoint : this->getEntryPoints())
+ {
+ allComponentTypes.add(entryPoint); // Add the entry point as a component type
+ }
+
+ auto composite = CompositeComponentType::create(
+ &linkage,
+ allComponentTypes);
+
+ TargetProgram tp(composite, targetReq);
+ tp.getOrCreateLayout(sink);
+ Slang::Index const entryPointCount = m_entryPoints.getCount();
+
+ CodeGenContext::EntryPointIndices entryPointIndices;
+
+ entryPointIndices.setCount(entryPointCount);
+ for (Index i = 0; i < entryPointCount; i++)
+ entryPointIndices[i] = i;
+ CodeGenContext::Shared sharedCodeGenContext(&tp, entryPointIndices, sink, endToEndReq);
+ CodeGenContext codeGenContext(&sharedCodeGenContext);
+
+ ComPtr<IArtifact> outArtifact;
+ SlangResult res = codeGenContext.emitTranslationUnit(outArtifact);
+ if (res != SLANG_OK)
+ {
+ return res;
+ }
+
+ ISlangBlob* blob;
+ outArtifact->loadBlob(ArtifactKeep::Yes, &blob);
+
+ auto builder = IRBuilder(module);
+ builder.setInsertInto(module);
+
+ switch (targetReq->getTarget())
+ {
+ case CodeGenTarget::DXIL:
+ builder.emitEmbeddedDXIL(blob);
+ break;
+ default:
+ assert(!"Unhandled target");
+ break;
+ }
+
+ return SLANG_OK;
+ }
+}
diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp
index 912e42572..1ef17df1d 100644
--- a/source/slang/slang-compiler.cpp
+++ b/source/slang/slang-compiler.cpp
@@ -762,6 +762,11 @@ namespace Slang
# pragma warning(pop)
#endif
+ SlangResult CodeGenContext::emitTranslationUnit(ComPtr<IArtifact>& outArtifact)
+ {
+ return emitWithDownstreamForEntryPoints(outArtifact);
+ }
+
String GetHLSLProfileName(Profile profile)
{
switch( profile.getFamily() )
@@ -1084,6 +1089,23 @@ namespace Slang
return SLANG_OK;
}
+ bool CodeGenContext::isPrecompiled()
+ {
+ auto program = getProgram();
+
+ bool allPrecompiled = true;
+ program->enumerateIRModules([&](IRModule* irModule)
+ {
+ // TODO: Conditionalize this on target
+ if (!irModule->precompiledDXIL)
+ {
+ allPrecompiled = false;
+ }
+ });
+
+ return allPrecompiled;
+ }
+
SlangResult CodeGenContext::emitWithDownstreamForEntryPoints(ComPtr<IArtifact>& outArtifact)
{
outArtifact.setNull();
@@ -1245,12 +1267,15 @@ namespace Slang
}
else
{
- CodeGenContext sourceCodeGenContext(this, sourceTarget, extensionTracker);
+ if (!isPrecompiled())
+ {
+ CodeGenContext sourceCodeGenContext(this, sourceTarget, extensionTracker);
- SLANG_RETURN_ON_FAIL(sourceCodeGenContext.emitEntryPointsSource(sourceArtifact));
- sourceCodeGenContext.maybeDumpIntermediate(sourceArtifact);
+ SLANG_RETURN_ON_FAIL(sourceCodeGenContext.emitEntryPointsSource(sourceArtifact));
+ sourceCodeGenContext.maybeDumpIntermediate(sourceArtifact);
- sourceLanguage = (SourceLanguage)TypeConvertUtil::getSourceLanguageFromTarget((SlangCompileTarget)sourceTarget);
+ sourceLanguage = (SourceLanguage)TypeConvertUtil::getSourceLanguageFromTarget((SlangCompileTarget)sourceTarget);
+ }
}
if (sourceArtifact)
@@ -1541,6 +1566,25 @@ namespace Slang
libraries.addRange(linkage->m_libModules.getBuffer(), linkage->m_libModules.getCount());
}
+ if (isPrecompiled())
+ {
+ auto program = getProgram();
+ program->enumerateIRModules([&](IRModule* irModule)
+ {
+ // TODO: conditionalize on target
+ if (irModule->precompiledDXIL)
+ {
+ ArtifactDesc desc = ArtifactDescUtil::makeDescForCompileTarget(SLANG_DXIL);
+ desc.kind = ArtifactKind::Library;
+
+ auto library = ArtifactUtil::createArtifact(desc);
+
+ library->addRepresentationUnknown(irModule->precompiledDXIL);
+ libraries.add(library);
+ }
+ });
+ }
+
options.compilerSpecificArguments = allocator.allocate(compilerSpecificArguments);
options.requiredCapabilityVersions = SliceUtil::asSlice(requiredCapabilityVersions);
options.libraries = SliceUtil::asSlice(libraries);
@@ -1991,7 +2035,10 @@ namespace Slang
{
if (auto artifact = targetProgram->getExistingWholeProgramResult())
{
- artifacts.add(ComPtr<IArtifact>(artifact));
+ if (!targetProgram->getOptionSet().getBoolOption(CompilerOptionName::EmbedDXIL))
+ {
+ artifacts.add(ComPtr<IArtifact>(artifact));
+ }
}
}
else
@@ -2251,7 +2298,7 @@ namespace Slang
void EndToEndCompileRequest::generateOutput()
{
generateOutput(getSpecializedGlobalAndEntryPointsComponentType());
-
+
// If we are in command-line mode, we might be expected to actually
// write output to one or more files here.
diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h
index 4bae6c10d..8e1cb0a88 100755
--- a/source/slang/slang-compiler.h
+++ b/source/slang/slang-compiler.h
@@ -1475,6 +1475,12 @@ namespace Slang
virtual SLANG_NO_THROW char const* SLANG_MCALL getDependencyFilePath(
SlangInt32 index) override;
+ /// Precompile TU to target language
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL precompileForTargets(
+ DiagnosticSink* sink,
+ EndToEndCompileRequest* endToEndReq,
+ TargetRequest* targetReq);
+
virtual void buildHash(DigestBuilder<SHA1>& builder) SLANG_OVERRIDE;
virtual slang::DeclReflection* getModuleReflection() SLANG_OVERRIDE;
@@ -2714,6 +2720,8 @@ namespace Slang
SlangResult emitEntryPoints(ComPtr<IArtifact>& outArtifact);
+ SlangResult emitTranslationUnit(ComPtr<IArtifact>& outArtifact);
+
void maybeDumpIntermediate(IArtifact* artifact);
protected:
@@ -2753,6 +2761,10 @@ namespace Slang
SlangResult _emitEntryPoints(ComPtr<IArtifact>& outArtifact);
+ /* Checks if all modules in the target program are already compiled to the
+ target language, indicating that a pass-through linking using the
+ downstream compiler is viable.*/
+ bool isPrecompiled();
private:
Shared* m_shared = nullptr;
};
@@ -2790,6 +2802,8 @@ namespace Slang
virtual SLANG_NO_THROW void SLANG_MCALL setTargetFloatingPointMode(int targetIndex, SlangFloatingPointMode mode) SLANG_OVERRIDE;
virtual SLANG_NO_THROW void SLANG_MCALL setTargetMatrixLayoutMode(int targetIndex, SlangMatrixLayoutMode mode) SLANG_OVERRIDE;
virtual SLANG_NO_THROW void SLANG_MCALL setTargetForceGLSLScalarBufferLayout(int targetIndex, bool value) SLANG_OVERRIDE;
+ virtual SLANG_NO_THROW void SLANG_MCALL setTargetGenerateWholeProgram(int targetIndex, bool value) SLANG_OVERRIDE;
+ virtual SLANG_NO_THROW void SLANG_MCALL setTargetEmbedDXIL(int targetIndex, bool value) SLANG_OVERRIDE;
virtual SLANG_NO_THROW void SLANG_MCALL setMatrixLayoutMode(SlangMatrixLayoutMode mode) SLANG_OVERRIDE;
virtual SLANG_NO_THROW void SLANG_MCALL setDebugInfoLevel(SlangDebugInfoLevel level) SLANG_OVERRIDE;
virtual SLANG_NO_THROW void SLANG_MCALL setOptimizationLevel(SlangOptimizationLevel level) SLANG_OVERRIDE;
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index 487f264d5..6d7be3f92 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -396,6 +396,9 @@ DIAGNOSTIC(36110, Error, stageIsIncompatibleWithCapabilityDefinition, "'$0' is d
DIAGNOSTIC(36111, Error, unexpectedCapability, "'$0' resolves into a disallowed `$1` Capability.")
DIAGNOSTIC(36112, Warning, entryPointAndProfileAreIncompatible, "'$0' is defined for stage '$1', which is incompatible with the declared profile '$2'.")
DIAGNOSTIC(36113, Warning, usingInternalCapabilityName, "'$0' resolves into a '_Internal' `_$1' Capability, use '$1' instead.")
+DIAGNOSTIC(36114, Warning, incompatibleWithPrecompileLib, "Precompiled library requires '$0', has `$1`, implicitly upgrading capabilities.")
+DIAGNOSTIC(36115, Error, incompatibleWithPrecompileLibRestrictive, "Precompiled library requires '$0', has `$1`.")
+
// Attributes
DIAGNOSTIC(31000, Warning, unknownAttributeName, "unknown attribute '$0'")
diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h
index 07694b066..0e84be2b2 100644
--- a/source/slang/slang-ir-inst-defs.h
+++ b/source/slang/slang-ir-inst-defs.h
@@ -294,6 +294,7 @@ INST(Block, block, 0, PARENT)
INST(FloatLit, float_constant, 0, 0)
INST(PtrLit, ptr_constant, 0, 0)
INST(StringLit, string_constant, 0, 0)
+ INST(BlobLit, string_constant, 0, 0)
INST(VoidLit, void_constant, 0, 0)
INST_RANGE(Constant, BoolLit, VoidLit)
@@ -1205,6 +1206,9 @@ INST(DebugLine, DebugLine, 5, 0)
INST(DebugVar, DebugVar, 4, 0)
INST(DebugValue, DebugValue, 2, 0)
+/* Embedded Precompiled Libraries */
+INST(EmbeddedDXIL, EmbeddedDXIL, 1, 0)
+
/* Inline assembly */
INST(SPIRVAsm, SPIRVAsm, 0, PARENT)
diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h
index 795a79c28..8a801e4e7 100644
--- a/source/slang/slang-ir-insts.h
+++ b/source/slang/slang-ir-insts.h
@@ -3431,6 +3431,7 @@ public:
IRInst* getIntValue(IRType* type, IRIntegerValue value);
IRInst* getFloatValue(IRType* type, IRFloatingPointValue value);
IRStringLit* getStringValue(const UnownedStringSlice& slice);
+ IRBlobLit* getBlobValue(ISlangBlob* blob);
IRPtrLit* _getPtrValue(void* ptr);
IRPtrLit* getNullPtrValue(IRType* type);
IRPtrLit* getNullVoidPtrValue() { return getNullPtrValue(getPtrType(getVoidType())); }
@@ -3947,6 +3948,8 @@ public:
IRInst* emitByteAddressBufferStore(IRInst* byteAddressBuffer, IRInst* offset, IRInst* value);
IRInst* emitByteAddressBufferStore(IRInst* byteAddressBuffer, IRInst* offset, IRInst* alignment, IRInst* value);
+ IRInst* emitEmbeddedDXIL(ISlangBlob* blob);
+
IRFunc* createFunc();
IRGlobalVar* createGlobalVar(
IRType* valueType);
diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp
index 1fc15f185..bfd6c20cf 100644
--- a/source/slang/slang-ir.cpp
+++ b/source/slang/slang-ir.cpp
@@ -2059,7 +2059,7 @@ namespace Slang
UnownedStringSlice IRConstant::getStringSlice()
{
- assert(getOp() == kIROp_StringLit);
+ assert(getOp() == kIROp_StringLit || getOp() == kIROp_BlobLit);
// If the transitory decoration is set, then this is uses the transitoryStringVal for the text storage.
// This is typically used when we are using a transitory IRInst held on the stack (such that it can be looked up in cached),
// that just points to a string elsewhere, and NOT the typical normal style, where the string is held after the instruction in memory.
@@ -2133,6 +2133,7 @@ namespace Slang
{
return value.ptrVal == rhs->value.ptrVal;
}
+ case kIROp_BlobLit:
case kIROp_StringLit:
{
return getStringSlice() == rhs->getStringSlice();
@@ -2174,6 +2175,7 @@ namespace Slang
{
return combineHash(code, Slang::getHashCode(value.ptrVal));
}
+ case kIROp_BlobLit:
case kIROp_StringLit:
{
const UnownedStringSlice slice = getStringSlice();
@@ -2264,6 +2266,7 @@ namespace Slang
irValue->value.ptrVal = keyInst.value.ptrVal;
break;
}
+ case kIROp_BlobLit:
case kIROp_StringLit:
{
const UnownedStringSlice slice = keyInst.getStringSlice();
@@ -2387,6 +2390,36 @@ namespace Slang
return static_cast<IRStringLit*>(_findOrEmitConstant(keyInst));
}
+ IRBlobLit* IRBuilder::getBlobValue(ISlangBlob* blob)
+ {
+ IRConstant keyInst;
+ memset(&keyInst, 0, sizeof(keyInst));
+
+ char* buffer = (char*)(getModule()->getMemoryArena().allocate(blob->getBufferSize()));
+ if (!buffer)
+ {
+ return nullptr;
+ }
+ memcpy(buffer, blob->getBufferPointer(), blob->getBufferSize());
+
+ UnownedStringSlice inSlice(buffer, blob->getBufferSize());
+
+ // Mark that this is on the stack...
+ IRDecoration stackDecoration;
+ memset(&stackDecoration, 0, sizeof(stackDecoration));
+ stackDecoration.m_op = kIROp_TransitoryDecoration;
+ stackDecoration.insertAtEnd(&keyInst);
+
+ keyInst.m_op = kIROp_BlobLit;
+ keyInst.typeUse.usedValue = nullptr; // not used
+
+ IRConstant::StringSliceValue& dstSlice = keyInst.value.transitoryStringVal;
+ dstSlice.chars = const_cast<char*>(inSlice.begin());
+ dstSlice.numChars = uint32_t(inSlice.getLength());
+
+ return static_cast<IRBlobLit*>(_findOrEmitConstant(keyInst));
+ }
+
IRPtrLit* IRBuilder::_getPtrValue(void* data)
{
auto type = getPtrType(getVoidType());
@@ -3800,6 +3833,13 @@ namespace Slang
return nullptr;
}
+ IRInst* IRBuilder::emitEmbeddedDXIL(ISlangBlob *blob)
+ {
+ IRInst* args[] = { getBlobValue(blob) };
+
+ return emitIntrinsicInst(getVoidType(), kIROp_EmbeddedDXIL, 1, args);
+ }
+
enum class TypeCastStyle
{
Unknown = -1,
@@ -7098,6 +7138,10 @@ namespace Slang
dump(context, irConst->value.intVal ? "true" : "false");
return;
+ case kIROp_BlobLit:
+ dump(context, "<binary blob>");
+ return;
+
case kIROp_StringLit:
dumpEncodeString(context, irConst->getStringSlice());
return;
diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h
index cb8e83df8..719b383c3 100644
--- a/source/slang/slang-ir.h
+++ b/source/slang/slang-ir.h
@@ -1157,6 +1157,11 @@ struct IRStringLit : IRConstant
IR_LEAF_ISA(StringLit);
};
+struct IRBlobLit : IRConstant
+{
+ IR_LEAF_ISA(BlobLit);
+};
+
struct IRPtrLit : IRConstant
{
IR_LEAF_ISA(PtrLit);
@@ -2340,6 +2345,9 @@ public:
{
return m_containerPool;
}
+
+ // TODO: make a map with lookup by target?
+ ComPtr<ISlangBlob> precompiledDXIL;
private:
IRModule() = delete;
diff --git a/source/slang/slang-module-library.cpp b/source/slang/slang-module-library.cpp
index 02ace07d3..42b9ff77a 100644
--- a/source/slang/slang-module-library.cpp
+++ b/source/slang/slang-module-library.cpp
@@ -83,6 +83,15 @@ SlangResult loadModuleLibrary(const Byte* inBytes, size_t bytesCount, String pat
module, &sink);
if (!loadedModule)
return SLANG_FAIL;
+
+ for (auto inst : module.irModule->getModuleInst()->getChildren())
+ {
+ if (inst->getOp() == kIROp_EmbeddedDXIL)
+ {
+ auto slice = static_cast<IRBlobLit*>(inst->getOperand(0))->getStringSlice();
+ module.irModule->precompiledDXIL = StringBlob::create(slice);
+ }
+ }
library->m_modules.add(loadedModule);
}
}
diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp
index c3a0eeddc..33103442d 100644
--- a/source/slang/slang-options.cpp
+++ b/source/slang/slang-options.cpp
@@ -353,7 +353,9 @@ void initCommandOptions(CommandOptions& options)
"The language to be used for source embedding. Defaults to C/C++. Currently only C/C++ are supported"},
{ OptionKind::DisableShortCircuit, "-disable-short-circuit", nullptr, "Disable short-circuiting for \"&&\" and \"||\" operations" },
{ OptionKind::UnscopedEnum, "-unscoped-enum", nullptr, "Treat enums types as unscoped by default."},
- { OptionKind::PreserveParameters, "-preserve-params", nullptr, "Preserve all resource parameters in the output code, even if they are not used by the shader."}
+ { OptionKind::PreserveParameters, "-preserve-params", nullptr, "Preserve all resource parameters in the output code, even if they are not used by the shader."},
+ { OptionKind::EmbedDXIL, "-embed-dxil", nullptr,
+ "Embed DXIL into emitted slang-modules for faster linking" },
};
_addOptions(makeConstArrayView(generalOpts), options);
@@ -426,7 +428,6 @@ void initCommandOptions(CommandOptions& options)
"A path to a specific spirv.core.grammar.json to use when generating SPIR-V output" },
{ OptionKind::IncompleteLibrary, "-incomplete-library", nullptr,
"Allow generating code from incomplete libraries with unresolved external functions" },
-
};
_addOptions(makeConstArrayView(targetOpts), options);
@@ -699,6 +700,8 @@ struct OptionsParser
void setProfileVersion(RawTarget* rawTarget, ProfileVersion profileVersion);
void setProfile(RawTarget* rawTarget, Profile profile);
void addCapabilityAtom(RawTarget* rawTarget, CapabilityName atom);
+
+ SlangResult addEmbeddedLibrary(const CodeGenTarget format, CompilerOptionName option);
void setFloatingPointMode(RawTarget* rawTarget, FloatingPointMode mode);
@@ -1636,6 +1639,23 @@ SlangResult OptionsParser::_parseProfile(const CommandLineArg& arg)
return SLANG_OK;
}
+// Creates a target of the specified type whose output will be embedded as IR metadata
+SlangResult OptionsParser::addEmbeddedLibrary(const CodeGenTarget format, CompilerOptionName option)
+{
+ RawTarget rawTarget;
+ rawTarget.format = format;
+ // Silently allow redundant targets if it is the same as the last specified target.
+ if (m_rawTargets.getCount() == 0 || m_rawTargets.getLast().format != rawTarget.format)
+ {
+ m_rawTargets.add(rawTarget);
+ }
+
+ getCurrentTarget()->optionSet.add(option, true);
+ getCurrentTarget()->optionSet.add(CompilerOptionName::GenerateWholeProgram, true);
+
+ return SLANG_OK;
+}
+
SlangResult OptionsParser::_parse(
int argc,
char const* const* argv)
@@ -1927,6 +1947,7 @@ SlangResult OptionsParser::_parse(
linkage->m_optionSet.set(optionKind, compressionType);
break;
}
+ case OptionKind::EmbedDXIL: SLANG_RETURN_ON_FAIL(addEmbeddedLibrary(CodeGenTarget::DXIL, CompilerOptionName::EmbedDXIL)); break;
case OptionKind::Target:
{
CommandLineArg name;
@@ -2758,6 +2779,16 @@ SlangResult OptionsParser::_parse(
{
m_compileRequest->setTargetForceGLSLScalarBufferLayout(targetID, true);
}
+
+ if (rawTarget.optionSet.getBoolOption(CompilerOptionName::GenerateWholeProgram))
+ {
+ m_compileRequest->setTargetGenerateWholeProgram(targetID, true);
+ }
+
+ if (rawTarget.optionSet.getBoolOption(CompilerOptionName::EmbedDXIL))
+ {
+ m_compileRequest->setTargetEmbedDXIL(targetID, true);
+ }
}
// Next we need to sort out the output files specified with `-o`, and
diff --git a/source/slang/slang-serialize-container.cpp b/source/slang/slang-serialize-container.cpp
index 50b9061e3..2229c74ea 100644
--- a/source/slang/slang-serialize-container.cpp
+++ b/source/slang/slang-serialize-container.cpp
@@ -348,6 +348,12 @@ namespace Slang {
}
}
+ // TODO:
+ // Serialization of target component IR is causing the embedded precompiled binary
+ // feature to fail. The resulting data modules contain both TU IR and TC IR, with only
+ // one module header. Yong suggested to ignore the TC IR for now, though also that
+ // OV was using the feature, so disabling this might cause problems.
+#if 0
if (data.targetComponents.getCount() && (options.optionFlags & SerialOptionFlag::IRModule))
{
// TODO: in the case where we have specialization, we might need
@@ -365,6 +371,7 @@ namespace Slang {
SLANG_RETURN_ON_FAIL(IRSerialWriter::writeContainer(serialData, options.compressionType, container));
}
}
+#endif
}
if (data.entryPoints.getCount())
diff --git a/source/slang/slang-serialize-ir.cpp b/source/slang/slang-serialize-ir.cpp
index ccd5a2e7d..a2d05fc5b 100644
--- a/source/slang/slang-serialize-ir.cpp
+++ b/source/slang/slang-serialize-ir.cpp
@@ -195,6 +195,14 @@ Result IRSerialWriter::write(IRModule* module, SerialSourceLocWriter* sourceLocW
switch (srcInst->getOp())
{
// Special handling for the ir const derived types
+ case kIROp_BlobLit:
+ {
+ // Blobs are serialized into string table like strings
+ auto stringLit = static_cast<IRBlobLit*>(srcInst);
+ dstInst.m_payloadType = PayloadType::String_1;
+ dstInst.m_payload.m_stringIndices[0] = getStringIndex(stringLit->getStringSlice());
+ break;
+ }
case kIROp_StringLit:
{
auto stringLit = static_cast<IRStringLit*>(srcInst);
@@ -790,6 +798,7 @@ Result IRSerialReader::read(const IRSerialData& data, Session* session, SerialSo
op, operandCount, prefixSize));
break;
}
+ case kIROp_BlobLit:
case kIROp_StringLit:
{
SLANG_ASSERT(srcInst.m_payloadType == PayloadType::String_1);
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index 6f5e79458..cf8c19033 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -3149,6 +3149,24 @@ SlangResult EndToEndCompileRequest::executeActionsInner()
return SLANG_OK;
}
+ // If requested, attempt to compile the translation unit all the way down to the target language
+ // and stash the result blob in an IR op.
+ for (auto targetReq : getLinkage()->targets)
+ {
+ if (targetReq->getOptionSet().getBoolOption(CompilerOptionName::EmbedDXIL))
+ {
+ auto frontEndReq = getFrontEndReq();
+
+ for (auto translationUnit : frontEndReq->translationUnits)
+ {
+ translationUnit->getModule()->precompileForTargets(
+ getSink(),
+ this,
+ targetReq);
+ }
+ }
+ }
+
// If codegen is enabled, we need to move along to
// apply any generic specialization that the user asked for.
//
@@ -5758,6 +5776,16 @@ void EndToEndCompileRequest::setTargetMatrixLayoutMode(int targetIndex, SlangMat
getTargetOptionSet(targetIndex).setMatrixLayoutMode(MatrixLayoutMode(mode));
}
+void EndToEndCompileRequest::setTargetGenerateWholeProgram(int targetIndex, bool value)
+{
+ getTargetOptionSet(targetIndex).set(CompilerOptionName::GenerateWholeProgram, value);
+}
+
+void EndToEndCompileRequest::setTargetEmbedDXIL(int targetIndex, bool value)
+{
+ getTargetOptionSet(targetIndex).set(CompilerOptionName::EmbedDXIL, value);
+}
+
void EndToEndCompileRequest::setTargetLineDirectiveMode(
SlangInt targetIndex,
SlangLineDirectiveMode mode)