diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/compiler-core/slang-dxc-compiler.cpp | 112 | ||||
| -rw-r--r-- | source/slang/slang-capabilities.capdef | 2 | ||||
| -rw-r--r-- | source/slang/slang-compiler-tu.cpp | 115 | ||||
| -rw-r--r-- | source/slang/slang-compiler.cpp | 59 | ||||
| -rwxr-xr-x | source/slang/slang-compiler.h | 14 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 3 | ||||
| -rw-r--r-- | source/slang/slang-ir-inst-defs.h | 4 | ||||
| -rw-r--r-- | source/slang/slang-ir-insts.h | 3 | ||||
| -rw-r--r-- | source/slang/slang-ir.cpp | 46 | ||||
| -rw-r--r-- | source/slang/slang-ir.h | 8 | ||||
| -rw-r--r-- | source/slang/slang-module-library.cpp | 9 | ||||
| -rw-r--r-- | source/slang/slang-options.cpp | 35 | ||||
| -rw-r--r-- | source/slang/slang-serialize-container.cpp | 7 | ||||
| -rw-r--r-- | source/slang/slang-serialize-ir.cpp | 9 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 28 |
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) |
