diff options
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) |
