summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/slang/slang-emit-c-like.cpp77
-rw-r--r--source/slang/slang-emit-c-like.h31
-rw-r--r--source/slang/slang-emit-cpp.cpp17
-rw-r--r--source/slang/slang-emit-glsl.cpp42
-rw-r--r--source/slang/slang-emit-glsl.h8
-rw-r--r--source/slang/slang-emit-hlsl.cpp44
-rw-r--r--source/slang/slang-emit-hlsl.h8
-rw-r--r--source/slang/slang-ir-bind-existentials.cpp8
-rw-r--r--source/slang/slang-ir-entry-point-uniforms.cpp47
-rw-r--r--source/slang/slang-ir-glsl-legalize.cpp94
-rw-r--r--source/slang/slang-ir-inst-defs.h42
-rw-r--r--source/slang/slang-ir-insts.h759
-rw-r--r--source/slang/slang-ir-legalize-types.cpp228
-rw-r--r--source/slang/slang-ir-link.cpp11
-rw-r--r--source/slang/slang-ir-union.cpp32
-rw-r--r--source/slang/slang-ir.cpp565
-rw-r--r--source/slang/slang-ir.h135
-rw-r--r--source/slang/slang-legalize-types.cpp111
-rw-r--r--source/slang/slang-legalize-types.h33
-rw-r--r--source/slang/slang-lower-to-ir.cpp287
-rw-r--r--source/slang/slang-type-layout.cpp132
-rw-r--r--source/slang/slang-type-layout.h58
22 files changed, 2163 insertions, 606 deletions
diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp
index c89eadfa3..a983a7a73 100644
--- a/source/slang/slang-emit-c-like.cpp
+++ b/source/slang/slang-emit-c-like.cpp
@@ -401,9 +401,9 @@ UInt CLikeSourceEmitter::getBindingOffset(EmitVarChain* chain, LayoutResourceKin
UInt offset = 0;
for(auto cc = chain; cc; cc = cc->next)
{
- if(auto resInfo = cc->varLayout->FindResourceInfo(kind))
+ if(auto resInfo = cc->varLayout->findOffsetAttr(kind))
{
- offset += resInfo->index;
+ offset += resInfo->getOffset();
}
}
return offset;
@@ -415,13 +415,13 @@ UInt CLikeSourceEmitter::getBindingSpace(EmitVarChain* chain, LayoutResourceKind
for(auto cc = chain; cc; cc = cc->next)
{
auto varLayout = cc->varLayout;
- if(auto resInfo = varLayout->FindResourceInfo(kind))
+ if(auto resInfo = varLayout->findOffsetAttr(kind))
{
- space += resInfo->space;
+ space += resInfo->getSpace();
}
- if(auto resInfo = varLayout->FindResourceInfo(LayoutResourceKind::RegisterSpace))
+ if(auto resInfo = varLayout->findOffsetAttr(LayoutResourceKind::RegisterSpace))
{
- space += resInfo->index;
+ space += resInfo->getOffset();
}
}
return space;
@@ -779,12 +779,6 @@ 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.
@@ -799,6 +793,15 @@ bool CLikeSourceEmitter::shouldFoldInstIntoUseSites(IRInst* inst)
return true;
}
+ // Layouts and attributes are only present to annotate other
+ // instructions, and should not be emitted as anything in
+ // source code.
+ //
+ if(as<IRLayout>(inst))
+ return true;
+ if(as<IRAttr>(inst))
+ return true;
+
switch( inst->op )
{
default:
@@ -2179,15 +2182,33 @@ void CLikeSourceEmitter::_emitInst(IRInst* inst)
}
}
-void CLikeSourceEmitter::emitSemantics(VarLayout* varLayout)
+void CLikeSourceEmitter::emitSemantics(IRVarLayout* varLayout)
{
- if(varLayout->flags & VarLayoutFlag::HasSemantic)
+ if(auto semanticAttr = varLayout->findAttr<IRSemanticAttr>())
{
+ // Note: We force the semantic name stored in the IR to
+ // upper-case here because that is what existing Slang
+ // tests had assumed and continue to rely upon.
+ //
+ // The original rationale for switching to uppercase was
+ // canonicalization for reflection (users can't accidentally
+ // write code that works for `COLOR` but not for `COLOR`),
+ // but it would probably be more ideal for our output code
+ // to give the semantic name as close to how it was originally spelled
+ // spelled as possible.
+ //
+ // TODO: Try removing this step and fixing up the test cases
+ // to see if we are happier with an approach that doesn't
+ // force uppercase.
+ //
+ String name = semanticAttr->getName();
+ name = name.toUpper();
+
m_writer->emit(" : ");
- m_writer->emit(varLayout->semanticName);
- if(varLayout->semanticIndex)
+ m_writer->emit(name);
+ if(auto index = semanticAttr->getIndex())
{
- m_writer->emit(varLayout->semanticIndex);
+ m_writer->emit(index);
}
}
}
@@ -2197,13 +2218,13 @@ void CLikeSourceEmitter::emitSemantics(IRInst* inst)
emitSemanticsImpl(inst);
}
-VarLayout* CLikeSourceEmitter::getVarLayout(IRInst* var)
+IRVarLayout* CLikeSourceEmitter::getVarLayout(IRInst* var)
{
auto decoration = var->findDecoration<IRLayoutDecoration>();
if (!decoration)
return nullptr;
- return (VarLayout*) decoration->getIRLayout()->getASTLayout();
+ return as<IRVarLayout>(decoration->getLayout());
}
void CLikeSourceEmitter::emitLayoutSemantics(IRInst* inst, char const* uniformSemanticSpelling)
@@ -2683,20 +2704,20 @@ void CLikeSourceEmitter::emitFuncDecl(IRFunc* func)
m_writer->emit(");\n\n");
}
-EntryPointLayout* CLikeSourceEmitter::getEntryPointLayout(IRFunc* func)
+IREntryPointLayout* CLikeSourceEmitter::getEntryPointLayout(IRFunc* func)
{
if( auto layoutDecoration = func->findDecoration<IRLayoutDecoration>() )
{
- return as<EntryPointLayout>(layoutDecoration->getIRLayout()->getASTLayout());
+ return as<IREntryPointLayout>(layoutDecoration->getLayout());
}
return nullptr;
}
-EntryPointLayout* CLikeSourceEmitter::asEntryPoint(IRFunc* func)
+IREntryPointLayout* CLikeSourceEmitter::asEntryPoint(IRFunc* func)
{
if (auto layoutDecoration = func->findDecoration<IRLayoutDecoration>())
{
- if (auto entryPointLayout = as<EntryPointLayout>(layoutDecoration->getIRLayout()->getASTLayout()))
+ if (auto entryPointLayout = as<IREntryPointLayout>(layoutDecoration->getLayout()))
{
return entryPointLayout;
}
@@ -2797,7 +2818,7 @@ void CLikeSourceEmitter::emitStruct(IRStructType* structType)
m_writer->emit("};\n\n");
}
-void CLikeSourceEmitter::emitInterpolationModifiers(IRInst* varInst, IRType* valueType, VarLayout* layout)
+void CLikeSourceEmitter::emitInterpolationModifiers(IRInst* varInst, IRType* valueType, IRVarLayout* layout)
{
emitInterpolationModifiersImpl(varInst, valueType, layout);
}
@@ -2835,7 +2856,7 @@ void CLikeSourceEmitter::emitTempModifiers(IRInst* temp)
}
}
-void CLikeSourceEmitter::emitVarModifiers(VarLayout* layout, IRInst* varDecl, IRType* varType)
+void CLikeSourceEmitter::emitVarModifiers(IRVarLayout* layout, IRInst* varDecl, IRType* varType)
{
// TODO(JS): We could push all of this onto the target impls, and then not need so many virtual hooks.
emitVarDecorationsImpl(varDecl);
@@ -2850,8 +2871,8 @@ void CLikeSourceEmitter::emitVarModifiers(VarLayout* layout, IRInst* varDecl, IR
// Target specific modifier output
emitImageFormatModifierImpl(varDecl, varType);
- if(layout->FindResourceInfo(LayoutResourceKind::VaryingInput)
- || layout->FindResourceInfo(LayoutResourceKind::VaryingOutput))
+ if(layout->usesResourceKind(LayoutResourceKind::VaryingInput)
+ || layout->usesResourceKind(LayoutResourceKind::VaryingOutput))
{
emitInterpolationModifiers(varDecl, varType, layout);
}
@@ -2990,7 +3011,7 @@ void CLikeSourceEmitter::emitGlobalVar(IRGlobalVar* varDecl)
// parameter.
//
SLANG_ASSERT(!getVarLayout(varDecl));
- VarLayout* layout = nullptr;
+ IRVarLayout* layout = nullptr;
// An ordinary global variable (which is not a
// shader parameter) may need special
diff --git a/source/slang/slang-emit-c-like.h b/source/slang/slang-emit-c-like.h
index 5aa5cf202..7b7ab5da6 100644
--- a/source/slang/slang-emit-c-like.h
+++ b/source/slang/slang-emit-c-like.h
@@ -77,7 +77,7 @@ public:
// A chain of variables to use for emitting semantic/layout info
struct EmitVarChain
{
- VarLayout* varLayout;
+ IRVarLayout* varLayout;
EmitVarChain* next;
EmitVarChain()
@@ -85,12 +85,12 @@ public:
, next(nullptr)
{}
- EmitVarChain(VarLayout* varLayout)
+ EmitVarChain(IRVarLayout* varLayout)
: varLayout(varLayout)
, next(nullptr)
{}
- EmitVarChain(VarLayout* varLayout, EmitVarChain* next)
+ EmitVarChain(IRVarLayout* varLayout, EmitVarChain* next)
: varLayout(varLayout)
, next(next)
{}
@@ -206,10 +206,17 @@ public:
void emitInst(IRInst* inst);
- void emitSemantics(VarLayout* varLayout);
+ // TODO: When this signature switched from `VarLayout` to `IRVarLayout`
+ // it became possible to get confused beetween this overload and the
+ // one that takes a base `IRInst`. We should probably be careful and
+ // rename one of the other of the `emitSemantics()` functions to avoid
+ // confusion.
+ //
+ void emitSemantics(IRVarLayout* varLayout);
+
void emitSemantics(IRInst* inst);
- static VarLayout* getVarLayout(IRInst* var);
+ static IRVarLayout* getVarLayout(IRInst* var);
void emitLayoutSemantics(IRInst* inst, char const* uniformSemanticSpelling = "register");
@@ -244,9 +251,9 @@ public:
void emitFuncDecl(IRFunc* func);
- EntryPointLayout* getEntryPointLayout(IRFunc* func);
+ IREntryPointLayout* getEntryPointLayout(IRFunc* func);
- EntryPointLayout* asEntryPoint(IRFunc* func);
+ IREntryPointLayout* asEntryPoint(IRFunc* func);
// Detect if the given IR function represents a
// declaration of an intrinsic/builtin for the
@@ -262,7 +269,7 @@ public:
void emitStruct(IRStructType* structType);
- void emitInterpolationModifiers(IRInst* varInst, IRType* valueType, VarLayout* layout);
+ void emitInterpolationModifiers(IRInst* varInst, IRType* valueType, IRVarLayout* layout);
UInt getRayPayloadLocation(IRInst* inst);
@@ -271,7 +278,7 @@ public:
/// Emit modifiers that should apply even for a declaration of an SSA temporary.
void emitTempModifiers(IRInst* temp);
- void emitVarModifiers(VarLayout* layout, IRInst* varDecl, IRType* varType);
+ void emitVarModifiers(IRVarLayout* layout, IRInst* varDecl, IRType* varType);
/// Emit the array brackets that go on the end of a declaration of the given type.
void emitArrayBrackets(IRType* inType);
@@ -317,16 +324,16 @@ public:
virtual void emitEntryPointAttributesImpl(IRFunc* irFunc, IREntryPointDecoration* entryPointDecor) = 0;
virtual void emitImageFormatModifierImpl(IRInst* varDecl, IRType* varType) { SLANG_UNUSED(varDecl); SLANG_UNUSED(varType); }
- virtual void emitLayoutQualifiersImpl(VarLayout* layout) { SLANG_UNUSED(layout); }
+ virtual void emitLayoutQualifiersImpl(IRVarLayout* layout) { SLANG_UNUSED(layout); }
virtual void emitPreprocessorDirectivesImpl() {}
virtual void emitLayoutDirectivesImpl(TargetRequest* targetReq) { SLANG_UNUSED(targetReq); }
virtual void emitRateQualifiersImpl(IRRate* rate) { SLANG_UNUSED(rate); }
virtual void emitSemanticsImpl(IRInst* inst) { SLANG_UNUSED(inst); }
virtual void emitSimpleFuncParamImpl(IRParam* param);
- virtual void emitInterpolationModifiersImpl(IRInst* varInst, IRType* valueType, VarLayout* layout) { SLANG_UNUSED(varInst); SLANG_UNUSED(valueType); SLANG_UNUSED(layout); }
+ virtual void emitInterpolationModifiersImpl(IRInst* varInst, IRType* valueType, IRVarLayout* layout) { SLANG_UNUSED(varInst); SLANG_UNUSED(valueType); SLANG_UNUSED(layout); }
virtual void emitSimpleTypeImpl(IRType* type) = 0;
virtual void emitVarDecorationsImpl(IRInst* varDecl) { SLANG_UNUSED(varDecl); }
- virtual void emitMatrixLayoutModifiersImpl(VarLayout* layout) { SLANG_UNUSED(layout); }
+ virtual void emitMatrixLayoutModifiersImpl(IRVarLayout* layout) { SLANG_UNUSED(layout); }
virtual void emitTypeImpl(IRType* type, const StringSliceLoc* nameLoc);
virtual void emitSimpleValueImpl(IRInst* inst);
virtual void emitModuleImpl(IRModule* module);
diff --git a/source/slang/slang-emit-cpp.cpp b/source/slang/slang-emit-cpp.cpp
index 479359d6b..5ee0bc873 100644
--- a/source/slang/slang-emit-cpp.cpp
+++ b/source/slang/slang-emit-cpp.cpp
@@ -2389,9 +2389,9 @@ void CPPSourceEmitter::emitOperandImpl(IRInst* inst, EmitOpInfo const& outerPre
if (varLayout)
{
- auto semanticNameSpelling = varLayout->systemValueSemantic;
- if (semanticNameSpelling.getLength())
+ if(auto systemValueSemantic = varLayout->findSystemValueSemanticAttr())
{
+ String semanticNameSpelling = systemValueSemantic->getName();
semanticNameSpelling = semanticNameSpelling.toLower();
if (semanticNameSpelling == "sv_dispatchthreadid")
@@ -2714,17 +2714,18 @@ void CPPSourceEmitter::emitModuleImpl(IRModule* module)
continue;
}
- VarLayout* varLayout = CLikeSourceEmitter::getVarLayout(action.inst);
+ IRVarLayout* varLayout = CLikeSourceEmitter::getVarLayout(action.inst);
SLANG_ASSERT(varLayout);
- const VarLayout::ResourceInfo* varInfo = varLayout->FindResourceInfo(LayoutResourceKind::Uniform);
- TypeLayout* typeLayout = varLayout->getTypeLayout();
- TypeLayout::ResourceInfo* typeInfo = typeLayout->FindResourceInfo(LayoutResourceKind::Uniform);
+
+ IRVarOffsetAttr* offsetAttr = varLayout->findOffsetAttr(LayoutResourceKind::Uniform);
+ IRTypeLayout* typeLayout = varLayout->getTypeLayout();
+ IRTypeSizeAttr* sizeAttr = typeLayout->findSizeAttr(LayoutResourceKind::Uniform);
GlobalParamInfo paramInfo;
paramInfo.inst = action.inst;
// Index is the byte offset for uniform
- paramInfo.offset = varInfo ? varInfo->index : 0;
- paramInfo.size = typeInfo ? typeInfo->count.raw : 0;
+ paramInfo.offset = offsetAttr ? offsetAttr->getOffset() : 0;
+ paramInfo.size = sizeAttr ? sizeAttr->getFiniteSize() : 0;
params.add(paramInfo);
}
diff --git a/source/slang/slang-emit-glsl.cpp b/source/slang/slang-emit-glsl.cpp
index abaa89e08..4aae8376c 100644
--- a/source/slang/slang-emit-glsl.cpp
+++ b/source/slang/slang-emit-glsl.cpp
@@ -195,13 +195,13 @@ void GLSLSourceEmitter::_emitGLSLParameterGroup(IRGlobalParam* varDecl, IRUnifor
EmitVarChain containerChain = blockChain;
EmitVarChain elementChain = blockChain;
- auto typeLayout = varLayout->typeLayout->unwrapArray();
- if (auto parameterGroupTypeLayout = as<ParameterGroupTypeLayout>(typeLayout))
+ auto typeLayout = varLayout->getTypeLayout()->unwrapArray();
+ if (auto parameterGroupTypeLayout = as<IRParameterGroupTypeLayout>(typeLayout))
{
- containerChain = EmitVarChain(parameterGroupTypeLayout->containerVarLayout, &blockChain);
- elementChain = EmitVarChain(parameterGroupTypeLayout->elementVarLayout, &blockChain);
+ containerChain = EmitVarChain(parameterGroupTypeLayout->getContainerVarLayout(), &blockChain);
+ elementChain = EmitVarChain(parameterGroupTypeLayout->getElementVarLayout(), &blockChain);
- typeLayout = parameterGroupTypeLayout->elementVarLayout->typeLayout;
+ typeLayout = parameterGroupTypeLayout->getElementVarLayout()->getTypeLayout();
}
/*
@@ -432,7 +432,7 @@ bool GLSLSourceEmitter::_emitGLSLLayoutQualifier(LayoutResourceKind kind, EmitVa
{
if (!chain)
return false;
- if (!chain->varLayout->FindResourceInfo(kind))
+ if (!chain->varLayout->findOffsetAttr(kind))
return false;
UInt index = getBindingOffset(chain, kind);
@@ -509,7 +509,7 @@ bool GLSLSourceEmitter::_emitGLSLLayoutQualifier(LayoutResourceKind kind, EmitVa
return true;
}
-void GLSLSourceEmitter::_emitGLSLLayoutQualifiers(RefPtr<VarLayout> layout, EmitVarChain* inChain, LayoutResourceKind filter)
+void GLSLSourceEmitter::_emitGLSLLayoutQualifiers(IRVarLayout* layout, EmitVarChain* inChain, LayoutResourceKind filter)
{
if (!layout) return;
@@ -524,16 +524,16 @@ void GLSLSourceEmitter::_emitGLSLLayoutQualifiers(RefPtr<VarLayout> layout, Emit
EmitVarChain chain(layout, inChain);
- for (auto info : layout->resourceInfos)
+ for (auto info : layout->getOffsetAttrs())
{
// Skip info that doesn't match our filter
if (filter != LayoutResourceKind::None
- && filter != info.kind)
+ && filter != info->getResourceKind())
{
continue;
}
- _emitGLSLLayoutQualifier(info.kind, &chain);
+ _emitGLSLLayoutQualifier(info->getResourceKind(), &chain);
}
}
@@ -849,16 +849,16 @@ void GLSLSourceEmitter::emitImageFormatModifierImpl(IRInst* varDecl, IRType* var
}
}
-void GLSLSourceEmitter::emitLayoutQualifiersImpl(VarLayout* layout)
+void GLSLSourceEmitter::emitLayoutQualifiersImpl(IRVarLayout* layout)
{
// Layout-related modifiers need to come before the declaration,
// so deal with them here.
_emitGLSLLayoutQualifiers(layout, nullptr);
// try to emit an appropriate leading qualifier
- for (auto rr : layout->resourceInfos)
+ for (auto rr : layout->getOffsetAttrs())
{
- switch (rr.kind)
+ switch (rr->getResourceKind())
{
case LayoutResourceKind::Uniform:
case LayoutResourceKind::ShaderResource:
@@ -1471,7 +1471,7 @@ static UnownedStringSlice _getInterpolationModifierText(IRInterpolationMode mode
}
}
-void GLSLSourceEmitter::emitInterpolationModifiersImpl(IRInst* varInst, IRType* valueType, VarLayout* layout)
+void GLSLSourceEmitter::emitInterpolationModifiersImpl(IRInst* varInst, IRType* valueType, IRVarLayout* layout)
{
bool anyModifiers = false;
@@ -1507,8 +1507,8 @@ void GLSLSourceEmitter::emitInterpolationModifiersImpl(IRInst* varInst, IRType*
// output everything with `flat` except for
// fragment *outputs* (and maybe vertex inputs).
//
- if (layout && layout->stage == Stage::Fragment
- && layout->FindResourceInfo(LayoutResourceKind::VaryingInput))
+ if (layout && layout->getStage() == Stage::Fragment
+ && layout->usesResourceKind(LayoutResourceKind::VaryingInput))
{
_maybeEmitGLSLFlatModifier(valueType);
}
@@ -1548,24 +1548,22 @@ void GLSLSourceEmitter::emitVarDecorationsImpl(IRInst* varDecl)
}
}
-void GLSLSourceEmitter::emitMatrixLayoutModifiersImpl(VarLayout* layout)
+void GLSLSourceEmitter::emitMatrixLayoutModifiersImpl(IRVarLayout* layout)
{
// When a variable has a matrix type, we want to emit an explicit
// layout qualifier based on what the layout has been computed to be.
//
- auto typeLayout = layout->typeLayout;
- while (auto arrayTypeLayout = as<ArrayTypeLayout>(typeLayout))
- typeLayout = arrayTypeLayout->elementTypeLayout;
+ auto typeLayout = layout->getTypeLayout()->unwrapArray();
- if (auto matrixTypeLayout = typeLayout.as<MatrixTypeLayout>())
+ if (auto matrixTypeLayout = as<IRMatrixTypeLayout>(typeLayout))
{
// Reminder: the meaning of row/column major layout
// in our semantics is the *opposite* of what GLSL
// calls them, because what they call "columns"
// are what we call "rows."
//
- switch (matrixTypeLayout->mode)
+ switch (matrixTypeLayout->getMode())
{
case kMatrixLayoutMode_ColumnMajor:
m_writer->emit("layout(row_major)\n");
diff --git a/source/slang/slang-emit-glsl.h b/source/slang/slang-emit-glsl.h
index e3517d5be..bbb9c132a 100644
--- a/source/slang/slang-emit-glsl.h
+++ b/source/slang/slang-emit-glsl.h
@@ -22,18 +22,18 @@ protected:
virtual void emitParameterGroupImpl(IRGlobalParam* varDecl, IRUniformParameterGroupType* type) SLANG_OVERRIDE;
virtual void emitEntryPointAttributesImpl(IRFunc* irFunc, IREntryPointDecoration* entryPointDecor) SLANG_OVERRIDE;
virtual void emitImageFormatModifierImpl(IRInst* varDecl, IRType* varType) SLANG_OVERRIDE;
- virtual void emitLayoutQualifiersImpl(VarLayout* layout) SLANG_OVERRIDE;
+ virtual void emitLayoutQualifiersImpl(IRVarLayout* layout) SLANG_OVERRIDE;
virtual void emitTextureOrTextureSamplerTypeImpl(IRTextureTypeBase* type, char const* baseName) SLANG_OVERRIDE { _emitGLSLTextureOrTextureSamplerType(type, baseName); }
virtual void emitPreprocessorDirectivesImpl() SLANG_OVERRIDE;
virtual void emitLayoutDirectivesImpl(TargetRequest* targetReq) SLANG_OVERRIDE;
virtual void emitRateQualifiersImpl(IRRate* rate) SLANG_OVERRIDE;
- virtual void emitInterpolationModifiersImpl(IRInst* varInst, IRType* valueType, VarLayout* layout) SLANG_OVERRIDE;
+ virtual void emitInterpolationModifiersImpl(IRInst* varInst, IRType* valueType, IRVarLayout* layout) SLANG_OVERRIDE;
virtual void emitSimpleTypeImpl(IRType* type) SLANG_OVERRIDE;
virtual void emitVectorTypeNameImpl(IRType* elementType, IRIntegerValue elementCount) SLANG_OVERRIDE;
virtual void emitVarDecorationsImpl(IRInst* varDecl) SLANG_OVERRIDE;
- virtual void emitMatrixLayoutModifiersImpl(VarLayout* layout) SLANG_OVERRIDE;
+ virtual void emitMatrixLayoutModifiersImpl(IRVarLayout* layout) SLANG_OVERRIDE;
virtual void handleCallExprDecorationsImpl(IRInst* funcValue) SLANG_OVERRIDE;
@@ -48,7 +48,7 @@ protected:
void _emitGLSLImageFormatModifier(IRInst* var, IRTextureType* resourceType);
- void _emitGLSLLayoutQualifiers(RefPtr<VarLayout> layout, EmitVarChain* inChain, LayoutResourceKind filter = LayoutResourceKind::None);
+ void _emitGLSLLayoutQualifiers(IRVarLayout* layout, EmitVarChain* inChain, LayoutResourceKind filter = LayoutResourceKind::None);
bool _emitGLSLLayoutQualifier(LayoutResourceKind kind, EmitVarChain* chain);
void _emitGLSLTypePrefix(IRType* type, bool promoteHalfToFloat = false);
diff --git a/source/slang/slang-emit-hlsl.cpp b/source/slang/slang-emit-hlsl.cpp
index 0ee51e117..9d2334dc3 100644
--- a/source/slang/slang-emit-hlsl.cpp
+++ b/source/slang/slang-emit-hlsl.cpp
@@ -40,7 +40,7 @@ void HLSLSourceEmitter::_emitHLSLRegisterSemantic(LayoutResourceKind kind, EmitV
{
if (!chain)
return;
- if (!chain->varLayout->FindResourceInfo(kind))
+ if (!chain->varLayout->usesResourceKind(kind))
return;
UInt index = getBindingOffset(chain, kind);
@@ -144,13 +144,13 @@ void HLSLSourceEmitter::_emitHLSLRegisterSemantics(EmitVarChain* chain, char con
break;
}
- for (auto rr : layout->resourceInfos)
+ for (auto rr : layout->getOffsetAttrs())
{
- _emitHLSLRegisterSemantic(rr.kind, chain, uniformSemanticSpelling);
+ _emitHLSLRegisterSemantic(rr->getResourceKind(), chain, uniformSemanticSpelling);
}
}
-void HLSLSourceEmitter::_emitHLSLRegisterSemantics(VarLayout* varLayout, char const* uniformSemanticSpelling)
+void HLSLSourceEmitter::_emitHLSLRegisterSemantics(IRVarLayout* varLayout, char const* uniformSemanticSpelling)
{
if (!varLayout)
return;
@@ -165,13 +165,13 @@ void HLSLSourceEmitter::_emitHLSLParameterGroupFieldLayoutSemantics(EmitVarChain
return;
auto layout = chain->varLayout;
- for (auto rr : layout->resourceInfos)
+ for (auto rr : layout->getOffsetAttrs())
{
- _emitHLSLRegisterSemantic(rr.kind, chain, "packoffset");
+ _emitHLSLRegisterSemantic(rr->getResourceKind(), chain, "packoffset");
}
}
-void HLSLSourceEmitter::_emitHLSLParameterGroupFieldLayoutSemantics(RefPtr<VarLayout> fieldLayout, EmitVarChain* inChain)
+void HLSLSourceEmitter::_emitHLSLParameterGroupFieldLayoutSemantics(IRVarLayout* fieldLayout, EmitVarChain* inChain)
{
EmitVarChain chain(fieldLayout, inChain);
_emitHLSLParameterGroupFieldLayoutSemantics(&chain);
@@ -197,13 +197,13 @@ void HLSLSourceEmitter::_emitHLSLParameterGroup(IRGlobalParam* varDecl, IRUnifor
EmitVarChain containerChain = blockChain;
EmitVarChain elementChain = blockChain;
- auto typeLayout = varLayout->typeLayout;
- if (auto parameterGroupTypeLayout = as<ParameterGroupTypeLayout>(typeLayout))
+ auto typeLayout = varLayout->getTypeLayout();
+ if (auto parameterGroupTypeLayout = as<IRParameterGroupTypeLayout>(typeLayout))
{
- containerChain = EmitVarChain(parameterGroupTypeLayout->containerVarLayout, &blockChain);
- elementChain = EmitVarChain(parameterGroupTypeLayout->elementVarLayout, &blockChain);
+ containerChain = EmitVarChain(parameterGroupTypeLayout->getContainerVarLayout(), &blockChain);
+ elementChain = EmitVarChain(parameterGroupTypeLayout->getElementVarLayout(), &blockChain);
- typeLayout = parameterGroupTypeLayout->elementVarLayout->typeLayout;
+ typeLayout = parameterGroupTypeLayout->getElementVarLayout()->getTypeLayout();
}
_emitHLSLRegisterSemantic(LayoutResourceKind::ConstantBuffer, &containerChain);
@@ -645,14 +645,14 @@ void HLSLSourceEmitter::emitSemanticsImpl(IRInst* inst)
if (auto layoutDecoration = inst->findDecoration<IRLayoutDecoration>())
{
- auto layout = layoutDecoration->getIRLayout()->getASTLayout();
- if (auto varLayout = as<VarLayout>(layout))
+ auto layout = layoutDecoration->getLayout();
+ if (auto varLayout = as<IRVarLayout>(layout))
{
emitSemantics(varLayout);
}
- else if (auto entryPointLayout = as<EntryPointLayout>(layout))
+ else if (auto entryPointLayout = as<IREntryPointLayout>(layout))
{
- if (auto resultLayout = entryPointLayout->resultLayout)
+ if (auto resultLayout = entryPointLayout->getResultLayout())
{
emitSemantics(resultLayout);
}
@@ -691,7 +691,7 @@ static UnownedStringSlice _getInterpolationModifierText(IRInterpolationMode mode
}
}
-void HLSLSourceEmitter::emitInterpolationModifiersImpl(IRInst* varInst, IRType* valueType, VarLayout* layout)
+void HLSLSourceEmitter::emitInterpolationModifiersImpl(IRInst* varInst, IRType* valueType, IRVarLayout* layout)
{
SLANG_UNUSED(layout);
SLANG_UNUSED(valueType);
@@ -720,19 +720,17 @@ void HLSLSourceEmitter::emitVarDecorationsImpl(IRInst* varDecl)
}
}
-void HLSLSourceEmitter::emitMatrixLayoutModifiersImpl(VarLayout* layout)
+void HLSLSourceEmitter::emitMatrixLayoutModifiersImpl(IRVarLayout* layout)
{
// When a variable has a matrix type, we want to emit an explicit
// layout qualifier based on what the layout has been computed to be.
//
- auto typeLayout = layout->typeLayout;
- while (auto arrayTypeLayout = as<ArrayTypeLayout>(typeLayout))
- typeLayout = arrayTypeLayout->elementTypeLayout;
+ auto typeLayout = layout->getTypeLayout()->unwrapArray();
- if (auto matrixTypeLayout = typeLayout.as<MatrixTypeLayout>())
+ if (auto matrixTypeLayout = as<IRMatrixTypeLayout>(typeLayout))
{
- switch (matrixTypeLayout->mode)
+ switch (matrixTypeLayout->getMode())
{
case kMatrixLayoutMode_ColumnMajor:
m_writer->emit("column_major ");
diff --git a/source/slang/slang-emit-hlsl.h b/source/slang/slang-emit-hlsl.h
index b06a24583..2120562e6 100644
--- a/source/slang/slang-emit-hlsl.h
+++ b/source/slang/slang-emit-hlsl.h
@@ -25,11 +25,11 @@ protected:
virtual void emitRateQualifiersImpl(IRRate* rate) SLANG_OVERRIDE;
virtual void emitSemanticsImpl(IRInst* inst) SLANG_OVERRIDE;
virtual void emitSimpleFuncParamImpl(IRParam* param) SLANG_OVERRIDE;
- virtual void emitInterpolationModifiersImpl(IRInst* varInst, IRType* valueType, VarLayout* layout) SLANG_OVERRIDE;
+ virtual void emitInterpolationModifiersImpl(IRInst* varInst, IRType* valueType, IRVarLayout* layout) SLANG_OVERRIDE;
virtual void emitSimpleTypeImpl(IRType* type) SLANG_OVERRIDE;
virtual void emitVectorTypeNameImpl(IRType* elementType, IRIntegerValue elementCount) SLANG_OVERRIDE;
virtual void emitVarDecorationsImpl(IRInst* varDecl) SLANG_OVERRIDE;
- virtual void emitMatrixLayoutModifiersImpl(VarLayout* layout) SLANG_OVERRIDE;
+ virtual void emitMatrixLayoutModifiersImpl(IRVarLayout* layout) SLANG_OVERRIDE;
virtual bool tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOuterPrec) SLANG_OVERRIDE;
@@ -39,10 +39,10 @@ protected:
// Emit all the `register` semantics that are appropriate for a particular variable layout
void _emitHLSLRegisterSemantics(EmitVarChain* chain, char const* uniformSemanticSpelling = "register");
- void _emitHLSLRegisterSemantics(VarLayout* varLayout, char const* uniformSemanticSpelling = "register");
+ void _emitHLSLRegisterSemantics(IRVarLayout* varLayout, char const* uniformSemanticSpelling = "register");
void _emitHLSLParameterGroupFieldLayoutSemantics(EmitVarChain* chain);
- void _emitHLSLParameterGroupFieldLayoutSemantics(RefPtr<VarLayout> fieldLayout, EmitVarChain* inChain);
+ void _emitHLSLParameterGroupFieldLayoutSemantics(IRVarLayout* fieldLayout, EmitVarChain* inChain);
void _emitHLSLParameterGroup(IRGlobalParam* varDecl, IRUniformParameterGroupType* type);
diff --git a/source/slang/slang-ir-bind-existentials.cpp b/source/slang/slang-ir-bind-existentials.cpp
index ed400ba0a..651143847 100644
--- a/source/slang/slang-ir-bind-existentials.cpp
+++ b/source/slang/slang-ir-bind-existentials.cpp
@@ -196,14 +196,14 @@ struct BindExistentialSlots
auto layoutDecoration = param->findDecoration<IRLayoutDecoration>();
if(!layoutDecoration)
return;
- auto varLayout = as<VarLayout>(layoutDecoration->getASTLayout());
+ auto varLayout = as<IRVarLayout>(layoutDecoration->getLayout());
if(!varLayout)
return;
// We only care about parameters that are associated
// with one or more existential slots.
//
- auto resInfo = varLayout->FindResourceInfo(LayoutResourceKind::ExistentialTypeParam);
+ auto resInfo = varLayout->findOffsetAttr(LayoutResourceKind::ExistentialTypeParam);
if(!resInfo)
return;
@@ -212,8 +212,8 @@ struct BindExistentialSlots
// the type to find out the number of slots.
//
UInt slotCount = 0;
- if(auto typeResInfo = varLayout->getTypeLayout()->FindResourceInfo(LayoutResourceKind::ExistentialTypeParam))
- slotCount = UInt(typeResInfo->count.getFiniteValue());
+ if(auto typeResInfo = varLayout->getTypeLayout()->findSizeAttr(LayoutResourceKind::ExistentialTypeParam))
+ slotCount = UInt(typeResInfo->getFiniteSize());
// At this point we know that the parameter consumes
// some number of slots, so it would be an error
diff --git a/source/slang/slang-ir-entry-point-uniforms.cpp b/source/slang/slang-ir-entry-point-uniforms.cpp
index 3a6e9e82c..ad535b747 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->getASTLayout());
+ auto entryPointLayout = as<IREntryPointLayout>(funcLayoutDecoration->getLayout());
SLANG_ASSERT(entryPointLayout);
if(!entryPointLayout)
return;
@@ -167,8 +167,10 @@ struct MoveEntryPointUniformParametersToGlobalScope
// If we are in the latter case we will need to make sure to allocate
// an explicit IR constant buffer for that wrapper,
//
- auto entryPointParamsLayout = entryPointLayout->parametersLayout;
- bool needConstantBuffer = targetNeedsConstantBuffer && entryPointParamsLayout->typeLayout.is<ParameterGroupTypeLayout>();
+ auto entryPointParamsLayout = entryPointLayout->getParamsLayout();
+ bool needConstantBuffer = targetNeedsConstantBuffer && as<IRParameterGroupTypeLayout>(entryPointParamsLayout->getTypeLayout());
+
+ auto entryPointParamsStructLayout = getScopeStructLayout(entryPointLayout);
// We will set up an IR builder so that we are ready to generate code.
//
@@ -196,9 +198,11 @@ struct MoveEntryPointUniformParametersToGlobalScope
// us modifying it along the way.
//
IRParam* nextParam = nullptr;
+ UInt paramCounter = 0;
for( IRParam* param = func->getFirstParam(); param; param = nextParam )
{
nextParam = param->getNextParam();
+ UInt paramIndex = paramCounter++;
// We expect all entry-point parameters to have layout information,
// but we will be defensive and skip parameters without the required
@@ -208,7 +212,7 @@ struct MoveEntryPointUniformParametersToGlobalScope
SLANG_ASSERT(layoutDecoration);
if(!layoutDecoration)
continue;
- auto paramLayout = as<VarLayout>(layoutDecoration->getIRLayout()->getASTLayout());
+ auto paramLayout = as<IRVarLayout>(layoutDecoration->getLayout());
SLANG_ASSERT(paramLayout);
if(!paramLayout)
continue;
@@ -268,7 +272,21 @@ struct MoveEntryPointUniformParametersToGlobalScope
auto paramType = param->getFullType();
builder->setInsertBefore(paramStructType);
- auto paramFieldKey = builder->createStructKey();
+
+ // We need to know the "key" that should be used for the parameter,
+ // so we will read it off of the entry-point layout information.
+ //
+ // TODO: Maybe we should associate the key to the parameter via
+ // a decoration to avoid this indirection?
+ //
+ // TODO: Alternatively, we should make this pass responsible for
+ // dealing with the transfer of layout information from the entry
+ // point to its parameters, rather than baking that behavior into
+ // the linker. After all, this pass is traversing the same information
+ // anyway, so it could do the work while it is here...
+ //
+ auto paramFieldKey = entryPointParamsStructLayout->getFieldLayoutAttrs()[paramIndex]->getFieldKey();
+
auto paramField = builder->createStructField(paramStructType, paramFieldKey, paramType);
SLANG_UNUSED(paramField);
@@ -280,17 +298,6 @@ struct MoveEntryPointUniformParametersToGlobalScope
//
param->transferDecorationsTo(paramFieldKey);
- // There is a bit of a hacky issue, where downstream passes (notably
- // type legalization) require the field keys for `struct` types to
- // have mangled names, because those mangled names will be used to
- // lookup field layout information inside of the layout information
- // for the `struct` type.
- //
- // TODO: We should fix that design choice in how layout information
- // is stored, to avoid the reliance on name strings.
- //
- builder->addExportDecoration(paramFieldKey, getMangledName(paramLayout->varDecl).getUnownedSlice());
-
// At this point we want to eliminate the original entry point
// parameter, in favor of the `struct` field we declared.
// That required replacing any uses of the parameter with
@@ -363,7 +370,7 @@ struct MoveEntryPointUniformParametersToGlobalScope
// We need to be able to determine if a parameter is logically
// a "varying" parameter based on its layout.
//
- bool isVaryingParameter(VarLayout* layout)
+ bool isVaryingParameter(IRVarLayout* layout)
{
// If *any* of the resources consumed by the parameter
// is a varying resource kind (e.g., varying input) then
@@ -372,9 +379,9 @@ struct MoveEntryPointUniformParametersToGlobalScope
// This is reasonable because there is no way to declare
// a parameter that mixes varying and non-varying fields.
//
- for( auto resInfo : layout->resourceInfos )
+ for( auto resInfo : layout->getOffsetAttrs() )
{
- if(isVaryingResourceKind(resInfo.kind))
+ if(isVaryingResourceKind(resInfo->getResourceKind()))
return true;
}
@@ -388,7 +395,7 @@ struct MoveEntryPointUniformParametersToGlobalScope
// Note: an empty `struct` parameter would also show up the same way, but
// we should eliminate any such parameters later on during type legalization.
//
- if(layout->resourceInfos.getCount() == 0)
+ if(layout->getOffsetAttrs().getCount() == 0)
return true;
// if none of the above tests determined that the
diff --git a/source/slang/slang-ir-glsl-legalize.cpp b/source/slang/slang-ir-glsl-legalize.cpp
index 373acb802..b70d37e80 100644
--- a/source/slang/slang-ir-glsl-legalize.cpp
+++ b/source/slang/slang-ir-glsl-legalize.cpp
@@ -209,7 +209,7 @@ struct GLSLLegalizationContext
GLSLSystemValueInfo* getGLSLSystemValueInfo(
GLSLLegalizationContext* context,
- VarLayout* varLayout,
+ IRVarLayout* varLayout,
LayoutResourceKind kind,
Stage stage,
GLSLSystemValueInfo* inStorage)
@@ -217,10 +217,11 @@ GLSLSystemValueInfo* getGLSLSystemValueInfo(
char const* name = nullptr;
char const* outerArrayName = nullptr;
- auto semanticNameSpelling = varLayout->systemValueSemantic;
- if(semanticNameSpelling.getLength() == 0)
+ auto semanticInst = varLayout->findSystemValueSemanticAttr();
+ if(!semanticInst)
return nullptr;
+ String semanticNameSpelling = semanticInst->getName();
auto semanticName = semanticNameSpelling.toLower();
// HLSL semantic types can be found here
@@ -543,7 +544,7 @@ GLSLSystemValueInfo* getGLSLSystemValueInfo(
return inStorage;
}
- context->getSink()->diagnose(varLayout->varDecl.getDecl()->loc, Diagnostics::unknownSystemValueSemantic, semanticNameSpelling);
+ context->getSink()->diagnose(varLayout->sourceLoc, Diagnostics::unknownSystemValueSemantic, semanticNameSpelling);
return nullptr;
}
@@ -551,8 +552,8 @@ ScalarizedVal createSimpleGLSLGlobalVarying(
GLSLLegalizationContext* context,
IRBuilder* builder,
IRType* inType,
- VarLayout* inVarLayout,
- TypeLayout* inTypeLayout,
+ IRVarLayout* inVarLayout,
+ IRTypeLayout* inTypeLayout,
LayoutResourceKind kind,
Stage stage,
UInt bindingIndex,
@@ -578,7 +579,7 @@ ScalarizedVal createSimpleGLSLGlobalVarying(
// Construct the actual type and type-layout for the global variable
//
- RefPtr<TypeLayout> typeLayout = inTypeLayout;
+ IRTypeLayout* typeLayout = inTypeLayout;
for( auto dd = declarator; dd; dd = dd->next )
{
// We only have one declarator case right now...
@@ -588,23 +589,18 @@ ScalarizedVal createSimpleGLSLGlobalVarying(
type,
dd->elementCount);
- RefPtr<ArrayTypeLayout> arrayTypeLayout = new ArrayTypeLayout();
-// arrayTypeLayout->type = arrayType;
- arrayTypeLayout->rules = typeLayout->rules;
- arrayTypeLayout->originalElementTypeLayout = typeLayout;
- arrayTypeLayout->elementTypeLayout = typeLayout;
- arrayTypeLayout->uniformStride = 0;
-
- if( auto resInfo = inTypeLayout->FindResourceInfo(kind) )
+ IRArrayTypeLayout::Builder arrayTypeLayoutBuilder(builder, typeLayout);
+ if( auto resInfo = inTypeLayout->findSizeAttr(kind) )
{
// TODO: it is kind of gross to be re-running some
// of the type layout logic here.
UInt elementCount = (UInt) GetIntVal(dd->elementCount);
- arrayTypeLayout->addResourceUsage(
+ arrayTypeLayoutBuilder.addResourceUsage(
kind,
- resInfo->count * elementCount);
+ resInfo->getSize() * elementCount);
}
+ auto arrayTypeLayout = arrayTypeLayoutBuilder.build();
type = arrayType;
typeLayout = arrayTypeLayout;
@@ -614,16 +610,11 @@ ScalarizedVal createSimpleGLSLGlobalVarying(
// if the original had its own layout, because it might be
// an `inout` parameter, and we only want to deal with the case
// described by our `kind` parameter.
- RefPtr<VarLayout> varLayout = new VarLayout();
- varLayout->varDecl = inVarLayout->varDecl;
- varLayout->typeLayout = typeLayout;
- varLayout->flags = inVarLayout->flags;
- varLayout->systemValueSemantic = inVarLayout->systemValueSemantic;
- varLayout->systemValueSemanticIndex = inVarLayout->systemValueSemanticIndex;
- varLayout->semanticName = inVarLayout->semanticName;
- varLayout->semanticIndex = inVarLayout->semanticIndex;
- varLayout->stage = inVarLayout->stage;
- varLayout->AddResourceInfo(kind)->index = bindingIndex;
+ //
+ IRVarLayout::Builder varLayoutBuilder(builder, typeLayout);
+ varLayoutBuilder.cloneEverythingButOffsetsFrom(inVarLayout);
+ varLayoutBuilder.findOrAddResourceInfo(kind)->offset = bindingIndex;
+ IRVarLayout* varLayout = varLayoutBuilder.build();
// We are going to be creating a global parameter to replace
// the function parameter, but we need to handle the case
@@ -678,8 +669,8 @@ ScalarizedVal createGLSLGlobalVaryingsImpl(
GLSLLegalizationContext* context,
IRBuilder* builder,
IRType* type,
- VarLayout* varLayout,
- TypeLayout* typeLayout,
+ IRVarLayout* varLayout,
+ IRTypeLayout* typeLayout,
LayoutResourceKind kind,
Stage stage,
UInt bindingIndex,
@@ -714,9 +705,9 @@ ScalarizedVal createGLSLGlobalVaryingsImpl(
auto elementType = arrayType->getElementType();
auto elementCount = arrayType->getElementCount();
- auto arrayLayout = as<ArrayTypeLayout>(typeLayout);
+ auto arrayLayout = as<IRArrayTypeLayout>(typeLayout);
SLANG_ASSERT(arrayLayout);
- auto elementTypeLayout = arrayLayout->elementTypeLayout;
+ auto elementTypeLayout = arrayLayout->getElementTypeLayout();
GlobalVaryingDeclarator arrayDeclarator;
arrayDeclarator.flavor = GlobalVaryingDeclarator::Flavor::array;
@@ -737,9 +728,9 @@ ScalarizedVal createGLSLGlobalVaryingsImpl(
else if( auto streamType = as<IRHLSLStreamOutputType>(type))
{
auto elementType = streamType->getElementType();
- auto streamLayout = as<StreamOutputTypeLayout>(typeLayout);
+ auto streamLayout = as<IRStreamOutputTypeLayout>(typeLayout);
SLANG_ASSERT(streamLayout);
- auto elementTypeLayout = streamLayout->elementTypeLayout;
+ auto elementTypeLayout = streamLayout->getElementTypeLayout();
return createGLSLGlobalVaryingsImpl(
context,
@@ -757,7 +748,7 @@ ScalarizedVal createGLSLGlobalVaryingsImpl(
// We need to recurse down into the individual fields,
// and generate a variable for each of them.
- auto structTypeLayout = as<StructTypeLayout>(typeLayout);
+ auto structTypeLayout = as<IRStructTypeLayout>(typeLayout);
SLANG_ASSERT(structTypeLayout);
RefPtr<ScalarizedTupleValImpl> tupleValImpl = new ScalarizedTupleValImpl();
@@ -781,18 +772,18 @@ ScalarizedVal createGLSLGlobalVaryingsImpl(
{
UInt fieldIndex = fieldCounter++;
- auto fieldLayout = structTypeLayout->fields[fieldIndex];
+ auto fieldLayout = structTypeLayout->getFieldLayout(fieldIndex);
UInt fieldBindingIndex = bindingIndex;
- if(auto fieldResInfo = fieldLayout->FindResourceInfo(kind))
- fieldBindingIndex += fieldResInfo->index;
+ if(auto fieldResInfo = fieldLayout->findOffsetAttr(kind))
+ fieldBindingIndex += fieldResInfo->getOffset();
auto fieldVal = createGLSLGlobalVaryingsImpl(
context,
builder,
field->getFieldType(),
fieldLayout,
- fieldLayout->typeLayout,
+ fieldLayout->getTypeLayout(),
kind,
stage,
fieldBindingIndex,
@@ -820,16 +811,16 @@ ScalarizedVal createGLSLGlobalVaryings(
GLSLLegalizationContext* context,
IRBuilder* builder,
IRType* type,
- VarLayout* layout,
+ IRVarLayout* layout,
LayoutResourceKind kind,
Stage stage)
{
UInt bindingIndex = 0;
- if(auto rr = layout->FindResourceInfo(kind))
- bindingIndex = rr->index;
+ if(auto rr = layout->findOffsetAttr(kind))
+ bindingIndex = rr->getOffset();
return createGLSLGlobalVaryingsImpl(
context,
- builder, type, layout, layout->typeLayout, kind, stage, bindingIndex, nullptr);
+ builder, type, layout, layout->getTypeLayout(), kind, stage, bindingIndex, nullptr);
}
ScalarizedVal extractField(
@@ -1189,7 +1180,7 @@ void legalizeRayTracingEntryPointParameterForGLSL(
GLSLLegalizationContext* context,
IRFunc* func,
IRParam* pp,
- VarLayout* paramLayout)
+ IRVarLayout* paramLayout)
{
auto builder = context->getBuilder();
auto paramType = pp->getDataType();
@@ -1241,7 +1232,7 @@ void legalizeEntryPointParameterForGLSL(
GLSLLegalizationContext* context,
IRFunc* func,
IRParam* pp,
- VarLayout* paramLayout)
+ IRVarLayout* paramLayout)
{
auto builder = context->getBuilder();
auto stage = context->getStage();
@@ -1553,22 +1544,25 @@ void legalizeEntryPointForGLSL(
DiagnosticSink* sink,
GLSLExtensionTracker* glslExtensionTracker)
{
+ auto entryPointDecor = func->findDecoration<IREntryPointDecoration>();
+ SLANG_ASSERT(entryPointDecor);
+
+ auto stage = entryPointDecor->getProfile().GetStage();
+
auto layoutDecoration = func->findDecoration<IRLayoutDecoration>();
SLANG_ASSERT(layoutDecoration);
- auto entryPointLayout = as<EntryPointLayout>(layoutDecoration->getIRLayout()->getASTLayout());
+ auto entryPointLayout = as<IREntryPointLayout>(layoutDecoration->getLayout());
SLANG_ASSERT(entryPointLayout);
GLSLLegalizationContext context;
context.session = session;
- context.stage = entryPointLayout->profile.GetStage();
+ context.stage = stage;
context.sink = sink;
context.glslExtensionTracker = glslExtensionTracker;
- Stage stage = entryPointLayout->profile.GetStage();
-
// We require that the entry-point function has no uses,
// because otherwise we'd invalidate the signature
// at all existing call sites.
@@ -1631,7 +1625,7 @@ void legalizeEntryPointForGLSL(
&context,
&builder,
resultType,
- entryPointLayout->resultLayout,
+ entryPointLayout->getResultLayout(),
LayoutResourceKind::VaryingOutput,
stage);
@@ -1684,7 +1678,7 @@ void legalizeEntryPointForGLSL(
//
auto paramLayoutDecoration = pp->findDecoration<IRLayoutDecoration>();
SLANG_ASSERT(paramLayoutDecoration);
- auto paramLayout = as<VarLayout>(paramLayoutDecoration->getIRLayout()->getASTLayout());
+ auto paramLayout = as<IRVarLayout>(paramLayoutDecoration->getLayout());
SLANG_ASSERT(paramLayout);
legalizeEntryPointParameterForGLSL(
diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h
index 2e896cc93..00ac21e70 100644
--- a/source/slang/slang-ir-inst-defs.h
+++ b/source/slang/slang-ir-inst-defs.h
@@ -456,18 +456,9 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0)
INST(ExportDecoration, export, 1, 0)
INST_RANGE(LinkageDecoration, ImportDecoration, ExportDecoration)
- /* Layout decorations that do not use AST */
- INST(StageLayoutDecoration, stageLayoutDecoration, 1, 0)
- INST(ResourceInfoLayoutDecoration, resourceInfoLayoutDecoration, 3, 0)
+ INST(SemanticDecoration, semantic, 2, 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)
+ INST_RANGE(Decoration, HighLevelDeclDecoration, SemanticDecoration)
//
@@ -495,11 +486,36 @@ INST(ExtractTaggedUnionPayload, extractTaggedUnionPayload, 1, 0)
INST(BitCast, bitCast, 1, 0)
/* Layout */
- INST(VarLayout, varLayout, 4, 0)
- INST(TypeLayout, typeLayout, 1, 0)
+ INST(VarLayout, varLayout, 1, 0)
+
+ /* TypeLayout */
+ INST(TypeLayoutBase, typeLayout, 0, 0)
+ INST(ParameterGroupTypeLayout, parameterGroupTypeLayout, 2, 0)
+ INST(ArrayTypeLayout, arrayTypeLayout, 1, 0)
+ INST(StreamOutputTypeLayout, streamOutputTypeLayout, 1, 0)
+ INST(MatrixTypeLayout, matrixTypeLayout, 1, 0)
+ INST(TaggedUnionTypeLayout, taggedUnionTypeLayout, 0, 0)
+ INST(StructTypeLayout, structTypeLayout, 0, 0)
+ INST_RANGE(TypeLayout, TypeLayoutBase, StructTypeLayout)
+
INST(EntryPointLayout, EntryPointLayout, 1, 0)
INST_RANGE(Layout, VarLayout, EntryPointLayout)
+/* Attr */
+ INST(PendingLayoutAttr, pendingLayout, 1, 0)
+ INST(StageAttr, stage, 1, 0)
+ INST(StructFieldLayoutAttr, fieldLayout, 2, 0)
+ INST(CaseTypeLayoutAttr, caseLayout, 1, 0)
+ /* SemanticAttr */
+ INST(UserSemanticAttr, userSemantic, 2, 0)
+ INST(SystemValueSemanticAttr, systemValueSemantic, 2, 0)
+ INST_RANGE(SemanticAttr, UserSemanticAttr, SystemValueSemanticAttr)
+ /* LayoutResourceInfoAttr */
+ INST(TypeSizeAttr, size, 2, 0)
+ INST(VarOffsetAttr, offset, 2, 0)
+ INST_RANGE(LayoutResourceInfoAttr, TypeSizeAttr, VarOffsetAttr)
+INST_RANGE(Attr, PendingLayoutAttr, VarOffsetAttr)
+
PSEUDO_INST(Pos)
PSEUDO_INST(PreInc)
diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h
index 96ef40103..b6a3c3e93 100644
--- a/source/slang/slang-ir-insts.h
+++ b/source/slang/slang-ir-insts.h
@@ -370,129 +370,688 @@ struct IRLookupWitnessTable : IRInst
// Layout decorations
-struct IRStageLayoutDecoration : public 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 : 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)
+ IR_LEAF_ISA(SemanticDecoration)
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
+ /// An attribute that can be attached to another instruction as an operand.
+ ///
+ /// Attributes serve a similar role to decorations, in that both are ways
+ /// to attach additional information to an instruction, where the operand
+ /// of the attribute/decoration identifies the purpose of the additional
+ /// information.
+ ///
+ /// The key difference between decorations and attributes is that decorations
+ /// are stored as children of an instruction (in terms of the ownership
+ /// hierarchy), while attributes are referenced as operands.
+ ///
+ /// The key benefit of having attributes be operands is that they must
+ /// be present at the time an instruction is created, which means that
+ /// they can affect the conceptual value/identity of an instruction
+ /// in cases where we deduplicate/hash instructions by value.
+ ///
+struct IRAttr : public IRInst
{
- enum { kOp = kIROp_SemanticDecoration };
- IR_LEAF_ISA(SemanticDecoration)
+ IR_PARENT_ISA(Attr);
};
-struct IRSystemSemanticDecoration : IRSemanticDecorationBase
+ /// An attribute that specifies layout information for a single resource kind.
+struct IRLayoutResourceInfoAttr : public IRAttr
{
- enum { kOp = kIROp_SystemSemanticDecoration };
- IR_LEAF_ISA(SystemSemanticDecoration)
+ IR_PARENT_ISA(LayoutResourceInfoAttr);
+
+ IRIntLit* getResourceKindInst() { return cast<IRIntLit>(getOperand(0)); }
+ LayoutResourceKind getResourceKind() { return LayoutResourceKind(GetIntVal(getResourceKindInst())); }
};
-/// 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
+ /// An attribute that specifies offset information for a single resource kind.
+ ///
+ /// This operation can appear as `varOffset(kind, offset)` or
+ /// `varOffset(kind, offset, space)`. The latter form is only
+ /// used when `space` is non-zero.
+ ///
+struct IRVarOffsetAttr : public IRLayoutResourceInfoAttr
{
- enum { kOp = kIROp_ResourceInfoLayoutDecoration };
- IR_LEAF_ISA(ResourceInfoLayoutDecoration)
+ IR_LEAF_ISA(VarOffsetAttr);
- // What kind of register was it?
- IRIntLit* getResourceKindInst() { return cast<IRIntLit>(getOperand(0)); }
- LayoutResourceKind getResourceKind() { return (LayoutResourceKind)GetIntVal(getResourceKindInst()); }
+ IRIntLit* getOffsetInst() { return cast<IRIntLit>(getOperand(1)); }
+ UInt getOffset() { return UInt(GetIntVal(getOffsetInst())); }
- // What binding space (HLSL) or set (Vulkan) are we placed in?
- IRIntLit* getSpaceInst() { return cast<IRIntLit>(getOperand(1)); }
- UInt getSpace() { return UInt(GetIntVal(getSpaceInst())); }
+ IRIntLit* getSpaceInst()
+ {
+ if(getOperandCount() > 2)
+ return cast<IRIntLit>(getOperand(2));
+ return nullptr;
+ }
- // 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())); }
+ UInt getSpace()
+ {
+ if(auto spaceInst = getSpaceInst())
+ return UInt(GetIntVal(spaceInst));
+ return 0;
+ }
+};
+
+ /// An attribute that specifies size information for a single resource kind.
+struct IRTypeSizeAttr : public IRLayoutResourceInfoAttr
+{
+ IR_LEAF_ISA(TypeSizeAttr);
+
+ IRIntLit* getSizeInst() { return cast<IRIntLit>(getOperand(1)); }
+ LayoutSize getSize() { return LayoutSize::fromRaw(LayoutSize::RawValue(GetIntVal(getSizeInst()))); }
+ size_t getFiniteSize() { return getSize().getFiniteValue(); }
};
// Layout
+ /// Base type for instructions that represent layout information.
+ ///
+ /// Layout instructions are effectively just meta-data constants.
+ ///
struct IRLayout : IRInst
{
IR_PARENT_ISA(Layout)
+};
+
+struct IRVarLayout;
+
+ /// An attribute to specify that a layout has another layout attached for "pending" data.
+ ///
+ /// "Pending" data refers to the parts of a type or variable that
+ /// couldn't be laid out until the concrete types for existential
+ /// type slots were filled in. The layout of pending data may not
+ /// be contiguous with the layout of the original type/variable.
+ ///
+struct IRPendingLayoutAttr : IRAttr
+{
+ IR_LEAF_ISA(PendingLayoutAttr);
- /// 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(); }
+ IRLayout* getLayout() { return cast<IRLayout>(getOperand(0)); }
};
+ /// Layout information for a type.
+ ///
+ /// The most important thing this instruction provides is the
+ /// resource usage (aka "size") of the type for each of the
+ /// resource kinds it consumes.
+ ///
+ /// Subtypes of `IRTypeLayout` will include additional type-specific
+ /// operands or attributes. For example, a type layout for a
+ /// `struct` type will include offset information for its fields.
+ ///
struct IRTypeLayout : IRLayout
{
- IR_LEAF_ISA(TypeLayout);
- TypeLayout* getLayout() { return static_cast<TypeLayout*>(getASTLayout()); }
+ IR_PARENT_ISA(TypeLayout);
+
+ /// Find the attribute that stores offset information for `kind`.
+ ///
+ /// Returns null if no attribute is found, indicating that this
+ /// type does not consume any resources of `kind`.
+ ///
+ IRTypeSizeAttr* findSizeAttr(LayoutResourceKind kind);
+
+ /// Get all the attributes representing size information.
+ IROperandList<IRTypeSizeAttr> getSizeAttrs();
+
+ /// Unwrap any layers of array-ness and return the outer-most non-array type.
+ IRTypeLayout* unwrapArray();
+
+ /// Get the layout for pending data, if present.
+ IRTypeLayout* getPendingDataTypeLayout();
+
+ /// A builder for constructing `IRTypeLayout`s
+ struct Builder
+ {
+ /// Begin building.
+ ///
+ /// The `irBuilder` will be used to construct the
+ /// type layout and any additional instructions required.
+ ///
+ Builder(IRBuilder* irBuilder);
+
+ /// Add `size` units of resource `kind` to the resource usage of this type.
+ void addResourceUsage(
+ LayoutResourceKind kind,
+ LayoutSize size);
+
+ /// Add the resource usage specified by `sizeAttr`.
+ void addResourceUsage(IRTypeSizeAttr* sizeAttr);
+
+ /// Add all resource usage from `typeLayout`.
+ void addResourceUsageFrom(IRTypeLayout* typeLayout);
+
+ /// Set the (optional) layout for pending data.
+ void setPendingTypeLayout(
+ IRTypeLayout* typeLayout)
+ {
+ m_pendingTypeLayout = typeLayout;
+ }
+
+ /// Build a type layout according to the information specified so far.
+ IRTypeLayout* build();
+
+ protected:
+ // The following services are provided so that
+ // subtypes of `IRTypeLayout` can provide their
+ // own `Builder` subtypes that construct appropriate
+ // layouts.
+
+ /// Override to customize the opcode of the generated layout.
+ virtual IROp getOp() { return kIROp_TypeLayoutBase; }
+
+ /// Override to add additional operands to the generated layout.
+ virtual void addOperandsImpl(List<IRInst*>&) {}
+
+ /// Override to add additional attributes to the generated layout.
+ virtual void addAttrsImpl(List<IRInst*>&) {}
+
+ /// Use to access the underlying IR builder.
+ IRBuilder* getIRBuilder() { return m_irBuilder; };
+
+ private:
+ void addOperands(List<IRInst*>&);
+ void addAttrs(List<IRInst*>& ioOperands);
+
+ IRBuilder* m_irBuilder = nullptr;
+ IRTypeLayout* m_pendingTypeLayout = nullptr;
+
+ struct ResInfo
+ {
+ LayoutResourceKind kind = LayoutResourceKind::None;
+ LayoutSize size = 0;
+ };
+ ResInfo m_resInfos[SLANG_PARAMETER_CATEGORY_COUNT];
+ };
};
+ /// Type layout for parameter groups (constant buffers and parameter blocks)
+struct IRParameterGroupTypeLayout : IRTypeLayout
+{
+private:
+ typedef IRTypeLayout Super;
+
+public:
+ IR_LEAF_ISA(ParameterGroupTypeLayout)
+
+ IRVarLayout* getContainerVarLayout()
+ {
+ return cast<IRVarLayout>(getOperand(0));
+ }
+
+ IRVarLayout* getElementVarLayout()
+ {
+ return cast<IRVarLayout>(getOperand(1));
+ }
+
+ // TODO: There shouldn't be a need for the IR to store an "offset" element type layout,
+ // but there are just enough places that currently use that information so that removing
+ // it would require some careful refactoring.
+ //
+ IRTypeLayout* getOffsetElementTypeLayout()
+ {
+ return cast<IRTypeLayout>(getOperand(2));
+ }
+
+ /// Specialized builder for parameter group type layouts.
+ struct Builder : Super::Builder
+ {
+ public:
+ Builder(IRBuilder* irBuilder)
+ : Super::Builder(irBuilder)
+ {}
+
+ void setContainerVarLayout(IRVarLayout* varLayout)
+ {
+ m_containerVarLayout = varLayout;
+ }
+
+ void setElementVarLayout(IRVarLayout* varLayout)
+ {
+ m_elementVarLayout = varLayout;
+ }
+
+ void setOffsetElementTypeLayout(IRTypeLayout* typeLayout)
+ {
+ m_offsetElementTypeLayout = typeLayout;
+ }
+
+ IRParameterGroupTypeLayout* build();
+
+ protected:
+ IROp getOp() SLANG_OVERRIDE { return kIROp_ParameterGroupTypeLayout; }
+ void addOperandsImpl(List<IRInst*>& ioOperands) SLANG_OVERRIDE;
+
+ IRVarLayout* m_containerVarLayout;
+ IRVarLayout* m_elementVarLayout;
+ IRTypeLayout* m_offsetElementTypeLayout;
+ };
+};
+
+ /// Specialized layout information for array types
+struct IRArrayTypeLayout : IRTypeLayout
+{
+ typedef IRTypeLayout Super;
+
+ IR_LEAF_ISA(ArrayTypeLayout)
+
+ IRTypeLayout* getElementTypeLayout()
+ {
+ return cast<IRTypeLayout>(getOperand(0));
+ }
+
+ struct Builder : Super::Builder
+ {
+ Builder(IRBuilder* irBuilder, IRTypeLayout* elementTypeLayout)
+ : Super::Builder(irBuilder)
+ , m_elementTypeLayout(elementTypeLayout)
+ {}
+
+ IRArrayTypeLayout* build()
+ {
+ return cast<IRArrayTypeLayout>(Super::Builder::build());
+ }
+
+ protected:
+ IROp getOp() SLANG_OVERRIDE { return kIROp_ArrayTypeLayout; }
+ void addOperandsImpl(List<IRInst*>& ioOperands) SLANG_OVERRIDE;
+
+ IRTypeLayout* m_elementTypeLayout;
+ };
+};
+
+ /// Specialized layout information for stream-output types
+struct IRStreamOutputTypeLayout : IRTypeLayout
+{
+ typedef IRTypeLayout Super;
+
+ IR_LEAF_ISA(StreamOutputTypeLayout)
+
+ IRTypeLayout* getElementTypeLayout()
+ {
+ return cast<IRTypeLayout>(getOperand(0));
+ }
+
+ struct Builder : Super::Builder
+ {
+ Builder(IRBuilder* irBuilder, IRTypeLayout* elementTypeLayout)
+ : Super::Builder(irBuilder)
+ , m_elementTypeLayout(elementTypeLayout)
+ {}
+
+ IRArrayTypeLayout* build()
+ {
+ return cast<IRArrayTypeLayout>(Super::Builder::build());
+ }
+
+ protected:
+ IROp getOp() SLANG_OVERRIDE { return kIROp_StreamOutputTypeLayout; }
+ void addOperandsImpl(List<IRInst*>& ioOperands) SLANG_OVERRIDE;
+
+ IRTypeLayout* m_elementTypeLayout;
+ };
+};
+
+ /// Specialized layout information for matrix types
+struct IRMatrixTypeLayout : IRTypeLayout
+{
+ typedef IRTypeLayout Super;
+
+ IR_LEAF_ISA(MatrixTypeLayout)
+
+ MatrixLayoutMode getMode()
+ {
+ return MatrixLayoutMode(GetIntVal(cast<IRIntLit>(getOperand(0))));
+ }
+
+ struct Builder : Super::Builder
+ {
+ Builder(IRBuilder* irBuilder, MatrixLayoutMode mode);
+
+ IRMatrixTypeLayout* build()
+ {
+ return cast<IRMatrixTypeLayout>(Super::Builder::build());
+ }
+
+ protected:
+ IROp getOp() SLANG_OVERRIDE { return kIROp_MatrixTypeLayout; }
+ void addOperandsImpl(List<IRInst*>& ioOperands) SLANG_OVERRIDE;
+
+ IRInst* m_modeInst = nullptr;
+ };
+};
+
+ /// Attribute that specifies the layout for one field of a structure type.
+struct IRStructFieldLayoutAttr : IRAttr
+{
+ IR_LEAF_ISA(StructFieldLayoutAttr)
+
+ IRStructKey* getFieldKey()
+ {
+ return cast<IRStructKey>(getOperand(0));
+ }
+
+ IRVarLayout* getLayout()
+ {
+ return cast<IRVarLayout>(getOperand(1));
+ }
+};
+
+ /// Specialized layout information for structure types.
+struct IRStructTypeLayout : IRTypeLayout
+{
+ IR_LEAF_ISA(StructTypeLayout)
+
+ typedef IRTypeLayout Super;
+
+ /// Get all of the attributes that represent field layouts.
+ IROperandList<IRStructFieldLayoutAttr> getFieldLayoutAttrs()
+ {
+ return findAttrs<IRStructFieldLayoutAttr>();
+ }
+
+ /// Get the number of fields for which layout information is stored.
+ UInt getFieldCount()
+ {
+ return getFieldLayoutAttrs().getCount();
+ }
+
+ /// Get the layout information for a field by `index`
+ IRVarLayout* getFieldLayout(UInt index)
+ {
+ return getFieldLayoutAttrs()[index]->getLayout();
+ }
+
+ /// Specialized builder for structure type layouts.
+ struct Builder : Super::Builder
+ {
+ Builder(IRBuilder* irBuilder)
+ : Super::Builder(irBuilder)
+ {}
+
+ void addField(IRStructKey* key, IRVarLayout* layout)
+ {
+ FieldInfo info;
+ info.key = key;
+ info.layout = layout;
+ m_fields.add(info);
+ }
+
+ IRStructTypeLayout* build()
+ {
+ return cast<IRStructTypeLayout>(Super::Builder::build());
+ }
+
+ protected:
+ IROp getOp() SLANG_OVERRIDE { return kIROp_StructTypeLayout; }
+ void addAttrsImpl(List<IRInst*>& ioOperands) SLANG_OVERRIDE;
+
+ struct FieldInfo
+ {
+ IRStructKey* key;
+ IRVarLayout* layout;
+ };
+
+ List<FieldInfo> m_fields;
+ };
+};
+
+ /// Attribute that represents the layout for one case of a union type
+struct IRCaseTypeLayoutAttr : IRAttr
+{
+ IR_LEAF_ISA(CaseTypeLayoutAttr);
+
+ IRTypeLayout* getTypeLayout()
+ {
+ return cast<IRTypeLayout>(getOperand(0));
+ }
+};
+
+ /// Specialized layout information for tagged union types
+struct IRTaggedUnionTypeLayout : IRTypeLayout
+{
+ typedef IRTypeLayout Super;
+
+ IR_LEAF_ISA(TaggedUnionTypeLayout)
+
+ /// Get the (byte) offset of the tagged union's tag (aka "discriminator") field
+ LayoutSize getTagOffset()
+ {
+ return LayoutSize::fromRaw(LayoutSize::RawValue(GetIntVal(cast<IRIntLit>(getOperand(0)))));
+ }
+
+ /// Get all the attributes representing layouts for the difference cases
+ IROperandList<IRCaseTypeLayoutAttr> getCaseTypeLayoutAttrs()
+ {
+ return findAttrs<IRCaseTypeLayoutAttr>();
+ }
+
+ /// Get the number of cases for which layout information is stored
+ UInt getCaseCount()
+ {
+ return getCaseTypeLayoutAttrs().getCount();
+ }
+
+ /// Get the layout information for the case at the given `index`
+ IRTypeLayout* getCaseTypeLayout(UInt index)
+ {
+ return getCaseTypeLayoutAttrs()[index]->getTypeLayout();
+ }
+
+ /// Specialized builder for tagged union type layouts
+ struct Builder : Super::Builder
+ {
+ Builder(IRBuilder* irBuilder, LayoutSize tagOffset);
+
+ void addCaseTypeLayout(IRTypeLayout* typeLayout);
+
+ IRTaggedUnionTypeLayout* build()
+ {
+ return cast<IRTaggedUnionTypeLayout>(Super::Builder::build());
+ }
+
+ protected:
+ IROp getOp() SLANG_OVERRIDE { return kIROp_TaggedUnionTypeLayout; }
+ void addOperandsImpl(List<IRInst*>& ioOperands) SLANG_OVERRIDE;
+ void addAttrsImpl(List<IRInst*>& ioOperands) SLANG_OVERRIDE;
+
+ IRInst* m_tagOffset = nullptr;
+ List<IRAttr*> m_caseTypeLayoutAttrs;
+ };
+};
+
+ /// Layout information for an entry point
struct IREntryPointLayout : IRLayout
{
IR_LEAF_ISA(EntryPointLayout)
- EntryPointLayout* getLayout() { return static_cast<EntryPointLayout*>(getASTLayout()); }
+
+ /// Get the layout information for the entry point parameters.
+ ///
+ /// The parameters layout will either be a structure type layout
+ /// with one field per parameter, or a parameter group type
+ /// layout wrapping such a structure, if the entry point parameters
+ /// needed to be allocated into a constant buffer.
+ ///
+ IRVarLayout* getParamsLayout()
+ {
+ return cast<IRVarLayout>(getOperand(0));
+ }
+
+ /// Get the layout information for the entry point result.
+ ///
+ /// This represents the return value of the entry point.
+ /// Note that it does *not* represent all of the entry
+ /// point outputs, because the parameter list may also
+ /// contain `out` or `inout` parameters.
+ ///
+ IRVarLayout* getResultLayout()
+ {
+ return cast<IRVarLayout>(getOperand(1));
+ }
+};
+
+ /// Given an entry-point layout, extract the layout for the parameters struct.
+IRStructTypeLayout* getScopeStructLayout(IREntryPointLayout* scopeLayout);
+
+ /// Attribute that associates a variable layout with a known stage.
+struct IRStageAttr : IRAttr
+{
+ IR_LEAF_ISA(StageAttr);
+
+ IRIntLit* getStageOperand() { return cast<IRIntLit>(getOperand(0)); }
+ Stage getStage() { return Stage(GetIntVal(getStageOperand())); }
+};
+
+ /// Base type for attributes that associate a variable layout with a semantic name and index.
+struct IRSemanticAttr : IRAttr
+{
+ IR_PARENT_ISA(SemanticAttr);
+
+ IRStringLit* getNameOperand() { return cast<IRStringLit>(getOperand(0)); }
+ UnownedStringSlice getName() { return getNameOperand()->getStringSlice(); }
+
+ IRIntLit* getIndexOperand() { return cast<IRIntLit>(getOperand(1)); }
+ UInt getIndex() { return UInt(GetIntVal(getIndexOperand())); }
+};
+
+ /// Attribute that associates a variable with a system-value semantic name and index
+struct IRSystemValueSemanticAttr : IRSemanticAttr
+{
+ IR_LEAF_ISA(SystemValueSemanticAttr);
};
-// 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
+ /// Attribute that associates a variable with a user-defined semantic name and index
+struct IRUserSemanticAttr : IRSemanticAttr
+{
+ IR_LEAF_ISA(UserSemanticAttr);
+};
+
+ /// Layout infromation for a single parameter/field
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 the type layout information for this variable
+ IRTypeLayout* getTypeLayout() { return cast<IRTypeLayout>(getOperand(0)); }
+
+ /// Get all the attributes representing resource-kind-specific offsets
+ IROperandList<IRVarOffsetAttr> getOffsetAttrs();
+
+ /// Find the offset information (if present) for the given resource `kind`
+ IRVarOffsetAttr* findOffsetAttr(LayoutResourceKind kind);
+
+ /// Does this variable use any resources of the given `kind`?
+ bool usesResourceKind(LayoutResourceKind kind);
+
+ /// Get the fixed/known stage that this variable is associated with.
+ ///
+ /// This will be a specific stage for entry-point parameters, but
+ /// will be `Stage::Unknown` for any parameter that is not bound
+ /// solely to one entry point.
+ ///
+ Stage getStage();
+
+ /// Find the system-value semantic attribute for this variable, if any.
+ IRSystemValueSemanticAttr* findSystemValueSemanticAttr();
+
+ /// Get the (optional) layout for any "pending" data assocaited with this variable.
+ IRVarLayout* getPendingVarLayout();
+
+ /// Builder for construction `IRVarLayout`s in a stateful fashion
+ struct Builder
+ {
+ /// Begin building a variable layout with the given `typeLayout`
+ ///
+ /// The result layout and any instructions needed along the way
+ /// will be allocated with `irBuilder`.
+ ///
+ Builder(
+ IRBuilder* irBuilder,
+ IRTypeLayout* typeLayout);
+
+ /// Represents resource-kind-specific offset information
+ struct ResInfo
+ {
+ LayoutResourceKind kind = LayoutResourceKind::None;
+ UInt offset = 0;
+ UInt space = 0;
+ };
+
+ /// Has any resource usage/offset been registered for the given resource `kind`?
+ bool usesResourceKind(LayoutResourceKind kind);
+
+ /// Either fetch or add a `ResInfo` record for `kind` and return it
+ ResInfo* findOrAddResourceInfo(LayoutResourceKind kind);
+
+ /// Set the (optional) variable layout for pending data.
+ void setPendingVarLayout(IRVarLayout* varLayout)
+ {
+ m_pendingVarLayout = varLayout;
+ }
+
+ /// Set the (optional) system-valeu semantic for this variable.
+ void setSystemValueSemantic(String const& name, UInt index);
+
+ /// Set the (optional) user-defined semantic for this variable.
+ void setUserSemantic(String const& name, UInt index);
+
+ /// Set the (optional) known stage for this variable.
+ void setStage(Stage stage);
+
+ /// Clone all of the layout information from the `other` layout, except for offsets.
+ ///
+ /// This is convenience when one wants to build a variable layout "like that other one, but..."
+ void cloneEverythingButOffsetsFrom(
+ IRVarLayout* other);
+
+ /// Build a variable layout using the current state that has been set.
+ IRVarLayout* build();
- /// Get/set absolute layout
- IRVarLayout* getAbsoluteLayout() { return cast<IRVarLayout>(getOperand(3)); }
- void setAbsoluteLayout(IRVarLayout* layout) { getOperands()[3].set(layout); }
+ private:
+ IRBuilder* m_irBuilder;
+ IRBuilder* getIRBuilder() { return m_irBuilder; };
+
+ IRTypeLayout* m_typeLayout = nullptr;
+ IRVarLayout* m_pendingVarLayout = nullptr;
+
+ IRSystemValueSemanticAttr* m_systemValueSemantic = nullptr;
+ IRUserSemanticAttr* m_userSemantic = nullptr;
+ IRStageAttr* m_stageAttr = nullptr;
+
+ ResInfo m_resInfos[SLANG_PARAMETER_CATEGORY_COUNT];
+ };
};
-// Associates an IR-level decoration with a source layout
+ /// Associate layout information with an instruction.
+ ///
+ /// This decoration is used in three main ways:
+ ///
+ /// * To attach an `IRVarLayout` to an `IRGlobalParam` or entry-point `IRParam` representing a shader parameter
+ /// * To attach an `IREntryPointLayout` to an `IRFunc` representing an entry point
+ /// * To attach an `IRTaggedUnionTypeLayout` to an `IRTaggedUnionType`
+ ///
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();
- }
+ /// Get the layout that is being attached to the parent instruction
+ IRLayout* getLayout() { return cast<IRLayout>(getOperand(0)); }
};
//
@@ -1434,9 +1993,57 @@ struct IRBuilder
void addHighLevelDeclDecoration(IRInst* value, Decl* decl);
- void addLayoutDecoration(IRInst* value, Layout* layout);
+// void addLayoutDecoration(IRInst* value, Layout* layout);
+ void addLayoutDecoration(IRInst* value, IRLayout* layout);
+
+// IRLayout* getLayout(Layout* astLayout);
+
+ IRTypeSizeAttr* getTypeSizeAttr(
+ LayoutResourceKind kind,
+ LayoutSize size);
+ IRVarOffsetAttr* getVarOffsetAttr(
+ LayoutResourceKind kind,
+ UInt offset,
+ UInt space = 0);
+ IRPendingLayoutAttr* getPendingLayoutAttr(
+ IRLayout* pendingLayout);
+ IRStructFieldLayoutAttr* getFieldLayoutAttr(
+ IRStructKey* key,
+ IRVarLayout* layout);
+ IRCaseTypeLayoutAttr* getCaseTypeLayoutAttr(
+ IRTypeLayout* layout);
+
+ IRSemanticAttr* getSemanticAttr(
+ IROp op,
+ String const& name,
+ UInt index);
+ IRSystemValueSemanticAttr* getSystemValueSemanticAttr(
+ String const& name,
+ UInt index)
+ {
+ return cast<IRSystemValueSemanticAttr>(getSemanticAttr(
+ kIROp_SystemValueSemanticAttr,
+ name,
+ index));
+ }
+ IRUserSemanticAttr* getUserSemanticAttr(
+ String const& name,
+ UInt index)
+ {
+ return cast<IRUserSemanticAttr>(getSemanticAttr(
+ kIROp_UserSemanticAttr,
+ name,
+ index));
+ }
+
+ IRStageAttr* getStageAttr(Stage stage);
+
+ IRTypeLayout* getTypeLayout(IROp op, List<IRInst*> const& operands);
+ IRVarLayout* getVarLayout(List<IRInst*> const& operands);
+ IREntryPointLayout* getEntryPointLayout(
+ IRVarLayout* paramsLayout,
+ IRVarLayout* resultLayout);
- IRLayout* getLayout(Layout* astLayout);
void addNameHintDecoration(IRInst* value, IRStringLit* name)
{
diff --git a/source/slang/slang-ir-legalize-types.cpp b/source/slang/slang-ir-legalize-types.cpp
index f2a3e3d9a..f9c78a021 100644
--- a/source/slang/slang-ir-legalize-types.cpp
+++ b/source/slang/slang-ir-legalize-types.cpp
@@ -123,7 +123,7 @@ static LegalVal declareVars(
IRTypeLegalizationContext* context,
IROp op,
LegalType type,
- TypeLayout* typeLayout,
+ IRTypeLayout* typeLayout,
LegalVarChain const& varChain,
UnownedStringSlice nameHint,
IRInst* leafVar,
@@ -1246,10 +1246,10 @@ static LegalVal legalizeInst(
}
}
-RefPtr<VarLayout> findVarLayout(IRInst* value)
+IRVarLayout* findVarLayout(IRInst* value)
{
if (auto layoutDecoration = value->findDecoration<IRLayoutDecoration>())
- return as<VarLayout>(layoutDecoration->getIRLayout()->getASTLayout());
+ return as<IRVarLayout>(layoutDecoration->getLayout());
return nullptr;
}
@@ -1274,8 +1274,8 @@ static LegalVal legalizeLocalVar(
auto originalRate = irLocalVar->getRate();
- RefPtr<VarLayout> varLayout = findVarLayout(irLocalVar);
- RefPtr<TypeLayout> typeLayout = varLayout ? varLayout->typeLayout : nullptr;
+ IRVarLayout* varLayout = findVarLayout(irLocalVar);
+ IRTypeLayout* typeLayout = varLayout ? varLayout->getTypeLayout() : nullptr;
// If we've decided to do implicit deref on the type,
// then go ahead and declare a value of the pointed-to type.
@@ -1580,7 +1580,7 @@ static LegalVal declareSimpleVar(
IRTypeLegalizationContext* context,
IROp op,
IRType* type,
- TypeLayout* typeLayout,
+ IRTypeLayout* typeLayout,
LegalVarChain const& varChain,
UnownedStringSlice nameHint,
IRInst* leafVar,
@@ -1588,9 +1588,7 @@ static LegalVal declareSimpleVar(
{
SLANG_UNUSED(globalNameInfo);
- RefPtr<VarLayout> varLayout = createVarLayout(varChain, typeLayout);
-
- DeclRef<VarDeclBase> varDeclRef = varChain.getLeafVarDeclRef();
+ IRVarLayout* varLayout = createVarLayout(context->builder, varChain, typeLayout);
IRBuilder* builder = context->builder;
@@ -1654,11 +1652,6 @@ static LegalVal declareSimpleVar(
builder->addLayoutDecoration(irVar, varLayout);
}
- if (varDeclRef)
- {
- builder->addHighLevelDeclDecoration(irVar, varDeclRef.getDecl());
- }
-
if( nameHint.size() )
{
context->builder->addNameHintDecoration(irVar, nameHint);
@@ -1710,11 +1703,12 @@ static LegalVal declareSimpleVar(
/// when the legal wrapped buffer type was created.
///
static void _addFieldsToWrappedBufferElementTypeLayout(
- TypeLayout* elementTypeLayout, // layout of the original field type
- StructTypeLayout* newTypeLayout, // layout we are filling in
- LegalElementWrapping const& elementInfo, // information on how the original type got wrapped
- LegalVarChain const& varChain, // chain of variables that is leading to this field
- bool isSpecial) // should we assume a leaf field is a special (interface) type?
+ IRBuilder* irBuilder,
+ IRTypeLayout* elementTypeLayout, // layout of the original field type
+ IRStructTypeLayout::Builder* newTypeLayout, // layout we are filling in
+ LegalElementWrapping const& elementInfo, // information on how the original type got wrapped
+ LegalVarChain const& varChain, // chain of variables that is leading to this field
+ bool isSpecial) // should we assume a leaf field is a special (interface) type?
{
// The way we handle things depends primary on the
// `elementInfo`, because that tells us how things
@@ -1760,14 +1754,17 @@ static void _addFieldsToWrappedBufferElementTypeLayout(
// cases. We will be computing layout information
// for a field of the new/wrapped buffer element type.
//
- RefPtr<VarLayout> newFieldLayout;
+ IRVarLayout* newFieldLayout = nullptr;
if(isSpecial)
{
// In the special case, that field will be laid out
// based on the "pending" var chain, and the type
// of the pending data for the element.
//
- newFieldLayout = createSimpleVarLayout(varChain.pendingChain, elementTypeLayout->pendingDataTypeLayout);
+ newFieldLayout = createSimpleVarLayout(
+ irBuilder,
+ varChain.pendingChain,
+ elementTypeLayout->getPendingDataTypeLayout());
}
else
{
@@ -1775,7 +1772,10 @@ static void _addFieldsToWrappedBufferElementTypeLayout(
// information and the primary/nominal type of
// the field.
//
- newFieldLayout = createSimpleVarLayout(varChain.primaryChain, elementTypeLayout);
+ newFieldLayout = createSimpleVarLayout(
+ irBuilder,
+ varChain.primaryChain,
+ elementTypeLayout);
}
// Either way, we add the new field to the struct type
@@ -1783,8 +1783,7 @@ static void _addFieldsToWrappedBufferElementTypeLayout(
// information so that we can find the field layout
// based on the IR key for the struct field.
//
- newTypeLayout->fields.add(newFieldLayout);
- newTypeLayout->mapKeyToLayout.Add(simpleInfo->key, newFieldLayout);
+ newTypeLayout->addField(simpleInfo->key, newFieldLayout);
}
break;
@@ -1799,6 +1798,7 @@ static void _addFieldsToWrappedBufferElementTypeLayout(
//
auto implicitDerefInfo = elementInfo.getImplicitDeref();
_addFieldsToWrappedBufferElementTypeLayout(
+ irBuilder,
elementTypeLayout,
newTypeLayout,
implicitDerefInfo->field,
@@ -1824,12 +1824,14 @@ static void _addFieldsToWrappedBufferElementTypeLayout(
//
auto pairElementInfo = elementInfo.getPair();
_addFieldsToWrappedBufferElementTypeLayout(
+ irBuilder,
elementTypeLayout,
newTypeLayout,
pairElementInfo->ordinary,
varChain,
false);
_addFieldsToWrappedBufferElementTypeLayout(
+ irBuilder,
elementTypeLayout,
newTypeLayout,
pairElementInfo->special,
@@ -1858,7 +1860,8 @@ static void _addFieldsToWrappedBufferElementTypeLayout(
LegalVarChainLink fieldChain(varChain, oldFieldLayout);
_addFieldsToWrappedBufferElementTypeLayout(
- oldFieldLayout->typeLayout,
+ irBuilder,
+ oldFieldLayout->getTypeLayout(),
newTypeLayout,
ee.field,
fieldChain,
@@ -1880,13 +1883,13 @@ static void _addFieldsToWrappedBufferElementTypeLayout(
/// being relative to the "pending" data.
///
static void _addOffsetVarLayoutEntry(
- VarLayout* resultVarLayout,
+ IRVarLayout::Builder* resultVarLayout,
LegalVarChain const& varChain,
LayoutResourceKind kind)
{
// If the target already has an offset for this kind, bail out.
//
- if(resultVarLayout->FindResourceInfo(kind))
+ if(resultVarLayout->usesResourceKind(kind))
return;
// Add the `ResourceInfo` that will represent the offset for
@@ -1901,10 +1904,10 @@ static void _addOffsetVarLayoutEntry(
//
for(auto vv = varChain.pendingChain; vv; vv = vv->next )
{
- if( auto chainResInfo = vv->varLayout->FindResourceInfo(kind) )
+ if( auto chainResInfo = vv->varLayout->findOffsetAttr(kind) )
{
- resultResInfo->index += chainResInfo->index;
- resultResInfo->space += chainResInfo->space;
+ resultResInfo->offset += chainResInfo->getOffset();
+ resultResInfo->space += chainResInfo->getSpace();
}
}
@@ -1914,10 +1917,10 @@ static void _addOffsetVarLayoutEntry(
//
for(auto vv = varChain.primaryChain; vv; vv = vv->next )
{
- if( auto chainResInfo = vv->varLayout->FindResourceInfo(kind) )
+ if( auto chainResInfo = vv->varLayout->findOffsetAttr(kind) )
{
- resultResInfo->index -= chainResInfo->index;
- resultResInfo->space -= chainResInfo->space;
+ resultResInfo->offset -= chainResInfo->getOffset();
+ resultResInfo->space -= chainResInfo->getSpace();
}
}
}
@@ -1929,42 +1932,43 @@ static void _addOffsetVarLayoutEntry(
/// to be made relative to the "primary" data, because we are
/// legalizing the pending data out of the code.
///
-static RefPtr<VarLayout> _createOffsetVarLayout(
+static IRVarLayout* _createOffsetVarLayout(
+ IRBuilder* irBuilder,
LegalVarChain const& varChain,
- TypeLayout* typeLayout)
+ IRTypeLayout* typeLayout)
{
- RefPtr<VarLayout> resultVarLayout = new VarLayout();
+ IRVarLayout::Builder resultVarLayoutBuilder(irBuilder, typeLayout);
// For every resource kind the type consumes, we will
// compute an adjusted offset for the variable that
// encodes the (absolute) offset of the pending data
// in `varChain` relative to its primary data.
//
- for( auto resInfo : typeLayout->resourceInfos )
+ for( auto resInfo : typeLayout->getSizeAttrs() )
{
- _addOffsetVarLayoutEntry(resultVarLayout, varChain, resInfo.kind);
+ _addOffsetVarLayoutEntry(&resultVarLayoutBuilder, varChain, resInfo->getResourceKind());
}
- return resultVarLayout;
+ return resultVarLayoutBuilder.build();
}
/// Place offset information from `srcResInfo` onto `dstLayout`,
/// offset by whatever is in `offsetVarLayout`
static void addOffsetResInfo(
- VarLayout* dstLayout,
- VarLayout::ResourceInfo const& srcResInfo,
- VarLayout* offsetVarLayout)
+ IRVarLayout::Builder* dstLayout,
+ IRVarOffsetAttr* srcResInfo,
+ IRVarLayout* offsetVarLayout)
{
- auto kind = srcResInfo.kind;
+ auto kind = srcResInfo->getResourceKind();
auto dstResInfo = dstLayout->findOrAddResourceInfo(kind);
- dstResInfo->index = srcResInfo.index;
- dstResInfo->space = srcResInfo.space;
+ dstResInfo->offset = srcResInfo->getOffset();
+ dstResInfo->space = srcResInfo->getSpace();
- if( auto offsetResInfo = offsetVarLayout->findOrAddResourceInfo(kind) )
+ if( auto offsetResInfo = offsetVarLayout->findOffsetAttr(kind) )
{
- dstResInfo->index += offsetResInfo->index;
- dstResInfo->space += offsetResInfo->space;
+ dstResInfo->offset += offsetResInfo->getOffset();
+ dstResInfo->space += offsetResInfo->getSpace();
}
}
@@ -1996,15 +2000,16 @@ static void addOffsetResInfo(
/// of the surrounding context (e.g., the global shader parameter
/// that has this type).
///
-static RefPtr<TypeLayout> _createWrappedBufferTypeLayout(
- TypeLayout* oldTypeLayout,
+static IRTypeLayout* _createWrappedBufferTypeLayout(
+ IRBuilder* irBuilder,
+ IRTypeLayout* oldTypeLayout,
WrappedBufferPseudoType* wrappedBufferTypeInfo,
LegalVarChain const& outerVarChain)
{
// We shouldn't get invoked unless there was a parameter group type,
// so we will sanity check for that just to be sure.
//
- auto oldParameterGroupTypeLayout = as<ParameterGroupTypeLayout>(oldTypeLayout);
+ auto oldParameterGroupTypeLayout = as<IRParameterGroupTypeLayout>(oldTypeLayout);
SLANG_ASSERT(oldParameterGroupTypeLayout);
if(!oldParameterGroupTypeLayout)
return oldTypeLayout;
@@ -2022,12 +2027,9 @@ static RefPtr<TypeLayout> _createWrappedBufferTypeLayout(
// re-create the original intention of the split layout (both primary
// and pending data) for a type that now only has the "primary" data.
//
- RefPtr<ParameterGroupTypeLayout> newTypeLayout = new ParameterGroupTypeLayout();
- newTypeLayout->type = oldTypeLayout->type;
- newTypeLayout->rules = oldTypeLayout->rules;
- newTypeLayout->uniformAlignment = oldTypeLayout->uniformAlignment;
- for(auto resInfo : oldTypeLayout->resourceInfos)
- newTypeLayout->addResourceUsage(resInfo);
+
+ IRParameterGroupTypeLayout::Builder newTypeLayoutBuilder(irBuilder);
+ newTypeLayoutBuilder.addResourceUsageFrom(oldTypeLayout);
// Any fields in the "pending" data will have offset information
// that is relative to the pending data for their parent, and so on.
@@ -2047,7 +2049,10 @@ static RefPtr<TypeLayout> _createWrappedBufferTypeLayout(
// itself, and so the offsets already *are* relative to the start
// of the buffer).
//
- auto offsetVarLayout = _createOffsetVarLayout(outerVarChain, oldTypeLayout->pendingDataTypeLayout);
+ auto offsetVarLayout = _createOffsetVarLayout(
+ irBuilder,
+ outerVarChain,
+ oldTypeLayout->getPendingDataTypeLayout());
LegalVarChainLink offsetVarChain(LegalVarChain(), offsetVarLayout);
// We will start our construction of the pieces of the output
@@ -2072,27 +2077,39 @@ static RefPtr<TypeLayout> _createWrappedBufferTypeLayout(
// container type/var layout, and constructing new objects
// that will represent the layout for our wrapped buffer.
//
- auto oldPrimaryContainerVarLayout = oldParameterGroupTypeLayout->containerVarLayout;
- auto oldPrimaryContainerTypeLayout = oldPrimaryContainerVarLayout->typeLayout;
+ auto oldPrimaryContainerVarLayout = oldParameterGroupTypeLayout->getContainerVarLayout();
+ auto oldPrimaryContainerTypeLayout = oldPrimaryContainerVarLayout->getTypeLayout();
+
+ IRTypeLayout::Builder newContainerTypeLayoutBuilder(irBuilder);
+ newContainerTypeLayoutBuilder.addResourceUsageFrom(oldPrimaryContainerTypeLayout);
- RefPtr<TypeLayout> newContainerTypeLayout = new TypeLayout();
- newContainerTypeLayout->type = oldPrimaryContainerTypeLayout->type;
+ if( auto oldPendingContainerVarLayout = oldPrimaryContainerVarLayout->getPendingVarLayout() )
+ {
+ // Whatever resources were allocated for the pending data type,
+ // our new combined container type needs to account for them
+ // (e.g., if we didn't have a constant buffer in the primary
+ // data, but one got allocated in the pending data, we need
+ // to end up with type layout information that includes a
+ // constnat buffer).
+ //
+ auto oldPendingContainerTypeLayout = oldPendingContainerVarLayout->getTypeLayout();
+ newContainerTypeLayoutBuilder.addResourceUsageFrom(oldPendingContainerTypeLayout);
+ }
+ auto newContainerTypeLayout = newContainerTypeLayoutBuilder.build();
- RefPtr<VarLayout> newContainerVarLayout = new VarLayout();
- newContainerVarLayout->typeLayout = newContainerTypeLayout;
- newTypeLayout->containerVarLayout = newContainerVarLayout;
+
+ IRVarLayout::Builder newContainerVarLayoutBuilder(irBuilder, newContainerTypeLayout);
// Whatever got allocated for the primary container should get copied
// over to the new layout (e.g., if we allocated a constant buffer
// for `gMat` then we need to retain that information).
//
- newContainerTypeLayout->addResourceUsageFrom(oldPrimaryContainerTypeLayout);
- for( auto resInfo : oldPrimaryContainerVarLayout->resourceInfos )
+ for( auto resInfo : oldPrimaryContainerVarLayout->getOffsetAttrs() )
{
- auto newResInfo = newContainerVarLayout->findOrAddResourceInfo(resInfo.kind);
- newResInfo->index = resInfo.index;
- newResInfo->space = resInfo.space;
+ auto newResInfo = newContainerVarLayoutBuilder.findOrAddResourceInfo(resInfo->getResourceKind());
+ newResInfo->offset = resInfo->getOffset();
+ newResInfo->space = resInfo->getSpace();
}
// It is possible that a constant buffer and/or space didn't get
@@ -2103,18 +2120,8 @@ static RefPtr<TypeLayout> _createWrappedBufferTypeLayout(
// we need to account for that case and copy over the relevant
// resource usage from the pending data, if there is any.
//
- if( auto oldPendingContainerVarLayout = oldPrimaryContainerVarLayout->pendingVarLayout )
+ if( auto oldPendingContainerVarLayout = oldPrimaryContainerVarLayout->getPendingVarLayout() )
{
- // Whatever resources were allocated for the pending data type,
- // our new combined container type needs to account for them
- // (e.g., if we didn't have a constant buffer in the primary
- // data, but one got allocated in the pending data, we need
- // to end up with type layout information that includes a
- // constnat buffer).
- //
- auto oldPendingContainerTypeLayout = oldPendingContainerVarLayout->typeLayout;
- newContainerTypeLayout->addResourceUsageFrom(oldPendingContainerTypeLayout);
-
// We also need to add offset information based on the "pending"
// var layout, but we need to deal with the fact that this information
// is currently stored relative to the pending var layout for the surrounding
@@ -2124,11 +2131,14 @@ static RefPtr<TypeLayout> _createWrappedBufferTypeLayout(
// in handy, because it represents the value(s) we need to
// add to each of the per-resource-kind offsets.
//
- for( auto resInfo : oldPendingContainerVarLayout->resourceInfos )
+ for( auto resInfo : oldPendingContainerVarLayout->getOffsetAttrs() )
{
- addOffsetResInfo(newContainerVarLayout, resInfo, offsetVarLayout);
+ addOffsetResInfo(&newContainerVarLayoutBuilder, resInfo, offsetVarLayout);
}
}
+
+ auto newContainerVarLayout = newContainerVarLayoutBuilder.build();
+ newTypeLayoutBuilder.setContainerVarLayout(newContainerVarLayout);
}
// Now that we've dealt with the container variable, we can turn
@@ -2142,14 +2152,13 @@ static RefPtr<TypeLayout> _createWrappedBufferTypeLayout(
// the objects we'll use to represent the type/var layout for
// the new element type.
//
- auto oldElementVarLayout = oldParameterGroupTypeLayout->elementVarLayout;
- auto oldElementTypeLayout = oldElementVarLayout->typeLayout;
+ auto oldElementVarLayout = oldParameterGroupTypeLayout->getElementVarLayout();
+ auto oldElementTypeLayout = oldElementVarLayout->getTypeLayout();
// Now matter what, the element type of a wrapped buffer
// will always have a structure type.
//
- RefPtr<StructTypeLayout> newElementTypeLayout = new StructTypeLayout();
- newElementTypeLayout->type = oldElementTypeLayout->type;
+ IRStructTypeLayout::Builder newElementTypeLayoutBuilder(irBuilder);
// The `wrappedBufferTypeInfo` that was passed in tells
// us how the fields of the original type got turned into
@@ -2171,12 +2180,15 @@ static RefPtr<TypeLayout> _createWrappedBufferTypeLayout(
varChainForElementType.pendingChain = offsetVarChain.primaryChain;
_addFieldsToWrappedBufferElementTypeLayout(
+ irBuilder,
oldElementTypeLayout,
- newElementTypeLayout,
+ &newElementTypeLayoutBuilder,
wrappedBufferTypeInfo->elementInfo,
varChainForElementType,
true);
+ auto newElementTypeLayout = newElementTypeLayoutBuilder.build();
+
// A parameter group type layout holds a `VarLayout` for the element type,
// which encodes the offset of the element type with respect to the
// start of the parameter group as a whole (e.g., to handle the case
@@ -2184,26 +2196,34 @@ static RefPtr<TypeLayout> _createWrappedBufferTypeLayout(
// element type, so the offset to the first `binding` for the element
// type is one, not zero.
//
- LegalVarChainLink elementVarChain(LegalVarChain(), oldParameterGroupTypeLayout->elementVarLayout);
- auto newElementVarLayout = createVarLayout(elementVarChain, newElementTypeLayout);
- newTypeLayout->elementVarLayout = newElementVarLayout;
+ LegalVarChainLink elementVarChain(LegalVarChain(), oldParameterGroupTypeLayout->getElementVarLayout());
+ auto newElementVarLayout = createVarLayout(irBuilder, elementVarChain, newElementTypeLayout);
+
+ newTypeLayoutBuilder.setElementVarLayout(newElementVarLayout);
// For legacy/API reasons, we also need to compute a version of the
// element type where the offset stored in the `elementVarLayout`
// gets "baked in" to the fields of the element type.
//
- newTypeLayout->offsetElementTypeLayout = applyOffsetToTypeLayout(
- newElementTypeLayout,
- newElementVarLayout);
+ // TODO: For IR-based layout information the offset layout should
+ // not really be required, and it is only being used in a few places
+ // that could in principle be refactored. We need to make sure to
+ // do that cleanup eventually.
+ //
+ newTypeLayoutBuilder.setOffsetElementTypeLayout(
+ applyOffsetToTypeLayout(
+ irBuilder,
+ newElementTypeLayout,
+ newElementVarLayout));
- return newTypeLayout;
+ return newTypeLayoutBuilder.build();
}
static LegalVal declareVars(
IRTypeLegalizationContext* context,
IROp op,
LegalType type,
- TypeLayout* inTypeLayout,
+ IRTypeLayout* inTypeLayout,
LegalVarChain const& inVarChain,
UnownedStringSlice nameHint,
IRInst* leafVar,
@@ -2211,7 +2231,7 @@ static LegalVal declareVars(
bool isSpecial)
{
LegalVarChain varChain = inVarChain;
- TypeLayout* typeLayout = inTypeLayout;
+ IRTypeLayout* typeLayout = inTypeLayout;
if( isSpecial )
{
if( varChain.pendingChain )
@@ -2221,7 +2241,7 @@ static LegalVal declareVars(
}
if( typeLayout )
{
- if( auto pendingTypeLayout = typeLayout->pendingDataTypeLayout )
+ if( auto pendingTypeLayout = typeLayout->getPendingDataTypeLayout() )
{
typeLayout = pendingTypeLayout;
}
@@ -2274,7 +2294,7 @@ static LegalVal declareVars(
for (auto ee : tupleType->elements)
{
auto fieldLayout = getFieldLayout(typeLayout, ee.key);
- RefPtr<TypeLayout> fieldTypeLayout = fieldLayout ? fieldLayout->typeLayout : nullptr;
+ IRTypeLayout* fieldTypeLayout = fieldLayout ? fieldLayout->getTypeLayout() : nullptr;
// If we have a type layout coming in, we really expect to have a layout for each field.
SLANG_ASSERT(fieldLayout || !typeLayout);
@@ -2326,7 +2346,11 @@ static LegalVal declareVars(
{
auto wrappedBuffer = type.getWrappedBuffer();
- auto wrappedTypeLayout = _createWrappedBufferTypeLayout(typeLayout, wrappedBuffer, varChain);
+ auto wrappedTypeLayout = _createWrappedBufferTypeLayout(
+ context->builder,
+ typeLayout,
+ wrappedBuffer,
+ varChain);
auto innerVal = declareSimpleVar(
context,
@@ -2403,8 +2427,8 @@ static LegalVal legalizeGlobalParam(
context,
irGlobalParam->getFullType());
- RefPtr<VarLayout> varLayout = findVarLayout(irGlobalParam);
- RefPtr<TypeLayout> typeLayout = varLayout ? varLayout->typeLayout : nullptr;
+ IRVarLayout* varLayout = findVarLayout(irGlobalParam);
+ IRTypeLayout* typeLayout = varLayout ? varLayout->getTypeLayout() : nullptr;
switch (legalValueType.flavor)
{
diff --git a/source/slang/slang-ir-link.cpp b/source/slang/slang-ir-link.cpp
index f46a0db09..1cdc2cfc9 100644
--- a/source/slang/slang-ir-link.cpp
+++ b/source/slang/slang-ir-link.cpp
@@ -754,23 +754,26 @@ static void maybeCopyLayoutInformationToParameters(
if(!layoutDecor)
return;
- auto entryPointLayout = as<EntryPointLayout>(layoutDecor->getASTLayout());
+ auto entryPointLayout = as<IREntryPointLayout>(layoutDecor->getLayout());
if(!entryPointLayout)
return;
if( auto firstBlock = func->getFirstBlock() )
{
auto paramsStructLayout = getScopeStructLayout(entryPointLayout);
- Index paramLayoutCount = paramsStructLayout->fields.getCount();
+ Index paramLayoutCount = paramsStructLayout->getFieldCount();
Index paramCounter = 0;
for( auto pp = firstBlock->getFirstParam(); pp; pp = pp->getNextParam() )
{
Index paramIndex = paramCounter++;
if( paramIndex < paramLayoutCount )
{
- auto paramLayout = paramsStructLayout->fields[paramIndex];
+ auto paramLayout = paramsStructLayout->getFieldLayout(paramIndex);
- auto offsetParamLayout = applyOffsetToVarLayout(paramLayout, entryPointLayout->parametersLayout);
+ auto offsetParamLayout = applyOffsetToVarLayout(
+ builder,
+ paramLayout,
+ entryPointLayout->getParamsLayout());
builder->addLayoutDecoration(
pp,
diff --git a/source/slang/slang-ir-union.cpp b/source/slang/slang-ir-union.cpp
index d456cebee..0efca5602 100644
--- a/source/slang/slang-ir-union.cpp
+++ b/source/slang/slang-ir-union.cpp
@@ -101,7 +101,7 @@ struct DesugarUnionTypesContext
// unions in the generated IR have an associated (target-specific)
// layout.
//
- TaggedUnionTypeLayout* taggedUnionTypeLayout;
+ IRTaggedUnionTypeLayout* taggedUnionTypeLayout;
// The basic approach we will use 16-byte chunks (represented as an array
// of `uint4`s) to reprent the "bulk" of a type, and then use a single field
@@ -269,8 +269,8 @@ struct DesugarUnionTypesContext
// for fields, etc.).
//
auto taggedUnionTypeLayout = taggedUnionInfo->taggedUnionTypeLayout;
- SLANG_ASSERT(caseTagIndex < UInt(taggedUnionTypeLayout->caseTypeLayouts.getCount()));
- auto caseTypeLayout = taggedUnionTypeLayout->caseTypeLayouts[caseTagIndex];
+ SLANG_ASSERT(caseTagIndex < UInt(taggedUnionTypeLayout->getCaseCount()));
+ auto caseTypeLayout = taggedUnionTypeLayout->getCaseTypeLayout(caseTagIndex);
// At this point we know the type we are trying to extract, as well
// as its layout. We will defer the actual implementation of extraction
@@ -342,7 +342,7 @@ struct DesugarUnionTypesContext
IRType* payloadType,
// - The memory layout of that payload type.
- TypeLayout* payloadTypeLayout,
+ IRTypeLayout* payloadTypeLayout,
// - The byte offset at which we want to fetch the payload.
UInt64 payloadOffset)
@@ -366,7 +366,7 @@ struct DesugarUnionTypesContext
// there to be complete type layout information for the
// types involved.
//
- auto structTypeLayout = as<StructTypeLayout>(payloadTypeLayout);
+ auto structTypeLayout = as<IRStructTypeLayout>(payloadTypeLayout);
SLANG_ASSERT(structTypeLayout);
// We are going to emit code to extract each of the fields
@@ -384,15 +384,15 @@ struct DesugarUnionTypesContext
// IR struct and the fields of the layout still align.
//
UInt fieldIndex = fieldCounter++;
- auto fieldLayout = structTypeLayout->fields[fieldIndex];
+ auto fieldLayout = structTypeLayout->getFieldLayout(fieldIndex);
auto fieldTypeLayout = fieldLayout->getTypeLayout();
// The offset of the field can be computed from the base
// offset passed in, plus the reflection data for the field.
//
UInt64 fieldOffset = payloadOffset;
- if(auto resInfo = fieldLayout->FindResourceInfo(LayoutResourceKind::Uniform))
- fieldOffset += resInfo->index;
+ if(auto resInfo = fieldLayout->findOffsetAttr(LayoutResourceKind::Uniform))
+ fieldOffset += resInfo->getOffset();
// We make a recursive call to extract each field, expecting
// that this will bottom out eventually.
@@ -429,10 +429,10 @@ struct DesugarUnionTypesContext
// no way to query the layout of the elements of a vector
// type. Until that gets added we will kludge things here.
//
- TypeLayout* elementTypeLayout = nullptr;
+ IRTypeLayout* elementTypeLayout = nullptr;
size_t elementSize = 0;
- if(auto resInfo = payloadTypeLayout->FindResourceInfo(LayoutResourceKind::Uniform))
- elementSize = resInfo->count.getFiniteValue() / elementCount;
+ if(auto resInfo = payloadTypeLayout->findSizeAttr(LayoutResourceKind::Uniform))
+ elementSize = resInfo->getSize().getFiniteValue() / elementCount;
// Similar to the `struct` case above, we will extract a
// value for each element of the vector, and then use
@@ -465,13 +465,13 @@ struct DesugarUnionTypesContext
// we have an individual scalar field that we need to fetch.
//
UInt64 payloadSize = 0;
- if( auto resInfo = payloadTypeLayout->FindResourceInfo(LayoutResourceKind::Uniform) )
+ if( auto resInfo = payloadTypeLayout->findSizeAttr(LayoutResourceKind::Uniform) )
{
// TODO: somebody before this point should generate an error if
// we have a `union` type that contains a potentially unbounded
// amount of data.
//
- payloadSize = resInfo->count.getFiniteValue();
+ payloadSize = resInfo->getSize().getFiniteValue();
}
if( payloadSize != 4 )
@@ -670,9 +670,9 @@ struct DesugarUnionTypesContext
//
auto layoutDecoration = type->findDecoration<IRLayoutDecoration>();
SLANG_ASSERT(layoutDecoration);
- auto layout = layoutDecoration->getIRLayout()->getASTLayout();
+ auto layout = layoutDecoration->getLayout();
SLANG_ASSERT(layout);
- auto taggedUnionTypeLayout = as<TaggedUnionTypeLayout>(layout);
+ auto taggedUnionTypeLayout = as<IRTaggedUnionTypeLayout>(layout);
SLANG_ASSERT(taggedUnionTypeLayout);
info->taggedUnionTypeLayout = taggedUnionTypeLayout;
@@ -684,7 +684,7 @@ struct DesugarUnionTypesContext
// of the tag's alignment. We should deal with that when/if we support
// types smaller than 4 bytes in unions.
//
- auto payloadSize = taggedUnionTypeLayout->tagOffset.getFiniteValue();
+ auto payloadSize = taggedUnionTypeLayout->getTagOffset().getFiniteValue();
// We are going to be construction IR code that makes use of the `int`
// and `uint` types in several cases, so we go ahead and get a pointer
diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp
index 78758d944..89e49816f 100644
--- a/source/slang/slang-ir.cpp
+++ b/source/slang/slang-ir.cpp
@@ -205,6 +205,24 @@ namespace Slang
return nullptr;
}
+ IROperandListBase IRInst::getAllAttrs()
+ {
+ // We assume as an invariant that all attributes appear at the end of the operand
+ // list, after all the non-attribute operands.
+ //
+ // We will therefore define a range that ends at the end of the operand list ...
+ //
+ IRUse* end = getOperands() + getOperandCount();
+ //
+ // ... and begins after the last non-attribute operand.
+ //
+ IRUse* cursor = getOperands();
+ while(cursor != end && !as<IRAttr>(cursor->get()))
+ cursor++;
+
+ return IROperandListBase(cursor, end);
+ }
+
// IRConstant
IRIntegerValue GetIntVal(IRInst* inst)
@@ -696,6 +714,371 @@ namespace Slang
}
//
+ // IRTypeLayout
+ //
+
+ IRTypeSizeAttr* IRTypeLayout::findSizeAttr(LayoutResourceKind kind)
+ {
+ // TODO: If we could assume the attributes were sorted
+ // by `kind`, then we could use a binary search here
+ // instead of linear.
+ //
+ // In practice, the number of entries will be very small,
+ // so the cost of the linear search should not be too bad.
+
+ for( auto sizeAttr : getSizeAttrs() )
+ {
+ if(sizeAttr->getResourceKind() == kind)
+ return sizeAttr;
+ }
+ return nullptr;
+ }
+
+ IRTypeLayout* IRTypeLayout::unwrapArray()
+ {
+ auto typeLayout = this;
+ while(auto arrayTypeLayout = as<IRArrayTypeLayout>(typeLayout))
+ typeLayout = arrayTypeLayout->getElementTypeLayout();
+ return typeLayout;
+ }
+
+ IRTypeLayout* IRTypeLayout::getPendingDataTypeLayout()
+ {
+ if(auto attr = findAttr<IRPendingLayoutAttr>())
+ return cast<IRTypeLayout>(attr->getLayout());
+ return nullptr;
+ }
+
+ IROperandList<IRTypeSizeAttr> IRTypeLayout::getSizeAttrs()
+ {
+ return findAttrs<IRTypeSizeAttr>();
+ }
+
+ IRTypeLayout::Builder::Builder(IRBuilder* irBuilder)
+ : m_irBuilder(irBuilder)
+ {}
+
+ void IRTypeLayout::Builder::addResourceUsage(
+ LayoutResourceKind kind,
+ LayoutSize size)
+ {
+ auto& resInfo = m_resInfos[Int(kind)];
+ resInfo.kind = kind;
+ resInfo.size += size;
+ }
+
+ void IRTypeLayout::Builder::addResourceUsage(IRTypeSizeAttr* sizeAttr)
+ {
+ addResourceUsage(
+ sizeAttr->getResourceKind(),
+ sizeAttr->getSize());
+ }
+
+ void IRTypeLayout::Builder::addResourceUsageFrom(IRTypeLayout* typeLayout)
+ {
+ for( auto sizeAttr : typeLayout->getSizeAttrs() )
+ {
+ addResourceUsage(sizeAttr);
+ }
+ }
+
+ IRTypeLayout* IRTypeLayout::Builder::build()
+ {
+ IRBuilder* irBuilder = getIRBuilder();
+
+ List<IRInst*> operands;
+
+ addOperands(operands);
+ addAttrs(operands);
+
+ return irBuilder->getTypeLayout(
+ getOp(),
+ operands);
+ }
+
+ void IRTypeLayout::Builder::addOperands(List<IRInst*>& operands)
+ {
+ addOperandsImpl(operands);
+ }
+
+ void IRTypeLayout::Builder::addAttrs(List<IRInst*>& operands)
+ {
+ auto irBuilder = getIRBuilder();
+
+ for(auto resInfo : m_resInfos)
+ {
+ if(resInfo.kind == LayoutResourceKind::None)
+ continue;
+
+ IRInst* sizeAttr = irBuilder->getTypeSizeAttr(
+ resInfo.kind,
+ resInfo.size);
+ operands.add(sizeAttr);
+ }
+
+ if( auto pendingTypeLayout = m_pendingTypeLayout )
+ {
+ operands.add(irBuilder->getPendingLayoutAttr(
+ pendingTypeLayout));
+ }
+
+ addAttrsImpl(operands);
+ }
+
+ //
+ // IRParameterGroupTypeLayout
+ //
+
+ void IRParameterGroupTypeLayout::Builder::addOperandsImpl(List<IRInst*>& ioOperands)
+ {
+ ioOperands.add(m_containerVarLayout);
+ ioOperands.add(m_elementVarLayout);
+ ioOperands.add(m_offsetElementTypeLayout);
+ }
+
+ IRParameterGroupTypeLayout* IRParameterGroupTypeLayout::Builder::build()
+ {
+ return cast<IRParameterGroupTypeLayout>(Super::Builder::build());
+ }
+
+ //
+ // IRStructTypeLayout
+ //
+
+ void IRStructTypeLayout::Builder::addAttrsImpl(List<IRInst*>& ioOperands)
+ {
+ auto irBuilder = getIRBuilder();
+ for(auto field : m_fields)
+ {
+ ioOperands.add(
+ irBuilder->getFieldLayoutAttr(field.key, field.layout));
+ }
+ }
+
+ //
+ // IRArrayTypeLayout
+ //
+
+ void IRArrayTypeLayout::Builder::addOperandsImpl(List<IRInst*>& ioOperands)
+ {
+ ioOperands.add(m_elementTypeLayout);
+ }
+
+ //
+ // IRStreamOutputTypeLayout
+ //
+
+ void IRStreamOutputTypeLayout::Builder::addOperandsImpl(List<IRInst*>& ioOperands)
+ {
+ ioOperands.add(m_elementTypeLayout);
+ }
+
+ //
+ // IRMatrixTypeLayout
+ //
+
+ IRMatrixTypeLayout::Builder::Builder(IRBuilder* irBuilder, MatrixLayoutMode mode)
+ : Super::Builder(irBuilder)
+ {
+ m_modeInst = irBuilder->getIntValue(irBuilder->getIntType(), IRIntegerValue(mode));
+ }
+
+ void IRMatrixTypeLayout::Builder::addOperandsImpl(List<IRInst*>& ioOperands)
+ {
+ ioOperands.add(m_modeInst);
+ }
+
+ //
+ // IRTaggedUnionTypeLayout
+ //
+
+ IRTaggedUnionTypeLayout::Builder::Builder(IRBuilder* irBuilder, LayoutSize tagOffset)
+ : Super::Builder(irBuilder)
+ {
+ m_tagOffset = irBuilder->getIntValue(irBuilder->getIntType(), tagOffset.raw);
+ }
+
+ void IRTaggedUnionTypeLayout::Builder::addCaseTypeLayout(IRTypeLayout* typeLayout)
+ {
+ m_caseTypeLayoutAttrs.add(getIRBuilder()->getCaseTypeLayoutAttr(typeLayout));
+ }
+
+ void IRTaggedUnionTypeLayout::Builder::addOperandsImpl(List<IRInst*>& ioOperands)
+ {
+ ioOperands.add(m_tagOffset);
+ }
+
+ void IRTaggedUnionTypeLayout::Builder::addAttrsImpl(List<IRInst*>& ioOperands)
+ {
+ for(auto attr : m_caseTypeLayoutAttrs)
+ ioOperands.add(attr);
+ }
+
+ //
+ // IRVarLayout
+ //
+
+ bool IRVarLayout::usesResourceKind(LayoutResourceKind kind)
+ {
+ // TODO: basing this check on whether or not the
+ // var layout has an entry for `kind` means that
+ // we can't just optimize away any entry where
+ // the offset is zero (which might be a small
+ // but nice optimization). We could consider shifting
+ // this test to use the entries on the type layout
+ // instead (since non-zero resource consumption
+ // should be an equivalent test).
+
+ return findOffsetAttr(kind) != nullptr;
+ }
+
+ IRSystemValueSemanticAttr* IRVarLayout::findSystemValueSemanticAttr()
+ {
+ return findAttr<IRSystemValueSemanticAttr>();
+ }
+
+ IRVarOffsetAttr* IRVarLayout::findOffsetAttr(LayoutResourceKind kind)
+ {
+ for( auto offsetAttr : getOffsetAttrs() )
+ {
+ if(offsetAttr->getResourceKind() == kind)
+ return offsetAttr;
+ }
+ return nullptr;
+ }
+
+ IROperandList<IRVarOffsetAttr> IRVarLayout::getOffsetAttrs()
+ {
+ return findAttrs<IRVarOffsetAttr>();
+ }
+
+ Stage IRVarLayout::getStage()
+ {
+ if(auto stageAttr = findAttr<IRStageAttr>())
+ return stageAttr->getStage();
+ return Stage::Unknown;
+ }
+
+ IRVarLayout* IRVarLayout::getPendingVarLayout()
+ {
+ if( auto pendingLayoutAttr = findAttr<IRPendingLayoutAttr>() )
+ {
+ return cast<IRVarLayout>(pendingLayoutAttr->getLayout());
+ }
+ return nullptr;
+ }
+
+ IRVarLayout::Builder::Builder(
+ IRBuilder* irBuilder,
+ IRTypeLayout* typeLayout)
+ : m_irBuilder(irBuilder)
+ , m_typeLayout(typeLayout)
+ {}
+
+ bool IRVarLayout::Builder::usesResourceKind(LayoutResourceKind kind)
+ {
+ return m_resInfos[Int(kind)].kind != LayoutResourceKind::None;
+ }
+
+ IRVarLayout::Builder::ResInfo* IRVarLayout::Builder::findOrAddResourceInfo(LayoutResourceKind kind)
+ {
+ auto& resInfo = m_resInfos[Int(kind)];
+ resInfo.kind = kind;
+ return &resInfo;
+ }
+
+ void IRVarLayout::Builder::setSystemValueSemantic(String const& name, UInt index)
+ {
+ m_systemValueSemantic = getIRBuilder()->getSystemValueSemanticAttr(name, index);
+ }
+
+ void IRVarLayout::Builder::setUserSemantic(String const& name, UInt index)
+ {
+ m_userSemantic = getIRBuilder()->getUserSemanticAttr(name, index);
+ }
+
+ void IRVarLayout::Builder::setStage(Stage stage)
+ {
+ m_stageAttr = getIRBuilder()->getStageAttr(stage);
+ }
+
+ void IRVarLayout::Builder::cloneEverythingButOffsetsFrom(
+ IRVarLayout* that)
+ {
+ if(auto systemValueSemantic = that->findAttr<IRSystemValueSemanticAttr>())
+ m_systemValueSemantic = systemValueSemantic;
+
+ if(auto userSemantic = that->findAttr<IRUserSemanticAttr>())
+ m_userSemantic = userSemantic;
+
+ if(auto stageAttr = that->findAttr<IRStageAttr>())
+ m_stageAttr = stageAttr;
+ }
+
+ IRVarLayout* IRVarLayout::Builder::build()
+ {
+ SLANG_ASSERT(m_typeLayout);
+
+ IRBuilder* irBuilder = getIRBuilder();
+
+ List<IRInst*> operands;
+
+ operands.add(m_typeLayout);
+
+ for(auto resInfo : m_resInfos)
+ {
+ if(resInfo.kind == LayoutResourceKind::None)
+ continue;
+
+ IRInst* varOffsetAttr = irBuilder->getVarOffsetAttr(
+ resInfo.kind,
+ resInfo.offset,
+ resInfo.space);
+ operands.add(varOffsetAttr);
+ }
+
+ if(auto semanticAttr = m_userSemantic)
+ operands.add(semanticAttr);
+
+ if(auto semanticAttr = m_systemValueSemantic)
+ operands.add(semanticAttr);
+
+ if(auto stageAttr = m_stageAttr)
+ operands.add(stageAttr);
+
+ if(auto pendingVarLayout = m_pendingVarLayout)
+ {
+ IRInst* pendingLayoutAttr = irBuilder->getPendingLayoutAttr(
+ pendingVarLayout);
+ operands.add(pendingLayoutAttr);
+ }
+
+ return irBuilder->getVarLayout(operands);
+ }
+
+ //
+ // IREntryPointLayout
+ //
+
+ IRStructTypeLayout* getScopeStructLayout(IREntryPointLayout* scopeLayout)
+ {
+ auto scopeTypeLayout = scopeLayout->getParamsLayout()->getTypeLayout();
+
+ if( auto constantBufferTypeLayout = as<IRParameterGroupTypeLayout>(scopeTypeLayout) )
+ {
+ scopeTypeLayout = constantBufferTypeLayout->getOffsetElementTypeLayout();
+ }
+
+ if( auto structTypeLayout = as<IRStructTypeLayout>(scopeTypeLayout) )
+ {
+ return structTypeLayout;
+ }
+
+ SLANG_UNEXPECTED("uhandled global-scope binding layout");
+ UNREACHABLE_RETURN(nullptr);
+ }
+
+ //
IRBlock* IRBuilder::getBlock()
{
@@ -3086,79 +3469,149 @@ namespace Slang
addDecoration(inst, kIROp_HighLevelDeclDecoration, ptrConst);
}
- void IRBuilder::addLayoutDecoration(IRInst* value, Layout* layout)
+ void IRBuilder::addLayoutDecoration(IRInst* value, IRLayout* layout)
+ {
+ addDecoration(value, kIROp_LayoutDecoration, layout);
+ }
+
+ IRTypeSizeAttr* IRBuilder::getTypeSizeAttr(
+ LayoutResourceKind kind,
+ LayoutSize size)
{
- IRLayout* irLayout = getLayout(layout);
- addDecoration(value, kIROp_LayoutDecoration, irLayout);
+ auto kindInst = getIntValue(getIntType(), IRIntegerValue(kind));
+ auto sizeInst = getIntValue(getIntType(), IRIntegerValue(size.raw));
+ IRInst* operands[] = { kindInst, sizeInst };
+ return cast<IRTypeSizeAttr>(findOrEmitHoistableInst(
+ getVoidType(),
+ kIROp_TypeSizeAttr,
+ SLANG_COUNT_OF(operands),
+ operands));
}
- IRLayout* IRBuilder::getLayout(Layout* astLayout)
+ IRVarOffsetAttr* IRBuilder::getVarOffsetAttr(
+ LayoutResourceKind kind,
+ UInt offset,
+ UInt space)
{
- if (astLayout == nullptr)
- {
- return nullptr;
- }
+ IRInst* operands[3];
+ UInt operandCount = 0;
- IRLayout* irLayout = nullptr;
- if(sharedBuilder->layoutMap.TryGetValue(astLayout, irLayout))
- {
- SLANG_ASSERT(irLayout->getASTLayout() == astLayout);
- return irLayout;
- }
+ auto kindInst = getIntValue(getIntType(), IRIntegerValue(kind));
+ operands[operandCount++] = kindInst;
+
+ auto offsetInst = getIntValue(getIntType(), IRIntegerValue(offset));
+ operands[operandCount++] = offsetInst;
- if (EntryPointLayout* entryPointLayout = as<EntryPointLayout>(astLayout))
+ if(space)
{
- irLayout = createInst<IREntryPointLayout>(this, kIROp_EntryPointLayout, nullptr, getPtrValue(astLayout));
+ auto spaceInst = getIntValue(getIntType(), IRIntegerValue(space));
+ operands[operandCount++] = spaceInst;
}
- 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)
- };
+ return cast<IRVarOffsetAttr>(findOrEmitHoistableInst(
+ getVoidType(),
+ kIROp_VarOffsetAttr,
+ operandCount,
+ operands));
+ }
- 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");
- }
+ IRPendingLayoutAttr* IRBuilder::getPendingLayoutAttr(
+ IRLayout* pendingLayout)
+ {
+ IRInst* operands[] = { pendingLayout };
+
+ return cast<IRPendingLayoutAttr>(findOrEmitHoistableInst(
+ getVoidType(),
+ kIROp_PendingLayoutAttr,
+ SLANG_COUNT_OF(operands),
+ operands));
+ }
+
+ IRStructFieldLayoutAttr* IRBuilder::getFieldLayoutAttr(
+ IRStructKey* key,
+ IRVarLayout* layout)
+ {
+ IRInst* operands[] = { key, layout };
+
+ return cast<IRStructFieldLayoutAttr>(findOrEmitHoistableInst(
+ getVoidType(),
+ kIROp_StructFieldLayoutAttr,
+ SLANG_COUNT_OF(operands),
+ operands));
+ }
+
+ IRCaseTypeLayoutAttr* IRBuilder::getCaseTypeLayoutAttr(
+ IRTypeLayout* layout)
+ {
+ IRInst* operands[] = { layout };
+
+ return cast<IRCaseTypeLayoutAttr>(findOrEmitHoistableInst(
+ getVoidType(),
+ kIROp_CaseTypeLayoutAttr,
+ SLANG_COUNT_OF(operands),
+ operands));
+ }
+
+ IRSemanticAttr* IRBuilder::getSemanticAttr(
+ IROp op,
+ String const& name,
+ UInt index)
+ {
+ auto nameInst = getStringValue(name.getUnownedSlice());
+ auto indexInst = getIntValue(getIntType(), index);
+
+ IRInst* operands[] = { nameInst, indexInst };
+
+ return cast<IRSemanticAttr>(findOrEmitHoistableInst(
+ getVoidType(),
+ op,
+ SLANG_COUNT_OF(operands),
+ operands));
+ }
+
+ IRStageAttr* IRBuilder::getStageAttr(Stage stage)
+ {
+ auto stageInst = getIntValue(getIntType(), IRIntegerValue(stage));
+ IRInst* operands[] = { stageInst };
+ return cast<IRStageAttr>(findOrEmitHoistableInst(
+ getVoidType(),
+ kIROp_StageAttr,
+ SLANG_COUNT_OF(operands),
+ operands));
+ }
- SLANG_ASSERT(irLayout);
- SLANG_ASSERT(irLayout->getASTLayout() == astLayout);
- sharedBuilder->layoutMap[astLayout] = irLayout;
+ IRTypeLayout* IRBuilder::getTypeLayout(IROp op, List<IRInst*> const& operands)
+ {
+ return cast<IRTypeLayout>(findOrEmitHoistableInst(
+ getVoidType(),
+ op,
+ operands.getCount(),
+ operands.getBuffer()));
+ }
- addGlobalValue(this, irLayout);
+ IRVarLayout* IRBuilder::getVarLayout(List<IRInst*> const& operands)
+ {
+ return cast<IRVarLayout>(findOrEmitHoistableInst(
+ getVoidType(),
+ kIROp_VarLayout,
+ operands.getCount(),
+ operands.getBuffer()));
+ }
- // need to keep in scope
- addRefObjectToFree(astLayout);
+ IREntryPointLayout* IRBuilder::getEntryPointLayout(
+ IRVarLayout* paramsLayout,
+ IRVarLayout* resultLayout)
+ {
+ IRInst* operands[] = { paramsLayout, resultLayout };
- return irLayout;
+ return cast<IREntryPointLayout>(findOrEmitHoistableInst(
+ getVoidType(),
+ kIROp_EntryPointLayout,
+ SLANG_COUNT_OF(operands),
+ operands));
}
//
diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h
index f13568356..fbb560a60 100644
--- a/source/slang/slang-ir.h
+++ b/source/slang/slang-ir.h
@@ -219,7 +219,108 @@ struct IRInstList : IRInstListBase
Iterator end();
};
+ /// A list of contiguous operands that can be iterated over as `IRInst`s.
+struct IROperandListBase
+{
+ IROperandListBase()
+ : m_begin(nullptr)
+ , m_end(nullptr)
+ {}
+
+ IROperandListBase(
+ IRUse* begin,
+ IRUse* end)
+ : m_begin(begin)
+ , m_end(end)
+ {}
+
+ struct Iterator
+ {
+ public:
+ Iterator()
+ : m_cursor(nullptr)
+ {}
+
+ Iterator(IRUse* use)
+ : m_cursor(use)
+ {}
+
+ IRInst* operator*() const
+ {
+ return m_cursor->get();
+ }
+
+ IRUse* getCursor() const { return m_cursor; }
+
+ void operator++()
+ {
+ m_cursor++;
+ }
+
+ bool operator!=(Iterator const& that) const
+ {
+ return m_cursor != that.m_cursor;
+ }
+
+ protected:
+ IRUse* m_cursor;
+ };
+
+ Iterator begin() const { return Iterator(m_begin); }
+ Iterator end() const { return Iterator(m_end); }
+
+ Int getCount() const { return m_end - m_begin; }
+
+ IRInst* operator[](Int index) const
+ {
+ return m_begin[index].get();
+ }
+
+protected:
+ IRUse* m_begin;
+ IRUse* m_end;
+};
+
+ /// A list of contiguous operands that can be iterated over as all being of type `T`.
+template<typename T>
+struct IROperandList : IROperandListBase
+{
+ typedef IROperandListBase Super;
+public:
+ IROperandList()
+ {}
+
+ IROperandList(
+ IRUse* begin,
+ IRUse* end)
+ : Super(begin, end)
+ {}
+
+ struct Iterator : public IROperandListBase::Iterator
+ {
+ typedef IROperandListBase::Iterator Super;
+ public:
+ Iterator()
+ {}
+ Iterator(IRUse* use)
+ : Super(use)
+ {}
+
+ T* operator*() const
+ {
+ return (T*) m_cursor->get();
+ }
+ };
+
+ Iterator begin() const { return Iterator(m_begin); }
+ Iterator end() const { return Iterator(m_end); }
+
+ T* operator[](Int index) const
+ {
+ return (T*) m_begin[index].get();
+ }
+};
// Every value in the IR is an instruction (even things
// like literal values).
@@ -260,6 +361,40 @@ struct IRInst
template<typename T>
T* findDecoration();
+ /// Get all the attributes attached to this instruction.
+ IROperandListBase getAllAttrs();
+
+ /// Find the first attribute of type `T` attached to this instruction.
+ template<typename T>
+ T* findAttr()
+ {
+ for( auto attr : getAllAttrs() )
+ {
+ if(auto found = as<T>(attr))
+ return found;
+ }
+ return nullptr;
+ }
+
+ /// Find all attributes of type `T` attached to this instruction.
+ ///
+ /// This operation assumes that attributes are grouped by type,
+ /// so that all the attributes of type `T` are contiguous.
+ ///
+ template<typename T>
+ IROperandList<T> findAttrs()
+ {
+ auto allAttrs = getAllAttrs();
+ auto bb = allAttrs.begin();
+ auto end = allAttrs.end();
+ while(bb != end && !as<T>(*bb))
+ ++bb;
+ auto ee = bb;
+ while(ee != end && as<T>(*ee))
+ ++ee;
+ return IROperandList<T>(bb.getCursor(),ee.getCursor());
+ }
+
// The first use of this value (start of a linked list)
IRUse* firstUse = nullptr;
diff --git a/source/slang/slang-legalize-types.cpp b/source/slang/slang-legalize-types.cpp
index d541818ba..cc729e1cf 100644
--- a/source/slang/slang-legalize-types.cpp
+++ b/source/slang/slang-legalize-types.cpp
@@ -1288,22 +1288,22 @@ LegalType legalizeType(
//
-RefPtr<TypeLayout> getDerefTypeLayout(
- TypeLayout* typeLayout)
+IRTypeLayout* getDerefTypeLayout(
+ IRTypeLayout* typeLayout)
{
if (!typeLayout)
return nullptr;
- if (auto parameterGroupTypeLayout = as<ParameterGroupTypeLayout>(typeLayout))
+ if (auto parameterGroupTypeLayout = as<IRParameterGroupTypeLayout>(typeLayout))
{
- return parameterGroupTypeLayout->offsetElementTypeLayout;
+ return parameterGroupTypeLayout->getOffsetElementTypeLayout();
}
return typeLayout;
}
-RefPtr<VarLayout> getFieldLayout(
- TypeLayout* typeLayout,
+IRVarLayout* getFieldLayout(
+ IRTypeLayout* typeLayout,
IRInst* fieldKey)
{
if (!typeLayout)
@@ -1311,13 +1311,13 @@ RefPtr<VarLayout> getFieldLayout(
for(;;)
{
- if(auto arrayTypeLayout = as<ArrayTypeLayout>(typeLayout))
+ if(auto arrayTypeLayout = as<IRArrayTypeLayout>(typeLayout))
{
- typeLayout = arrayTypeLayout->elementTypeLayout;
+ typeLayout = arrayTypeLayout->getElementTypeLayout();
}
- else if(auto parameterGroupTypeLayout = as<ParameterGroupTypeLayout>(typeLayout))
+ else if(auto parameterGroupTypeLayout = as<IRParameterGroupTypeLayout>(typeLayout))
{
- typeLayout = parameterGroupTypeLayout->offsetElementTypeLayout;
+ typeLayout = parameterGroupTypeLayout->getOffsetElementTypeLayout();
}
else
{
@@ -1326,30 +1326,13 @@ RefPtr<VarLayout> getFieldLayout(
}
- if (auto structTypeLayout = as<StructTypeLayout>(typeLayout))
+ if (auto structTypeLayout = as<IRStructTypeLayout>(typeLayout))
{
- // First, let's see if the field had a layout registered
- // directly using its IR key.
- //
- RefPtr<VarLayout> fieldLayout;
- if(structTypeLayout->mapKeyToLayout.TryGetValue(fieldKey, fieldLayout))
- return fieldLayout;
-
- // Otherwise, fall back to doing lookup using the linkage
- // attached to the key, and its mangled name.
- //
- auto fieldLinkage = fieldKey->findDecoration<IRLinkageDecoration>();
- if(!fieldLinkage)
- return nullptr;
- auto mangledFieldName = fieldLinkage->getMangledName();
-
- // In this case we fall back to a linear search over the fields.
- //
- for(auto ff : structTypeLayout->fields)
+ for(auto ff : structTypeLayout->getFieldLayoutAttrs())
{
- if(mangledFieldName == getMangledName(ff->varDecl.getDecl()).getUnownedSlice() )
+ if(ff->getFieldKey() == fieldKey)
{
- return ff;
+ return ff->getLayout();
}
}
}
@@ -1357,22 +1340,22 @@ RefPtr<VarLayout> getFieldLayout(
return nullptr;
}
-RefPtr<VarLayout> createSimpleVarLayout(
+void buildSimpleVarLayout(
+ IRVarLayout::Builder* builder,
SimpleLegalVarChain* varChain,
- TypeLayout* typeLayout)
+ IRTypeLayout* typeLayout)
{
- if (!typeLayout)
- return nullptr;
-
// We need to construct a layout for the new variable
// that reflects both the type we have given it, as
// well as all the offset information that has accumulated
// along the chain of parent variables.
- // TODO: this logic needs to propagate through semantics...
-
- RefPtr<VarLayout> varLayout = new VarLayout();
- varLayout->typeLayout = typeLayout;
+ // TODO: This logic doesn't currently handle semantics or
+ // other attributes that might have been present on the
+ // original variable layout. That is probably okay for now
+ // as the legalization logic does not apply to varying
+ // parameters (where resource types would be illegal anyway),
+ // but it is probably worth addressing sooner or later.
// For most resource kinds, the register index/space to use should
// be the sum along the entire chain of variables.
@@ -1387,16 +1370,17 @@ RefPtr<VarLayout> createSimpleVarLayout(
// the offset for `s` (10 texture registers) to get the final
// binding to apply.
//
- for (auto rr : typeLayout->resourceInfos)
+ for (auto rr : typeLayout->getSizeAttrs())
{
- auto resInfo = varLayout->findOrAddResourceInfo(rr.kind);
+ auto kind = rr->getResourceKind();
+ auto resInfo = builder->findOrAddResourceInfo(kind);
for (auto vv = varChain; vv; vv = vv->next)
{
- if (auto parentResInfo = vv->varLayout->FindResourceInfo(rr.kind))
+ if (auto parentResInfo = vv->varLayout->findOffsetAttr(kind))
{
- resInfo->index += parentResInfo->index;
- resInfo->space += parentResInfo->space;
+ resInfo->offset += parentResInfo->getOffset();
+ resInfo->space += parentResInfo->getSpace();
}
}
}
@@ -1404,44 +1388,57 @@ RefPtr<VarLayout> createSimpleVarLayout(
// As a special case, if the leaf variable doesn't hold an entry for
// `RegisterSpace`, but at least one declaration in the chain *does*,
// then we want to make sure that we add such an entry.
- if (!varLayout->FindResourceInfo(LayoutResourceKind::RegisterSpace))
+ //
+ if (!builder->usesResourceKind(LayoutResourceKind::RegisterSpace))
{
// Sum up contributions from all parents.
UInt space = 0;
for (auto vv = varChain; vv; vv = vv->next)
{
- if (auto parentResInfo = vv->varLayout->FindResourceInfo(LayoutResourceKind::RegisterSpace))
+ if (auto parentResInfo = vv->varLayout->findOffsetAttr(LayoutResourceKind::RegisterSpace))
{
- space += parentResInfo->index;
+ space += parentResInfo->getOffset();
}
}
// If there were non-zero contributions, then add an entry to represent them.
if (space)
{
- varLayout->findOrAddResourceInfo(LayoutResourceKind::RegisterSpace)->index = space;
+ builder->findOrAddResourceInfo(LayoutResourceKind::RegisterSpace)->offset = space;
}
}
-
- return varLayout;
}
+IRVarLayout* createSimpleVarLayout(
+ IRBuilder* irBuilder,
+ SimpleLegalVarChain* varChain,
+ IRTypeLayout* typeLayout)
+{
+ if (!typeLayout)
+ return nullptr;
+ IRVarLayout::Builder varLayoutBuilder(irBuilder, typeLayout);
+ buildSimpleVarLayout(&varLayoutBuilder, varChain, typeLayout);
+ return varLayoutBuilder.build();
+}
-RefPtr<VarLayout> createVarLayout(
+IRVarLayout* createVarLayout(
+ IRBuilder* irBuilder,
LegalVarChain const& varChain,
- TypeLayout* typeLayout)
+ IRTypeLayout* typeLayout)
{
if(!typeLayout)
return nullptr;
- auto varLayout = createSimpleVarLayout(varChain.primaryChain, typeLayout);
+ IRVarLayout::Builder varLayoutBuilder(irBuilder, typeLayout);
+ buildSimpleVarLayout(&varLayoutBuilder, varChain.primaryChain, typeLayout);
- if(auto pendingDataTypeLayout = typeLayout->pendingDataTypeLayout)
+ if(auto pendingDataTypeLayout = typeLayout->getPendingDataTypeLayout())
{
- varLayout->pendingVarLayout = createSimpleVarLayout(varChain.pendingChain, typeLayout);
+ varLayoutBuilder.setPendingVarLayout(
+ createSimpleVarLayout(irBuilder, varChain.pendingChain, typeLayout));
}
- return varLayout;
+ return varLayoutBuilder.build();
}
//
diff --git a/source/slang/slang-legalize-types.h b/source/slang/slang-legalize-types.h
index e92a9fc41..1201f669d 100644
--- a/source/slang/slang-legalize-types.h
+++ b/source/slang/slang-legalize-types.h
@@ -323,11 +323,11 @@ struct WrappedBufferPseudoType : LegalTypeImpl
//
-RefPtr<TypeLayout> getDerefTypeLayout(
- TypeLayout* typeLayout);
+IRTypeLayout* getDerefTypeLayout(
+ IRTypeLayout* typeLayout);
-RefPtr<VarLayout> getFieldLayout(
- TypeLayout* typeLayout,
+IRVarLayout* getFieldLayout(
+ IRTypeLayout* typeLayout,
IRInst* fieldKey);
/// Represents a "chain" of variables leading to some leaf field.
@@ -362,7 +362,7 @@ struct SimpleLegalVarChain
SimpleLegalVarChain* next = nullptr;
// The layout for the variable at this link in thain.
- VarLayout* varLayout = nullptr;
+ IRVarLayout* varLayout = nullptr;
};
/// A "chain" of variable declarations that can handle both primary and "pending" data.
@@ -389,15 +389,6 @@ struct LegalVarChain
// The chain of variables that represents the pending allocation.
SimpleLegalVarChain* pendingChain = nullptr;
-
- // If the primary chain is non-empty, gets the variable at the leaf.
- DeclRef<VarDeclBase> getLeafVarDeclRef() const
- {
- if(!primaryChain)
- return DeclRef<VarDeclBase>();
-
- return primaryChain->varLayout->varDecl;
- }
};
/// RAII type for adding a link to a `LegalVarChain` as needed.
@@ -432,7 +423,7 @@ struct LegalVarChainLink : LegalVarChain
{}
/// Construct a chain that extends `parent` with `varLayout`, if it is non-null.
- LegalVarChainLink(LegalVarChain const& parent, VarLayout* varLayout)
+ LegalVarChainLink(LegalVarChain const& parent, IRVarLayout* varLayout)
: LegalVarChain(parent)
{
if( varLayout )
@@ -441,7 +432,7 @@ struct LegalVarChainLink : LegalVarChain
primaryLink.varLayout = varLayout;
primaryChain = &primaryLink;
- if( auto pendingVarLayout = varLayout->pendingVarLayout )
+ if( auto pendingVarLayout = varLayout->getPendingVarLayout() )
{
pendingLink.next = parent.pendingChain;
pendingLink.varLayout = pendingVarLayout;
@@ -454,13 +445,15 @@ struct LegalVarChainLink : LegalVarChain
SimpleLegalVarChain pendingLink;
};
-RefPtr<VarLayout> createVarLayout(
+IRVarLayout* createVarLayout(
+ IRBuilder* irBuilder,
LegalVarChain const& varChain,
- TypeLayout* typeLayout);
+ IRTypeLayout* typeLayout);
-RefPtr<VarLayout> createSimpleVarLayout(
+IRVarLayout* createSimpleVarLayout(
+ IRBuilder* irBuilder,
SimpleLegalVarChain* varChain,
- TypeLayout* typeLayout);
+ IRTypeLayout* typeLayout);
//
// The result of legalizing an IR value will be
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index cd398f4e7..113dcbfad 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -6714,6 +6714,278 @@ RefPtr<IRModule> TargetProgram::getOrCreateIRModuleForLayout(DiagnosticSink* sin
return m_irModuleForLayout;
}
+ /// Specialized IR generation context for when generating IR for layouts.
+struct IRLayoutGenContext : IRGenContext
+{
+ IRLayoutGenContext(SharedIRGenContext* shared)
+ : IRGenContext(shared)
+ {}
+
+ /// Cache for custom key instructions used for entry-point parameter layout information.
+ Dictionary<ParamDecl*, IRStructKey*> mapEntryPointParamToKey;
+};
+
+ /// Lower an AST-level type layout to an IR-level type layout.
+IRTypeLayout* lowerTypeLayout(
+ IRLayoutGenContext* context,
+ TypeLayout* typeLayout);
+
+ /// Lower an AST-level variable layout to an IR-level variable layout.
+IRVarLayout* lowerVarLayout(
+ IRLayoutGenContext* context,
+ VarLayout* varLayout);
+
+ /// Shared code for most `lowerTypeLayout` cases.
+ ///
+ /// Handles copying of resource usage and pending data type layout
+ /// from the AST `typeLayout` to the specified `builder`.
+ ///
+static IRTypeLayout* _lowerTypeLayoutCommon(
+ IRLayoutGenContext* context,
+ IRTypeLayout::Builder* builder,
+ TypeLayout* typeLayout)
+{
+ for( auto resInfo : typeLayout->resourceInfos )
+ {
+ builder->addResourceUsage(resInfo.kind, resInfo.count);
+ }
+
+ if( auto pendingTypeLayout = typeLayout->pendingDataTypeLayout )
+ {
+ builder->setPendingTypeLayout(
+ lowerTypeLayout(context, pendingTypeLayout));
+ }
+
+ return builder->build();
+}
+
+IRTypeLayout* lowerTypeLayout(
+ IRLayoutGenContext* context,
+ TypeLayout* typeLayout)
+{
+ // TODO: We chould consider caching the layouts we create based on `typeLayout`
+ // and re-using them. This isn't strictly necessary because we emit the
+ // instructions as "hoistable" which should give us de-duplication, and it wouldn't
+ // help much until/unless the AST level gets less wasteful about how it computes layout.
+
+ // We will use casting to detect if `typeLayout` is
+ // one of the cases that requires a dedicated sub-type
+ // of IR type layout.
+ //
+ if( auto paramGroupTypeLayout = as<ParameterGroupTypeLayout>(typeLayout) )
+ {
+ IRParameterGroupTypeLayout::Builder builder(context->irBuilder);
+
+ builder.setContainerVarLayout(
+ lowerVarLayout(context, paramGroupTypeLayout->containerVarLayout));
+ builder.setElementVarLayout(
+ lowerVarLayout(context, paramGroupTypeLayout->elementVarLayout));
+ builder.setOffsetElementTypeLayout(
+ lowerTypeLayout(context, paramGroupTypeLayout->offsetElementTypeLayout));
+
+ return _lowerTypeLayoutCommon(context, &builder, paramGroupTypeLayout);
+ }
+ else if( auto structTypeLayout = as<StructTypeLayout>(typeLayout) )
+ {
+ IRStructTypeLayout::Builder builder(context->irBuilder);
+
+ for( auto fieldLayout : structTypeLayout->fields )
+ {
+ auto fieldDecl = fieldLayout->varDecl;
+
+ IRStructKey* irFieldKey = nullptr;
+ if(auto paramDecl = as<ParamDecl>(fieldDecl) )
+ {
+ // There is a subtle special case here.
+ //
+ // A `StructTypeLayout` might be used to represent
+ // the parameters of an entry point, and this is the
+ // one and only case where the "fields" being used
+ // might actually be `ParamDecl`s.
+ //
+ // The IR encoding of structure type layouts relies
+ // on using field "key" instructions to identify
+ // the fields, but these don't exist (by default)
+ // for function parameters.
+ //
+ // To get around this problem we will create key
+ // instructions to stand in for the entry-point parameters
+ // as needed when generating layout.
+ //
+ // We need to cache the generated keys on the context,
+ // so that if we run into another type layout for the
+ // same entry point we will re-use the same keys.
+ //
+ if( !context->mapEntryPointParamToKey.TryGetValue(paramDecl, irFieldKey) )
+ {
+ irFieldKey = context->irBuilder->createStructKey();
+
+ // TODO: It might eventually be a good idea to attach a mangled
+ // name to the key we just generated (derived from the entry point
+ // and parameter name), even though parameters don't usually have
+ // linkage.
+ //
+ // Doing so would ensure that if we ever combined partial layout
+ // information from different modules they would agree on the key
+ // to use for entry-point parameters.
+ //
+ // For now this is a non-issue because both the creation and use
+ // of these keys will be local to a single `IREntryPointLayout`,
+ // and we don't support combination at a finer granularity than that.
+
+ context->mapEntryPointParamToKey.Add(paramDecl, irFieldKey);
+ }
+ }
+ else
+ {
+ IRInst* irFieldKeyInst = getSimpleVal(context,
+ ensureDecl(context, fieldDecl));
+ irFieldKey = as<IRStructKey>(irFieldKeyInst);
+ }
+ SLANG_ASSERT(irFieldKey);
+
+ auto irFieldLayout = lowerVarLayout(context, fieldLayout);
+ builder.addField(irFieldKey, irFieldLayout);
+ }
+
+ return _lowerTypeLayoutCommon(context, &builder, structTypeLayout);
+ }
+ else if( auto arrayTypeLayout = as<ArrayTypeLayout>(typeLayout) )
+ {
+ auto irElementTypeLayout = lowerTypeLayout(context, arrayTypeLayout->elementTypeLayout);
+ IRArrayTypeLayout::Builder builder(context->irBuilder, irElementTypeLayout);
+ return _lowerTypeLayoutCommon(context, &builder, arrayTypeLayout);
+ }
+ else if( auto taggedUnionTypeLayout = as<TaggedUnionTypeLayout>(typeLayout) )
+ {
+ IRTaggedUnionTypeLayout::Builder builder(context->irBuilder, taggedUnionTypeLayout->tagOffset);
+
+ for( auto caseTypeLayout : taggedUnionTypeLayout->caseTypeLayouts )
+ {
+ builder.addCaseTypeLayout(
+ lowerTypeLayout(
+ context,
+ caseTypeLayout));
+ }
+
+ return _lowerTypeLayoutCommon(context, &builder, taggedUnionTypeLayout);
+ }
+ else if( auto streamOutputTypeLayout = as<StreamOutputTypeLayout>(typeLayout) )
+ {
+ auto irElementTypeLayout = lowerTypeLayout(context, streamOutputTypeLayout->elementTypeLayout);
+
+ IRStreamOutputTypeLayout::Builder builder(context->irBuilder, irElementTypeLayout);
+ return _lowerTypeLayoutCommon(context, &builder, streamOutputTypeLayout);
+ }
+ else if( auto matrixTypeLayout = as<MatrixTypeLayout>(typeLayout) )
+ {
+ // TODO: Our support for explicit layouts on matrix types is minimal, so whether
+ // or not we even include `IRMatrixTypeLayout` doesn't impact any behavior we
+ // currently test.
+ //
+ // Our handling of matrix types and their layout needs a complete overhaul, but
+ // that isn't something we can get to right away, so we'll just try to pass
+ // along this data as best we can for now.
+
+ IRMatrixTypeLayout::Builder builder(context->irBuilder, matrixTypeLayout->mode);
+ return _lowerTypeLayoutCommon(context, &builder, matrixTypeLayout);
+ }
+ else
+ {
+ // If no special case applies we will build a generic `IRTypeLayout`.
+ //
+ IRTypeLayout::Builder builder(context->irBuilder);
+ return _lowerTypeLayoutCommon(context, &builder, typeLayout);
+ }
+}
+
+IRVarLayout* lowerVarLayout(
+ IRLayoutGenContext* context,
+ VarLayout* varLayout)
+{
+ auto irTypeLayout = lowerTypeLayout(context, varLayout->typeLayout);
+ IRVarLayout::Builder irLayoutBuilder(context->irBuilder, irTypeLayout);
+
+ for( auto resInfo : varLayout->resourceInfos )
+ {
+ auto irResInfo = irLayoutBuilder.findOrAddResourceInfo(resInfo.kind);
+ irResInfo->offset = resInfo.index;
+ irResInfo->space = resInfo.space;
+ }
+
+ if( auto pendingVarLayout = varLayout->pendingVarLayout )
+ {
+ irLayoutBuilder.setPendingVarLayout(
+ lowerVarLayout(context, pendingVarLayout));
+ }
+
+ // We will only generate layout information with *either* a system-value
+ // semantic or a user-defined semantic, and we will always check for
+ // the system-value semantic first because the AST-level representation
+ // seems to encode both when a system-value semantic is present.
+ //
+ if( varLayout->systemValueSemantic.getLength() )
+ {
+ irLayoutBuilder.setSystemValueSemantic(
+ varLayout->systemValueSemantic,
+ varLayout->systemValueSemanticIndex);
+ }
+ else if( varLayout->semanticName.getLength() )
+ {
+ irLayoutBuilder.setUserSemantic(
+ varLayout->semanticName,
+ varLayout->semanticIndex);
+ }
+
+ if( varLayout->stage != Stage::Unknown )
+ {
+ irLayoutBuilder.setStage(varLayout->stage);
+ }
+
+ return irLayoutBuilder.build();
+}
+
+ /// Handle the lowering of an entry-point result layout to the IR
+IRVarLayout* lowerEntryPointResultLayout(
+ IRLayoutGenContext* context,
+ VarLayout* layout)
+{
+ // The easy case is when there is a non-null `layout`, because we
+ // can handle it like any other var layout.
+ //
+ if(layout)
+ return lowerVarLayout(context, layout);
+
+ // Right now the AST-level layout logic will leave a null layout
+ // for the result when an entry point has a `void` result type.
+ //
+ // TODO: We should fix this at the AST level instead of the IR,
+ // but doing so would impact reflection, where clients could
+ // be using a null check to test for a `void` result.
+ //
+ // As a workaround, we will create an empty type layout and
+ // an empty var layout that represents it, consistent with the
+ // way that a `void` value consumes no resources.
+ //
+ IRTypeLayout::Builder typeLayoutBuilder(context->irBuilder);
+ auto irTypeLayout = typeLayoutBuilder.build();
+ IRVarLayout::Builder varLayoutBuilder(context->irBuilder, irTypeLayout);
+ return varLayoutBuilder.build();
+}
+
+ /// Lower AST-level layout information for an entry point to the IR
+IREntryPointLayout* lowerEntryPointLayout(
+ IRLayoutGenContext* context,
+ EntryPointLayout* entryPointLayout)
+{
+ auto irParamsLayout = lowerVarLayout(context, entryPointLayout->parametersLayout);
+ auto irResultLayout = lowerEntryPointResultLayout(context, entryPointLayout->resultLayout);
+
+ return context->irBuilder->getEntryPointLayout(
+ irParamsLayout,
+ irResultLayout);
+}
+
RefPtr<IRModule> TargetProgram::createIRModuleForLayout(DiagnosticSink* sink)
{
if(m_irModuleForLayout)
@@ -6735,7 +7007,7 @@ RefPtr<IRModule> TargetProgram::createIRModuleForLayout(DiagnosticSink* sink)
sink);
auto sharedContext = &sharedContextStorage;
- IRGenContext contextStorage(sharedContext);
+ IRLayoutGenContext contextStorage(sharedContext);
auto context = &contextStorage;
SharedIRBuilder sharedBuilderStorage;
@@ -6768,9 +7040,11 @@ RefPtr<IRModule> TargetProgram::createIRModuleForLayout(DiagnosticSink* sink)
//
auto irVar = getSimpleVal(context, ensureDecl(context, varDecl));
+ auto irLayout = lowerVarLayout(context, varLayout);
+
// Now attach the decoration to the variable.
//
- builder->addLayoutDecoration(irVar, varLayout);
+ builder->addLayoutDecoration(irVar, irLayout);
}
for( auto entryPointLayout : programLayout->entryPoints )
@@ -6785,14 +7059,19 @@ RefPtr<IRModule> TargetProgram::createIRModuleForLayout(DiagnosticSink* sink)
builder->addImportDecoration(irFunc, getMangledName(funcDeclRef).getUnownedSlice());
}
- builder->addLayoutDecoration(irFunc, entryPointLayout);
+ auto irEntryPointLayout = lowerEntryPointLayout(context, entryPointLayout);
+
+ builder->addLayoutDecoration(irFunc, irEntryPointLayout);
}
for( auto taggedUnionTypeLayout : programLayout->taggedUnionTypeLayouts )
{
auto taggedUnionType = taggedUnionTypeLayout->getType();
auto irType = lowerType(context, taggedUnionType);
- builder->addLayoutDecoration(irType, taggedUnionTypeLayout);
+
+ auto irTypeLayout = lowerTypeLayout(context, taggedUnionTypeLayout);
+
+ builder->addLayoutDecoration(irType, irTypeLayout);
}
m_irModuleForLayout = irModule;
diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp
index 807d0cab4..29ebe7de6 100644
--- a/source/slang/slang-type-layout.cpp
+++ b/source/slang/slang-type-layout.cpp
@@ -2,6 +2,7 @@
#include "slang-type-layout.h"
#include "slang-syntax.h"
+#include "slang-ir-insts.h"
#include <assert.h>
@@ -1356,73 +1357,110 @@ RefPtr<TypeLayout> applyOffsetToTypeLayout(
return newTypeLayout;
}
-RefPtr<VarLayout> applyOffsetToVarLayout(
- VarLayout* baseLayout,
- VarLayout* offsetLayout)
+IRTypeLayout* applyOffsetToTypeLayout(
+ IRBuilder* irBuilder,
+ IRTypeLayout* oldTypeLayout,
+ IRVarLayout* offsetVarLayout)
{
- RefPtr<VarLayout> adjustedLayout = new VarLayout();
- adjustedLayout->typeLayout = baseLayout->typeLayout;
- adjustedLayout->varDecl = baseLayout->varDecl;
- adjustedLayout->flags = baseLayout->flags;
- adjustedLayout->semanticName = baseLayout->semanticName;
- adjustedLayout->semanticIndex = baseLayout->semanticIndex;
- adjustedLayout->systemValueSemantic = baseLayout->systemValueSemantic;
- adjustedLayout->systemValueSemanticIndex = baseLayout->systemValueSemanticIndex;
- adjustedLayout->stage = baseLayout->stage;
+ // The body of this function is derived from the AST case defined above.
+ //
+ // TODO: We shouldn't need this function at all because "offset" type
+ // layouts were only introduced as a legacy workaround for some bad choices
+ // in the reflection API.
+ //
- if( auto basePendingLayout = baseLayout->pendingVarLayout )
+ // There is no need to apply offsets if the old type and the offset
+ // don't share any resource infos in common.
+ bool anyHit = false;
+ for (auto oldResInfo : oldTypeLayout->getSizeAttrs())
{
- if( auto offsetPendingLayout = offsetLayout->pendingVarLayout )
+ if (auto offsetResInfo = offsetVarLayout->findOffsetAttr(oldResInfo->getResourceKind()))
{
- adjustedLayout->pendingVarLayout = applyOffsetToVarLayout(
- basePendingLayout,
- offsetPendingLayout);
+ anyHit = true;
+ break;
}
}
- for( auto baseResInfo : baseLayout->resourceInfos )
+ if (!anyHit)
+ return oldTypeLayout;
+
+ if (auto oldStructTypeLayout = as<IRStructTypeLayout>(oldTypeLayout))
{
- auto adjustedResInfo = baseResInfo;
- if( auto offsetResInfo = offsetLayout->FindResourceInfo(baseResInfo.kind) )
+ IRStructTypeLayout::Builder newStructTypeLayoutBuilder(irBuilder);
+ newStructTypeLayoutBuilder.addResourceUsageFrom(oldTypeLayout);
+
+ for (auto oldFieldAttr : oldStructTypeLayout->getFieldLayoutAttrs())
{
- adjustedResInfo.index += offsetResInfo->index;
- adjustedResInfo.space += offsetResInfo->space;
- }
- adjustedLayout->resourceInfos.add(adjustedResInfo);
- }
+ auto fieldKey = oldFieldAttr->getFieldKey();
+ auto oldFieldLayout = oldFieldAttr->getLayout();
- return adjustedLayout;
-}
+ IRVarLayout::Builder newFieldBuilder(irBuilder, oldFieldLayout->getTypeLayout());
+ newFieldBuilder.cloneEverythingButOffsetsFrom(oldFieldLayout);
-EntryPointLayout* EntryPointLayout::getAbsoluteLayout(
- VarLayout* parentLayout)
-{
- SLANG_ASSERT(parentLayout);
+ for (auto oldResInfo : oldFieldLayout->getOffsetAttrs())
+ {
+ auto kind = oldResInfo->getResourceKind();
+ auto newResInfo = newFieldBuilder.findOrAddResourceInfo(kind);
+ newResInfo->offset = oldResInfo->getOffset();
+ newResInfo->space = oldResInfo->getSpace();
+ if (auto offsetResInfo = offsetVarLayout->findOffsetAttr(kind))
+ {
+ newResInfo->offset += offsetResInfo->getOffset();
+ }
+ }
- if(m_absoluteLayout)
- return m_absoluteLayout;
+ newStructTypeLayoutBuilder.addField(fieldKey, newFieldBuilder.build());
+ }
- RefPtr<EntryPointLayout> adjustedLayout = new EntryPointLayout();
- adjustedLayout->entryPoint = this->entryPoint;
- adjustedLayout->flags = this->flags;
- adjustedLayout->parametersLayout = this->parametersLayout->getAbsoluteLayout(parentLayout);
- adjustedLayout->profile = this->profile;
- if( auto baseResultLayout = this->resultLayout )
+ return newStructTypeLayoutBuilder.build();
+ }
+ else
{
- adjustedLayout->resultLayout = baseResultLayout->getAbsoluteLayout(parentLayout);
+ // We can only effectively apply this offsetting to basic struct types,
+ // and so we won't even attempt it for anything else. This matches the
+ // AST implementation of this function, and shouldn't matter in the long
+ // run since we will remove the concept of offset type layouts from
+ // the IR.
+ //
+ return oldTypeLayout;
}
-
- m_absoluteLayout = adjustedLayout;
- return adjustedLayout;
}
-VarLayout* VarLayout::getAbsoluteLayout(VarLayout* parentAbsoluteLayout)
+IRVarLayout* applyOffsetToVarLayout(
+ IRBuilder* irBuilder,
+ IRVarLayout* baseLayout,
+ IRVarLayout* offsetLayout)
{
- if( !m_absoluteLayout )
+ IRVarLayout::Builder adjustedLayoutBuilder(irBuilder, baseLayout->getTypeLayout());
+ adjustedLayoutBuilder.cloneEverythingButOffsetsFrom(baseLayout);
+
+ if( auto basePendingLayout = baseLayout->getPendingVarLayout() )
{
- m_absoluteLayout = applyOffsetToVarLayout(this, parentAbsoluteLayout);
+ if( auto offsetPendingLayout = offsetLayout->getPendingVarLayout() )
+ {
+ adjustedLayoutBuilder.setPendingVarLayout(
+ applyOffsetToVarLayout(
+ irBuilder,
+ basePendingLayout,
+ offsetPendingLayout));
+ }
+ }
+
+ for( auto baseResInfo : baseLayout->getOffsetAttrs() )
+ {
+ auto kind = baseResInfo->getResourceKind();
+ auto adjustedResInfo = adjustedLayoutBuilder.findOrAddResourceInfo(kind);
+ adjustedResInfo->offset = baseResInfo->getOffset();
+ adjustedResInfo->space = baseResInfo->getSpace();
+
+ if( auto offsetResInfo = offsetLayout->findOffsetAttr(baseResInfo->getResourceKind()) )
+ {
+ adjustedResInfo->offset += offsetResInfo->getOffset();
+ adjustedResInfo->space += offsetResInfo->getSpace();
+ }
}
- return m_absoluteLayout;
+
+ return adjustedLayoutBuilder.build();
}
static bool _usesResourceKind(RefPtr<TypeLayout> typeLayout, LayoutResourceKind kind)
diff --git a/source/slang/slang-type-layout.h b/source/slang/slang-type-layout.h
index f63dd01c0..ac0ef3bd7 100644
--- a/source/slang/slang-type-layout.h
+++ b/source/slang/slang-type-layout.h
@@ -44,6 +44,13 @@ struct LayoutSize
SLANG_ASSERT(size != RawValue(-1));
}
+ static LayoutSize fromRaw(RawValue raw)
+ {
+ LayoutSize size;
+ size.raw = raw;
+ return size;
+ }
+
static LayoutSize infinite()
{
LayoutSize result;
@@ -469,21 +476,6 @@ public:
}
RefPtr<VarLayout> pendingVarLayout;
-
-
- /// Get the "absolute" layout of this variable, if applicable.
- ///
- /// The `parentAbsoluteLayout` must be the absolute layout
- /// of the parent of this variable.
- ///
- /// The absolute layout will be created once and cached on
- /// future accesses; if `parentAbsoluteLayout` is not
- /// consistent at different call sites an unexpected
- /// layout could be returned.
- ///
- VarLayout* getAbsoluteLayout(VarLayout* parentAbsoluteLayout);
-
- RefPtr<VarLayout> m_absoluteLayout;
};
// type layout for a variable that has a constant-buffer type
@@ -510,16 +502,6 @@ public:
// so that any fields (if the element type is a `struct`)
// will be offset by the resource usage of the container.
RefPtr<TypeLayout> offsetElementTypeLayout;
-
- // If the element type layout had any "pending" data, then
- // as much of that data as possible will be flushed to
- // fit into the overall layout of the parameter group.
- //
- // This field stores the offset information for where
- // the pending data got stored relative to the start of
- // the group.
- //
-// RefPtr<VarLayout> flushedDataVarLayout;
};
// type layout for a variable that has a constant-buffer type
@@ -604,12 +586,6 @@ public:
// in the array above, rather than to the actual pointer,
// so that we
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"
- // instructions to map to fields.
- //
- Dictionary<IRInst*, RefPtr<VarLayout>> mapKeyToLayout;
};
class GenericParamTypeLayout : public TypeLayout
@@ -691,9 +667,9 @@ public:
};
unsigned flags = 0;
- EntryPointLayout* getAbsoluteLayout(VarLayout* parentLayout);
+// EntryPointLayout* getAbsoluteLayout(VarLayout* parentLayout);
- RefPtr<EntryPointLayout> m_absoluteLayout;
+// RefPtr<EntryPointLayout> m_absoluteLayout;
};
/// Reflection/layout information about a specialization parameter
@@ -1170,10 +1146,20 @@ RefPtr<TypeLayout> applyOffsetToTypeLayout(
RefPtr<TypeLayout> oldTypeLayout,
RefPtr<VarLayout> offsetVarLayout);
+struct IRBuilder;
+struct IRTypeLayout;
+struct IRVarLayout;
+
+IRTypeLayout* applyOffsetToTypeLayout(
+ IRBuilder* irBuilder,
+ IRTypeLayout* oldTypeLayout,
+ IRVarLayout* offsetVarLayout);
+
/// Create a layout like `baseLayout`, but offset by `offsetLayout`
-RefPtr<VarLayout> applyOffsetToVarLayout(
- VarLayout* baseLayout,
- VarLayout* offsetLayout);
+IRVarLayout* applyOffsetToVarLayout(
+ IRBuilder* irBuilder,
+ IRVarLayout* baseLayout,
+ IRVarLayout* offsetLayout);
}