summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/slang/slang-compiler.cpp39
-rw-r--r--source/slang/slang-compiler.h22
-rw-r--r--source/slang/slang-dxc-support.cpp2
-rw-r--r--source/slang/slang-emit-c-like.cpp21
-rw-r--r--source/slang/slang-emit-c-like.h36
-rw-r--r--source/slang/slang-emit-hlsl.cpp2
-rw-r--r--source/slang/slang-emit.cpp26
-rw-r--r--source/slang/slang-emit.h30
-rw-r--r--source/slang/slang-ir-bind-existentials.cpp2
-rw-r--r--source/slang/slang-ir-dce.cpp5
-rw-r--r--source/slang/slang-ir-entry-point-uniforms.cpp4
-rw-r--r--source/slang/slang-ir-glsl-legalize.cpp4
-rw-r--r--source/slang/slang-ir-inst-defs.h21
-rw-r--r--source/slang/slang-ir-insts.h169
-rw-r--r--source/slang/slang-ir-legalize-types.cpp2
-rw-r--r--source/slang/slang-ir-link.cpp235
-rw-r--r--source/slang/slang-ir-link.h9
-rw-r--r--source/slang/slang-ir-union.cpp2
-rw-r--r--source/slang/slang-ir.cpp79
-rw-r--r--source/slang/slang-lower-to-ir.cpp94
-rw-r--r--source/slang/slang-parameter-binding.cpp4
-rw-r--r--source/slang/slang-type-layout.cpp2
-rw-r--r--source/slang/slang-type-layout.h4
-rw-r--r--source/slang/slang.cpp55
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
//