summaryrefslogtreecommitdiff
path: root/source/slang/slang-ir-spirv-legalize.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2025-03-06 14:26:34 -0800
committerGitHub <noreply@github.com>2025-03-06 14:26:34 -0800
commit4485cf3eaf142cfd5f8470e86739acc67d4e12ea (patch)
treec6ce220dfe5f3ab25ea558f2512f3761c9565c69 /source/slang/slang-ir-spirv-legalize.cpp
parent55dd2deaff82bbdb72e125ba4b350030b7e5f427 (diff)
Update SPIRV-Tools and fix new validation errors. (#6511)
* Update SPIRV-Tools and fix new validation errors. * Implement pointers for glsl target. * Reworked packStorage/unpackStorage code gen to operate on pointers rather than values.
Diffstat (limited to 'source/slang/slang-ir-spirv-legalize.cpp')
-rw-r--r--source/slang/slang-ir-spirv-legalize.cpp135
1 files changed, 130 insertions, 5 deletions
diff --git a/source/slang/slang-ir-spirv-legalize.cpp b/source/slang/slang-ir-spirv-legalize.cpp
index b19af364e..2e2ba358f 100644
--- a/source/slang/slang-ir-spirv-legalize.cpp
+++ b/source/slang/slang-ir-spirv-legalize.cpp
@@ -9,6 +9,7 @@
#include "slang-ir-dominators.h"
#include "slang-ir-float-non-uniform-resource-index.h"
#include "slang-ir-glsl-legalize.h"
+#include "slang-ir-inline.h"
#include "slang-ir-insts.h"
#include "slang-ir-layout.h"
#include "slang-ir-legalize-global-values.h"
@@ -132,6 +133,7 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
inst->getElementType(),
builder.getIntValue(builder.getIntType(), elementSize.getStride()));
const auto structType = builder.createStructType();
+ builder.addPhysicalTypeDecoration(structType);
const auto arrayKey = builder.createStructKey();
builder.createStructField(structType, arrayKey, arrayType);
IRSizeAndAlignment structSize;
@@ -213,6 +215,7 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
IRBuilder builder(cbParamInst);
builder.setInsertBefore(cbParamInst);
auto structType = builder.createStructType();
+ builder.addPhysicalTypeDecoration(structType);
addToWorkList(structType);
StringBuilder sb;
sb << "cbuffer_";
@@ -1850,6 +1853,120 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
}
};
+ void propagateAddressAlignment()
+ {
+ // Work list of load/store insts to add Aligned attribute to.
+ List<IRInst*> loadStoreInsts;
+
+ for (auto globalInst : m_module->getGlobalInsts())
+ {
+ auto func = as<IRFunc>(globalInst);
+ if (!func)
+ continue;
+ for (auto block : func->getBlocks())
+ {
+ for (auto inst : block->getChildren())
+ {
+ switch (inst->getOp())
+ {
+ case kIROp_GetElementPtr:
+ case kIROp_FieldAddress:
+ {
+ auto base = inst->getOperand(0);
+ auto ptrType = as<IRPtrTypeBase>(base->getDataType());
+ if (!ptrType)
+ break;
+ // Propagate address alignment if possible.
+ auto alignDecor = base->findDecoration<IRAlignedAddressDecoration>();
+ if (!alignDecor)
+ break;
+ auto valueType = ptrType->getValueType();
+ auto layout = valueType->findDecoration<IRSizeAndAlignmentDecoration>();
+ if (!layout)
+ break;
+ auto alignment = getIntVal(alignDecor->getAlignment());
+ if (inst->getOp() == kIROp_GetElementPtr)
+ {
+ if (alignment >= layout->getAlignment())
+ {
+ IRBuilder builder(inst);
+ builder.addAlignedAddressDecoration(
+ inst,
+ alignDecor->getAlignment());
+ }
+ }
+ else
+ {
+ IRTypeLayoutRuleName layoutRuleName = layout->getLayoutName();
+ auto field = findStructField(
+ valueType,
+ (IRStructKey*)as<IRFieldAddress>(inst)->getField());
+ if (!field)
+ break;
+ IRIntegerValue offset = 0;
+ if (getOffset(
+ m_sharedContext->m_targetProgram->getOptionSet(),
+ IRTypeLayoutRules::get(layoutRuleName),
+ field,
+ &offset) != SLANG_OK)
+ break;
+ if (offset % alignment == 0)
+ {
+ IRBuilder builder(inst);
+ builder.addAlignedAddressDecoration(
+ inst,
+ alignDecor->getAlignment());
+ }
+ }
+ }
+ break;
+ case kIROp_Load:
+ case kIROp_Store:
+ {
+ if (inst->findAttr<IRAlignedAttr>())
+ break;
+ loadStoreInsts.add(inst);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // Process the work list.
+ // If load/store doesn't have Aligned attribute, and the ptr has
+ // a IRAlignedAddress decoration, we should create a load/store
+ // with a Aligned attribute.
+ for (auto inst : loadStoreInsts)
+ {
+
+ if (auto load = as<IRLoad>(inst))
+ {
+ auto ptr = load->getPtr();
+ if (auto decor = ptr->findDecoration<IRAlignedAddressDecoration>())
+ {
+ IRBuilder builder(inst);
+ builder.setInsertBefore(inst);
+ auto newLoad =
+ builder.emitLoad(load->getFullType(), ptr, decor->getAlignment());
+ load->replaceUsesWith(newLoad);
+ load->removeAndDeallocate();
+ }
+ }
+ else if (auto store = as<IRStore>(inst))
+ {
+ auto ptr = store->getPtr();
+ if (auto decor = ptr->findDecoration<IRAlignedAddressDecoration>())
+ {
+ IRBuilder builder(inst);
+ builder.setInsertBefore(inst);
+ builder.emitStore(ptr, store->getVal(), decor->getAlignment());
+ store->removeAndDeallocate();
+ }
+ }
+ }
+ }
+
void processModule()
{
determineSpirvVersion();
@@ -1914,8 +2031,8 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
legalizeSPIRVEntryPoint(func, entryPointDecor);
}
// SPIRV requires a dominator block to appear before dominated blocks.
- // After legalizing the control flow, we need to sort our blocks to ensure this is
- // true.
+ // After legalizing the control flow, we need to sort our blocks to ensure this
+ // is true.
sortBlocksInFunc(func);
}
}
@@ -1939,15 +2056,23 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
m_module,
bufferElementTypeLoweringOptions);
- // The above step may produce empty struct types, so we need to lower them out of existence.
+ // Inline all pack/unpack storage type functions generated during buffer element
+ // lowering pass.
+ performForceInlining(m_module);
+
+ // The above step may produce empty struct types, so we need to lower them out of
+ // existence.
legalizeEmptyTypes(m_sharedContext->m_targetProgram, m_module, m_sink);
+ // Propagate alignment hints on address instructions.
+ propagateAddressAlignment();
+
// Specalize address space for all pointers.
SpirvAddressSpaceAssigner addressSpaceAssigner;
specializeAddressSpace(m_module, &addressSpaceAssigner);
- // For SPIR-V, we don't skip this validation, because we might then be generating invalid
- // SPIR-V.
+ // For SPIR-V, we don't skip this validation, because we might then be generating
+ // invalid SPIR-V.
bool skipFuncParamValidation = false;
validateAtomicOperations(skipFuncParamValidation, m_sink, m_module->getModuleInst());
}