summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/visual-studio/slang/slang.vcxproj2
-rw-r--r--build/visual-studio/slang/slang.vcxproj.filters6
-rw-r--r--source/slang/slang-emit-spirv-ops.h6
-rw-r--r--source/slang/slang-emit-spirv.cpp175
-rw-r--r--source/slang/slang-emit.cpp2
-rw-r--r--source/slang/slang-ir-byte-address-legalize.cpp16
-rw-r--r--source/slang/slang-ir-dll-import.cpp2
-rw-r--r--source/slang/slang-ir-extract-value-from-type.cpp12
-rw-r--r--source/slang/slang-ir-generics-lowering-context.cpp6
-rw-r--r--source/slang/slang-ir-inst-defs.h14
-rw-r--r--source/slang/slang-ir-insts.h52
-rw-r--r--source/slang/slang-ir-layout-on-types.cpp153
-rw-r--r--source/slang/slang-ir-layout-on-types.h8
-rw-r--r--source/slang/slang-ir-layout.cpp561
-rw-r--r--source/slang/slang-ir-layout.h25
-rw-r--r--source/slang/slang-ir-lower-bit-cast.cpp8
-rw-r--r--source/slang/slang-ir-lower-buffer-element-type.cpp168
-rw-r--r--source/slang/slang-ir-lower-buffer-element-type.h5
-rw-r--r--source/slang/slang-ir-lower-generics.cpp30
-rw-r--r--source/slang/slang-ir-lower-size-of.cpp2
-rw-r--r--source/slang/slang-ir-spirv-legalize.cpp92
-rw-r--r--source/slang/slang-ir.cpp25
-rw-r--r--source/slang/slang-ir.h28
-rw-r--r--source/slang/slang-spirv-val.cpp25
-rw-r--r--tests/expected-failure.txt3
25 files changed, 635 insertions, 791 deletions
diff --git a/build/visual-studio/slang/slang.vcxproj b/build/visual-studio/slang/slang.vcxproj
index 29437c152..235595039 100644
--- a/build/visual-studio/slang/slang.vcxproj
+++ b/build/visual-studio/slang/slang.vcxproj
@@ -398,7 +398,6 @@ IF EXIST ..\..\..\external\slang-glslang\bin\windows-aarch64\release\slang-glsla
<ClInclude Include="..\..\..\source\slang\slang-ir-inst-defs.h" />
<ClInclude Include="..\..\..\source\slang\slang-ir-inst-pass-base.h" />
<ClInclude Include="..\..\..\source\slang\slang-ir-insts.h" />
- <ClInclude Include="..\..\..\source\slang\slang-ir-layout-on-types.h" />
<ClInclude Include="..\..\..\source\slang\slang-ir-layout.h" />
<ClInclude Include="..\..\..\source\slang\slang-ir-legalize-array-return-type.h" />
<ClInclude Include="..\..\..\source\slang\slang-ir-legalize-mesh-outputs.h" />
@@ -607,7 +606,6 @@ IF EXIST ..\..\..\external\slang-glslang\bin\windows-aarch64\release\slang-glsla
<ClCompile Include="..\..\..\source\slang\slang-ir-glsl-liveness.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ir-init-local-var.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ir-inline.cpp" />
- <ClCompile Include="..\..\..\source\slang\slang-ir-layout-on-types.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ir-layout.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ir-legalize-array-return-type.cpp" />
<ClCompile Include="..\..\..\source\slang\slang-ir-legalize-mesh-outputs.cpp" />
diff --git a/build/visual-studio/slang/slang.vcxproj.filters b/build/visual-studio/slang/slang.vcxproj.filters
index 00c3bf74d..8931f782b 100644
--- a/build/visual-studio/slang/slang.vcxproj.filters
+++ b/build/visual-studio/slang/slang.vcxproj.filters
@@ -282,9 +282,6 @@
<ClInclude Include="..\..\..\source\slang\slang-ir-insts.h">
<Filter>Header Files</Filter>
</ClInclude>
- <ClInclude Include="..\..\..\source\slang\slang-ir-layout-on-types.h">
- <Filter>Header Files</Filter>
- </ClInclude>
<ClInclude Include="..\..\..\source\slang\slang-ir-layout.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -905,9 +902,6 @@
<ClCompile Include="..\..\..\source\slang\slang-ir-inline.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="..\..\..\source\slang\slang-ir-layout-on-types.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
<ClCompile Include="..\..\..\source\slang\slang-ir-layout.cpp">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/source/slang/slang-emit-spirv-ops.h b/source/slang/slang-emit-spirv-ops.h
index 445f6f7d0..d91afad0c 100644
--- a/source/slang/slang-emit-spirv-ops.h
+++ b/source/slang/slang-emit-spirv-ops.h
@@ -235,7 +235,7 @@ SpvInst* emitOpTypeArray(IRInst* inst, const T1& elementType, const T2& length)
{
static_assert(isSingular<T1>);
static_assert(isSingular<T2>);
- return emitInstMemoized(
+ return emitInst(
getSection(SpvLogicalSectionID::ConstantsAndTypes),
inst,
SpvOpTypeArray,
@@ -250,7 +250,7 @@ template<typename T>
SpvInst* emitOpTypeRuntimeArray(IRInst* inst, const T& elementType)
{
static_assert(isSingular<T>);
- return emitInstMemoized(
+ return emitInst(
getSection(SpvLogicalSectionID::ConstantsAndTypes),
inst,
SpvOpTypeRuntimeArray,
@@ -264,7 +264,7 @@ template<typename Ts>
SpvInst* emitOpTypeStruct(IRInst* inst, const Ts& member0TypeMember1TypeEtc)
{
static_assert(isPlural<Ts>);
- return emitInstMemoized(
+ return emitInst(
getSection(SpvLogicalSectionID::ConstantsAndTypes),
inst,
SpvOpTypeStruct,
diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp
index 10adb9708..3ba06b55c 100644
--- a/source/slang/slang-emit-spirv.cpp
+++ b/source/slang/slang-emit-spirv.cpp
@@ -1217,7 +1217,6 @@ struct SPIRVEmitContext
case kIROp_StructType:
{
List<IRType*> types;
- // TODO: decorate offset
for (auto field : static_cast<IRStructType*>(inst)->getFields())
types.add(field->getFieldType());
auto spvStructType = emitOpTypeStruct(
@@ -1225,6 +1224,7 @@ struct SPIRVEmitContext
types
);
emitDecorations(inst, getID(spvStructType));
+ emitLayoutDecorations(as<IRStructType>(inst), getID(spvStructType));
return spvStructType;
}
case kIROp_VectorType:
@@ -1248,35 +1248,6 @@ struct SPIRVEmitContext
vectorSpvType,
SpvLiteralInteger::from32(int32_t(columnCount))
);
- // TODO: properly compute matrix stride.
- uint32_t stride = 0;
- switch (columnCount)
- {
- case 1:
- stride = 4;
- break;
- case 2:
- stride = 8;
- break;
- case 3:
- case 4:
- stride = 16;
- break;
- default:
- break;
- }
- // TODO: This decoration is not legal here. It must be placed
- // on a struct member (which may entail wrapping matrices)
- emitOpDecorate(
- getSection(SpvLogicalSectionID::Annotations),
- nullptr,
- matrixSPVType,
- SpvDecorationRowMajor);
- emitOpDecorateMatrixStride(
- getSection(SpvLogicalSectionID::Annotations),
- nullptr,
- matrixSPVType,
- SpvLiteralInteger::from32(stride));
return matrixSPVType;
}
case kIROp_ArrayType:
@@ -1286,15 +1257,23 @@ struct SPIRVEmitContext
const auto arrayType = inst->getOp() == kIROp_ArrayType
? emitOpTypeArray(inst, elementType, static_cast<IRArrayTypeBase*>(inst)->getElementCount())
: emitOpTypeRuntimeArray(inst, elementType);
- // TODO: properly decorate stride.
- // TODO: don't do this more than once
- IRSizeAndAlignment sizeAndAlignment;
- getNaturalSizeAndAlignment(this->m_targetRequest, elementType, &sizeAndAlignment);
+ auto strideInst = as<IRArrayTypeBase>(inst)->getArrayStride();
+ int stride = 0;
+ if (strideInst)
+ {
+ stride = (int)getIntVal(strideInst);
+ }
+ else
+ {
+ IRSizeAndAlignment sizeAndAlignment;
+ getNaturalSizeAndAlignment(elementType, &sizeAndAlignment);
+ stride = (int)sizeAndAlignment.getStride();
+ }
emitOpDecorateArrayStride(
getSection(SpvLogicalSectionID::Annotations),
nullptr,
arrayType,
- SpvLiteralInteger::from32(int32_t(sizeAndAlignment.getStride())));
+ SpvLiteralInteger::from32(stride));
return arrayType;
}
@@ -1841,13 +1820,6 @@ struct SPIRVEmitContext
return emitLoad(parent, as<IRLoad>(inst));
case kIROp_Store:
return emitStore(parent, as<IRStore>(inst));
- case kIROp_StructuredBufferLoad:
- case kIROp_StructuredBufferLoadStatus:
- case kIROp_RWStructuredBufferLoad:
- case kIROp_RWStructuredBufferLoadStatus:
- return emitStructuredBufferLoad(parent, inst);
- case kIROp_RWStructuredBufferStore:
- return emitStructuredBufferStore(parent, inst);
case kIROp_RWStructuredBufferGetElementPtr:
return emitStructuredBufferGetElementPtr(parent, inst);
case kIROp_swizzle:
@@ -2072,39 +2044,6 @@ struct SPIRVEmitContext
default:
break;
- case kIROp_LayoutDecoration:
- {
- // Basic offsets for structs used in buffers
- if(const auto typeLayout = as<IRTypeLayout>(as<IRLayoutDecoration>(decoration)->getLayout()))
- {
- if(const auto structTypeLayout = as<IRStructTypeLayout>(typeLayout))
- {
- auto section = getSection(SpvLogicalSectionID::Annotations);
- SpvWord i = 0;
- for(const auto fieldLayoutAttr : structTypeLayout->getFieldLayoutAttrs())
- {
- if(const auto structFieldLayoutAttr = as<IRStructFieldLayoutAttr>(fieldLayoutAttr))
- {
- const auto varLayout = structFieldLayoutAttr->getLayout();
- if(const auto varOffsetAttr = varLayout->findOffsetAttr(LayoutResourceKind::Uniform))
- {
- const auto offset = static_cast<SpvWord>(varOffsetAttr->getOffset());
- emitOpMemberDecorateOffset(
- section,
- fieldLayoutAttr,
- dstID,
- SpvLiteralInteger::from32(i),
- SpvLiteralInteger::from32(offset)
- );
- }
- }
- ++i;
- }
- }
- }
- }
- break;
-
// [3.32.2. Debug Instructions]
//
// > OpName
@@ -2221,6 +2160,76 @@ struct SPIRVEmitContext
}
}
+ void emitLayoutDecorations(IRStructType* structType, SpvWord spvStructID)
+ {
+ /*****
+ * SPIRV Spec:
+ * Each structure-type member must have an Offset decoration.
+ *
+ * Each array type must have an ArrayStride decoration, unless it is an
+ * array that contains a structure decorated with Block or BufferBlock, in
+ * which case it must not have an ArrayStride decoration.
+ *
+ * Each structure-type member that is a matrix or array-of-matrices must be
+ * decorated with a MatrixStride Decoration, and one of the RowMajor or
+ * ColMajor decorations.
+ *
+ * The ArrayStride, MatrixStride, and Offset decorations must be large
+ * enough to hold the size of the objects they affect (that is, specifying
+ * overlap is invalid). Each ArrayStride and MatrixStride must be greater
+ * than zero, and it is invalid for two members of a given structure to be
+ * assigned the same Offset.
+ *
+ *****/
+ auto layout = structType->findDecoration<IRSizeAndAlignmentDecoration>();
+ IRTypeLayoutRuleName layoutRuleName = IRTypeLayoutRuleName::Natural;
+ if (layout)
+ {
+ layoutRuleName = layout->getLayoutName();
+ }
+ int32_t id = 0;
+ for (auto field : structType->getFields())
+ {
+ IRIntegerValue offset = 0;
+ getOffset(IRTypeLayoutRules::get(layoutRuleName), field, &offset);
+ emitOpMemberDecorateOffset(
+ getSection(SpvLogicalSectionID::Annotations),
+ nullptr,
+ spvStructID,
+ SpvLiteralInteger::from32(id),
+ SpvLiteralInteger::from32(int32_t(offset)));
+ auto matrixType = as<IRMatrixType>(field->getFieldType());
+ auto arrayType = as<IRArrayTypeBase>(field->getFieldType());
+ if (!matrixType && arrayType)
+ {
+ matrixType = as<IRMatrixType>(arrayType->getElementType());
+ }
+ if (matrixType)
+ {
+ IRSizeAndAlignment matrixSize;
+ getSizeAndAlignment(IRTypeLayoutRules::get(layoutRuleName), matrixType, &matrixSize);
+ // Reminder: the meaning of row/column major layout
+ // in our semantics is the *opposite* of what GLSL/SPIRV
+ // calls them, because what they call "columns"
+ // are what we call "rows."
+ //
+ emitOpMemberDecorate(
+ getSection(SpvLogicalSectionID::Annotations),
+ nullptr,
+ spvStructID,
+ SpvLiteralInteger::from32(id),
+ getIntVal(matrixType->getLayout()) == SLANG_MATRIX_LAYOUT_COLUMN_MAJOR? SpvDecorationRowMajor : SpvDecorationColMajor);
+ emitOpMemberDecorateMatrixStride(
+ getSection(SpvLogicalSectionID::Annotations),
+ nullptr,
+ spvStructID,
+ SpvLiteralInteger::from32(id),
+ SpvLiteralInteger::from32((int32_t)matrixSize.getStride()));
+ }
+ id++;
+ }
+ }
+
/// Map a Slang `Stage` to a corresponding SPIR-V execution model
SpvExecutionModel mapStageToExecutionModel(Stage stage)
{
@@ -2862,22 +2871,6 @@ struct SPIRVEmitContext
return emitOpStore(parent, inst, inst->getPtr(), inst->getVal());
}
- SpvInst* emitStructuredBufferLoad(SpvInstParent* parent, IRInst* inst)
- {
- //"%addr = OpAccessChain resultType*StorageBuffer resultId _0 const(int, 0) _1; OpLoad resultType resultId %addr;"
- IRBuilder builder(inst);
- auto addr = emitInst(parent, inst, SpvOpAccessChain, inst->getOperand(0)->getDataType(), kResultID, inst->getOperand(0), emitIntConstant(0, builder.getIntType()), inst->getOperand(1));
- return emitInst(parent, inst, SpvOpLoad, inst->getFullType(), kResultID, addr);
- }
-
- SpvInst* emitStructuredBufferStore(SpvInstParent* parent, IRInst* inst)
- {
- //"%addr = OpAccessChain resultType*StorageBuffer resultId _0 const(int, 0) _1; OpStore %addr _2;"
- IRBuilder builder(inst);
- auto addr = emitInst(parent, inst, SpvOpAccessChain, inst->getOperand(0)->getDataType(), kResultID, inst->getOperand(0), emitIntConstant(0, builder.getIntType()), inst->getOperand(1));
- return emitInst(parent, inst, SpvOpStore, addr, inst->getOperand(2));
- }
-
SpvInst* emitStructuredBufferGetElementPtr(SpvInstParent* parent, IRInst* inst)
{
//"%addr = OpAccessChain resultType*StorageBuffer resultId _0 const(int, 0) _1;"
diff --git a/source/slang/slang-emit.cpp b/source/slang/slang-emit.cpp
index 4b95ca9c8..82f2a8fd3 100644
--- a/source/slang/slang-emit.cpp
+++ b/source/slang/slang-emit.cpp
@@ -859,7 +859,7 @@ Result linkAndOptimizeIR(
legalizeMeshOutputTypes(irModule);
// We need to lower any types used in a buffer resource (e.g. ContantBuffer or StructuredBuffer) into
- // a simple storage type that has target independent layout.
+ // a simple storage type that has target independent layout based on the kind of buffer resource.
lowerBufferElementTypeToStorageType(targetRequest, irModule);
// Rewrite functions that return arrays to return them via `out` parameter,
diff --git a/source/slang/slang-ir-byte-address-legalize.cpp b/source/slang/slang-ir-byte-address-legalize.cpp
index b3260c8c7..40fe64693 100644
--- a/source/slang/slang-ir-byte-address-legalize.cpp
+++ b/source/slang/slang-ir-byte-address-legalize.cpp
@@ -208,18 +208,18 @@ struct ByteAddressBufferLegalizationContext
{
if (target->getHLSLToVulkanLayoutOptions() && target->getHLSLToVulkanLayoutOptions()->shouldUseGLLayout())
{
- return getStd430Offset(target, field, outOffset);
+ return getStd430Offset(field, outOffset);
}
- return getNaturalOffset(target, field, outOffset);
+ return getNaturalOffset(field, outOffset);
}
SlangResult getSizeAndAlignment(TargetRequest* target, IRType* type, IRSizeAndAlignment* outSizeAlignment)
{
if (target->getHLSLToVulkanLayoutOptions() && target->getHLSLToVulkanLayoutOptions()->shouldUseGLLayout())
{
- return getStd430SizeAndAlignment(target, type, outSizeAlignment);
+ return getStd430SizeAndAlignment(type, outSizeAlignment);
}
- return getNaturalSizeAndAlignment(target, type, outSizeAlignment);
+ return getNaturalSizeAndAlignment(type, outSizeAlignment);
}
// The core workhorse routine for the load case is `emitLegalLoad`,
@@ -456,7 +456,7 @@ struct ByteAddressBufferLegalizationContext
// the "stride" of the element type.
//
IRSizeAndAlignment elementLayout;
- SLANG_RETURN_NULL_ON_FAIL(getNaturalSizeAndAlignment(m_target, elementType, &elementLayout));
+ SLANG_RETURN_NULL_ON_FAIL(getNaturalSizeAndAlignment(elementType, &elementLayout));
IRIntegerValue elementStride = elementLayout.getStride();
// We will collect all the element values into an array so
@@ -546,7 +546,7 @@ struct ByteAddressBufferLegalizationContext
auto offsetType = offset->getDataType();
IRSizeAndAlignment typeLayout;
- SLANG_RETURN_NULL_ON_FAIL(getNaturalSizeAndAlignment(m_target, type, &typeLayout));
+ SLANG_RETURN_NULL_ON_FAIL(getNaturalSizeAndAlignment(type, &typeLayout));
auto typeStrideVal = typeLayout.getStride();
auto typeStrideInst = m_builder.getIntValue(offsetType, typeStrideVal);
@@ -950,7 +950,7 @@ struct ByteAddressBufferLegalizationContext
auto indexType = offset->getDataType();
IRSizeAndAlignment typeLayout;
- SLANG_RETURN_ON_FAIL(getNaturalSizeAndAlignment(m_target, type, &typeLayout));
+ SLANG_RETURN_ON_FAIL(getNaturalSizeAndAlignment(type, &typeLayout));
auto typeStride = m_builder.getIntValue(indexType, typeLayout.getStride());
@@ -978,7 +978,7 @@ struct ByteAddressBufferLegalizationContext
// We iterate over the elements and fetch then store each one.
//
IRSizeAndAlignment elementLayout;
- SLANG_RETURN_ON_FAIL(getNaturalSizeAndAlignment(m_target, elementType, &elementLayout));
+ SLANG_RETURN_ON_FAIL(getNaturalSizeAndAlignment(elementType, &elementLayout));
IRIntegerValue elementStride = elementLayout.getStride();
auto indexType = m_builder.getIntType();
diff --git a/source/slang/slang-ir-dll-import.cpp b/source/slang/slang-ir-dll-import.cpp
index 2da89ad3e..a2a0c7071 100644
--- a/source/slang/slang-ir-dll-import.cpp
+++ b/source/slang/slang-ir-dll-import.cpp
@@ -91,7 +91,7 @@ struct DllImportContext
for (auto param : func->getParams())
{
IRSizeAndAlignment sizeAndAlignment;
- getNaturalSizeAndAlignment(targetReq, param->getDataType(), &sizeAndAlignment);
+ getNaturalSizeAndAlignment(param->getDataType(), &sizeAndAlignment);
result += (uint32_t)align(sizeAndAlignment.size, 4);
}
return result;
diff --git a/source/slang/slang-ir-extract-value-from-type.cpp b/source/slang/slang-ir-extract-value-from-type.cpp
index fa8c6e441..ba3b73736 100644
--- a/source/slang/slang-ir-extract-value-from-type.cpp
+++ b/source/slang/slang-ir-extract-value-from-type.cpp
@@ -42,8 +42,8 @@ FindLeafValueResult findLeafValueAtOffset(
{
IRIntegerValue fieldOffset = 0;
IRSizeAndAlignment fieldLayout;
- CHECK(getNaturalSizeAndAlignment(targetReq, field->getFieldType(), &fieldLayout));
- CHECK(getNaturalOffset(targetReq, field, &fieldOffset));
+ CHECK(getNaturalSizeAndAlignment(field->getFieldType(), &fieldLayout));
+ CHECK(getNaturalOffset(field, &fieldOffset));
if (fieldOffset + fieldLayout.size > offset)
{
if (fieldOffset > offset)
@@ -81,7 +81,7 @@ FindLeafValueResult findLeafValueAtOffset(
auto arrayType = as<IRArrayType>(dataType);
auto elementType = arrayType->getElementType();
IRSizeAndAlignment elementLayout;
- CHECK(getNaturalSizeAndAlignment(targetReq, elementType, &elementLayout));
+ CHECK(getNaturalSizeAndAlignment(elementType, &elementLayout));
if (elementLayout.getStride() == 0)
{
result.leafValue = builder.getIntValue(builder.getUIntType(), 0);
@@ -106,7 +106,7 @@ FindLeafValueResult findLeafValueAtOffset(
auto vectorType = as<IRVectorType>(dataType);
auto elementType = vectorType->getElementType();
IRSizeAndAlignment elementLayout;
- CHECK(getNaturalSizeAndAlignment(targetReq, elementType, &elementLayout));
+ CHECK(getNaturalSizeAndAlignment(elementType, &elementLayout));
uint32_t index =
elementLayout.getStride() == 0 ? 0 : (uint32_t)(offset / elementLayout.getStride());
auto elementValue = builder.emitElementExtract(
@@ -129,7 +129,7 @@ FindLeafValueResult findLeafValueAtOffset(
auto columnCount = as<IRIntLit>(matrixType->getColumnCount())->value.intVal;
auto rowType = builder.getVectorType(elementType, matrixType->getColumnCount());
IRSizeAndAlignment rowLayout;
- CHECK(getNaturalSizeAndAlignment(targetReq, rowType, &rowLayout));
+ CHECK(getNaturalSizeAndAlignment(rowType, &rowLayout));
uint32_t rowIndex = rowLayout.getStride() == 0
? 0
: (uint32_t)(offset / (columnCount * rowLayout.getStride()));
@@ -266,7 +266,7 @@ IRInst* extractValueAtOffset(
{
auto dataType = src->getDataType();
IRSizeAndAlignment typeLayout;
- SLANG_RETURN_NULL_ON_FAIL(getNaturalSizeAndAlignment(targetReq, dataType, &typeLayout));
+ SLANG_RETURN_NULL_ON_FAIL(getNaturalSizeAndAlignment(dataType, &typeLayout));
if (offset + size > typeLayout.size)
{
return builder.getIntValue(builder.getIntType(), 0);
diff --git a/source/slang/slang-ir-generics-lowering-context.cpp b/source/slang/slang-ir-generics-lowering-context.cpp
index 325568040..2172e7d21 100644
--- a/source/slang/slang-ir-generics-lowering-context.cpp
+++ b/source/slang/slang-ir-generics-lowering-context.cpp
@@ -66,7 +66,7 @@ namespace Slang
// For now the only type info we encapsualte is type size.
IRSizeAndAlignment sizeAndAlignment;
- getNaturalSizeAndAlignment(targetReq, (IRType*)typeInst, &sizeAndAlignment);
+ getNaturalSizeAndAlignment((IRType*)typeInst, &sizeAndAlignment);
builder->addRTTITypeSizeDecoration(result, sizeAndAlignment.size);
// Give a name to the rtti object.
@@ -234,7 +234,7 @@ namespace Slang
// value must be stored out-of-line.
//
IRSizeAndAlignment sizeAndAlignment;
- Result result = getNaturalSizeAndAlignment(targetReq, concreteType, &sizeAndAlignment);
+ Result result = getNaturalSizeAndAlignment(concreteType, &sizeAndAlignment);
if(SLANG_FAILED(result) || (sizeAndAlignment.size > anyValueSize))
{
// If the value must be stored out-of-line, we construct
@@ -385,7 +385,7 @@ namespace Slang
if (outLimit) *outLimit = anyValueSize;
IRSizeAndAlignment sizeAndAlignment;
- Result result = getNaturalSizeAndAlignment(targetReq, concreteType, &sizeAndAlignment);
+ Result result = getNaturalSizeAndAlignment(concreteType, &sizeAndAlignment);
if (outTypeSize) *outTypeSize = sizeAndAlignment.size;
if(SLANG_FAILED(result) || (sizeAndAlignment.size > anyValueSize))
diff --git a/source/slang/slang-ir-inst-defs.h b/source/slang/slang-ir-inst-defs.h
index 3007351d2..f110c07e7 100644
--- a/source/slang/slang-ir-inst-defs.h
+++ b/source/slang/slang-ir-inst-defs.h
@@ -731,17 +731,11 @@ INST(HighLevelDeclDecoration, highLevelDecl, 1, 0)
/// A `[ForceUnroll]` decoration indicates the loop should be unrolled by the Slang compiler.
INST(ForceUnrollDecoration, ForceUnroll, 0, 0)
- /// A `[naturalSizeAndAlignment(s,a)]` decoration is attached to a type to indicate that is has natural size `s` and alignment `a`
- INST(NaturalSizeAndAlignmentDecoration, naturalSizeAndAlignment, 2, 0)
+ /// A `[SizeAndAlignment(l,s,a)]` decoration is attached to a type to indicate that is has size `s` and alignment `a` under layout rules `l`.
+ INST(SizeAndAlignmentDecoration, SizeAndAlignment, 3, 0)
- /// A `[naturalOffset(o)]` decoration is attached to a field to indicate that it has natural offset `o` in the parent type
- INST(NaturalOffsetDecoration, naturalOffset, 1, 0)
-
- /// A `[std430SizeAndAlignment(s,a)]` decoration is attached to a type to indicate that is has std430 size `s` and alignment `a`
- INST(Std430SizeAndAlignmentDecoration, naturalSizeAndAlignment, 2, 0)
-
- /// A `[std430Offset(o)]` decoration is attached to a field to indicate that it has std430 offset `o` in the parent type
- INST(Std430OffsetDecoration, naturalOffset, 1, 0)
+ /// A `[Offset(l, o)]` decoration is attached to a field to indicate that it has offset `o` in the parent type under layout rules `l`.
+ INST(OffsetDecoration, Offset, 2, 0)
/* LinkageDecoration */
INST(ImportDecoration, import, 1, 0)
diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h
index f4489611d..dade0e2f4 100644
--- a/source/slang/slang-ir-insts.h
+++ b/source/slang/slang-ir-insts.h
@@ -593,48 +593,25 @@ IR_SIMPLE_DECORATION(ForceInlineDecoration)
IR_SIMPLE_DECORATION(ForceUnrollDecoration)
-
-struct IRNaturalSizeAndAlignmentDecoration : IRDecoration
-{
- enum { kOp = kIROp_NaturalSizeAndAlignmentDecoration };
- IR_LEAF_ISA(NaturalSizeAndAlignmentDecoration)
-
- IRIntLit* getSizeOperand() { return cast<IRIntLit>(getOperand(0)); }
- IRIntLit* getAlignmentOperand() { return cast<IRIntLit>(getOperand(1)); }
-
- IRIntegerValue getSize() { return getSizeOperand()->getValue(); }
- IRIntegerValue getAlignment() { return getAlignmentOperand()->getValue(); }
-};
-
-struct IRNaturalOffsetDecoration : IRDecoration
-{
- enum { kOp = kIROp_NaturalOffsetDecoration };
- IR_LEAF_ISA(NaturalOffsetDecoration)
-
- IRIntLit* getOffsetOperand() { return cast<IRIntLit>(getOperand(0)); }
-
- IRIntegerValue getOffset() { return getOffsetOperand()->getValue(); }
-};
-
-struct IRStd430SizeAndAlignmentDecoration : IRDecoration
+struct IRSizeAndAlignmentDecoration : IRDecoration
{
- enum { kOp = kIROp_Std430SizeAndAlignmentDecoration };
- IR_LEAF_ISA(Std430SizeAndAlignmentDecoration)
-
- IRIntLit* getSizeOperand() { return cast<IRIntLit>(getOperand(0)); }
- IRIntLit* getAlignmentOperand() { return cast<IRIntLit>(getOperand(1)); }
+ IR_LEAF_ISA(SizeAndAlignmentDecoration)
+ IRTypeLayoutRuleName getLayoutName() { return IRTypeLayoutRuleName(cast<IRIntLit>(getOperand(0))->getValue()); }
+
+ IRIntLit* getSizeOperand() { return cast<IRIntLit>(getOperand(1)); }
+ IRIntLit* getAlignmentOperand() { return cast<IRIntLit>(getOperand(2)); }
IRIntegerValue getSize() { return getSizeOperand()->getValue(); }
IRIntegerValue getAlignment() { return getAlignmentOperand()->getValue(); }
};
-struct IRStd430OffsetDecoration : IRDecoration
+struct IROffsetDecoration : IRDecoration
{
- enum { kOp = kIROp_Std430OffsetDecoration };
- IR_LEAF_ISA(Std430OffsetDecoration)
+ IR_LEAF_ISA(OffsetDecoration)
- IRIntLit* getOffsetOperand() { return cast<IRIntLit>(getOperand(0)); }
+ IRTypeLayoutRuleName getLayoutName() { return IRTypeLayoutRuleName(cast<IRIntLit>(getOperand(0))->getValue()); }
+ IRIntLit* getOffsetOperand() { return cast<IRIntLit>(getOperand(1)); }
IRIntegerValue getOffset() { return getOffsetOperand()->getValue(); }
};
@@ -3104,6 +3081,15 @@ public:
IRUnsizedArrayType* getUnsizedArrayType(
IRType* elementType);
+ IRArrayType* getArrayType(
+ IRType* elementType,
+ IRInst* elementCount,
+ IRInst* stride);
+
+ IRUnsizedArrayType* getUnsizedArrayType(
+ IRType* elementType,
+ IRInst* stride);
+
IRVectorType* getVectorType(
IRType* elementType,
IRInst* elementCount);
diff --git a/source/slang/slang-ir-layout-on-types.cpp b/source/slang/slang-ir-layout-on-types.cpp
deleted file mode 100644
index a1e480067..000000000
--- a/source/slang/slang-ir-layout-on-types.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-#include "slang-ir-layout-on-types.h"
-
-#include "slang-ir-insts.h"
-#include "slang-ir.h"
-
-namespace Slang
-{
-
-struct TypeTypeLayout
-{
- IRType* type;
- IRTypeLayout* layout;
-};
-
-template<typename Struct, typename StructuredBuffer, typename Array, typename Base>
-static void zipPreorderTypeAndTypeLayout(
- Struct struct_,
- StructuredBuffer structuredBuffer,
- Array array,
- Base base,
- IRType* type,
- IRTypeLayout* layout)
-{
- auto go = [&](auto& go, IRType* type, IRLayout* layout) -> void{
- if(const auto structTypeLayout = as<IRStructTypeLayout>(layout))
- {
- const auto structType = as<IRStructType>(type);
- SLANG_ASSERT(structType);
- struct_(structType, structTypeLayout);
-
- Index i = 0;
- for(const auto field : structType->getFields())
- {
- const auto fieldVarLayout = structTypeLayout->getFieldLayout(i);
- const auto fieldTypeLayout = fieldVarLayout->getTypeLayout();
- const auto fieldType = field->getFieldType();
- go(go, fieldType, fieldTypeLayout);
- ++i;
- }
- }
- else if(const auto structuredBufferTypeLayout = as<IRStructuredBufferTypeLayout>(layout))
- {
- const auto structuredBufferType = as<IRHLSLStructuredBufferTypeBase>(type);
- SLANG_ASSERT(structuredBufferType);
- structuredBuffer(structuredBufferType, structuredBufferTypeLayout);
-
- go(go, structuredBufferType->getElementType(), structuredBufferTypeLayout->getElementTypeLayout());
- }
- else if(const auto arrayTypeLayout = as<IRArrayTypeLayout>(layout))
- {
- const auto arrayType = as<IRArrayTypeBase>(type);
- SLANG_ASSERT(arrayType);
- array(arrayType , arrayTypeLayout);
-
- go(go, arrayType->getElementType(), arrayTypeLayout->getElementTypeLayout());
- }
- else if(const auto existentialTypeLayout = as<IRExistentialTypeLayout>(layout))
- {
- // TODO: To resolve this we should
- // - Record the interface width in each IRExistentialTypeLayout
- // - To allow us to replace them with IRTupleTypeLayout when we lower existentials
- // - To allow us to replace them with IRStructTypeLayout when we lower tuples
- SLANG_UNEXPECTED("Existentials (or their layouts) have not been erased before SPIR-V emit");
- }
- else
- {
- base((IRType*)type, (IRTypeLayout*)layout);
- }
- };
- go(go, type, layout);
-}
-
-static Dictionary<IRType*, IRTypeLayout*> associateTypesWithLayouts(IRModule* module)
-{
- List<TypeTypeLayout> worklist;
- for(auto globalInst : module->getGlobalInsts())
- {
- if(const auto varLayout = as<IRVarLayout>(globalInst))
- {
- auto typeLayout = varLayout->getTypeLayout();
- List<IRInst*> vars;
- traverseUsers(varLayout, [&](IRInst* varLayoutUser){
- if(const auto dec = as<IRLayoutDecoration>(varLayoutUser))
- {
- if(const auto globalParam = as<IRGlobalParam>(dec->getParent()))
- vars.add(globalParam);
- else
- {
- // todo
- }
- }
- else if(as<IREntryPointLayout>(varLayoutUser))
- {
- // todo
- }
- else if(as<IRStructFieldLayoutAttr>(varLayoutUser))
- {
- // todo
- }
- else if(as<IRParameterGroupTypeLayout>(varLayoutUser))
- {
- // todo
- }
- else
- SLANG_UNEXPECTED("Var layout was used somewhere unexpected");
- });
- if(vars.getCount() == 1)
- {
- auto type = vars[0]->getDataType();
- worklist.add({type, typeLayout});
- }
- else if(vars.getCount() > 2)
- {
- SLANG_UNIMPLEMENTED_X("vars with different layouts");
- }
- }
- }
-
- Dictionary<IRType*, IRTypeLayout*> ret;
- while(!worklist.getCount() == 0)
- {
- const auto ttl = worklist.getLast();
- worklist.removeLast();
- const auto add = [&](IRType* type, IRTypeLayout* typeLayout){
- const auto* otherTypeLayout = ret.tryGetValueOrAdd(type, typeLayout);
- if(otherTypeLayout)
- SLANG_ASSERT(*otherTypeLayout == typeLayout);
- };
- zipPreorderTypeAndTypeLayout(add, add, add, add, ttl.type, ttl.layout);
- }
-
- return ret;
-}
-
-static void decorateTypesWithLayouts(IRModule* module, const Dictionary<IRType*, IRTypeLayout*>& assocs)
-{
- IRBuilder builder(module);
- for(const auto& [type, layout] : assocs)
- {
- builder.setInsertBefore(type);
- // TODO: types with more than one decoration (needs deduplicating)
- builder.addLayoutDecoration(type, layout);
- }
-}
-
-void placeTypeLayoutsOnTypes(IRModule* module, CodeGenContext* codeGenContext)
-{
- SLANG_ASSERT(module);
- SLANG_ASSERT(codeGenContext);
- const auto assocs = associateTypesWithLayouts(module);
- decorateTypesWithLayouts(module, assocs);
-}
-}
diff --git a/source/slang/slang-ir-layout-on-types.h b/source/slang/slang-ir-layout-on-types.h
deleted file mode 100644
index 4cf6f887b..000000000
--- a/source/slang/slang-ir-layout-on-types.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#pragma once
-
-namespace Slang
-{
- struct IRModule;
- struct CodeGenContext;
- void placeTypeLayoutsOnTypes(IRModule* module, CodeGenContext* codeGenContext);
-}
diff --git a/source/slang/slang-ir-layout.cpp b/source/slang/slang-ir-layout.cpp
index df2f50b30..244ff2039 100644
--- a/source/slang/slang-ir-layout.cpp
+++ b/source/slang/slang-ir-layout.cpp
@@ -50,31 +50,29 @@
namespace Slang
{
-
-static Result _calcNaturalArraySizeAndAlignment(
- TargetRequest* target,
- IRType* elementType,
- IRInst* elementCountInst,
+static Result _calcArraySizeAndAlignment(
+ IRTypeLayoutRules* rules,
+ IRType* elementType,
+ IRInst* elementCountInst,
IRSizeAndAlignment* outSizeAndAlignment)
{
auto elementCountLit = as<IRIntLit>(elementCountInst);
- if(!elementCountLit)
+ if (!elementCountLit)
return SLANG_FAIL;
auto elementCount = elementCountLit->getValue();
- if( elementCount == 0 )
+ if (elementCount == 0)
{
*outSizeAndAlignment = IRSizeAndAlignment(0, 1);
return SLANG_OK;
}
IRSizeAndAlignment elementTypeLayout;
- SLANG_RETURN_ON_FAIL(getNaturalSizeAndAlignment(target, elementType, &elementTypeLayout));
-
- auto elementStride = elementTypeLayout.getStride();
+ SLANG_RETURN_ON_FAIL(getSizeAndAlignment(rules, elementType, &elementTypeLayout));
+ elementTypeLayout = rules->alignCompositeElement(elementTypeLayout);
*outSizeAndAlignment = IRSizeAndAlignment(
- elementStride * (elementCount - 1) + elementTypeLayout.size,
+ elementTypeLayout.getStride() * (elementCount - 1) + elementTypeLayout.size,
elementTypeLayout.alignment);
return SLANG_OK;
}
@@ -85,308 +83,8 @@ IRIntegerValue getIntegerValueFromInst(IRInst* inst)
return as<IRIntLit>(inst)->value.intVal;
}
-static Result _calcNaturalSizeAndAlignment(
- TargetRequest* target,
- IRType* type,
- IRSizeAndAlignment* outSizeAndAlignment)
-{
- switch( type->getOp() )
- {
-
-#define CASE(TYPE, SIZE, ALIGNMENT) \
- case kIROp_##TYPE##Type: \
- *outSizeAndAlignment = IRSizeAndAlignment(SIZE, ALIGNMENT); \
- return SLANG_OK \
- /* end */
-
- // Most base types are "naturally aligned" (meaning alignment and size are the same)
-#define BASE(TYPE, SIZE) CASE(TYPE, SIZE, SIZE)
-
- BASE(Int8, 1);
- BASE(UInt8, 1);
-
- BASE(Int16, 2);
- BASE(UInt16, 2);
- BASE(Half, 2);
-
- BASE(Int, 4);
- BASE(UInt, 4);
- BASE(Float, 4);
-
- BASE(Int64, 8);
- BASE(UInt64, 8);
- BASE(Double, 8);
-
- // We are currently handling `bool` following the HLSL
- // precednet of storing it in 4 bytes.
- //
- // TODO: It would be good to try to make this follow
- // per-platform conventions, or at least to be able
- // to use a 1-byte encoding where available.
- //
- BASE(Bool, 4);
-
- // The Slang `void` type is treated as a zero-byte
- // type, so that it does not influence layout at all.
- //
- CASE(Void, 0, 1);
-
-#undef CASE
-
-#undef CASE
-
- case kIROp_StructType:
- {
- auto structType = cast<IRStructType>(type);
- IRSizeAndAlignment structLayout;
- for( auto field : structType->getFields() )
- {
- IRSizeAndAlignment fieldTypeLayout;
- SLANG_RETURN_ON_FAIL(getNaturalSizeAndAlignment(target, field->getFieldType(), &fieldTypeLayout));
-
- structLayout.size = align(structLayout.size, fieldTypeLayout.alignment);
- structLayout.alignment = std::max(structLayout.alignment, fieldTypeLayout.alignment);
-
- IRIntegerValue fieldOffset = structLayout.size;
- if( auto module = type->getModule() )
- {
- // If we are in a situation where attaching new
- // decorations is possible, then we want to
- // cache the field offset on the IR field
- // instruction.
- //
- IRBuilder builder(module);
-
- auto intType = builder.getIntType();
- builder.addDecoration(
- field,
- kIROp_NaturalOffsetDecoration,
- builder.getIntValue(intType, fieldOffset));
- }
-
- structLayout.size += fieldTypeLayout.size;
- }
- *outSizeAndAlignment = structLayout;
- return SLANG_OK;
- }
- break;
-
- case kIROp_ArrayType:
- {
- auto arrayType = cast<IRArrayType>(type);
-
- return _calcNaturalArraySizeAndAlignment(
- target,
- arrayType->getElementType(),
- arrayType->getElementCount(),
- outSizeAndAlignment);
- }
- break;
-
- case kIROp_VectorType:
- {
- auto vecType = cast<IRVectorType>(type);
-
- return _calcNaturalArraySizeAndAlignment(
- target,
- vecType->getElementType(),
- vecType->getElementCount(),
- outSizeAndAlignment);
- }
- break;
- case kIROp_AnyValueType:
- {
- auto anyValType = cast<IRAnyValueType>(type);
- outSizeAndAlignment->size = getIntVal(anyValType->getSize());
- outSizeAndAlignment->alignment = 4;
- return SLANG_OK;
- }
- break;
- case kIROp_TupleType:
- {
- auto tupleType = cast<IRTupleType>(type);
- IRSizeAndAlignment resultLayout;
- for (UInt i = 0; i < tupleType->getOperandCount(); i++)
- {
- auto elementType = tupleType->getOperand(i);
- IRSizeAndAlignment fieldTypeLayout;
- SLANG_RETURN_ON_FAIL(getNaturalSizeAndAlignment(target, (IRType*)elementType, &fieldTypeLayout));
- resultLayout.size = align(resultLayout.size, fieldTypeLayout.alignment);
- resultLayout.alignment = std::max(resultLayout.alignment, fieldTypeLayout.alignment);
- }
- *outSizeAndAlignment = resultLayout;
- return SLANG_OK;
- }
- break;
- case kIROp_WitnessTableType:
- case kIROp_WitnessTableIDType:
- case kIROp_RTTIHandleType:
- {
- outSizeAndAlignment->size = kRTTIHandleSize;
- outSizeAndAlignment->alignment = 4;
- return SLANG_OK;
- }
- break;
- case kIROp_InterfaceType:
- {
- auto interfaceType = cast<IRInterfaceType>(type);
- auto size = SharedGenericsLoweringContext::getInterfaceAnyValueSize(interfaceType, interfaceType->sourceLoc);
- size += kRTTIHeaderSize;
- size = align(size, 4);
- IRSizeAndAlignment resultLayout;
- resultLayout.size = size;
- resultLayout.alignment = 4;
- *outSizeAndAlignment = resultLayout;
- return SLANG_OK;
- }
- break;
- case kIROp_MatrixType:
- {
- auto matType = cast<IRMatrixType>(type);
- auto rowCount = getIntegerValueFromInst(matType->getRowCount());
- auto colCount = getIntegerValueFromInst(matType->getColumnCount());
- IRBuilder builder(type->getModule());
-
- return _calcNaturalArraySizeAndAlignment(
- target, matType->getElementType(),
- builder.getIntValue(builder.getUIntType(), rowCount * colCount),
- outSizeAndAlignment);
- }
- break;
- case kIROp_OutType:
- case kIROp_InOutType:
- case kIROp_RefType:
- case kIROp_RawPointerType:
- case kIROp_PtrType:
- case kIROp_NativePtrType:
- case kIROp_ComPtrType:
- case kIROp_NativeStringType:
- {
- *outSizeAndAlignment = IRSizeAndAlignment(sizeof(void*), sizeof(void*));
- return SLANG_OK;
- }
- break;
- default:
- break;
- }
-
- if( areResourceTypesBindlessOnTarget(target) )
- {
- // TODO: need this to be based on target, instead of hard-coded
- int pointerSize = sizeof(void*);
-
- if(as<IRTextureType>(type) )
- {
- *outSizeAndAlignment = IRSizeAndAlignment(pointerSize, pointerSize);
- return SLANG_OK;
- }
- else if(as<IRSamplerStateTypeBase>(type) )
- {
- *outSizeAndAlignment = IRSizeAndAlignment(pointerSize, pointerSize);
- return SLANG_OK;
- }
- // TODO: the remaining cases for "bindless" resources on CPU/CUDA targets
- }
-
- return SLANG_FAIL;
-}
-
-Result getNaturalSizeAndAlignment(TargetRequest* target, IRType* type, IRSizeAndAlignment* outSizeAndAlignment)
-{
- if( auto decor = type->findDecoration<IRNaturalSizeAndAlignmentDecoration>() )
- {
- *outSizeAndAlignment = IRSizeAndAlignment(decor->getSize(), (int)decor->getAlignment());
- return SLANG_OK;
- }
-
- IRSizeAndAlignment sizeAndAlignment;
- SLANG_RETURN_ON_FAIL(_calcNaturalSizeAndAlignment(target, type, &sizeAndAlignment));
-
- if( auto module = type->getModule() )
- {
- IRBuilder builder(module);
-
- auto intType = builder.getIntType();
- builder.addDecoration(
- type,
- kIROp_NaturalSizeAndAlignmentDecoration,
- builder.getIntValue(intType, sizeAndAlignment.size),
- builder.getIntValue(intType, sizeAndAlignment.alignment));
- }
-
- *outSizeAndAlignment = sizeAndAlignment;
- return SLANG_OK;
-}
-
-
-Result getNaturalOffset(TargetRequest* target, IRStructField* field, IRIntegerValue* outOffset)
-{
- if( auto decor = field->findDecoration<IRNaturalOffsetDecoration>() )
- {
- *outOffset = decor->getOffset();
- return SLANG_OK;
- }
-
- // Offsets are computed as part of layout out types,
- // so we expect that layout of the "parent" type
- // of the field should add an offset to it if
- // possible.
-
- auto structType = as<IRStructType>(field->getParent());
- if(!structType)
- return SLANG_FAIL;
-
- IRSizeAndAlignment structTypeLayout;
- SLANG_RETURN_ON_FAIL(getNaturalSizeAndAlignment(target, structType, &structTypeLayout));
-
- if( auto decor = field->findDecoration<IRNaturalOffsetDecoration>() )
- {
- *outOffset = decor->getOffset();
- return SLANG_OK;
- }
-
- // If attempting to lay out the parent type didn't
- // cause the field to get an offset, then we are
- // in an unexpected case with no easy answer.
- //
- return SLANG_FAIL;
-}
-
-
-//////////////////////////
-// Std430 Layout
-//////////////////////////
-
-static Result _calcStd430ArraySizeAndAlignment(
- TargetRequest* target,
- IRType* elementType,
- IRInst* elementCountInst,
- IRSizeAndAlignment* outSizeAndAlignment)
-{
- auto elementCountLit = as<IRIntLit>(elementCountInst);
- if (!elementCountLit)
- return SLANG_FAIL;
- auto elementCount = elementCountLit->getValue();
-
- if (elementCount == 0)
- {
- *outSizeAndAlignment = IRSizeAndAlignment(0, 1);
- return SLANG_OK;
- }
-
- IRSizeAndAlignment elementTypeLayout;
- SLANG_RETURN_ON_FAIL(getStd430SizeAndAlignment(target, elementType, &elementTypeLayout));
-
- auto elementStride = elementTypeLayout.getStride();
-
- *outSizeAndAlignment = IRSizeAndAlignment(
- elementStride * (elementCount - 1) + elementTypeLayout.size,
- elementTypeLayout.alignment);
- return SLANG_OK;
-}
-
-static Result _calcStd430SizeAndAlignment(
- TargetRequest* target,
+static Result _calcSizeAndAlignment(
+ IRTypeLayoutRules* rules,
IRType* type,
IRSizeAndAlignment* outSizeAndAlignment)
{
@@ -394,12 +92,12 @@ static Result _calcStd430SizeAndAlignment(
{
#define CASE(TYPE, SIZE, ALIGNMENT) \
- case kIROp_##TYPE##Type: \
- *outSizeAndAlignment = IRSizeAndAlignment(SIZE, ALIGNMENT); \
- return SLANG_OK \
- /* end */
+case kIROp_##TYPE##Type: \
+ *outSizeAndAlignment = IRSizeAndAlignment(SIZE, ALIGNMENT); \
+ return SLANG_OK \
+ /* end */
- // Most base types are "std430 aligned" (meaning alignment and size are the same)
+ // Most base types are "naturally aligned" (meaning alignment and size are the same)
#define BASE(TYPE, SIZE) CASE(TYPE, SIZE, SIZE)
BASE(Int8, 1);
@@ -415,6 +113,8 @@ static Result _calcStd430SizeAndAlignment(
BASE(Int64, 8);
BASE(UInt64, 8);
+ BASE(IntPtr, 8);
+ BASE(UIntPtr, 8);
BASE(Double, 8);
// We are currently handling `bool` following the HLSL
@@ -442,8 +142,7 @@ static Result _calcStd430SizeAndAlignment(
for (auto field : structType->getFields())
{
IRSizeAndAlignment fieldTypeLayout;
- SLANG_RETURN_ON_FAIL(getStd430SizeAndAlignment(target, field->getFieldType(), &fieldTypeLayout));
-
+ SLANG_RETURN_ON_FAIL(getSizeAndAlignment(rules, field->getFieldType(), &fieldTypeLayout));
structLayout.size = align(structLayout.size, fieldTypeLayout.alignment);
structLayout.alignment = std::max(structLayout.alignment, fieldTypeLayout.alignment);
@@ -460,13 +159,14 @@ static Result _calcStd430SizeAndAlignment(
auto intType = builder.getIntType();
builder.addDecoration(
field,
- kIROp_Std430OffsetDecoration,
+ kIROp_OffsetDecoration,
+ builder.getIntValue(intType, (IRIntegerValue)rules->ruleName),
builder.getIntValue(intType, fieldOffset));
}
structLayout.size += fieldTypeLayout.size;
}
- *outSizeAndAlignment = structLayout;
+ *outSizeAndAlignment = rules->alignCompositeElement(structLayout);
return SLANG_OK;
}
break;
@@ -475,8 +175,8 @@ static Result _calcStd430SizeAndAlignment(
{
auto arrayType = cast<IRArrayType>(type);
- return _calcStd430ArraySizeAndAlignment(
- target,
+ return _calcArraySizeAndAlignment(
+ rules ,
arrayType->getElementType(),
arrayType->getElementCount(),
outSizeAndAlignment);
@@ -486,15 +186,9 @@ static Result _calcStd430SizeAndAlignment(
case kIROp_VectorType:
{
auto vecType = cast<IRVectorType>(type);
- auto elementCount = getIntegerValueFromInst(vecType->getElementCount());
- auto alignmentMultiplier = elementCount;
- if (elementCount == 3)
- alignmentMultiplier = 4;
- IRSizeAndAlignment sizeAndAlignment;
- SLANG_RETURN_ON_FAIL(getStd430SizeAndAlignment(target, vecType->getElementType(), &sizeAndAlignment));
- sizeAndAlignment.size *= (int)elementCount;
- sizeAndAlignment.alignment *= (int)alignmentMultiplier;
- *outSizeAndAlignment = sizeAndAlignment;
+ IRSizeAndAlignment elementTypeLayout;
+ getSizeAndAlignment(rules, vecType->getElementType(), &elementTypeLayout);
+ *outSizeAndAlignment = rules->getVectorSizeAndAlignment(elementTypeLayout, getIntegerValueFromInst(vecType->getElementCount()));
return SLANG_OK;
}
break;
@@ -503,6 +197,7 @@ static Result _calcStd430SizeAndAlignment(
auto anyValType = cast<IRAnyValueType>(type);
outSizeAndAlignment->size = getIntVal(anyValType->getSize());
outSizeAndAlignment->alignment = 4;
+ *outSizeAndAlignment = rules->alignCompositeElement(*outSizeAndAlignment);
return SLANG_OK;
}
break;
@@ -514,11 +209,11 @@ static Result _calcStd430SizeAndAlignment(
{
auto elementType = tupleType->getOperand(i);
IRSizeAndAlignment fieldTypeLayout;
- SLANG_RETURN_ON_FAIL(getStd430SizeAndAlignment(target, (IRType*)elementType, &fieldTypeLayout));
+ SLANG_RETURN_ON_FAIL(getSizeAndAlignment(rules, (IRType*)elementType, &fieldTypeLayout));
resultLayout.size = align(resultLayout.size, fieldTypeLayout.alignment);
resultLayout.alignment = std::max(resultLayout.alignment, fieldTypeLayout.alignment);
}
- *outSizeAndAlignment = resultLayout;
+ *outSizeAndAlignment = rules->alignCompositeElement(resultLayout);
return SLANG_OK;
}
break;
@@ -540,7 +235,7 @@ static Result _calcStd430SizeAndAlignment(
IRSizeAndAlignment resultLayout;
resultLayout.size = size;
resultLayout.alignment = 4;
- *outSizeAndAlignment = resultLayout;
+ *outSizeAndAlignment = rules->alignCompositeElement(resultLayout);
return SLANG_OK;
}
break;
@@ -548,12 +243,24 @@ static Result _calcStd430SizeAndAlignment(
{
auto matType = cast<IRMatrixType>(type);
IRBuilder builder(type->getModule());
- builder.setInsertBefore(matType);
- auto rowType = builder.getVectorType(matType->getElementType(), matType->getColumnCount());
- return _calcStd430ArraySizeAndAlignment(
- target, rowType,
- matType->getRowCount(),
- outSizeAndAlignment);
+ if (getIntegerValueFromInst(matType->getLayout()) == SLANG_MATRIX_LAYOUT_COLUMN_MAJOR)
+ {
+ auto colVector = builder.getVectorType(matType->getElementType(), matType->getRowCount());
+ return _calcArraySizeAndAlignment(
+ rules,
+ colVector,
+ matType->getColumnCount(),
+ outSizeAndAlignment);
+ }
+ else
+ {
+ auto rowVector = builder.getVectorType(matType->getElementType(), matType->getColumnCount());
+ return _calcArraySizeAndAlignment(
+ rules,
+ rowVector,
+ matType->getRowCount(),
+ outSizeAndAlignment);
+ }
}
break;
case kIROp_OutType:
@@ -564,46 +271,46 @@ static Result _calcStd430SizeAndAlignment(
case kIROp_NativePtrType:
case kIROp_ComPtrType:
case kIROp_NativeStringType:
+ case kIROp_HLSLConstBufferPointerType:
{
- *outSizeAndAlignment = IRSizeAndAlignment(sizeof(void*), sizeof(void*));
+ *outSizeAndAlignment = IRSizeAndAlignment(8, 8);
return SLANG_OK;
}
break;
default:
break;
}
-
- if (areResourceTypesBindlessOnTarget(target))
+ if (as<IRResourceTypeBase>(type) || as<IRSamplerStateTypeBase>(type))
{
- // TODO: need this to be based on target, instead of hard-coded
- int pointerSize = sizeof(void*);
+ *outSizeAndAlignment = IRSizeAndAlignment(8, 8);
+ return SLANG_OK;
+ }
+ return SLANG_FAIL;
+}
- if (as<IRTextureType>(type))
- {
- *outSizeAndAlignment = IRSizeAndAlignment(pointerSize, pointerSize);
- return SLANG_OK;
- }
- else if (as<IRSamplerStateTypeBase>(type))
+IRSizeAndAlignmentDecoration* findSizeAndAlignmentDecorationForLayout(IRType* type, IRTypeLayoutRuleName layoutName)
+{
+ for (auto decorInst : type->getDecorations())
+ {
+ if (auto decor = as<IRSizeAndAlignmentDecoration>(decorInst))
{
- *outSizeAndAlignment = IRSizeAndAlignment(pointerSize, pointerSize);
- return SLANG_OK;
+ if (decor->getLayoutName() == layoutName)
+ return decor;
}
- // TODO: the remaining cases for "bindless" resources on CPU/CUDA targets
}
-
- return SLANG_FAIL;
+ return nullptr;
}
-Result getStd430SizeAndAlignment(TargetRequest* target, IRType* type, IRSizeAndAlignment* outSizeAndAlignment)
+Result getSizeAndAlignment(IRTypeLayoutRules* rules, IRType* type, IRSizeAndAlignment* outSizeAndAlignment)
{
- if (auto decor = type->findDecoration<IRStd430SizeAndAlignmentDecoration>())
+ if (auto decor = findSizeAndAlignmentDecorationForLayout(type, rules->ruleName))
{
*outSizeAndAlignment = IRSizeAndAlignment(decor->getSize(), (int)decor->getAlignment());
return SLANG_OK;
}
IRSizeAndAlignment sizeAndAlignment;
- SLANG_RETURN_ON_FAIL(_calcStd430SizeAndAlignment(target, type, &sizeAndAlignment));
+ SLANG_RETURN_ON_FAIL(_calcSizeAndAlignment(rules, type, &sizeAndAlignment));
if (auto module = type->getModule())
{
@@ -612,7 +319,8 @@ Result getStd430SizeAndAlignment(TargetRequest* target, IRType* type, IRSizeAndA
auto intType = builder.getIntType();
builder.addDecoration(
type,
- kIROp_Std430SizeAndAlignmentDecoration,
+ kIROp_SizeAndAlignmentDecoration,
+ builder.getIntValue(intType, (IRIntegerValue)rules->ruleName),
builder.getIntValue(intType, sizeAndAlignment.size),
builder.getIntValue(intType, sizeAndAlignment.alignment));
}
@@ -620,11 +328,22 @@ Result getStd430SizeAndAlignment(TargetRequest* target, IRType* type, IRSizeAndA
*outSizeAndAlignment = sizeAndAlignment;
return SLANG_OK;
}
+IROffsetDecoration* findOffsetDecorationForLayout(IRStructField* field, IRTypeLayoutRuleName layoutName)
+{
+ for (auto decorInst : field->getDecorations())
+ {
+ if (auto decor = as<IROffsetDecoration>(decorInst))
+ {
+ if (decor->getLayoutName() == layoutName)
+ return decor;
+ }
+ }
+ return nullptr;
+}
-
-Result getStd430Offset(TargetRequest* target, IRStructField* field, IRIntegerValue* outOffset)
+Result getOffset(IRTypeLayoutRules* rules, IRStructField* field, IRIntegerValue* outOffset)
{
- if (auto decor = field->findDecoration<IRStd430OffsetDecoration>())
+ if (auto decor = findOffsetDecorationForLayout(field, rules->ruleName))
{
*outOffset = decor->getOffset();
return SLANG_OK;
@@ -640,9 +359,9 @@ Result getStd430Offset(TargetRequest* target, IRStructField* field, IRIntegerVal
return SLANG_FAIL;
IRSizeAndAlignment structTypeLayout;
- SLANG_RETURN_ON_FAIL(getStd430SizeAndAlignment(target, structType, &structTypeLayout));
+ SLANG_RETURN_ON_FAIL(getSizeAndAlignment(rules, structType, &structTypeLayout));
- if (auto decor = field->findDecoration<IRStd430OffsetDecoration>())
+ if (auto decor = findOffsetDecorationForLayout(field, rules->ruleName))
{
*outOffset = decor->getOffset();
return SLANG_OK;
@@ -655,5 +374,113 @@ Result getStd430Offset(TargetRequest* target, IRStructField* field, IRIntegerVal
return SLANG_FAIL;
}
+struct NaturalLayoutRules : IRTypeLayoutRules
+{
+ NaturalLayoutRules()
+ {
+ ruleName = IRTypeLayoutRuleName::Natural;
+ }
+
+ virtual IRSizeAndAlignment alignCompositeElement(IRSizeAndAlignment elementSize)
+ {
+ return elementSize;
+ }
+ virtual IRSizeAndAlignment getVectorSizeAndAlignment(IRSizeAndAlignment element, IRIntegerValue count)
+ {
+ return IRSizeAndAlignment(element.size * count, element.alignment);
+ }
+};
+
+struct Std430LayoutRules : IRTypeLayoutRules
+{
+ Std430LayoutRules()
+ {
+ ruleName = IRTypeLayoutRuleName::Std430;
+ }
+
+ virtual IRSizeAndAlignment alignCompositeElement(IRSizeAndAlignment elementSize)
+ {
+ return elementSize;
+ }
+ virtual IRSizeAndAlignment getVectorSizeAndAlignment(IRSizeAndAlignment element, IRIntegerValue count)
+ {
+ if (count == 3)
+ count = 4;
+ return IRSizeAndAlignment((int)(element.size * count), (int)(element.size * count));
+ }
+};
+
+struct Std140LayoutRules : IRTypeLayoutRules
+{
+ Std140LayoutRules()
+ {
+ ruleName = IRTypeLayoutRuleName::Std140;
+ }
+
+ virtual IRSizeAndAlignment alignCompositeElement(IRSizeAndAlignment elementSize)
+ {
+ elementSize.alignment = (int)align(elementSize.alignment, 16);
+ elementSize.size = align(elementSize.size, elementSize.alignment);
+ return elementSize;
+ }
+ virtual IRSizeAndAlignment getVectorSizeAndAlignment(IRSizeAndAlignment element, IRIntegerValue count)
+ {
+ if (count == 3)
+ count = 4;
+ return IRSizeAndAlignment((int)(element.size * count), (int)(element.size * count));
+ }
+};
+
+Result getNaturalSizeAndAlignment(IRType* type, IRSizeAndAlignment* outSizeAndAlignment)
+{
+ return getSizeAndAlignment(IRTypeLayoutRules::getNatural(), type, outSizeAndAlignment);
+
+}
+
+Result getNaturalOffset(IRStructField* field, IRIntegerValue* outOffset)
+{
+ return getOffset(IRTypeLayoutRules::getNatural(), field, outOffset);
+}
+
+
+//////////////////////////
+// Std430 Layout
+//////////////////////////
+
+Result getStd430SizeAndAlignment(IRType* type, IRSizeAndAlignment* outSizeAndAlignment)
+{
+ return getSizeAndAlignment(IRTypeLayoutRules::getStd430(), type, outSizeAndAlignment);
+}
+
+Result getStd430Offset(IRStructField* field, IRIntegerValue* outOffset)
+{
+ return getOffset(IRTypeLayoutRules::getStd430(), field, outOffset);
+}
+
+IRTypeLayoutRules* IRTypeLayoutRules::getStd430()
+{
+ static Std430LayoutRules rules;
+ return &rules;
+}
+IRTypeLayoutRules* IRTypeLayoutRules::getStd140()
+{
+ static Std140LayoutRules rules;
+ return &rules;
+}
+IRTypeLayoutRules* IRTypeLayoutRules::getNatural()
+{
+ static NaturalLayoutRules rules;
+ return &rules;
+}
+IRTypeLayoutRules* IRTypeLayoutRules::get(IRTypeLayoutRuleName name)
+{
+ switch (name)
+ {
+ case IRTypeLayoutRuleName::Std430: return getStd430();
+ case IRTypeLayoutRuleName::Std140: return getStd140();
+ case IRTypeLayoutRuleName::Natural: return getNatural();
+ default: return nullptr;
+ }
+}
}
diff --git a/source/slang/slang-ir-layout.h b/source/slang/slang-ir-layout.h
index d4e4c570a..12da047d2 100644
--- a/source/slang/slang-ir-layout.h
+++ b/source/slang/slang-ir-layout.h
@@ -18,7 +18,6 @@
#include "slang-ir.h"
-
namespace Slang
{
class TargetRequest;
@@ -51,13 +50,29 @@ struct IRSizeAndAlignment
}
};
+struct IRTypeLayoutRules
+{
+public:
+ IRTypeLayoutRuleName ruleName;
+ virtual IRSizeAndAlignment alignCompositeElement(IRSizeAndAlignment elementSize) = 0;
+ virtual IRSizeAndAlignment getVectorSizeAndAlignment(IRSizeAndAlignment element, IRIntegerValue count) = 0;
+ static IRTypeLayoutRules* getStd430();
+ static IRTypeLayoutRules* getStd140();
+ static IRTypeLayoutRules* getNatural();
+ static IRTypeLayoutRules* get(IRTypeLayoutRuleName name);
+};
+
+Result getOffset(IRTypeLayoutRules* rules, IRStructField* field, IRIntegerValue* outOffset);
+
+Result getSizeAndAlignment(IRTypeLayoutRules* rules, IRType* type, IRSizeAndAlignment* outSizeAndAlignment);
+
/// Compute (if necessary) and return the natural size and alignment of `type`.
///
/// This operation may fail if `type` is not one that can be stored in
/// general-purpose memory for the current target. In that case the
/// type is considered to have no natural layout.
///
-Result getNaturalSizeAndAlignment(TargetRequest* target, IRType* type, IRSizeAndAlignment* outSizeAndAlignment);
+Result getNaturalSizeAndAlignment(IRType* type, IRSizeAndAlignment* outSizeAndAlignment);
/// Compute (if necessary) and return the natural offset of `field`
///
@@ -65,7 +80,7 @@ Result getNaturalSizeAndAlignment(TargetRequest* target, IRType* type, IRSizeAnd
/// that can be stored in general-purpose memory. In that case, the
/// field is considered to have no natural offset.
///
-Result getNaturalOffset(TargetRequest* target, IRStructField* field, IRIntegerValue* outOffset);
+Result getNaturalOffset(IRStructField* field, IRIntegerValue* outOffset);
/// Compute (if necessary) and return the std430 size and alignment of `type`.
///
@@ -73,7 +88,7 @@ Result getNaturalOffset(TargetRequest* target, IRStructField* field, IRIntegerVa
/// general-purpose memory for the current target. In that case the
/// type is considered to have no std430 layout.
///
-Result getStd430SizeAndAlignment(TargetRequest* target, IRType* type, IRSizeAndAlignment* outSizeAndAlignment);
+Result getStd430SizeAndAlignment(IRType* type, IRSizeAndAlignment* outSizeAndAlignment);
/// Compute (if necessary) and return the std430 offset of `field`
///
@@ -81,7 +96,7 @@ Result getStd430SizeAndAlignment(TargetRequest* target, IRType* type, IRSizeAndA
/// that can be stored in general-purpose memory. In that case, the
/// field is considered to have no std430 offset.
///
-Result getStd430Offset(TargetRequest* target, IRStructField* field, IRIntegerValue* outOffset);
+Result getStd430Offset(IRStructField* field, IRIntegerValue* outOffset);
}
diff --git a/source/slang/slang-ir-lower-bit-cast.cpp b/source/slang/slang-ir-lower-bit-cast.cpp
index b63f32dab..a5ac05ead 100644
--- a/source/slang/slang-ir-lower-bit-cast.cpp
+++ b/source/slang/slang-ir-lower-bit-cast.cpp
@@ -72,7 +72,7 @@ struct BitCastLoweringContext
{
IRIntegerValue fieldOffset = 0;
SLANG_RELEASE_ASSERT(
- getNaturalOffset(targetReq, field, &fieldOffset) == SLANG_OK);
+ getNaturalOffset(field, &fieldOffset) == SLANG_OK);
auto fieldType = field->getFieldType();
auto fieldValue =
readObject(builder, src, fieldType, (uint32_t)(fieldOffset + offset));
@@ -90,7 +90,7 @@ struct BitCastLoweringContext
IRSizeAndAlignment elementLayout;
SLANG_RELEASE_ASSERT(
getNaturalSizeAndAlignment(
- targetReq, arrayType->getElementType(), &elementLayout) == SLANG_OK);
+ arrayType->getElementType(), &elementLayout) == SLANG_OK);
for (IRIntegerValue i = 0; i < arrayCount->value.intVal; i++)
{
elements.add(readObject(
@@ -111,7 +111,7 @@ struct BitCastLoweringContext
IRSizeAndAlignment elementLayout;
SLANG_RELEASE_ASSERT(
getNaturalSizeAndAlignment(
- targetReq, vectorType->getElementType(), &elementLayout) == SLANG_OK);
+ vectorType->getElementType(), &elementLayout) == SLANG_OK);
for (IRIntegerValue i = 0; i < elementCount->value.intVal; i++)
{
elements.add(readObject(
@@ -136,7 +136,7 @@ struct BitCastLoweringContext
matrixType->getElementType(), matrixType->getColumnCount());
IRSizeAndAlignment elementLayout;
SLANG_RELEASE_ASSERT(
- getNaturalSizeAndAlignment(targetReq, elementType, &elementLayout) == SLANG_OK);
+ getNaturalSizeAndAlignment(elementType, &elementLayout) == SLANG_OK);
for (IRIntegerValue i = 0; i < elementCount->value.intVal; i++)
{
elements.add(readObject(
diff --git a/source/slang/slang-ir-lower-buffer-element-type.cpp b/source/slang/slang-ir-lower-buffer-element-type.cpp
index 3ef94d415..0472e44df 100644
--- a/source/slang/slang-ir-lower-buffer-element-type.cpp
+++ b/source/slang/slang-ir-lower-buffer-element-type.cpp
@@ -3,6 +3,7 @@
#include "slang-ir-insts.h"
#include "slang-ir-util.h"
#include "slang-ir-clone.h"
+#include "slang-ir-layout.h"
namespace Slang
{
@@ -17,13 +18,15 @@ namespace Slang
IRFunc* convertOriginalToLowered = nullptr;
IRFunc* convertLoweredToOriginal = nullptr;
};
- Dictionary<IRType*, LoweredElementTypeInfo> loweredTypeInfo;
- Dictionary<IRType*, LoweredElementTypeInfo> mapLoweredTypeToInfo;
+
+ Dictionary<IRType*, LoweredElementTypeInfo> loweredTypeInfo[(int)IRTypeLayoutRuleName::_Count];
+ Dictionary<IRType*, LoweredElementTypeInfo> mapLoweredTypeToInfo[(int)IRTypeLayoutRuleName::_Count];
SlangMatrixLayoutMode defaultMatrixLayout = SLANG_MATRIX_LAYOUT_ROW_MAJOR;
+ TargetRequest* target;
- LoweredElementTypeContext(SlangMatrixLayoutMode inDefaultMatrixLayout)
- : defaultMatrixLayout(inDefaultMatrixLayout)
+ LoweredElementTypeContext(TargetRequest* target, SlangMatrixLayoutMode inDefaultMatrixLayout)
+ : target(target), defaultMatrixLayout(inDefaultMatrixLayout)
{}
IRFunc* createMatrixUnpackFunc(
@@ -200,7 +203,18 @@ namespace Slang
return func;
}
- LoweredElementTypeInfo getLoweredTypeInfoImpl(IRType* type)
+ const char* getLayoutName(IRTypeLayoutRuleName name)
+ {
+ switch (name)
+ {
+ case IRTypeLayoutRuleName::Std140: return "std140";
+ case IRTypeLayoutRuleName::Std430: return "std430";
+ case IRTypeLayoutRuleName::Natural: return "natural";
+ default: return "default";
+ }
+ }
+
+ LoweredElementTypeInfo getLoweredTypeInfoImpl(IRType* type, IRTypeLayoutRules* rules)
{
IRBuilder builder(type);
builder.setInsertAfter(type);
@@ -224,12 +238,20 @@ namespace Slang
nameSB << getIntVal(matrixType->getRowCount()) << "x" << getIntVal(matrixType->getColumnCount());
if (isColMajor)
nameSB << "_ColMajor";
+ nameSB << getLayoutName(rules->ruleName);
builder.addNameHintDecoration(loweredType, nameSB.produceString().getUnownedSlice());
auto structKey = builder.createStructKey();
builder.addNameHintDecoration(structKey, UnownedStringSlice("data"));
auto vectorType = builder.getVectorType(matrixType->getElementType(),
isColMajor?matrixType->getRowCount():matrixType->getColumnCount());
- auto arrayType = builder.getArrayType(vectorType, isColMajor?matrixType->getColumnCount():matrixType->getRowCount());
+ IRSizeAndAlignment elementSizeAlignment;
+ getSizeAndAlignment(rules, vectorType, &elementSizeAlignment);
+ elementSizeAlignment = rules->alignCompositeElement(elementSizeAlignment);
+
+ auto arrayType = builder.getArrayType(
+ vectorType,
+ isColMajor?matrixType->getColumnCount():matrixType->getRowCount(),
+ builder.getIntValue(builder.getIntType(), elementSizeAlignment.size));
builder.createStructField(loweredType, structKey, arrayType);
info.loweredType = loweredType;
@@ -241,45 +263,48 @@ namespace Slang
}
else if (auto arrayType = as<IRArrayType>(type))
{
- auto loweredInnerTypeInfo = getLoweredTypeInfo(arrayType->getElementType());
-
- if (loweredInnerTypeInfo.loweredType != loweredInnerTypeInfo.originalType)
- {
- auto loweredType = builder.createStructType();
- info.loweredType = loweredType;
- StringBuilder nameSB;
- nameSB << "_ArrayStorage_";
- getTypeNameHint(nameSB, arrayType->getElementType());
- nameSB << getIntVal(arrayType->getElementCount());
- builder.addNameHintDecoration(loweredType, nameSB.produceString().getUnownedSlice());
- auto structKey = builder.createStructKey();
- builder.addNameHintDecoration(structKey, UnownedStringSlice("data"));
- auto innerArrayType = builder.getArrayType(loweredInnerTypeInfo.loweredType, arrayType->getElementCount());
- builder.createStructField(loweredType, structKey, innerArrayType);
- info.loweredInnerArrayType = innerArrayType;
- info.loweredInnerStructKey = structKey;
- info.convertLoweredToOriginal = createArrayUnpackFunc(arrayType, loweredType, structKey, innerArrayType, loweredInnerTypeInfo);
- info.convertOriginalToLowered = createArrayPackFunc(arrayType, loweredType, innerArrayType, loweredInnerTypeInfo);
- }
- else
+ auto loweredInnerTypeInfo = getLoweredTypeInfo(arrayType->getElementType(), rules);
+ if (!loweredInnerTypeInfo.convertLoweredToOriginal && rules->ruleName == IRTypeLayoutRuleName::Natural)
{
info.loweredType = type;
+ return info;
}
+ auto loweredType = builder.createStructType();
+ info.loweredType = loweredType;
+ StringBuilder nameSB;
+ nameSB << "_Array_" << getLayoutName(rules->ruleName) << "_";
+ getTypeNameHint(nameSB, arrayType->getElementType());
+ nameSB << getIntVal(arrayType->getElementCount());
+ builder.addNameHintDecoration(loweredType, nameSB.produceString().getUnownedSlice());
+ auto structKey = builder.createStructKey();
+ builder.addNameHintDecoration(structKey, UnownedStringSlice("data"));
+ IRSizeAndAlignment elementSizeAlignment;
+ getSizeAndAlignment(rules, loweredType, &elementSizeAlignment);
+ elementSizeAlignment = rules->alignCompositeElement(elementSizeAlignment);
+ auto innerArrayType = builder.getArrayType(
+ loweredInnerTypeInfo.loweredType,
+ arrayType->getElementCount(),
+ builder.getIntValue(builder.getIntType(), elementSizeAlignment.size));
+ builder.createStructField(loweredType, structKey, innerArrayType);
+ info.loweredInnerArrayType = innerArrayType;
+ info.loweredInnerStructKey = structKey;
+ info.convertLoweredToOriginal = createArrayUnpackFunc(arrayType, loweredType, structKey, innerArrayType, loweredInnerTypeInfo);
+ info.convertOriginalToLowered = createArrayPackFunc(arrayType, loweredType, innerArrayType, loweredInnerTypeInfo);
+
return info;
}
else if (auto structType = as<IRStructType>(type))
{
- bool hasNonTrivialField = false;
List<LoweredElementTypeInfo> fieldLoweredTypeInfo;
+ bool isTrivial = true;
for (auto field : structType->getFields())
{
- auto loweredFieldTypeInfo = getLoweredTypeInfo(field->getFieldType());
+ auto loweredFieldTypeInfo = getLoweredTypeInfo(field->getFieldType(), rules);
fieldLoweredTypeInfo.add(loweredFieldTypeInfo);
- if (loweredFieldTypeInfo.loweredType != loweredFieldTypeInfo.originalType)
- hasNonTrivialField = true;
+ if (loweredFieldTypeInfo.convertLoweredToOriginal || rules->ruleName != IRTypeLayoutRuleName::Natural)
+ isTrivial = false;
}
-
- if (!hasNonTrivialField)
+ if (isTrivial)
{
info.loweredType = type;
return info;
@@ -288,10 +313,9 @@ namespace Slang
auto loweredType = builder.createStructType();
StringBuilder nameSB;
getTypeNameHint(nameSB, type);
- nameSB << "_Storage";
+ nameSB << "_" << getLayoutName(rules->ruleName);
builder.addNameHintDecoration(loweredType, nameSB.produceString().getUnownedSlice());
info.loweredType = loweredType;
-
// Create fields.
{
Index fieldId = 0;
@@ -340,7 +364,7 @@ namespace Slang
Index fieldId = 0;
for (auto field : structType->getFields())
{
- auto fieldVal = builder.emitFieldExtract(type, param, field->getKey());
+ auto fieldVal = builder.emitFieldExtract(field->getFieldType(), param, field->getKey());
auto packedField = fieldLoweredTypeInfo[fieldId].convertOriginalToLowered
? builder.emitCallInst(fieldLoweredTypeInfo[fieldId].loweredType, fieldLoweredTypeInfo[fieldId].convertOriginalToLowered, 1, &fieldVal)
: fieldVal;
@@ -358,14 +382,16 @@ namespace Slang
return info;
}
- LoweredElementTypeInfo getLoweredTypeInfo(IRType* type)
+ LoweredElementTypeInfo getLoweredTypeInfo(IRType* type, IRTypeLayoutRules* rules)
{
LoweredElementTypeInfo info;
- if (loweredTypeInfo.tryGetValue(type, info))
+ if (loweredTypeInfo[(int)rules->ruleName].tryGetValue(type, info))
return info;
- info = getLoweredTypeInfoImpl(type);
- loweredTypeInfo[type] = info;
- mapLoweredTypeToInfo[info.loweredType] = info;
+ info = getLoweredTypeInfoImpl(type, rules);
+ IRSizeAndAlignment sizeAlignment;
+ getSizeAndAlignment(rules, info.loweredType, &sizeAlignment);
+ loweredTypeInfo[(int)rules->ruleName].set(type, info);
+ mapLoweredTypeToInfo[(int)rules->ruleName].set(info.loweredType, info);
return info;
}
@@ -389,6 +415,12 @@ namespace Slang
return nullptr;
}
+ struct MatrixAddrWorkItem
+ {
+ IRInst* matrixAddrInst;
+ IRTypeLayoutRules* layoutRules;
+ };
+
void processModule(IRModule* module)
{
IRBuilder builder(module);
@@ -414,13 +446,15 @@ namespace Slang
// Maintain a pending work list of all matrix addresses, and try to lower them out of existance
// after everything else has been lowered.
- List<IRInst*> matrixAddrInsts;
+
+ List<MatrixAddrWorkItem> matrixAddrInsts;
for (auto bufferTypeInfo : bufferTypeInsts)
{
auto bufferType = bufferTypeInfo.bufferType;
auto elementType = bufferTypeInfo.elementType;
- auto loweredBufferElementTypeInfo = getLoweredTypeInfo(elementType);
+ auto layoutRules = getTypeLayoutRuleForBuffer(target, bufferType);
+ auto loweredBufferElementTypeInfo = getLoweredTypeInfo(elementType, layoutRules);
// If the lowered type is the same as original type, no change is required.
if (!loweredBufferElementTypeInfo.convertLoweredToOriginal)
@@ -450,7 +484,7 @@ namespace Slang
auto ptrVal = ptrValsWorkList[i];
auto oldPtrType = ptrVal->getFullType();
auto originalElementType = oldPtrType->getOperand(0);
- auto loweredElementTypeInfo = getLoweredTypeInfo((IRType*)originalElementType);
+ auto loweredElementTypeInfo = getLoweredTypeInfo((IRType*)originalElementType, layoutRules);
if (!loweredElementTypeInfo.convertLoweredToOriginal)
continue;
@@ -517,7 +551,7 @@ namespace Slang
// We are tring to get a pointer to a lowered matrix element.
// We process this insts at a later phase.
SLANG_ASSERT(user->getOp() == kIROp_GetElementPtr);
- matrixAddrInsts.add(user);
+ matrixAddrInsts.add(MatrixAddrWorkItem{ user, layoutRules });
}
else
{
@@ -544,19 +578,24 @@ namespace Slang
bufferType->removeAndDeallocate();
}
+ // Process all matrix address uses.
lowerMatrixAddresses(module, matrixAddrInsts);
}
// Lower all getElementPtr insts of a lowered matrix out of existance.
- void lowerMatrixAddresses(IRModule* module, List<IRInst*>& matrixAddrInsts)
+ void lowerMatrixAddresses(IRModule* module, List<MatrixAddrWorkItem>& matrixAddrInsts)
{
IRBuilder builder(module);
- for (auto majorAddr : matrixAddrInsts)
+ for (auto workItem : matrixAddrInsts)
{
+ auto majorAddr = workItem.matrixAddrInst;
+ auto layoutRules = workItem.layoutRules;
+
+ int layoutRuleName = (int)layoutRules->ruleName;
auto majorGEP = as<IRGetElementPtr>(majorAddr);
SLANG_ASSERT(majorGEP);
auto loweredMatrixType = cast<IRPtrTypeBase>(majorGEP->getBase()->getFullType())->getValueType();
- auto matrixTypeInfo = mapLoweredTypeToInfo.tryGetValue(loweredMatrixType);
+ auto matrixTypeInfo = mapLoweredTypeToInfo[layoutRuleName].tryGetValue(loweredMatrixType);
SLANG_ASSERT(matrixTypeInfo);
auto matrixType = as<IRMatrixType>(matrixTypeInfo->originalType);
auto rowCount = getIntVal(matrixType->getRowCount());
@@ -652,7 +691,38 @@ namespace Slang
SlangMatrixLayoutMode defaultMatrixMode = (SlangMatrixLayoutMode)target->getDefaultMatrixLayoutMode();
if (defaultMatrixMode == SLANG_MATRIX_LAYOUT_MODE_UNKNOWN)
defaultMatrixMode = SLANG_MATRIX_LAYOUT_ROW_MAJOR;
- LoweredElementTypeContext context(defaultMatrixMode);
+ LoweredElementTypeContext context(target, defaultMatrixMode);
context.processModule(module);
}
+
+
+ IRTypeLayoutRules* getTypeLayoutRuleForBuffer(TargetRequest* target, IRType* bufferType)
+ {
+ if (!isKhronosTarget(target))
+ return IRTypeLayoutRules::getNatural();
+
+ // If we are just emitting GLSL, we can just use the general layout rule.
+ if (!target->shouldEmitSPIRVDirectly())
+ return IRTypeLayoutRules::getNatural();
+
+ // If the user specified a scalar buffer layout, then just use that.
+ if (target->getForceGLSLScalarBufferLayout())
+ return IRTypeLayoutRules::getNatural();
+
+ // The default behavior is to use std140 for constant buffers and std430 for other buffers.
+ switch (bufferType->getOp())
+ {
+ case kIROp_HLSLStructuredBufferType:
+ case kIROp_HLSLRWStructuredBufferType:
+ case kIROp_HLSLAppendStructuredBufferType:
+ case kIROp_HLSLConsumeStructuredBufferType:
+ case kIROp_HLSLRasterizerOrderedStructuredBufferType:
+ return IRTypeLayoutRules::getStd430();
+ case kIROp_ConstantBufferType:
+ case kIROp_ParameterBlockType:
+ return IRTypeLayoutRules::getStd140();
+ }
+ return IRTypeLayoutRules::getNatural();
+ }
+
}
diff --git a/source/slang/slang-ir-lower-buffer-element-type.h b/source/slang/slang-ir-lower-buffer-element-type.h
index bbee71df4..b96a34c6e 100644
--- a/source/slang/slang-ir-lower-buffer-element-type.h
+++ b/source/slang/slang-ir-lower-buffer-element-type.h
@@ -5,6 +5,8 @@ namespace Slang
{
struct IRModule;
class TargetRequest;
+ struct IRTypeLayoutRules;
+ struct IRType;
// For each struct type S used as element type of a ConstantBuffer, ParameterBlock or [RW]StructuredBuffer,
// we create a lowered type L, where matrix types are lowered to arrays of vectors based on major-ness,
@@ -15,6 +17,9 @@ namespace Slang
//
void lowerBufferElementTypeToStorageType(TargetRequest* target, IRModule* module);
+
+ // Returns the type layout rules should be used for a buffer resource type.
+ IRTypeLayoutRules* getTypeLayoutRuleForBuffer(TargetRequest* target, IRType* bufferType);
}
#endif
diff --git a/source/slang/slang-ir-lower-generics.cpp b/source/slang/slang-ir-lower-generics.cpp
index a7c0f51e6..f535b97d2 100644
--- a/source/slang/slang-ir-lower-generics.cpp
+++ b/source/slang/slang-ir-lower-generics.cpp
@@ -176,6 +176,30 @@ namespace Slang
});
}
+ void stripWrapExistential(IRModule* module)
+ {
+ auto& workList = *module->getContainerPool().getList<IRInst>();
+ workList.add(module->getModuleInst());
+ for (Index i = 0; i < workList.getCount(); i++)
+ {
+ auto inst = workList[i];
+ switch (inst->getOp())
+ {
+ case kIROp_WrapExistential:
+ {
+ auto operand = inst->getOperand(0);
+ inst->replaceUsesWith(operand);
+ inst->removeAndDeallocate();
+ }
+ break;
+ default:
+ for (auto child : inst->getChildren())
+ workList.add(child);
+ break;
+ }
+ }
+ }
+
void lowerGenerics(
TargetRequest* targetReq,
IRModule* module,
@@ -234,5 +258,11 @@ namespace Slang
generateAnyValueMarshallingFunctions(&sharedContext);
if (sink->getErrorCount() != 0)
return;
+
+ // At this point, we should no longer need to care any `WrapExistential` insts,
+ // although they could still exist in the IR in order to call generic stdlib functions,
+ // e.g. RWStucturedBuffer.Load(WrapExistential(sbuffer, type), index).
+ // We should remove them now.
+ stripWrapExistential(module);
}
} // namespace Slang
diff --git a/source/slang/slang-ir-lower-size-of.cpp b/source/slang/slang-ir-lower-size-of.cpp
index a8b599031..ffef82797 100644
--- a/source/slang/slang-ir-lower-size-of.cpp
+++ b/source/slang/slang-ir-lower-size-of.cpp
@@ -55,7 +55,7 @@ struct SizeOfLikeLoweringContext
IRSizeAndAlignment sizeAndAlignment;
- if (SLANG_FAILED(getNaturalSizeAndAlignment(m_targetReq, typeOperand, &sizeAndAlignment)))
+ if (SLANG_FAILED(getNaturalSizeAndAlignment(typeOperand, &sizeAndAlignment)))
{
// Output a diagnostic failure
if(sizeOfLikeInst->getOp() == kIROp_AlignOf)
diff --git a/source/slang/slang-ir-spirv-legalize.cpp b/source/slang/slang-ir-spirv-legalize.cpp
index 0fb472df7..6afdcf102 100644
--- a/source/slang/slang-ir-spirv-legalize.cpp
+++ b/source/slang/slang-ir-spirv-legalize.cpp
@@ -3,12 +3,12 @@
#include "slang-ir-glsl-legalize.h"
-#include "slang-ir-layout-on-types.h"
#include "slang-ir.h"
#include "slang-ir-insts.h"
#include "slang-emit-base.h"
#include "slang-glsl-extension-tracker.h"
-#include "slang-type-layout.h"
+#include "slang-ir-lower-buffer-element-type.h"
+#include "slang-ir-layout.h"
namespace Slang
{
@@ -57,6 +57,9 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
auto ptrType = as<IRPtrTypeBase>(inst->getDataType());
if (!ptrType)
{
+ if (as<IRResourceTypeBase>(inst))
+ return;
+
SpvStorageClass storageClass = SpvStorageClassPrivate;
// Figure out storage class based on var layout.
if (auto layout = getVarLayout(inst))
@@ -86,6 +89,12 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
if(const auto constantBufferType = as<IRConstantBufferType>(innerType))
{
innerType = constantBufferType->getElementType();
+ storageClass = SpvStorageClassUniform;
+ }
+ else if (auto paramBlockType = as<IRParameterBlockType>(innerType))
+ {
+ innerType = paramBlockType->getElementType();
+ storageClass = SpvStorageClassUniform;
}
// Make a pointer type of storageClass.
@@ -255,6 +264,43 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
processGetElementPtrImpl(gepInst, gepInst->getBase(), gepInst->getIndex());
}
+ void processStructuredBufferLoad(IRInst* loadInst)
+ {
+ auto sb = loadInst->getOperand(0);
+ auto index = loadInst->getOperand(1);
+ IRBuilder builder(sb);
+ builder.setInsertBefore(loadInst);
+ IRInst* args[] = { sb, index };
+ auto addrInst = builder.emitIntrinsicInst(
+ builder.getPtrType(kIROp_PtrType, loadInst->getFullType(), SpvStorageClassStorageBuffer),
+ kIROp_RWStructuredBufferGetElementPtr,
+ 2,
+ args);
+ auto value = builder.emitLoad(addrInst);
+ loadInst->replaceUsesWith(value);
+ loadInst->removeAndDeallocate();
+ addUsersToWorkList(value);
+ }
+
+ void processRWStructuredBufferStore(IRInst* storeInst)
+ {
+ auto sb = storeInst->getOperand(0);
+ auto index = storeInst->getOperand(1);
+ auto value = storeInst->getOperand(2);
+ IRBuilder builder(sb);
+ builder.setInsertBefore(storeInst);
+ IRInst* args[] = { sb, index };
+ auto addrInst = builder.emitIntrinsicInst(
+ builder.getPtrType(kIROp_PtrType, value->getFullType(), SpvStorageClassStorageBuffer),
+ kIROp_RWStructuredBufferGetElementPtr,
+ 2,
+ args);
+ auto newStore = builder.emitStore(addrInst, value);
+ storeInst->replaceUsesWith(newStore);
+ storeInst->removeAndDeallocate();
+ addUsersToWorkList(newStore);
+ }
+
void processFieldAddress(IRFieldAddress* inst)
{
if (auto ptrType = as<IRPtrTypeBase>(inst->getBase()->getDataType()))
@@ -279,33 +325,24 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
}
}
- void processStructuredBufferType(IRHLSLStructuredBufferTypeBase* inst)
+ void processStructuredBufferType(IRHLSLStructuredBufferTypeBase * inst)
{
- // const auto elementTypeLayout = inst->getElementType()->findDecoration<IRTypeLayout>();
- // SLANG_ASSERT(elementTypeLayout);
- const auto typeLayoutDecoration = inst->findDecoration<IRLayoutDecoration>();
- SLANG_ASSERT(typeLayoutDecoration);
- const auto typeLayout = as<IRStructuredBufferTypeLayout>(typeLayoutDecoration->getLayout());
- SLANG_ASSERT(typeLayout);
- const auto elemTypeLayout = typeLayout->getElementTypeLayout();
- SLANG_ASSERT(elemTypeLayout);
+ auto layoutRules = getTypeLayoutRuleForBuffer(m_sharedContext->m_targetRequest, inst);
IRBuilder builder(m_sharedContext->m_irModule);
builder.setInsertBefore(inst);
- const auto arrayType = builder.getUnsizedArrayType(inst->getElementType());
- IRArrayTypeLayout::Builder arrayTypeLayoutBuilder(&builder, elemTypeLayout);
- const auto arrayTypeLayout = arrayTypeLayoutBuilder.build();
- IRVarLayout::Builder varLayoutBuilder(&builder, arrayTypeLayout);
- varLayoutBuilder.findOrAddResourceInfo(LayoutResourceKind::Uniform);
- const auto arrayFieldVarLayout = varLayoutBuilder.build();
+ auto elementType = inst->getElementType();
+ IRSizeAndAlignment elementSize;
+ getSizeAndAlignment(layoutRules, elementType, &elementSize);
+ elementSize = layoutRules->alignCompositeElement(elementSize);
+ const auto arrayType = builder.getUnsizedArrayType(inst->getElementType(), builder.getIntValue(builder.getIntType(), elementSize.getStride()));
const auto structType = builder.createStructType();
- IRStructTypeLayout::Builder structTypeLayoutBuilder(&builder);
const auto arrayKey = builder.createStructKey();
builder.createStructField(structType, arrayKey, arrayType);
- structTypeLayoutBuilder.addField(arrayKey, arrayFieldVarLayout);
- const auto structTypeLayout = structTypeLayoutBuilder.build();
+ IRSizeAndAlignment structSize;
+ getSizeAndAlignment(layoutRules, structType, &structSize);
const auto ptrType = builder.getPtrType(kIROp_PtrType, structType, SpvStorageClassStorageBuffer);
@@ -321,14 +358,15 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
case kIROp_HLSLConsumeStructuredBufferType:
nameSb << "ConsumeStructuredBuffer";
break;
+ case kIROp_HLSLRasterizerOrderedStructuredBufferType:
+ nameSb << "RasterizerOrderedStructuredBuffer";
+ break;
default:
nameSb << "StructuredBuffer";
break;
}
builder.addNameHintDecoration(structType, nameSb.getUnownedSlice());
builder.addDecoration(structType, kIROp_SPIRVBufferBlockDecoration);
- SLANG_ASSERT(!structType->findDecoration<IRLayoutDecoration>());
- builder.addLayoutDecoration(structType, structTypeLayout);
inst->replaceUsesWith(ptrType);
inst->removeAndDeallocate();
addUsersToWorkList(ptrType);
@@ -364,6 +402,15 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
case kIROp_RWStructuredBufferGetElementPtr:
processRWStructuredBufferGetElementPtr(as<IRRWStructuredBufferGetElementPtr>(inst));
break;
+ case kIROp_RWStructuredBufferLoad:
+ case kIROp_StructuredBufferLoad:
+ case kIROp_RWStructuredBufferLoadStatus:
+ case kIROp_StructuredBufferLoadStatus:
+ processStructuredBufferLoad(inst);
+ break;
+ case kIROp_RWStructuredBufferStore:
+ processRWStructuredBufferStore(inst);
+ break;
case kIROp_HLSLStructuredBufferType:
case kIROp_HLSLRWStructuredBufferType:
processStructuredBufferType(as<IRHLSLStructuredBufferTypeBase>(inst));
@@ -408,7 +455,6 @@ void legalizeIRForSPIRV(
const List<IRFunc*>& entryPoints,
CodeGenContext* codeGenContext)
{
- placeTypeLayoutsOnTypes(module, codeGenContext);
GLSLExtensionTracker extensionTracker;
legalizeEntryPointsForGLSL(module->getSession(), module, entryPoints, codeGenContext, &extensionTracker);
legalizeSPIRV(context, module);
diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp
index 1a499842d..c666ccc08 100644
--- a/source/slang/slang-ir.cpp
+++ b/source/slang/slang-ir.cpp
@@ -317,7 +317,7 @@ namespace Slang
IRInst* IRArrayTypeBase::getElementCount()
{
if (auto arrayType = as<IRArrayType>(this))
- return arrayType->getElementCount();
+ return arrayType->getOperand(1);
return nullptr;
}
@@ -2809,6 +2809,29 @@ namespace Slang
operands);
}
+ IRArrayType* IRBuilder::getArrayType(
+ IRType* elementType,
+ IRInst* elementCount,
+ IRInst* stride)
+ {
+ IRInst* operands[] = { elementType, elementCount, stride };
+ return (IRArrayType*)getType(
+ kIROp_ArrayType,
+ sizeof(operands) / sizeof(operands[0]),
+ operands);
+ }
+
+ IRUnsizedArrayType* IRBuilder::getUnsizedArrayType(
+ IRType* elementType,
+ IRInst* stride)
+ {
+ IRInst* operands[] = { elementType, stride };
+ return (IRUnsizedArrayType*)getType(
+ kIROp_UnsizedArrayType,
+ sizeof(operands) / sizeof(operands[0]),
+ operands);
+ }
+
IRVectorType* IRBuilder::getVectorType(
IRType* elementType,
IRInst* elementCount)
diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h
index b765f6aee..413410880 100644
--- a/source/slang/slang-ir.h
+++ b/source/slang/slang-ir.h
@@ -555,6 +555,15 @@ enum class SideEffectAnalysisOptions
UseDominanceTree,
};
+enum class IRTypeLayoutRuleName
+{
+ Natural,
+ Scalar = Natural,
+ Std430,
+ Std140,
+ _Count,
+};
+
// Every value in the IR is an instruction (even things
// like literal values).
//
@@ -1472,13 +1481,28 @@ struct IRArrayTypeBase : IRType
// for an `IRUnsizedArrayType`.
IRInst* getElementCount();
+ IRInst* getArrayStride()
+ {
+ switch (m_op)
+ {
+ case kIROp_ArrayType:
+ if (getOperandCount() == 3)
+ return getOperand(2);
+ return nullptr;
+
+ case kIROp_UnsizedArrayType:
+ if (getOperandCount() == 2)
+ return getOperand(1);
+ return nullptr;
+ }
+ return nullptr;
+ }
+
IR_PARENT_ISA(ArrayTypeBase)
};
struct IRArrayType: IRArrayTypeBase
{
- IRInst* getElementCount() { return getOperand(1); }
-
IR_LEAF_ISA(ArrayType)
};
diff --git a/source/slang/slang-spirv-val.cpp b/source/slang/slang-spirv-val.cpp
index c2381fa0e..29a4b8617 100644
--- a/source/slang/slang-spirv-val.cpp
+++ b/source/slang/slang-spirv-val.cpp
@@ -21,24 +21,27 @@ static SlangResult disassembleSPIRV(const List<uint8_t>& spirv, String& outErr,
in->close();
// Wait for it to finish
- if(!p->waitForTermination(1000))
- return SLANG_FAIL;
-
- // TODO: allow inheriting stderr in Process
List<Byte> outData;
- SLANG_RETURN_ON_FAIL(StreamUtil::readAll(out, 0, outData));
- outErr = String(
- reinterpret_cast<const char*>(outData.begin()),
- reinterpret_cast<const char*>(outData.end())
- );
+ List<Byte> outErrData;
+ while (!out->isEnd() || !err->isEnd())
+ {
+ if (!out->isEnd())
+ StreamUtil::readAll(out, 0, outData);
+ if (!err->isEnd())
+ StreamUtil::readAll(err, 0, outErrData);
+ }
+ SLANG_RETURN_ON_FAIL(p->waitForTermination(10));
- outData.clear();
- SLANG_RETURN_ON_FAIL(StreamUtil::readAll(err, 0, outData));
outDis = String(
reinterpret_cast<const char*>(outData.begin()),
reinterpret_cast<const char*>(outData.end())
);
+ outErr = String(
+ reinterpret_cast<const char*>(outErrData.begin()),
+ reinterpret_cast<const char*>(outErrData.end())
+ );
+
const auto ret = p->getReturnValue();
return ret == 0 ? SLANG_OK : SLANG_FAIL;
}
diff --git a/tests/expected-failure.txt b/tests/expected-failure.txt
index af19025e4..ad1901ca3 100644
--- a/tests/expected-failure.txt
+++ b/tests/expected-failure.txt
@@ -52,7 +52,6 @@ tests/bugs/bool-op.slang.1 (vk)
tests/bugs/buffer-swizzle-store.slang.1 (vk)
tests/bugs/byte-address-buffer-interlocked-add-f32.slang (vk)
tests/bugs/dxbc-double-problem.slang.1 (vk)
-tests/bugs/generic-type-duplication.slang.1 (vk)
tests/bugs/gh-3075.slang.2 (vk)
tests/bugs/glsl-static-const-array.slang (vk)
tests/bugs/loop-optimize.slang.1 (vk)
@@ -66,8 +65,6 @@ tests/bugs/inlining/global-const-inline.slang.1 (vk)
tests/compute/buffer-layout.slang.2 (vk)
tests/compute/byte-address-buffer.slang.2 (vk)
tests/compute/column-major.slang.3 (vk)
-tests/compute/dynamic-dispatch-13.slang.2 (vk)
-tests/compute/dynamic-dispatch-14.slang.3 (vk)
tests/compute/dynamic-dispatch-16.slang (vk)
tests/compute/dynamic-dispatch-17.slang (vk)
tests/compute/dynamic-dispatch-18.slang.2 (vk)