diff options
Diffstat (limited to 'source')
24 files changed, 614 insertions, 255 deletions
diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp index ecd34ccd3..ec959536a 100644 --- a/source/slang/slang-compiler.cpp +++ b/source/slang/slang-compiler.cpp @@ -9,6 +9,7 @@ #include "slang-compiler.h" #include "slang-lexer.h" #include "slang-lower-to-ir.h" +#include "slang-mangle.h" #include "slang-parameter-binding.h" #include "slang-parser.h" #include "slang-preprocessor.h" @@ -328,6 +329,23 @@ namespace Slang return getModule(); } + String EntryPoint::getEntryPointMangledName(Index index) + { + SLANG_UNUSED(index); + SLANG_ASSERT(index == 0); + + // Note: this routine might get called on the "dummy" + // `EntryPoint` objects we create when doing pass-through + // compilation, in which case there won't be any + // function decl to be referenced and thus have + // its mangled name computed. + // + if(auto funcDeclRef = getFuncDeclRef()) + return getMangledName(funcDeclRef); + else + return String(); + } + void EntryPoint::acceptVisitor(ComponentTypeVisitor* visitor, SpecializationInfo* specializationInfo) { visitor->visitEntryPoint(this, as<EntryPointSpecializationInfo>(specializationInfo)); @@ -597,7 +615,6 @@ namespace Slang String emitHLSLForEntryPoint( BackEndCompileRequest* compileRequest, - EntryPoint* entryPoint, Int entryPointIndex, TargetRequest* targetReq, EndToEndCompileRequest* endToEndReq) @@ -622,7 +639,7 @@ namespace Slang { return emitEntryPoint( compileRequest, - entryPoint, + entryPointIndex, CodeGenTarget::HLSL, targetReq); } @@ -630,7 +647,6 @@ namespace Slang String emitCPPForEntryPoint( BackEndCompileRequest* compileRequest, - EntryPoint* entryPoint, Int entryPointIndex, TargetRequest* targetReq, EndToEndCompileRequest* endToEndReq) @@ -653,13 +669,12 @@ namespace Slang } else { - return emitEntryPoint(compileRequest, entryPoint, CodeGenTarget::CPPSource, targetReq); + return emitEntryPoint(compileRequest, entryPointIndex, CodeGenTarget::CPPSource, targetReq); } } String emitGLSLForEntryPoint( BackEndCompileRequest* compileRequest, - EntryPoint* entryPoint, Int entryPointIndex, TargetRequest* targetReq, EndToEndCompileRequest* endToEndReq) @@ -694,11 +709,9 @@ namespace Slang } else { - // TODO(tfoley): need to pass along the entry point - // so that we properly emit it as the `main` function. return emitEntryPoint( compileRequest, - entryPoint, + entryPointIndex, CodeGenTarget::GLSL, targetReq); } @@ -896,7 +909,7 @@ namespace Slang return SLANG_FAIL; } - auto hlslCode = emitHLSLForEntryPoint(compileRequest, entryPoint, entryPointIndex, targetReq, endToEndReq); + auto hlslCode = emitHLSLForEntryPoint(compileRequest, entryPointIndex, targetReq, endToEndReq); maybeDumpIntermediate(compileRequest, hlslCode.getBuffer(), CodeGenTarget::HLSL); auto profile = getEffectiveProfile(entryPoint, targetReq); @@ -1163,7 +1176,6 @@ SlangResult dissassembleDXILUsingDXC( SlangResult emitCPUBinaryForEntryPoint( BackEndCompileRequest* slangRequest, - EntryPoint* entryPoint, Int entryPointIndex, TargetRequest* targetReq, EndToEndCompileRequest* endToEndReq, @@ -1330,7 +1342,6 @@ SlangResult dissassembleDXILUsingDXC( { rawSource = emitCPPForEntryPoint( slangRequest, - entryPoint, entryPointIndex, targetReq, endToEndReq); @@ -1602,7 +1613,6 @@ SlangResult dissassembleDXILUsingDXC( String rawGLSL = emitGLSLForEntryPoint( slangRequest, - entryPoint, entryPointIndex, targetReq, endToEndReq); @@ -1677,7 +1687,6 @@ SlangResult dissassembleDXILUsingDXC( List<uint8_t> code; if (SLANG_SUCCEEDED(emitCPUBinaryForEntryPoint( compileRequest, - entryPoint, entryPointIndex, targetReq, endToEndReq, @@ -1700,7 +1709,6 @@ SlangResult dissassembleDXILUsingDXC( { String code = emitHLSLForEntryPoint( compileRequest, - entryPoint, entryPointIndex, targetReq, endToEndReq); @@ -1713,7 +1721,6 @@ SlangResult dissassembleDXILUsingDXC( { String code = emitGLSLForEntryPoint( compileRequest, - entryPoint, entryPointIndex, targetReq, endToEndReq); @@ -1727,7 +1734,7 @@ SlangResult dissassembleDXILUsingDXC( { return emitEntryPoint( compileRequest, - entryPoint, + entryPointIndex, target, targetReq); } diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index ebde8b6d3..143d3bdaf 100644 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -307,6 +307,9 @@ namespace Slang /// Get one of the entry points linked into this component type. virtual RefPtr<EntryPoint> getEntryPoint(Index index) = 0; + /// Get the mangled name of one of the entry points linked into this component type. + virtual String getEntryPointMangledName(Index index) = 0; + /// Get the number of global shader parameters linked into this component type. virtual Index getShaderParamCount() = 0; @@ -495,6 +498,7 @@ namespace Slang Index getEntryPointCount() SLANG_OVERRIDE; RefPtr<EntryPoint> getEntryPoint(Index index) SLANG_OVERRIDE; + String getEntryPointMangledName(Index index) SLANG_OVERRIDE; Index getShaderParamCount() SLANG_OVERRIDE; GlobalShaderParamInfo getShaderParam(Index index) SLANG_OVERRIDE; @@ -543,6 +547,7 @@ namespace Slang // points, parameters, etc. while giving a better overall memory usage. // List<EntryPoint*> m_entryPoints; + List<String> m_entryPointMangledNames; List<GlobalShaderParamInfo> m_shaderParams; List<SpecializationParam> m_specializationParams; List<ComponentType*> m_requirements; @@ -580,6 +585,7 @@ namespace Slang Index getEntryPointCount() SLANG_OVERRIDE { return m_base->getEntryPointCount(); } RefPtr<EntryPoint> getEntryPoint(Index index) SLANG_OVERRIDE { return m_base->getEntryPoint(index); } + String getEntryPointMangledName(Index index) SLANG_OVERRIDE; Index getShaderParamCount() SLANG_OVERRIDE { return m_base->getShaderParamCount(); } GlobalShaderParamInfo getShaderParam(Index index) SLANG_OVERRIDE { return m_base->getShaderParam(index); } @@ -621,6 +627,8 @@ namespace Slang SpecializationArgs m_specializationArgs; RefPtr<IRModule> m_irModule; + List<String> m_entryPointMangledNames; + // Any tagged union types that were referenced by the specialization arguments. List<RefPtr<TaggedUnionType>> m_taggedUnionTypes; @@ -701,6 +709,7 @@ namespace Slang Index getEntryPointCount() SLANG_OVERRIDE { return 1; }; RefPtr<EntryPoint> getEntryPoint(Index index) SLANG_OVERRIDE { SLANG_UNUSED(index); return this; } + String getEntryPointMangledName(Index index) SLANG_OVERRIDE; Index getShaderParamCount() SLANG_OVERRIDE { return 0; } GlobalShaderParamInfo getShaderParam(Index index) SLANG_OVERRIDE { SLANG_UNUSED(index); return GlobalShaderParamInfo(); } @@ -861,6 +870,7 @@ namespace Slang Index getEntryPointCount() SLANG_OVERRIDE { return 0; } RefPtr<EntryPoint> getEntryPoint(Index index) SLANG_OVERRIDE { SLANG_UNUSED(index); return nullptr; } + String getEntryPointMangledName(Index index) SLANG_OVERRIDE { SLANG_UNUSED(index); return String(); } Index getShaderParamCount() SLANG_OVERRIDE { return m_shaderParams.getCount(); } GlobalShaderParamInfo getShaderParam(Index index) SLANG_OVERRIDE { return m_shaderParams[index]; } @@ -1450,6 +1460,7 @@ namespace Slang Index getEntryPointCount() SLANG_OVERRIDE { return 0; } RefPtr<EntryPoint> getEntryPoint(Index index) SLANG_OVERRIDE { SLANG_UNUSED(index); return nullptr; } + String getEntryPointMangledName(Index index) SLANG_OVERRIDE { SLANG_UNUSED(index); return String(); } Index getShaderParamCount() SLANG_OVERRIDE { return m_shaderParams.getCount(); } GlobalShaderParamInfo getShaderParam(Index index) SLANG_OVERRIDE { return m_shaderParams[index]; } @@ -1594,7 +1605,16 @@ namespace Slang BackEndCompileRequest* backEndRequest, EndToEndCompileRequest* endToEndRequest); + RefPtr<IRModule> getOrCreateIRModuleForLayout(DiagnosticSink* sink); + + RefPtr<IRModule> getExistingIRModuleForLayout() + { + return m_irModuleForLayout; + } + private: + RefPtr<IRModule> createIRModuleForLayout(DiagnosticSink* sink); + // The program being compiled or laid out ComponentType* m_program; @@ -1608,6 +1628,8 @@ namespace Slang // in the parent `Program` (indexing matches // the order they are given in the `Program`) List<CompileResult> m_entryPointResults; + + RefPtr<IRModule> m_irModuleForLayout; }; /// A request to generate code for a program diff --git a/source/slang/slang-dxc-support.cpp b/source/slang/slang-dxc-support.cpp index b4bc77fe5..816de5960 100644 --- a/source/slang/slang-dxc-support.cpp +++ b/source/slang/slang-dxc-support.cpp @@ -31,7 +31,6 @@ namespace Slang String GetHLSLProfileName(Profile profile); String emitHLSLForEntryPoint( BackEndCompileRequest* compileRequest, - EntryPoint* entryPoint, Int entryPointIndex, TargetRequest* targetReq, EndToEndCompileRequest* endToEndReq); @@ -95,7 +94,6 @@ namespace Slang // point, since we'll need that to feed into dxc. auto hlslCode = emitHLSLForEntryPoint( compileRequest, - entryPoint, entryPointIndex, targetReq, endToEndReq); diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index 991540782..c89eadfa3 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -127,13 +127,8 @@ CLikeSourceEmitter::CLikeSourceEmitter(const Desc& desc) m_target = desc.target; m_compileRequest = desc.compileRequest; - m_entryPoint = desc.entryPoint; + m_entryPointStage = desc.entryPointStage; m_effectiveProfile = desc.effectiveProfile; - - m_entryPointLayout = desc.entryPointLayout; - - m_programLayout = desc.programLayout; - m_globalStructLayout = desc.globalStructLayout; } // @@ -784,6 +779,12 @@ bool CLikeSourceEmitter::shouldFoldInstIntoUseSites(IRInst* inst) case kIROp_BoolLit: return true; + // Treat these as folded, because they don't make sense to emit on their own. + case kIROp_TypeLayout: + case kIROp_VarLayout: + case kIROp_EntryPointLayout: + return true; + // Always fold these in, because their results // cannot be represented in the type system of // our current targets. @@ -1477,7 +1478,7 @@ void CLikeSourceEmitter::emitTargetIntrinsicCallExpr( // The `$XT` case handles selecting between // the `gl_HitTNV` and `gl_RayTmaxNV` builtins, // based on what stage we are using: - switch( m_entryPoint->getStage() ) + switch( m_entryPointStage ) { default: m_writer->emit("gl_RayTmaxNV"); @@ -2202,7 +2203,7 @@ VarLayout* CLikeSourceEmitter::getVarLayout(IRInst* var) if (!decoration) return nullptr; - return (VarLayout*) decoration->getLayout(); + return (VarLayout*) decoration->getIRLayout()->getASTLayout(); } void CLikeSourceEmitter::emitLayoutSemantics(IRInst* inst, char const* uniformSemanticSpelling) @@ -2686,7 +2687,7 @@ EntryPointLayout* CLikeSourceEmitter::getEntryPointLayout(IRFunc* func) { if( auto layoutDecoration = func->findDecoration<IRLayoutDecoration>() ) { - return as<EntryPointLayout>(layoutDecoration->getLayout()); + return as<EntryPointLayout>(layoutDecoration->getIRLayout()->getASTLayout()); } return nullptr; } @@ -2695,7 +2696,7 @@ EntryPointLayout* CLikeSourceEmitter::asEntryPoint(IRFunc* func) { if (auto layoutDecoration = func->findDecoration<IRLayoutDecoration>()) { - if (auto entryPointLayout = as<EntryPointLayout>(layoutDecoration->getLayout())) + if (auto entryPointLayout = as<EntryPointLayout>(layoutDecoration->getIRLayout()->getASTLayout())) { return entryPointLayout; } diff --git a/source/slang/slang-emit-c-like.h b/source/slang/slang-emit-c-like.h index 1f0a6c818..5aa5cf202 100644 --- a/source/slang/slang-emit-c-like.h +++ b/source/slang/slang-emit-c-like.h @@ -25,23 +25,13 @@ public: BackEndCompileRequest* compileRequest = nullptr; // The target language we want to generate code for CodeGenTarget target = CodeGenTarget::Unknown; - // The entry point we are being asked to compile - EntryPoint* entryPoint = nullptr; + // The stage for the entry point we are being asked to compile + Stage entryPointStage = Stage::Unknown; // The "effective" profile that is being used to emit code, // combining information from the target and entry point. Profile effectiveProfile = Profile::RawEnum::Unknown; SourceWriter* sourceWriter = nullptr; - // The layout for the entry point - EntryPointLayout* entryPointLayout = nullptr; - - ProgramLayout* programLayout = nullptr; - // We track the original global-scope layout so that we can - // find layout information for `import`ed parameters. - // - // TODO: This will probably change if we represent imports - // explicitly in the layout data. - StructTypeLayout* globalStructLayout = nullptr; }; enum @@ -361,11 +351,14 @@ public: BackEndCompileRequest* m_compileRequest = nullptr; - // The entry point we are being asked to compile - EntryPoint* m_entryPoint; - - // The layout for the entry point - EntryPointLayout* m_entryPointLayout; + // The stage for which we are emitting code. + // + // TODO: We should support emitting code that includes multiple + // entry points for different stages, but this value is used + // in some very specific cases to determine how a construct + // should map to GLSL. + // + Stage m_entryPointStage; // The target language we want to generate code for CodeGenTarget m_target; @@ -379,15 +372,6 @@ public: // we maintain a set of already-emitted modules. HashSet<ModuleDecl*> m_modulesAlreadyEmitted; - // We track the original global-scope layout so that we can - // find layout information for `import`ed parameters. - // - // TODO: This will probably change if we represent imports - // explicitly in the layout data. - StructTypeLayout* m_globalStructLayout; - - ProgramLayout* m_programLayout; - ModuleDecl* m_program; GLSLExtensionTracker m_glslExtensionTracker; diff --git a/source/slang/slang-emit-hlsl.cpp b/source/slang/slang-emit-hlsl.cpp index 565f5ae94..0ee51e117 100644 --- a/source/slang/slang-emit-hlsl.cpp +++ b/source/slang/slang-emit-hlsl.cpp @@ -645,7 +645,7 @@ void HLSLSourceEmitter::emitSemanticsImpl(IRInst* inst) if (auto layoutDecoration = inst->findDecoration<IRLayoutDecoration>()) { - auto layout = layoutDecoration->getLayout(); + auto layout = layoutDecoration->getIRLayout()->getASTLayout(); if (auto varLayout = as<VarLayout>(layout)) { emitSemantics(varLayout); diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp index 5a4e8300a..f60febe0b 100644 --- a/source/slang/slang-emit.cpp +++ b/source/slang/slang-emit.cpp @@ -158,16 +158,15 @@ static void dumpIRIfEnabled( String emitEntryPoint( BackEndCompileRequest* compileRequest, - EntryPoint* entryPoint, + Int entryPointIndex, CodeGenTarget target, TargetRequest* targetRequest) { auto sink = compileRequest->getSink(); auto program = compileRequest->getProgram(); auto targetProgram = program->getTargetProgram(targetRequest); - auto programLayout = targetProgram->getOrCreateLayout(sink); -// auto translationUnit = entryPoint->getTranslationUnit(); + auto entryPoint = program->getEntryPoint(entryPointIndex); auto lineDirectiveMode = compileRequest->getLineDirectiveMode(); // To try to make the default behavior reasonable, we will @@ -187,24 +186,10 @@ String emitEntryPoint( desc.compileRequest = compileRequest; desc.target = target; - desc.entryPoint = entryPoint; + desc.entryPointStage = entryPoint->getStage(); desc.effectiveProfile = getEffectiveProfile(entryPoint, targetRequest); desc.sourceWriter = &sourceWriter; - if (entryPoint && programLayout) - { - desc.entryPointLayout = findEntryPointLayout(programLayout, entryPoint); - } - - desc.programLayout = programLayout; - - // Layout information for the global scope is either an ordinary - // `struct` in the common case, or a constant buffer in the case - // where there were global-scope uniforms. - - StructTypeLayout* globalStructLayout = programLayout ? getGlobalStructLayout(programLayout) : nullptr; - desc.globalStructLayout = globalStructLayout; - RefPtr<CLikeSourceEmitter> sourceEmitter; typedef CLikeSourceEmitter::SourceStyle SourceStyle; @@ -251,10 +236,9 @@ String emitEntryPoint( // linkedIR = linkIR( compileRequest, - entryPoint, - programLayout, + entryPointIndex, target, - targetRequest); + targetProgram); auto irModule = linkedIR.module; auto irEntryPoint = linkedIR.entryPoint; diff --git a/source/slang/slang-emit.h b/source/slang/slang-emit.h index c0981a5e4..46131d726 100644 --- a/source/slang/slang-emit.h +++ b/source/slang/slang-emit.h @@ -12,16 +12,32 @@ namespace Slang class ProgramLayout; class TranslationUnitRequest; - // Emit code for a single entry point, based on - // the input translation unit. + /// Emit source code for a single entry point. + /// + /// This function generates source code for the + /// entry point with index `entryPointIndex` + /// inside the program being compiled in `compileRequest`. + /// + /// The code is generated for the language specified + /// as `target` (e.g., HLSL or GLSL). + /// + /// The `targetRequest` gives further information about + /// the compilation target and its options. + /// + /// Note: it is possible that `target` and `targetRequest` + /// do not store the same target format. For example + /// `target` might be HLSL, while `targetRequest` is + /// a DXIL target. The split information here tells us + /// both the immediate target language (HLSL) as well + /// as the eventual destination format (DXIL) in case + /// we need to customize the output (e.g., we might + /// generate different HLSL output if we know it + /// will be used to generate SPIR-V). + /// String emitEntryPoint( BackEndCompileRequest* compileRequest, - EntryPoint* entryPoint, - - // The target language to generate code in (e.g., HLSL/GLSL) + Int entryPointIndex, CodeGenTarget target, - - // The full target request TargetRequest* targetRequest); } #endif diff --git a/source/slang/slang-ir-bind-existentials.cpp b/source/slang/slang-ir-bind-existentials.cpp index a99da3410..ed400ba0a 100644 --- a/source/slang/slang-ir-bind-existentials.cpp +++ b/source/slang/slang-ir-bind-existentials.cpp @@ -196,7 +196,7 @@ struct BindExistentialSlots auto layoutDecoration = param->findDecoration<IRLayoutDecoration>(); if(!layoutDecoration) return; - auto varLayout = as<VarLayout>(layoutDecoration->getLayout()); + auto varLayout = as<VarLayout>(layoutDecoration->getASTLayout()); if(!varLayout) return; diff --git a/source/slang/slang-ir-dce.cpp b/source/slang/slang-ir-dce.cpp index 6dc315c76..4d58947d4 100644 --- a/source/slang/slang-ir-dce.cpp +++ b/source/slang/slang-ir-dce.cpp @@ -222,6 +222,11 @@ struct DeadCodeEliminationContext // if(inst->mightHaveSideEffects()) return true; + + // If it's a layout instruction we don't want to remove it + if (as<IRLayout>(inst)) + return true; + // // The `mightHaveSideEffects` query is conservative, and will // return `true` as its default mode, so once we are past that diff --git a/source/slang/slang-ir-entry-point-uniforms.cpp b/source/slang/slang-ir-entry-point-uniforms.cpp index 9e36c0853..3a6e9e82c 100644 --- a/source/slang/slang-ir-entry-point-uniforms.cpp +++ b/source/slang/slang-ir-entry-point-uniforms.cpp @@ -155,7 +155,7 @@ struct MoveEntryPointUniformParametersToGlobalScope if(!funcLayoutDecoration) return; - auto entryPointLayout = as<EntryPointLayout>(funcLayoutDecoration->getLayout()); + auto entryPointLayout = as<EntryPointLayout>(funcLayoutDecoration->getASTLayout()); SLANG_ASSERT(entryPointLayout); if(!entryPointLayout) return; @@ -208,7 +208,7 @@ struct MoveEntryPointUniformParametersToGlobalScope SLANG_ASSERT(layoutDecoration); if(!layoutDecoration) continue; - auto paramLayout = as<VarLayout>(layoutDecoration->getLayout()); + auto paramLayout = as<VarLayout>(layoutDecoration->getIRLayout()->getASTLayout()); SLANG_ASSERT(paramLayout); if(!paramLayout) continue; diff --git a/source/slang/slang-ir-glsl-legalize.cpp b/source/slang/slang-ir-glsl-legalize.cpp index 6ccff806f..373acb802 100644 --- a/source/slang/slang-ir-glsl-legalize.cpp +++ b/source/slang/slang-ir-glsl-legalize.cpp @@ -1556,7 +1556,7 @@ void legalizeEntryPointForGLSL( auto layoutDecoration = func->findDecoration<IRLayoutDecoration>(); SLANG_ASSERT(layoutDecoration); - auto entryPointLayout = as<EntryPointLayout>(layoutDecoration->getLayout()); + auto entryPointLayout = as<EntryPointLayout>(layoutDecoration->getIRLayout()->getASTLayout()); SLANG_ASSERT(entryPointLayout); @@ -1684,7 +1684,7 @@ void legalizeEntryPointForGLSL( // auto paramLayoutDecoration = pp->findDecoration<IRLayoutDecoration>(); SLANG_ASSERT(paramLayoutDecoration); - auto paramLayout = as<VarLayout>(paramLayoutDecoration->getLayout()); + auto paramLayout = as<VarLayout>(paramLayoutDecoration->getIRLayout()->getASTLayout()); SLANG_ASSERT(paramLayout); legalizeEntryPointParameterForGLSL( diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h index 3912a3915..2e896cc93 100644 --- a/source/slang/slang-ir-inst-defs.h +++ b/source/slang/slang-ir-inst-defs.h @@ -394,7 +394,7 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0) INST(TargetIntrinsicDecoration, targetIntrinsic, 2, 0) INST_RANGE(TargetSpecificDecoration, TargetDecoration, TargetIntrinsicDecoration) INST(GLSLOuterArrayDecoration, glslOuterArray, 1, 0) - INST(SemanticDecoration, semantic, 1, 0) + INST(InterpolationModeDecoration, interpolationMode, 1, 0) INST(NameHintDecoration, nameHint, 1, 0) @@ -456,7 +456,18 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0) INST(ExportDecoration, export, 1, 0) INST_RANGE(LinkageDecoration, ImportDecoration, ExportDecoration) -INST_RANGE(Decoration, HighLevelDeclDecoration, ExportDecoration) + /* Layout decorations that do not use AST */ + INST(StageLayoutDecoration, stageLayoutDecoration, 1, 0) + INST(ResourceInfoLayoutDecoration, resourceInfoLayoutDecoration, 3, 0) + + /* SemanticLayoutDecoration */ + INST(SemanticDecoration, semantic, 2, 0) + INST(SystemSemanticDecoration, systemSemantic, 2, 0) + INST_RANGE(SemanticDecorationBase, SemanticDecoration, SystemSemanticDecoration) + + INST(PendingVarLayoutDecoration, pendingVarLayoutDecoration, 1, 0) + +INST_RANGE(Decoration, HighLevelDeclDecoration, PendingVarLayoutDecoration) // @@ -483,6 +494,12 @@ INST(ExtractTaggedUnionPayload, extractTaggedUnionPayload, 1, 0) INST(BitCast, bitCast, 1, 0) +/* Layout */ + INST(VarLayout, varLayout, 4, 0) + INST(TypeLayout, typeLayout, 1, 0) + INST(EntryPointLayout, EntryPointLayout, 1, 0) +INST_RANGE(Layout, VarLayout, EntryPointLayout) + PSEUDO_INST(Pos) PSEUDO_INST(PreInc) diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h index ec327b1a9..96ef40103 100644 --- a/source/slang/slang-ir-insts.h +++ b/source/slang/slang-ir-insts.h @@ -39,16 +39,6 @@ struct IRHighLevelDeclDecoration : IRDecoration Decl* getDecl() { return (Decl*) getDeclOperand()->getValue(); } }; -// Associates an IR-level decoration with a source layout -struct IRLayoutDecoration : IRDecoration -{ - enum { kOp = kIROp_LayoutDecoration }; - IR_LEAF_ISA(LayoutDecoration) - - IRPtrLit* getLayoutOperand() { return cast<IRPtrLit>(getOperand(0)); } - Layout* getLayout() { return (Layout*) getLayoutOperand()->getValue(); } -}; - enum IRLoopControl { kIRLoopControl_Unroll, @@ -112,28 +102,6 @@ struct IRGLSLOuterArrayDecoration : IRDecoration } }; -// A decoration that marks a field key as having been associated -// with a particular simple semantic (e.g., `COLOR` or `SV_Position`, -// but not a `register` semantic). -// -// This is currently needed so that we can round-trip HLSL `struct` -// types that get used for varying input/output. This is an unfortunate -// case where some amount of "layout" information can't just come -// in via the `TypeLayout` part of things. -// -struct IRSemanticDecoration : IRDecoration -{ - enum { kOp = kIROp_SemanticDecoration }; - IR_LEAF_ISA(SemanticDecoration) - - IRStringLit* getSemanticNameOperand() { return cast<IRStringLit>(getOperand(0)); } - - UnownedStringSlice getSemanticName() - { - return getSemanticNameOperand()->getStringSlice(); - } -}; - enum class IRInterpolationMode { Linear, @@ -400,6 +368,133 @@ struct IRLookupWitnessTable : IRInst IRUse interfaceType; }; +// Layout decorations + +struct IRStageLayoutDecoration : public IRDecoration +{ + enum { kOp = kIROp_StageLayoutDecoration }; + IR_LEAF_ISA(StageLayoutDecoration) + + IRIntLit* getStageInst() { return cast<IRIntLit>(getOperand(0)); } + Stage getStage() { return Stage(GetIntVal(getStageInst())); } +}; + +struct IRSemanticDecorationBase : public IRDecoration +{ + IR_PARENT_ISA(SemanticDecorationBase) + + IRStringLit* getSemanticNameOperand() { return cast<IRStringLit>(getOperand(0)); } + UnownedStringSlice getSemanticName() { return getSemanticNameOperand()->getStringSlice(); } + IRIntLit* getSemanticIndexOperand() { return cast<IRIntLit>(getOperand(1)); } + int getSemanticIndex() { return int(GetIntVal(getSemanticIndexOperand())); } +}; + +// A decoration that marks a field key as having been associated +// with a particular simple semantic (e.g., `COLOR` or `SV_Position`, +// but not a `register` semantic). +// +// This is currently needed so that we can round-trip HLSL `struct` +// types that get used for varying input/output. This is an unfortunate +// case where some amount of "layout" information can't just come +// in via the `TypeLayout` part of things. +// +struct IRSemanticDecoration : IRSemanticDecorationBase +{ + enum { kOp = kIROp_SemanticDecoration }; + IR_LEAF_ISA(SemanticDecoration) +}; + +struct IRSystemSemanticDecoration : IRSemanticDecorationBase +{ + enum { kOp = kIROp_SystemSemanticDecoration }; + IR_LEAF_ISA(SystemSemanticDecoration) +}; + +/// Holds the resource usage. Typically bound to an IRVarLayout. Note that there can be multiple decorations, +/// for each resource kind. That there should at most be one decoration connected to an instruction for a *kind*. +struct IRResourceInfoLayoutDecoration : public IRDecoration +{ + enum { kOp = kIROp_ResourceInfoLayoutDecoration }; + IR_LEAF_ISA(ResourceInfoLayoutDecoration) + + // What kind of register was it? + IRIntLit* getResourceKindInst() { return cast<IRIntLit>(getOperand(0)); } + LayoutResourceKind getResourceKind() { return (LayoutResourceKind)GetIntVal(getResourceKindInst()); } + + // What binding space (HLSL) or set (Vulkan) are we placed in? + IRIntLit* getSpaceInst() { return cast<IRIntLit>(getOperand(1)); } + UInt getSpace() { return UInt(GetIntVal(getSpaceInst())); } + + // What is our starting register in that space? + // + // (In the case of uniform data, this is a byte offset) + IRIntLit* getIndexInst() { return cast<IRIntLit>(getOperand(2)); } + UInt getIndex() { return UInt(GetIntVal(getIndexInst())); } +}; + +// Layout + +struct IRLayout : IRInst +{ + IR_PARENT_ISA(Layout) + + /// TODO(JS): Hold the pointer to the AST for now, whilst process of transitioning + /// Over to using IR layout. + IRPtrLit* getASTLayoutOperand() { return cast<IRPtrLit>(getOperand(0)); } + Layout* getASTLayout() { return (VarLayout*)getASTLayoutOperand()->getValue(); } +}; + +struct IRTypeLayout : IRLayout +{ + IR_LEAF_ISA(TypeLayout); + TypeLayout* getLayout() { return static_cast<TypeLayout*>(getASTLayout()); } +}; + +struct IREntryPointLayout : IRLayout +{ + IR_LEAF_ISA(EntryPointLayout) + EntryPointLayout* getLayout() { return static_cast<EntryPointLayout*>(getASTLayout()); } +}; + +// Associated data can be attached via the following decorations +// * SemanticDecoration/SystemSemanticDecoration for semantics +// * (potentially multiple) ResourceInfoLayoutDecoration +// * StageLayoutDecoration to indicate a specific associated stage +// * PendingVarLayoutDecoration to indicate pending var layout +// The VarLayoutFlag::HasSemantic flag is equivalent to having the SemanticDecoration +struct IRVarLayout : IRLayout +{ + IR_LEAF_ISA(VarLayout) + + /// The name of this variable + IRStringLit* getName() { return cast<IRStringLit>(getOperand(1)); } + /// For now this uses a link back into the AST representation. Will be replaced by IR based type representation + IRTypeLayout* getTypeLayout() { return cast<IRTypeLayout>(getOperand(2)); } + + /// Get/set absolute layout + IRVarLayout* getAbsoluteLayout() { return cast<IRVarLayout>(getOperand(3)); } + void setAbsoluteLayout(IRVarLayout* layout) { getOperands()[3].set(layout); } +}; + +// Associates an IR-level decoration with a source layout +struct IRLayoutDecoration : IRDecoration +{ + enum { kOp = kIROp_LayoutDecoration }; + IR_LEAF_ISA(LayoutDecoration) + + IRLayout* getIRLayout() { return cast<IRLayout>(getOperand(0)); } + + Layout* getASTLayout() + { + IRLayout* irLayout = getIRLayout(); + if (!irLayout) + { + return nullptr; + } + return irLayout->getASTLayout(); + } +}; + // struct IRCall : IRInst @@ -803,6 +898,9 @@ struct SharedIRBuilder Dictionary<IRInstKey, IRInst*> globalValueNumberingMap; Dictionary<IRConstantKey, IRConstant*> constantMap; + + // TODO: We probably shouldn't use this in the long run. + Dictionary<void*, IRLayout*> layoutMap; }; struct IRBuilderSourceLocRAII; @@ -1335,8 +1433,11 @@ struct IRBuilder } void addHighLevelDeclDecoration(IRInst* value, Decl* decl); + void addLayoutDecoration(IRInst* value, Layout* layout); + IRLayout* getLayout(Layout* astLayout); + void addNameHintDecoration(IRInst* value, IRStringLit* name) { addDecoration(value, kIROp_NameHintDecoration, name); @@ -1362,9 +1463,9 @@ struct IRBuilder addDecoration(value, kIROp_LoopControlDecoration, getIntValue(getIntType(), IRIntegerValue(mode))); } - void addSemanticDecoration(IRInst* value, UnownedStringSlice const& text) + void addSemanticDecoration(IRInst* value, UnownedStringSlice const& text, int index = 0) { - addDecoration(value, kIROp_SemanticDecoration, getStringValue(text)); + addDecoration(value, kIROp_SemanticDecoration, getStringValue(text), getIntValue(getIntType(), index)); } void addTargetIntrinsicDecoration(IRInst* value, UnownedStringSlice const& target, UnownedStringSlice const& definition) diff --git a/source/slang/slang-ir-legalize-types.cpp b/source/slang/slang-ir-legalize-types.cpp index 8fab0fd09..f2a3e3d9a 100644 --- a/source/slang/slang-ir-legalize-types.cpp +++ b/source/slang/slang-ir-legalize-types.cpp @@ -1249,7 +1249,7 @@ static LegalVal legalizeInst( RefPtr<VarLayout> findVarLayout(IRInst* value) { if (auto layoutDecoration = value->findDecoration<IRLayoutDecoration>()) - return as<VarLayout>(layoutDecoration->getLayout()); + return as<VarLayout>(layoutDecoration->getIRLayout()->getASTLayout()); return nullptr; } diff --git a/source/slang/slang-ir-link.cpp b/source/slang/slang-ir-link.cpp index 56b06a499..f46a0db09 100644 --- a/source/slang/slang-ir-link.cpp +++ b/source/slang/slang-ir-link.cpp @@ -54,10 +54,6 @@ struct IRSharedSpecContext struct IRSpecContextBase { - // A map from the mangled name of a global variable - // to the layout to use for it. - Dictionary<String, VarLayout*> globalVarLayouts; - IRSharedSpecContext* shared; IRSharedSpecContext* getShared() { return shared; } @@ -231,6 +227,7 @@ IRInst* IRSpecContext::maybeCloneValue(IRInst* originalValue) case kIROp_StructKey: case kIROp_GlobalGenericParam: case kIROp_WitnessTable: + case kIROp_TaggedUnionType: return cloneGlobalValue(this, originalValue); case kIROp_BoolLit: @@ -414,6 +411,17 @@ static void cloneExtraDecorations( IRBuilder* builder = &builderStorage; builder->setInsertInto(clonedInst); + // If the `clonedInst` already has any non-decoration + // children, then we want to insert before those, + // to maintain the invariant that decorations always + // precede non-decoration instructions in the list of + // decorations and children. + // + if(auto firstChild = clonedInst->getFirstChild()) + { + builder->setInsertBefore(firstChild); + } + for(auto sym = originalValues.sym; sym; sym = sym->nextWithSameName) { for(auto decoration : sym->irGlobalValue->getDecorations()) @@ -424,6 +432,7 @@ static void cloneExtraDecorations( break; case kIROp_BindExistentialSlotsDecoration: + case kIROp_LayoutDecoration: if(!clonedInst->findDecorationImpl(decoration->op)) { cloneInst(context, builder, decoration); @@ -431,6 +440,14 @@ static void cloneExtraDecorations( break; } } + + // We will also copy over source location information from the alternative + // values, in case any of them has it available. + // + if(sym->irGlobalValue->sourceLoc.isValid() && !clonedInst->sourceLoc.isValid()) + { + clonedInst->sourceLoc = sym->irGlobalValue->sourceLoc; + } } } @@ -472,16 +489,6 @@ IRGlobalParam* cloneGlobalParamImpl( cloneType(context, originalVal->getFullType())); cloneSimpleGlobalValueImpl(context, originalVal, originalValues, clonedVal); - if(auto linkage = originalVal->findDecoration<IRLinkageDecoration>()) - { - auto mangledName = String(linkage->getMangledName()); - VarLayout* layout = nullptr; - if (context->globalVarLayouts.TryGetValue(mangledName, layout)) - { - builder->addLayoutDecoration(clonedVal, layout); - } - } - return clonedVal; } @@ -723,9 +730,63 @@ void cloneFunctionCommon( IRInst* specializeGeneric( IRSpecialize* specializeInst); + /// Copy layout information for an entry-point function to its parameters. + /// + /// When layout information is initially attached to an IR entry point, + /// it may be attached to a declaration that would have no `IRParam`s + /// to represent the entry-point parameters. + /// + /// After linking, we expect an entry point to have a full definition, + /// so it becomes possible to copy per-parameter layout information + /// from the entry-point layout down to the individual parameters, + /// which simplifies subsequent IR steps taht want to look for + /// per-parameter layout information. + /// + /// TODO: This step should probably be hoisted out to be an independent + /// IR pass that runs after linking, rather than being folded into + /// the linking step. + /// +static void maybeCopyLayoutInformationToParameters( + IRFunc* func, + IRBuilder* builder) +{ + auto layoutDecor = func->findDecoration<IRLayoutDecoration>(); + if(!layoutDecor) + return; + + auto entryPointLayout = as<EntryPointLayout>(layoutDecor->getASTLayout()); + if(!entryPointLayout) + return; + + if( auto firstBlock = func->getFirstBlock() ) + { + auto paramsStructLayout = getScopeStructLayout(entryPointLayout); + Index paramLayoutCount = paramsStructLayout->fields.getCount(); + Index paramCounter = 0; + for( auto pp = firstBlock->getFirstParam(); pp; pp = pp->getNextParam() ) + { + Index paramIndex = paramCounter++; + if( paramIndex < paramLayoutCount ) + { + auto paramLayout = paramsStructLayout->fields[paramIndex]; + + auto offsetParamLayout = applyOffsetToVarLayout(paramLayout, entryPointLayout->parametersLayout); + + builder->addLayoutDecoration( + pp, + offsetParamLayout); + } + else + { + SLANG_UNEXPECTED("too many parameters"); + } + } + } +} + IRFunc* specializeIRForEntryPoint( IRSpecContext* context, - EntryPointLayout* entryPointLayout) + String const& mangledName) { // We start by looking up the IR symbol that // matches the mangled name given to the @@ -736,7 +797,6 @@ IRFunc* specializeIRForEntryPoint( // so that the mangled name of the decl-ref is // not the same as the mangled name of the decl. // - auto mangledName = getMangledName(entryPointLayout->getFuncDeclRef()); RefPtr<IRSpecSymbol> sym; if (!context->getSymbols().TryGetValue(mangledName, sym)) { @@ -744,8 +804,14 @@ IRFunc* specializeIRForEntryPoint( return nullptr; } - // TODO: deal with the case where we might - // have multiple (profile-overloaded) versions... + // Note: it is possible that `sym` shows multiple + // definitions, coming from different IR modules that + // were input to the linking process. We don't have + // to do anything special about that here, because + // we can use *any* of the IR values as the starting + // point for cloning, and `cloneGlobalValue` will + // follow the linkage decoration and discover the + // other values on its own. // auto originalVal = sym->irGlobalValue; @@ -788,26 +854,21 @@ IRFunc* specializeIRForEntryPoint( // we don't want to share the definition between // an entry point and an ordinary function anyway. // - clonedVal = specializeGeneric(clonedSpec); - } + auto specializedClone = specializeGeneric(clonedSpec); - // TODO: If there is an existential-related decoration - // on the entry point, we need to transfer it over - // to the specialized function. - if( auto bindExistentialSlots = originalVal->findDecorationImpl(kIROp_BindExistentialSlotsDecoration) ) - { - if( !clonedVal->findDecorationImpl(kIROp_BindExistentialSlotsDecoration) ) - { - IRBuilder builderStorage = *context->builder; - IRBuilder* builder = &builderStorage; - builder->setInsertInto(clonedVal); + // One special case we need to be aware of is that there + // might be decorations attached to the `specialize` + // instruction, which we then want to copy over to the + // result of specialization. + // + cloneExtraDecorations(context, specializedClone, IROriginalValuesForClone(sym)); - auto clonedBind = cloneInst(context, builder, bindExistentialSlots); - clonedBind->moveToStart(); - } + // Now we will move to considering the specialized instruction + // instead of the unspecialized one for all further steps. + // + clonedVal = specializedClone; } - auto clonedFunc = as<IRFunc>(clonedVal); if(!clonedFunc) { @@ -820,42 +881,11 @@ IRFunc* specializeIRForEntryPoint( context->builder->addKeepAliveDecoration(clonedFunc); } - // We need to attach the layout information for - // the entry point to this declaration, so that - // we can use it to inform downstream code emit. - // - context->builder->addLayoutDecoration( - clonedFunc, - entryPointLayout); - // We will also go on and attach layout information // to the function parameters, so that we have it // available directly on the parameters, rather // than having to look it up on the original entry-point layout. - if( auto firstBlock = clonedFunc->getFirstBlock() ) - { - auto paramsStructLayout = getScopeStructLayout(entryPointLayout); - Index paramLayoutCount = paramsStructLayout->fields.getCount(); - Index paramCounter = 0; - for( auto pp = firstBlock->getFirstParam(); pp; pp = pp->getNextParam() ) - { - Index paramIndex = paramCounter++; - if( paramIndex < paramLayoutCount ) - { - auto paramLayout = paramsStructLayout->fields[paramIndex]; - - auto offsetParamLayout = applyOffsetToVarLayout(paramLayout, entryPointLayout->parametersLayout); - - context->builder->addLayoutDecoration( - pp, - offsetParamLayout); - } - else - { - SLANG_UNEXPECTED("too many parameters"); - } - } - } + maybeCopyLayoutInformationToParameters(clonedFunc, context->builder); return clonedFunc; } @@ -1073,6 +1103,7 @@ IRInst* cloneInst( builder->addInst(clonedInst); context->builder = oldBuilder; cloneDecorations(context, clonedInst, originalInst); + cloneExtraDecorations(context, clonedInst, originalValues); return clonedInst; } @@ -1251,7 +1282,6 @@ void initializeSharedSpecContext( struct IRSpecializationState { - ProgramLayout* programLayout; CodeGenTarget target; TargetRequest* targetReq; @@ -1279,11 +1309,12 @@ struct IRSpecializationState LinkedIR linkIR( BackEndCompileRequest* compileRequest, - EntryPoint* entryPoint, - ProgramLayout* programLayout, + Int entryPointIndex, CodeGenTarget target, - TargetRequest* targetReq) + TargetProgram* targetProgram) { + auto targetReq = targetProgram->getTargetReq(); + // TODO: We need to make sure that the program we are being asked // to compile has been "resolved" so that it has no outstanding // unsatisfied requirements. @@ -1291,7 +1322,6 @@ LinkedIR linkIR( IRSpecializationState stateStorage; auto state = &stateStorage; - state->programLayout = programLayout; state->target = target; state->targetReq = targetReq; @@ -1316,34 +1346,18 @@ LinkedIR linkIR( insertGlobalValueSymbols(sharedContext, irModule); }); + // We will also insert the IR global symbols from the IR module + // attached to the `TargetProgram`, since this module is + // responsible for associating layout information to those + // global symbols via decorations. + // + insertGlobalValueSymbols(sharedContext, targetProgram->getExistingIRModuleForLayout()); + auto context = state->getContext(); context->shared = sharedContext; context->builder = &sharedContext->builderStorage; - // Next, we want to optimize lookup for layout information - // associated with global declarations, so that we can - // look things up based on the IR values (using mangled names) - // - // Note: We are scanning over all the key-value pairs for - // entries in the global scope, to account for the fact - // that the "same" shader parameter could be declared in - // multiple translation units, and thus end up with - // multiple mangled names (when the unique translation - // unit name gets involved). - // - auto globalStructLayout = getScopeStructLayout(programLayout); - for(auto entry : globalStructLayout->mapVarToLayout) - { - auto mangledName = getMangledName(entry.Key); - auto globalVarLayout = entry.Value; - context->globalVarLayouts.AddIfNotExists(mangledName, globalVarLayout); - } - - auto entryPointLayout = findEntryPointLayout(programLayout, entryPoint); - - auto offsetEntryPointLayout = entryPointLayout; - context->builder->setInsertInto(context->getModule()->getModuleInst()); // for now, clone all unreferenced witness tables @@ -1362,7 +1376,15 @@ LinkedIR linkIR( // the entry point function itself, and rely on // this step to recursively copy over anything else // it might reference. - auto irEntryPoint = specializeIRForEntryPoint(context, offsetEntryPointLayout); + // + // Note: We query the mangled name of the entry point from + // the `program` instead of the `entryPoint` directly, + // because the `program` will include any specialization + // arguments which might end up affecting the mangled + // entry point name. + // + auto entryPointMangledName = program->getEntryPointMangledName(entryPointIndex); + auto irEntryPoint = specializeIRForEntryPoint(context, entryPointMangledName); // Bindings for global generic parameters are currently represented // as stand-alone global-scope instructions in the IR module for @@ -1388,29 +1410,6 @@ LinkedIR linkIR( } }); - // HACK: we need to ensure that any tagged union types - // in the IR module have layout information copied over to them. - // - // Note that we do this *after* cloning the `bindGlobalGenericParam` - // instructions, since we expected the tagged union type(s) to - // be referenced by them. - // - for( auto taggedUnionTypeLayout : programLayout->taggedUnionTypeLayouts ) - { - auto taggedUnionType = taggedUnionTypeLayout->getType(); - auto mangledName = getMangledTypeName(taggedUnionType); - - RefPtr<IRSpecSymbol> sym; - if(!context->getSymbols().TryGetValue(mangledName, sym)) - continue; - - IRInst* clonedType = findClonedValue(context, sym->irGlobalValue); - if(!clonedType) - continue; - - context->builder->addLayoutDecoration(clonedType, taggedUnionTypeLayout); - } - // TODO: *technically* we should consider the case where // we have global variables with initializers, since // these should get run whether or not the entry point diff --git a/source/slang/slang-ir-link.h b/source/slang/slang-ir-link.h index 4cea3941e..9fc9cb975 100644 --- a/source/slang/slang-ir-link.h +++ b/source/slang/slang-ir-link.h @@ -15,15 +15,14 @@ namespace Slang // Clone the IR values reachable from the given entry point // into the IR module associated with the specialization state. // When multiple definitions of a symbol are found, the one - // that is best specialized for the given `targetReq` will be - // used. + // that is best specialized for the appropriate compilation + // target will be used. // LinkedIR linkIR( BackEndCompileRequest* compileRequest, - EntryPoint* entryPoint, - ProgramLayout* programLayout, + Int entryPointIndex, CodeGenTarget target, - TargetRequest* targetReq); + TargetProgram* targetProgram); // Replace any global constants in the IR module with their // definitions, if possible. diff --git a/source/slang/slang-ir-union.cpp b/source/slang/slang-ir-union.cpp index e39fae262..d456cebee 100644 --- a/source/slang/slang-ir-union.cpp +++ b/source/slang/slang-ir-union.cpp @@ -670,7 +670,7 @@ struct DesugarUnionTypesContext // auto layoutDecoration = type->findDecoration<IRLayoutDecoration>(); SLANG_ASSERT(layoutDecoration); - auto layout = layoutDecoration->getLayout(); + auto layout = layoutDecoration->getIRLayout()->getASTLayout(); SLANG_ASSERT(layout); auto taggedUnionTypeLayout = as<TaggedUnionTypeLayout>(layout); SLANG_ASSERT(taggedUnionTypeLayout); diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp index ea6a4afda..78758d944 100644 --- a/source/slang/slang-ir.cpp +++ b/source/slang/slang-ir.cpp @@ -10,6 +10,9 @@ namespace Slang { struct IRSpecContext; + + SLANG_COMPILE_TIME_ASSERT(kIROpCount < kIRPseudoOp_First); + IRInst* cloneGlobalValueWithLinkage( IRSpecContext* context, IRInst* originalVal, @@ -3083,14 +3086,82 @@ namespace Slang addDecoration(inst, kIROp_HighLevelDeclDecoration, ptrConst); } - void IRBuilder::addLayoutDecoration(IRInst* inst, Layout* layout) + void IRBuilder::addLayoutDecoration(IRInst* value, Layout* layout) { - auto ptrConst = getPtrValue(addRefObjectToFree(layout)); - addDecoration(inst, kIROp_LayoutDecoration, ptrConst); + IRLayout* irLayout = getLayout(layout); + addDecoration(value, kIROp_LayoutDecoration, irLayout); + + } - // + IRLayout* IRBuilder::getLayout(Layout* astLayout) + { + if (astLayout == nullptr) + { + return nullptr; + } + + IRLayout* irLayout = nullptr; + if(sharedBuilder->layoutMap.TryGetValue(astLayout, irLayout)) + { + SLANG_ASSERT(irLayout->getASTLayout() == astLayout); + return irLayout; + } + + if (EntryPointLayout* entryPointLayout = as<EntryPointLayout>(astLayout)) + { + irLayout = createInst<IREntryPointLayout>(this, kIROp_EntryPointLayout, nullptr, getPtrValue(astLayout)); + } + else if (VarLayout* varLayout = as<VarLayout>(astLayout)) + { + UnownedStringSlice nameSlice; + if (varLayout->getVariable()) + { + Name* name = varLayout->getName(); + if (name) + { + nameSlice = name->text.getUnownedSlice(); + } + } + + // Get the name as a literal. + // We use an empty length string, as we can't use a null inst ptr. + // If there was a 'null' instruction then it might make more sense to use that + IRStringLit* nameLit = getStringValue(nameSlice); + + // Layout, name, type layout, absolute layout + IRInst* args[4] = { + getPtrValue(astLayout), + nameLit, + getLayout(varLayout->getTypeLayout()), + getLayout(varLayout->m_absoluteLayout) + }; + + irLayout = createInst<IRVarLayout>(this, kIROp_VarLayout, nullptr, 4, args); + } + else if (TypeLayout* typeLayout = as<TypeLayout>(astLayout)) + { + irLayout = createInst<IRTypeLayout>(this, kIROp_TypeLayout, nullptr, getPtrValue(astLayout)); + } + else + { + SLANG_UNEXPECTED("Unknown layout type"); + } + + SLANG_ASSERT(irLayout); + SLANG_ASSERT(irLayout->getASTLayout() == astLayout); + + sharedBuilder->layoutMap[astLayout] = irLayout; + + addGlobalValue(this, irLayout); + // need to keep in scope + addRefObjectToFree(astLayout); + + return irLayout; + } + + // struct IRDumpContext { diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index 50ac6948b..cd398f4e7 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -6707,4 +6707,98 @@ RefPtr<IRModule> generateIRForSpecializedComponentType( return context.process(componentType, sink); } + +RefPtr<IRModule> TargetProgram::getOrCreateIRModuleForLayout(DiagnosticSink* sink) +{ + getOrCreateLayout(sink); + return m_irModuleForLayout; +} + +RefPtr<IRModule> TargetProgram::createIRModuleForLayout(DiagnosticSink* sink) +{ + if(m_irModuleForLayout) + return m_irModuleForLayout; + + + // Okay, now we need to fill it in. + + auto programLayout = getOrCreateLayout(sink); + if(!programLayout) + return nullptr; + + auto program = getProgram(); + auto linkage = program->getLinkage(); + auto session = linkage->getSessionImpl(); + + SharedIRGenContext sharedContextStorage( + session, + sink); + auto sharedContext = &sharedContextStorage; + + IRGenContext contextStorage(sharedContext); + auto context = &contextStorage; + + SharedIRBuilder sharedBuilderStorage; + auto sharedBuilder = &sharedBuilderStorage; + sharedBuilder->module = nullptr; + sharedBuilder->session = session; + + IRBuilder builderStorage; + auto builder = &builderStorage; + builder->sharedBuilder = sharedBuilder; + + RefPtr<IRModule> irModule = builder->createModule(); + sharedBuilder->module = irModule; + + builder->setInsertInto(irModule->getModuleInst()); + + context->irBuilder = builder; + + + // Okay, now we need to walk through and decorate everything. + auto globalStructLayout = getScopeStructLayout(programLayout); + for(auto globalVarPair : globalStructLayout->mapVarToLayout) + { + auto varDecl = globalVarPair.Key; + auto varLayout = globalVarPair.Value; + + // Ensure that an `[import(...)]` declaration for the variable + // has been emitted to this module, so that we will have something + // to decorate. + // + auto irVar = getSimpleVal(context, ensureDecl(context, varDecl)); + + // Now attach the decoration to the variable. + // + builder->addLayoutDecoration(irVar, varLayout); + } + + for( auto entryPointLayout : programLayout->entryPoints ) + { + auto funcDeclRef = entryPointLayout->entryPoint; + + auto irFuncType = lowerType(context, getFuncType(session, funcDeclRef)); + auto irFunc = getSimpleVal(context, emitDeclRef(context, funcDeclRef, irFuncType)); + + if( !irFunc->findDecoration<IRLinkageDecoration>() ) + { + builder->addImportDecoration(irFunc, getMangledName(funcDeclRef).getUnownedSlice()); + } + + builder->addLayoutDecoration(irFunc, entryPointLayout); + } + + for( auto taggedUnionTypeLayout : programLayout->taggedUnionTypeLayouts ) + { + auto taggedUnionType = taggedUnionTypeLayout->getType(); + auto irType = lowerType(context, taggedUnionType); + builder->addLayoutDecoration(irType, taggedUnionTypeLayout); + } + + m_irModuleForLayout = irModule; + return irModule; +} + + + } // namespace Slang diff --git a/source/slang/slang-parameter-binding.cpp b/source/slang/slang-parameter-binding.cpp index 6e5838da5..a2353824c 100644 --- a/source/slang/slang-parameter-binding.cpp +++ b/source/slang/slang-parameter-binding.cpp @@ -3227,6 +3227,10 @@ ProgramLayout* TargetProgram::getOrCreateLayout(DiagnosticSink* sink) if( !m_layout ) { m_layout = generateParameterBindings(this, sink); + if( m_layout ) + { + m_irModuleForLayout = createIRModuleForLayout(sink); + } } return m_layout; } diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp index ff1f2c147..807d0cab4 100644 --- a/source/slang/slang-type-layout.cpp +++ b/source/slang/slang-type-layout.cpp @@ -2384,7 +2384,7 @@ static RefPtr<TypeLayout> maybeAdjustLayoutForArrayElementType( for( auto p : originalStructTypeLayout->mapVarToLayout ) { - Decl* key = p.Key; + VarDeclBase* key = p.Key; RefPtr<VarLayout> originalVal = p.Value; RefPtr<VarLayout> adjustedVal; if( mapOriginalFieldToAdjusted.TryGetValue(originalVal, adjustedVal) ) diff --git a/source/slang/slang-type-layout.h b/source/slang/slang-type-layout.h index 5e86be113..f63dd01c0 100644 --- a/source/slang/slang-type-layout.h +++ b/source/slang/slang-type-layout.h @@ -15,6 +15,8 @@ namespace Slang { enum class BaseType; class Type; +struct IRLayout; + // #if 0 @@ -601,7 +603,7 @@ public: // TODO: This should map from a declaration to the *index* // in the array above, rather than to the actual pointer, // so that we - Dictionary<Decl*, RefPtr<VarLayout>> mapVarToLayout; + Dictionary<VarDeclBase*, RefPtr<VarLayout>> mapVarToLayout; // As an accellerator for type layouts created at the // IR layer, we include a second map that use IR "key" diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 5f22f8a23..4ae3f4654 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -7,6 +7,7 @@ #include "slang-parameter-binding.h" #include "slang-lower-to-ir.h" +#include "slang-mangle.h" #include "slang-parser.h" #include "slang-preprocessor.h" #include "slang-reflection.h" @@ -1136,6 +1137,7 @@ SlangResult FrontEndCompileRequest::executeActionsInner() { auto targetProgram = m_globalAndEntryPointsComponentType->getTargetProgram(targetReq); targetProgram->getOrCreateLayout(getSink()); + targetProgram->getOrCreateIRModuleForLayout(getSink()); } if (getSink()->GetErrorCount() != 0) return SLANG_FAIL; @@ -2033,6 +2035,7 @@ CompositeComponentType::CompositeComponentType( for(Index cc = 0; cc < childEntryPointCount; ++cc) { m_entryPoints.add(child->getEntryPoint(cc)); + m_entryPointMangledNames.add(child->getEntryPointMangledName(cc)); } auto childShaderParamCount = child->getShaderParamCount(); @@ -2079,6 +2082,11 @@ RefPtr<EntryPoint> CompositeComponentType::getEntryPoint(Index index) return m_entryPoints[index]; } +String CompositeComponentType::getEntryPointMangledName(Index index) +{ + return m_entryPointMangledNames[index]; +} + Index CompositeComponentType::getShaderParamCount() { return m_shaderParams.getCount(); @@ -2198,6 +2206,48 @@ SpecializedComponentType::SpecializedComponentType( m_taggedUnionTypes.add(taggedUnionType); } + + // Because we are specializing shader code, the mangled entry + // point names for this component type may be different than + // for the base component type (e.g., the mangled name for `f<int>` + // is different than that that of the generic `f` function + // itself). + // + // We will compute the mangled names of all the entry points and + // store them here, so that we don't have to do it on the fly. + // Because the `ComponentType` structure is hierarchical, we + // need to use a recursive visitor to compute the names, + // and we will define that visitor locally: + // + struct EntryPointMangledNameCollector : ComponentTypeVisitor + { + List<String>* mangledEntryPointNames; + + void visitEntryPoint(EntryPoint* entryPoint, EntryPoint::EntryPointSpecializationInfo* specializationInfo) SLANG_OVERRIDE + { + auto funcDeclRef = entryPoint->getFuncDeclRef(); + if(specializationInfo) + funcDeclRef = specializationInfo->specializedFuncDeclRef; + + (*mangledEntryPointNames).add(getMangledName(funcDeclRef)); + } + + void visitModule(Module*, Module::ModuleSpecializationInfo*) SLANG_OVERRIDE + {} + void visitComposite(CompositeComponentType* composite, CompositeComponentType::CompositeSpecializationInfo* specializationInfo) SLANG_OVERRIDE + { visitChildren(composite, specializationInfo); } + void visitSpecialized(SpecializedComponentType* specialized) SLANG_OVERRIDE + { visitChildren(specialized); } + void visitLegacy(LegacyProgram* legacy, CompositeComponentType::CompositeSpecializationInfo* specializationInfo) SLANG_OVERRIDE + { visitChildren(legacy, specializationInfo); } + }; + + // With the visitor defined, we apply it to ourself to compute + // and collect the mangled entry point names. + // + EntryPointMangledNameCollector collector; + collector.mangledEntryPointNames = &m_entryPointMangledNames; + collector.visitSpecialized(this); } void SpecializedComponentType::acceptVisitor(ComponentTypeVisitor* visitor, SpecializationInfo* specializationInfo) @@ -2221,6 +2271,11 @@ RefPtr<ComponentType> SpecializedComponentType::getRequirement(Index index) return m_base->getRequirement(index); } +String SpecializedComponentType::getEntryPointMangledName(Index index) +{ + return m_entryPointMangledNames[index]; +} + // // LegacyProgram // |
