diff --git a/include/slang.h b/include/slang.h index 7c417e74e0..ed29665925 100644 --- a/include/slang.h +++ b/include/slang.h @@ -4929,9 +4929,7 @@ namespace slang int targetIndex, bool value) = 0; - virtual SLANG_NO_THROW void SLANG_MCALL setTargetEmbedDXIL( - int targetIndex, - bool value) = 0; + virtual SLANG_NO_THROW void SLANG_MCALL setEmbedDXIL(bool value) = 0; virtual SLANG_NO_THROW void SLANG_MCALL setTargetForceDXLayout(int targetIndex, bool value) = 0; }; diff --git a/source/compiler-core/slang-artifact-associated-impl.cpp b/source/compiler-core/slang-artifact-associated-impl.cpp index f6f64e294d..f29c0f596f 100644 --- a/source/compiler-core/slang-artifact-associated-impl.cpp +++ b/source/compiler-core/slang-artifact-associated-impl.cpp @@ -308,4 +308,9 @@ Slice ArtifactPostEmitMetadata::getUsedBindingRanges() return Slice(m_usedBindings.getBuffer(), m_usedBindings.getCount()); } +Slice ArtifactPostEmitMetadata::getExportedFunctionMangledNames() +{ + return Slice(m_exportedFunctionMangledNames.getBuffer(), m_exportedFunctionMangledNames.getCount()); +} + } // namespace Slang diff --git a/source/compiler-core/slang-artifact-associated-impl.h b/source/compiler-core/slang-artifact-associated-impl.h index 5144fe7a7e..a6e323b0a1 100644 --- a/source/compiler-core/slang-artifact-associated-impl.h +++ b/source/compiler-core/slang-artifact-associated-impl.h @@ -155,13 +155,15 @@ class ArtifactPostEmitMetadata : public ComBaseObject, public IArtifactPostEmitM // IArtifactPostEmitMetadata SLANG_NO_THROW virtual Slice SLANG_MCALL getUsedBindingRanges() SLANG_OVERRIDE; - + SLANG_NO_THROW virtual Slice SLANG_MCALL getExportedFunctionMangledNames() SLANG_OVERRIDE; + void* getInterface(const Guid& uuid); void* getObject(const Guid& uuid); static ComPtr create() { return ComPtr(new ThisType); } List m_usedBindings; + List m_exportedFunctionMangledNames; }; } // namespace Slang diff --git a/source/compiler-core/slang-artifact-associated.h b/source/compiler-core/slang-artifact-associated.h index f63b8a6730..7664942713 100644 --- a/source/compiler-core/slang-artifact-associated.h +++ b/source/compiler-core/slang-artifact-associated.h @@ -124,6 +124,9 @@ class IArtifactPostEmitMetadata : public ICastable /// Get the binding ranges SLANG_NO_THROW virtual Slice SLANG_MCALL getUsedBindingRanges() = 0; + + /// Get the list of functions that were exported in the linked IR + SLANG_NO_THROW virtual Slice SLANG_MCALL getExportedFunctionMangledNames() = 0; }; } // namespace Slang diff --git a/source/slang/slang-compiler-tu.cpp b/source/slang/slang-compiler-tu.cpp index d4f3976a63..fe778148bb 100644 --- a/source/slang/slang-compiler-tu.cpp +++ b/source/slang/slang-compiler-tu.cpp @@ -4,10 +4,91 @@ #include "../core/slang-basic.h" #include "slang-compiler.h" #include "slang-ir-insts.h" +#include "slang-ir-util.h" #include "slang-capability.h" namespace Slang { + // Only attempt to precompile functions: + // 1) With function bodies (not just empty decls) + // 2) Not marked with unsafeForceInlineDecoration + // 3) Have a simple HLSL data type as the return or parameter type + static bool attemptPrecompiledExport(IRInst* inst) + { + if (inst->getOp() != kIROp_Func) + { + return false; + } + + // Skip functions with no body + bool hasBody = false; + for (auto child : inst->getChildren()) + { + if (child->getOp() == kIROp_Block) + { + hasBody = true; + break; + } + } + if (!hasBody) + { + return false; + } + + // Skip functions marked with unsafeForceInlineDecoration + if (inst->findDecoration()) + { + return false; + } + + // Skip non-simple HLSL data types, filters out generics + if (!isSimpleHLSLDataType(inst)) + { + return false; + } + + return true; + } + + /* + * Precompile the module for the given target. + * + * This function creates a target program and emits the precompiled blob as + * an embedded blob in the module IR, e.g. DXIL. + * Because the IR for the Slang Module may violate the restrictions of the + * target language, the emitted target blob may not be able to include the + * full module, but rather only the subset that can be precompiled. For + * example, DXIL libraries do not allow resources like structured buffers + * to appear in the library interface. Also, no target languages allow + * generics to be precompiled. + * + * Some restrictions can be enforced up front before linking, but some are + * done during target generation in between IR linking+legalization and + * target source emission. + * + * Functions which can be rejected up front: + * - Functions with no body + * - Functions marked with unsafeForceInlineDecoration + * - Functions that define or use generics + * + * The functions not rejected up front are marked with + * DownstreamModuleExportDecoration which indicates functions we're trying to + * export for precompilation, and this also helps to identify the functions + * in the linked IR which survived the additional pruning. + * + * Functions that are rejected after linking+legalization (inside + * emitPrecompiled*): + * - (DXIL) Functions that return or take a HLSLStructuredBufferType + * - (DXIL) Functions that return or take a Matrix type + * + * emitPrecompiled* produces the output artifact containing target language + * blob, and as metadata, the list of functions which survived the second + * phase of filtering. + * + * The original module IR functions matching those are then marked with + * "AvailableIn*" (e.g. AvailableInDXILDecoration) to indicate to future + * module users which functions are present in the precompiled blob. + */ SLANG_NO_THROW SlangResult SLANG_MCALL Module::precompileForTarget( SlangCompileTarget target, slang::IBlob** outDiagnostics) @@ -20,6 +101,7 @@ namespace Slang auto module = getIRModule(); auto linkage = getLinkage(); + auto builder = IRBuilder(module); DiagnosticSink sink(linkage->getSourceManager(), Lexer::sourceLocationLexer); applySettingsToDiagnosticSink(&sink, &sink, linkage->m_optionSet); @@ -48,6 +130,7 @@ namespace Slang { case CodeGenTarget::DXIL: tp.getOptionSet().add(CompilerOptionName::Profile, Profile::RawEnum::DX_Lib_6_6); + tp.getOptionSet().add(CompilerOptionName::EmbedDXIL, true); break; } @@ -59,20 +142,69 @@ namespace Slang CodeGenContext::Shared sharedCodeGenContext(&tp, entryPointIndices, &sink, nullptr); CodeGenContext codeGenContext(&sharedCodeGenContext); + // Mark all public functions as exported, ensure there's at least one. Store a mapping + // of function name to IRInst* for later reference. After linking is done, we'll scan + // the linked result to see which functions survived the pruning and are included in the + // precompiled blob. + Dictionary nameToFunction; + bool hasAtLeastOneFunction = false; + for (auto inst : module->getGlobalInsts()) + { + if (attemptPrecompiledExport(inst)) + { + hasAtLeastOneFunction = true; + builder.addDecoration(inst, kIROp_DownstreamModuleExportDecoration); + nameToFunction[inst->findDecoration()->getMangledName()] = inst; + } + } + + // Bail if there are no functions to export. That's not treated as an error + // because it's possible that the module just doesn't have any simple HLSL. + if (!hasAtLeastOneFunction) + { + return SLANG_OK; + } + ComPtr outArtifact; - SlangResult res = codeGenContext.emitTranslationUnit(outArtifact); + SlangResult res = codeGenContext.emitPrecompiledDXIL(outArtifact); sink.getBlobIfNeeded(outDiagnostics); - if (res != SLANG_OK) { return res; } + auto metadata = findAssociatedRepresentation(outArtifact); + if (!metadata) + { + return SLANG_E_NOT_AVAILABLE; + } + + for (const auto& mangledName : metadata->getExportedFunctionMangledNames()) + { + auto moduleInst = nameToFunction[mangledName]; + builder.addDecoration(moduleInst, kIROp_AvailableInDXILDecoration); + auto moduleDec = moduleInst->findDecoration(); + moduleDec->removeAndDeallocate(); + } + + // Finally, clean up the transient export decorations left over in the module. These are + // represent functions that were pruned from the IR after linking, before target generation. + for (auto moduleInst : module->getGlobalInsts()) + { + if (moduleInst->getOp() == kIROp_Func) + { + if (auto dec = moduleInst->findDecoration()) + { + dec->removeAndDeallocate(); + } + } + } + ISlangBlob* blob; outArtifact->loadBlob(ArtifactKeep::Yes, &blob); - auto builder = IRBuilder(module); + // Add the precompiled blob to the module builder.setInsertInto(module); switch (targetReq->getTarget()) diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp index 428532658c..a5a09204bc 100644 --- a/source/slang/slang-compiler.cpp +++ b/source/slang/slang-compiler.cpp @@ -350,7 +350,7 @@ namespace Slang Profile Profile::lookUp(UnownedStringSlice const& name) { #define PROFILE(TAG, NAME, STAGE, VERSION) if(name == UnownedTerminatedStringSlice(#NAME)) return Profile::TAG; - #define PROFILE_ALIAS(TAG, DEF, NAME) if(name == UnownedTerminatedStringSlice(#NAME)) return Profile::TAG; + #define PROFILE_ALIAS(TAG, DEF, NAME) if(name == UnownedTerminatedStringSlice(#NAME)) return Profile::TAG; #include "slang-profile-defs.h" return Profile::Unknown; @@ -767,7 +767,7 @@ namespace Slang # pragma warning(pop) #endif - SlangResult CodeGenContext::emitTranslationUnit(ComPtr& outArtifact) + SlangResult CodeGenContext::emitPrecompiledDXIL(ComPtr& outArtifact) { return emitWithDownstreamForEntryPoints(outArtifact); } @@ -1094,23 +1094,6 @@ 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& outArtifact) { outArtifact.setNull(); @@ -1272,15 +1255,17 @@ namespace Slang } else { - if (!isPrecompiled()) + CodeGenContext sourceCodeGenContext(this, sourceTarget, extensionTracker); + + if (target == CodeGenTarget::DXILAssembly || target == CodeGenTarget::DXIL) { - CodeGenContext sourceCodeGenContext(this, sourceTarget, extensionTracker); + sourceCodeGenContext.removeAvailableInDXIL = true; + } - 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) @@ -1571,24 +1556,29 @@ namespace Slang libraries.addRange(linkage->m_libModules.getBuffer(), linkage->m_libModules.getCount()); } - if (isPrecompiled()) + auto program = getProgram(); + + // Load embedded precompiled libraries from IR into library artifacts + program->enumerateIRModules([&](IRModule* irModule) { - auto program = getProgram(); - program->enumerateIRModules([&](IRModule* irModule) + for (auto inst : irModule->getModuleInst()->getChildren()) + { + if (target == CodeGenTarget::DXILAssembly || target == CodeGenTarget::DXIL) { - // TODO: conditionalize on target - if (irModule->precompiledDXIL) + if (inst->getOp() == kIROp_EmbeddedDXIL) { + auto slice = static_cast(inst->getOperand(0))->getStringSlice(); ArtifactDesc desc = ArtifactDescUtil::makeDescForCompileTarget(SLANG_DXIL); desc.kind = ArtifactKind::Library; auto library = ArtifactUtil::createArtifact(desc); - library->addRepresentationUnknown(irModule->precompiledDXIL); + library->addRepresentationUnknown(StringBlob::create(slice)); libraries.add(library); } - }); - } + } + } + }); options.compilerSpecificArguments = allocator.allocate(compilerSpecificArguments); options.requiredCapabilityVersions = SliceUtil::asSlice(requiredCapabilityVersions); diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index 9d796f48d6..54f43b382f 100755 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -555,7 +555,6 @@ namespace Slang /// and parsing via Slang reflection, and is not recommended for future APIs to use. /// Scope* _getOrCreateScopeForLegacyLookup(ASTBuilder* astBuilder); - protected: ComponentType(Linkage* linkage); @@ -2732,10 +2731,14 @@ namespace Slang SlangResult emitEntryPoints(ComPtr& outArtifact); - SlangResult emitTranslationUnit(ComPtr& outArtifact); + SlangResult emitPrecompiledDXIL(ComPtr& outArtifact); void maybeDumpIntermediate(IArtifact* artifact); + // Used to cause instructions available in precompiled DXIL to be + // removed between IR linking and target source generation. + bool removeAvailableInDXIL = false; + protected: CodeGenTarget m_targetFormat = CodeGenTarget::Unknown; ExtensionTracker* m_extensionTracker = nullptr; @@ -2772,11 +2775,6 @@ namespace Slang SlangResult _emitEntryPoints(ComPtr& 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; }; @@ -2816,7 +2814,7 @@ namespace Slang virtual SLANG_NO_THROW void SLANG_MCALL setTargetForceGLSLScalarBufferLayout(int targetIndex, bool value) SLANG_OVERRIDE; virtual SLANG_NO_THROW void SLANG_MCALL setTargetForceDXLayout(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 setEmbedDXIL(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-emit.cpp b/source/slang/slang-emit.cpp index 103cd15ab4..caa8ca8eae 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -58,6 +58,7 @@ #include "slang-ir-metadata.h" #include "slang-ir-optix-entry-point-uniforms.h" #include "slang-ir-pytorch-cpp-binding.h" +#include "slang-ir-redundancy-removal.h" #include "slang-ir-restructure.h" #include "slang-ir-restructure-scoping.h" #include "slang-ir-sccp.h" @@ -415,6 +416,37 @@ bool checkStaticAssert(IRInst* inst, DiagnosticSink* sink) return false; } +static void unexportNonEmbeddableDXIL(IRModule* irModule) +{ + for (auto inst : irModule->getGlobalInsts()) + { + if (inst->getOp() == kIROp_Func) + { + // DXIL does not permit HLSLStructureBufferType in exported functions + // or sadly Matrices (https://github.com/shader-slang/slang/issues/4880) + auto type = as(inst->getFullType()); + auto argCount = type->getOperandCount(); + for (UInt aa = 0; aa < argCount; ++aa) + { + auto operand = type->getOperand(aa); + if (operand->getOp() == kIROp_HLSLStructuredBufferType || + operand->getOp() == kIROp_MatrixType) + { + if (auto dec = inst->findDecoration()) + { + dec->removeAndDeallocate(); + } + if (auto dec = inst->findDecoration()) + { + dec->removeAndDeallocate(); + } + break; + } + } + } + } +} + Result linkAndOptimizeIR( CodeGenContext* codeGenContext, LinkingAndOptimizationOptions const& options, @@ -746,6 +778,11 @@ Result linkAndOptimizeIR( break; } + if (codeGenContext->removeAvailableInDXIL) + { + removeAvailableInDownstreamModuleDecorations(irModule); + } + if (targetProgram->getOptionSet().shouldRunNonEssentialValidation()) { checkForRecursiveTypes(irModule, sink); @@ -1453,6 +1490,13 @@ Result linkAndOptimizeIR( auto metadata = new ArtifactPostEmitMetadata; outLinkedIR.metadata = metadata; + if (targetProgram->getOptionSet().getBoolOption(CompilerOptionName::EmbedDXIL)) + { + // We need to make sure that we don't try to export any functions that can't + // be part of a DXIL library interface, eg. with resources. + unexportNonEmbeddableDXIL(irModule); + } + collectMetadata(irModule, *metadata); outLinkedIR.metadata = metadata; diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h index eb4e88c41f..09cb7952c8 100644 --- a/source/slang/slang-ir-inst-defs.h +++ b/source/slang/slang-ir-inst-defs.h @@ -790,6 +790,7 @@ INST_RANGE(BindingQuery, GetRegisterIndex, GetRegisterSpace) INST(PreciseDecoration, precise, 0, 0) INST(PublicDecoration, public, 0, 0) INST(HLSLExportDecoration, hlslExport, 0, 0) + INST(DownstreamModuleExportDecoration, downstreamModuleExport, 0, 0) INST(PatchConstantFuncDecoration, patchConstantFunc, 1, 0) INST(OutputControlPointsDecoration, outputControlPoints, 1, 0) INST(OutputTopologyDecoration, outputTopology, 1, 0) @@ -800,6 +801,8 @@ INST_RANGE(BindingQuery, GetRegisterIndex, GetRegisterSpace) INST(NumThreadsDecoration, numThreads, 3, 0) INST(WaveSizeDecoration, waveSize, 1, 0) + INST(AvailableInDXILDecoration, availableInDXIL, 0, 0) + // Added to IRParam parameters to an entry point /* GeometryInputPrimitiveTypeDecoration */ INST(PointInputPrimitiveTypeDecoration, pointPrimitiveType, 0, 0) diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h index f8836219e8..9b94005d99 100644 --- a/source/slang/slang-ir-insts.h +++ b/source/slang/slang-ir-insts.h @@ -430,6 +430,8 @@ IR_SIMPLE_DECORATION(NonCopyableTypeDecoration) IR_SIMPLE_DECORATION(HLSLMeshPayloadDecoration) IR_SIMPLE_DECORATION(GlobalInputDecoration) IR_SIMPLE_DECORATION(GlobalOutputDecoration) +IR_SIMPLE_DECORATION(AvailableInDXILDecoration) +IR_SIMPLE_DECORATION(DownstreamModuleExportDecoration) struct IRGLSLLocationDecoration : IRDecoration { diff --git a/source/slang/slang-ir-link.cpp b/source/slang/slang-ir-link.cpp index 8b08b9045c..94ba75a446 100644 --- a/source/slang/slang-ir-link.cpp +++ b/source/slang/slang-ir-link.cpp @@ -1461,7 +1461,7 @@ static bool _isHLSLExported(IRInst* inst) for (auto decoration : inst->getDecorations()) { const auto op = decoration->getOp(); - if (op == kIROp_HLSLExportDecoration) + if (op == kIROp_HLSLExportDecoration || op == kIROp_DownstreamModuleExportDecoration) { return true; } diff --git a/source/slang/slang-ir-metadata.cpp b/source/slang/slang-ir-metadata.cpp index 641c272a20..030fde1571 100644 --- a/source/slang/slang-ir-metadata.cpp +++ b/source/slang/slang-ir-metadata.cpp @@ -42,8 +42,18 @@ static void _insertBinding(List& ranges, LayoutResourceKind void collectMetadata(const IRModule* irModule, ArtifactPostEmitMetadata& outMetadata) { // Scan the instructions looking for global resource declarations + // and exported functions. for (const auto& inst : irModule->getGlobalInsts()) { + if (auto func = as(inst)) + { + if (func->findDecoration()) + { + auto name = func->findDecoration()->getMangledName(); + outMetadata.m_exportedFunctionMangledNames.add(name); + } + } + auto param = as(inst); if (!param) continue; diff --git a/source/slang/slang-ir-redundancy-removal.cpp b/source/slang/slang-ir-redundancy-removal.cpp index fa3cd444a8..038412fbfa 100644 --- a/source/slang/slang-ir-redundancy-removal.cpp +++ b/source/slang/slang-ir-redundancy-removal.cpp @@ -159,6 +159,36 @@ bool removeRedundancyInFunc(IRGlobalValueWithCode* func) return result; } +// Remove IR definitions from all [AvailableInDXIL] functions when compiling DXIL, +// as these functions are already defined in the embedded precompiled DXIL library. +void removeAvailableInDownstreamModuleDecorations(IRModule* module) +{ + List toRemove; + for (auto globalInst : module->getGlobalInsts()) + { + auto funcInst = as(globalInst); + if (!funcInst) + { + continue; + } + if (globalInst->findDecoration()) + { + // Gut the function definition, turning it into a declaration + for (auto inst : funcInst->getChildren()) + { + if (inst->getOp() == kIROp_Block) + { + toRemove.add(inst); + } + } + } + } + for (auto inst : toRemove) + { + inst->removeAndDeallocate(); + } +} + static IRInst* _getRootVar(IRInst* inst) { while (inst) diff --git a/source/slang/slang-ir-redundancy-removal.h b/source/slang/slang-ir-redundancy-removal.h index c2df7853e8..117f52708a 100644 --- a/source/slang/slang-ir-redundancy-removal.h +++ b/source/slang/slang-ir-redundancy-removal.h @@ -10,4 +10,6 @@ namespace Slang bool removeRedundancyInFunc(IRGlobalValueWithCode* func); bool eliminateRedundantLoadStore(IRGlobalValueWithCode* func); + + void removeAvailableInDownstreamModuleDecorations(IRModule* module); } diff --git a/source/slang/slang-ir-util.cpp b/source/slang/slang-ir-util.cpp index 817c10ec21..c4fc60bd22 100644 --- a/source/slang/slang-ir-util.cpp +++ b/source/slang/slang-ir-util.cpp @@ -244,6 +244,14 @@ bool isSimpleDataType(IRType* type) } } +bool isSimpleHLSLDataType(IRInst* inst) +{ + // TODO: Add criteria + // https://github.com/shader-slang/slang/issues/4792 + SLANG_UNUSED(inst); + return true; +} + SourceLoc findFirstUseLoc(IRInst* inst) { for (auto use = inst->firstUse; use; use = use->nextUse) diff --git a/source/slang/slang-ir-util.h b/source/slang/slang-ir-util.h index c7d6a15441..78d24d4411 100644 --- a/source/slang/slang-ir-util.h +++ b/source/slang/slang-ir-util.h @@ -99,6 +99,8 @@ bool isValueType(IRInst* type); bool isSimpleDataType(IRType* type); +bool isSimpleHLSLDataType(IRInst* inst); + SourceLoc findFirstUseLoc(IRInst* inst); inline bool isChildInstOf(IRInst* inst, IRInst* parent) diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h index 99c62b214f..375107d1d4 100644 --- a/source/slang/slang-ir.h +++ b/source/slang/slang-ir.h @@ -2389,9 +2389,6 @@ struct IRModule : RefObject { return m_containerPool; } - - // TODO: make a map with lookup by target? - ComPtr precompiledDXIL; private: IRModule() = delete; diff --git a/source/slang/slang-module-library.cpp b/source/slang/slang-module-library.cpp index 42b9ff77a8..02ace07d3c 100644 --- a/source/slang/slang-module-library.cpp +++ b/source/slang/slang-module-library.cpp @@ -83,15 +83,6 @@ 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(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 12b32998f4..cf0dd2f20a 100644 --- a/source/slang/slang-options.cpp +++ b/source/slang/slang-options.cpp @@ -702,8 +702,6 @@ struct OptionsParser 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); SlangResult parse( @@ -1640,23 +1638,6 @@ 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) @@ -1948,7 +1929,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::EmbedDXIL: m_compileRequest->setEmbedDXIL(true); break; case OptionKind::Target: { CommandLineArg name; @@ -2795,11 +2776,6 @@ SlangResult OptionsParser::_parse( { 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.cpp b/source/slang/slang.cpp index 23e25249d7..4a6d33363b 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -3300,19 +3300,16 @@ SlangResult EndToEndCompileRequest::executeActionsInner() // 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 (getOptionSet().getBoolOption(CompilerOptionName::EmbedDXIL)) { - if (targetReq->getOptionSet().getBoolOption(CompilerOptionName::EmbedDXIL)) - { - auto frontEndReq = getFrontEndReq(); + auto frontEndReq = getFrontEndReq(); - for (auto translationUnit : frontEndReq->translationUnits) - { - SlangCompileTarget target = SlangCompileTarget(targetReq->getTarget()); - translationUnit->getModule()->precompileForTarget( - target, - nullptr); - } + for (auto translationUnit : frontEndReq->translationUnits) + { + SlangCompileTarget target = SlangCompileTarget(SlangCompileTarget::SLANG_DXIL); + SLANG_RETURN_ON_FAIL(translationUnit->getModule()->precompileForTarget( + target, + nullptr)); } } @@ -5935,9 +5932,9 @@ void EndToEndCompileRequest::setTargetGenerateWholeProgram(int targetIndex, bool getTargetOptionSet(targetIndex).set(CompilerOptionName::GenerateWholeProgram, value); } -void EndToEndCompileRequest::setTargetEmbedDXIL(int targetIndex, bool value) +void EndToEndCompileRequest::setEmbedDXIL(bool value) { - getTargetOptionSet(targetIndex).set(CompilerOptionName::EmbedDXIL, value); + getOptionSet().set(CompilerOptionName::EmbedDXIL, value); } void EndToEndCompileRequest::setTargetLineDirectiveMode( @@ -6861,4 +6858,4 @@ SlangResult EndToEndCompileRequest::isParameterLocationUsed(Int entryPointIndex, return SLANG_OK; } -} // namespace Slang \ No newline at end of file +} // namespace Slang diff --git a/tests/library/export-library-generics.slang b/tests/library/export-library-generics.slang new file mode 100644 index 0000000000..f88541da33 --- /dev/null +++ b/tests/library/export-library-generics.slang @@ -0,0 +1,39 @@ +//TEST_IGNORE_FILE: + +// export-library-generics.slang + +module "export-library-generics"; + +public cbuffer Constants { + public float x; + public float y; +} + +interface MyInterface +{ + int myMethod(int a); +} + +struct MyType : MyInterface +{ + int myMethod(int a) + { + return a * 3; + } +} + +int genericFunc(T arg) +{ + return arg.myMethod(3); +} + +public int normalFuncUsesGeneric(int a) +{ + MyType obj; + return genericFunc(obj); +} + +public int normalFunc(int a) +{ + return a - 2; +} diff --git a/tests/library/module-library-matrix.slang b/tests/library/module-library-matrix.slang new file mode 100644 index 0000000000..85e4685cc9 --- /dev/null +++ b/tests/library/module-library-matrix.slang @@ -0,0 +1,8 @@ +//TEST_IGNORE_FILE: + +module "module-library-matrix"; + +public float4x4 to4x4(float3x4 source) +{ + return float4x4(source[0], source[1], source[2], float4(0.0f, 0.0f, 0.0f, 1.0f)); +} diff --git a/tests/library/precompiled-dxil-generics.slang b/tests/library/precompiled-dxil-generics.slang new file mode 100644 index 0000000000..f01291a8ee --- /dev/null +++ b/tests/library/precompiled-dxil-generics.slang @@ -0,0 +1,28 @@ +// precompiled-dxil-generics.slang + +// A test that uses slang-modules with embedded precompiled DXIL and a library containing generics. +// The test compiles a library slang (export-library-generics.slang) with -embed-dxil then links the +// library to entrypoint slang (this file). +// The test passes if there is no errror thrown. +// TODO: Check if final linkage used only the precompiled dxil. + +//TEST(windows):COMPILE: tests/library/export-library-generics.slang -o tests/library/export-library-generics.slang-module -embed-dxil -profile lib_6_6 -incomplete-library +//TEST(windows):COMPILE: tests/library/precompiled-dxil-generics.slang -target dxil -stage anyhit -entry anyhit -o tests/library/linked.dxil + +import "export-library-generics"; + +struct Payload +{ + int val; +} + +struct Attributes +{ + float2 bary; +} + +[shader("anyhit")] +void anyhit(inout Payload payload, Attributes attrib) +{ + payload.val = normalFunc(x * y) + normalFuncUsesGeneric(y); +} diff --git a/tests/library/precompiled-dxil-matrix.slang b/tests/library/precompiled-dxil-matrix.slang new file mode 100644 index 0000000000..271a7e214b --- /dev/null +++ b/tests/library/precompiled-dxil-matrix.slang @@ -0,0 +1,26 @@ +// precompiled-dxil-matrix.slang + +// This test imports a precompiled module that exports a matrix type, which is known to +// cause https://github.com/shader-slang/slang/issues/4880 without driver mitigation. + +//TEST(windows):COMPILE: tests/library/module-library-matrix.slang -o tests/library/module-library-matrix.slang-module -embed-dxil -profile lib_6_6 -incomplete-library +//TEST(windows):COMPILE: tests/library/precompiled-dxil-matrix.slang -stage anyhit -entry shadow -target dxil -o precompiled-dxil-matrix.dxil + +import "module-library-matrix"; + +struct ShadowHitInfo +{ + bool isHit; + uint seed; +}; + +struct Attributes +{ + float2 bary; +}; + +[shader("anyhit")] +void shadow(inout ShadowHitInfo payload, Attributes attrib) +{ + IgnoreHit(); +} diff --git a/tests/library/precompiled-dxil.slang b/tests/library/precompiled-dxil.slang index 19f67b075c..8cc25bab5a 100644 --- a/tests/library/precompiled-dxil.slang +++ b/tests/library/precompiled-dxil.slang @@ -8,8 +8,7 @@ // TODO: Check if final linkage used only the precompiled dxil. //TEST(windows):COMPILE: tests/library/export-library.slang -o tests/library/export-library.slang-module -embed-dxil -profile lib_6_6 -incomplete-library -//TEST(windows):COMPILE: tests/library/precompiled-dxil.slang -o tests/library/precompiled-dxil.slang-module -embed-dxil -profile lib_6_6 -incomplete-library -//TEST(windows):COMPILE: tests/library/export-library.slang-module tests/library/precompiled-dxil.slang-module -target dxil -entry computeMain -profile cs_6_6 -o tests/library/linked.dxil +//TEST(windows):COMPILE: tests/library/precompiled-dxil.slang tests/library/export-library.slang-module -target dxil -entry computeMain -profile cs_6_6 -o tests/library/linked.dxil extern int foo(int a); diff --git a/tests/library/precompiled-module-library-resource.slang b/tests/library/precompiled-module-library-resource.slang new file mode 100644 index 0000000000..79c3daaa10 --- /dev/null +++ b/tests/library/precompiled-module-library-resource.slang @@ -0,0 +1,33 @@ +// precompiled-module-library-resource.slang + +// Compile this library source with -embed-dxil option. Tests that modules can be +// precompiled to dxil despite having resource parameters or return types. + +//TEST(windows):COMPILE: tests/library/precompiled-module-library-resource.slang -o tests/library/precompiled-module-library-resource.slang-module -embed-dxil -profile lib_6_6 -incomplete-library + +module "precompiled-module-library-resource"; + +public struct ResourceStruct { + public StructuredBuffer buffer; +}; + +public int resource_in_parameter(StructuredBuffer buffer) +{ + return buffer[0]; +} + +public int resource_in_struct_parameter(ResourceStruct rs) +{ + return rs.buffer[0]; +} + +internal int matrix_in_parameter_internal(int1x1 matrix) +{ + return matrix[0][0]; +} + +public int matrix_in_parameter_public(int a) +{ + int1x1 matrix = {a}; + return matrix_in_parameter_internal(matrix); +}