summaryrefslogtreecommitdiff
path: root/source/slang/slang-emit-spirv.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang-emit-spirv.cpp')
-rw-r--r--source/slang/slang-emit-spirv.cpp262
1 files changed, 144 insertions, 118 deletions
diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp
index 3a8a913ec..8bcd1429f 100644
--- a/source/slang/slang-emit-spirv.cpp
+++ b/source/slang/slang-emit-spirv.cpp
@@ -4569,33 +4569,37 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
break;
case kIROp_AtomicLoad:
{
- IRBuilder builder{inst};
- if (isAtomicableAddressSpace(inst->getOperand(0)->getDataType()))
+ IRAtomicLoad* atomicLoad = as<IRAtomicLoad>(inst);
+ auto ptr = atomicLoad->getPtr();
+ IRBuilder builder{atomicLoad};
+ if (isAtomicableAddressSpace(ptr->getDataType()))
{
if (m_memoryModel == SpvMemoryModelVulkan)
requireSPIRVCapability(SpvCapabilityVulkanMemoryModelDeviceScope);
const auto memoryScope =
emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType());
- const auto memorySemantics =
- emitMemorySemanticMask(inst->getOperand(1), inst->getOperand(0));
+ const auto memorySemantics = emitMemorySemanticMask(inst->getOperand(1), ptr);
result = emitOpAtomicLoad(
parent,
inst,
inst->getFullType(),
- inst->getOperand(0),
+ ptr,
memoryScope,
memorySemantics);
ensureAtomicCapability(inst, SpvOpAtomicLoad);
}
else
{
- result = emitLoadMaybeCoherent(parent, inst);
+ result = emitLoad(parent, inst, ptr);
}
}
break;
case kIROp_AtomicStore:
{
+ IRAtomicStore* atomicStore = as<IRAtomicStore>(inst);
+ auto ptr = atomicStore->getPtr();
+ auto val = atomicStore->getVal();
IRBuilder builder{inst};
if (isAtomicableAddressSpace(inst->getOperand(0)->getDataType()))
{
@@ -4604,48 +4608,44 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
const auto memoryScope =
emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType());
- const auto memorySemantics =
- emitMemorySemanticMask(inst->getOperand(2), inst->getOperand(0));
- result = emitOpAtomicStore(
- parent,
- inst,
- inst->getOperand(0),
- memoryScope,
- memorySemantics,
- inst->getOperand(1));
+ const auto memorySemantics = emitMemorySemanticMask(inst->getOperand(2), ptr);
+ result =
+ emitOpAtomicStore(parent, inst, ptr, memoryScope, memorySemantics, val);
ensureAtomicCapability(inst, SpvOpAtomicStore);
}
else
{
- result = emitStoreMaybeCoherent(parent, inst);
+ result = emitStore(parent, inst, ptr, val);
}
}
break;
case kIROp_AtomicExchange:
{
+ IRAtomicExchange* atomicExchange = as<IRAtomicExchange>(inst);
+ auto ptr = atomicExchange->getPtr();
+ auto val = atomicExchange->getOperand(1);
IRBuilder builder{inst};
- if (isAtomicableAddressSpace(inst->getOperand(0)->getDataType()))
+ if (isAtomicableAddressSpace(ptr->getDataType()))
{
if (m_memoryModel == SpvMemoryModelVulkan)
requireSPIRVCapability(SpvCapabilityVulkanMemoryModelDeviceScope);
const auto memoryScope =
emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType());
- const auto memorySemantics =
- emitMemorySemanticMask(inst->getOperand(2), inst->getOperand(0));
+ const auto memorySemantics = emitMemorySemanticMask(inst->getOperand(2), ptr);
result = emitOpAtomicExchange(
parent,
inst,
inst->getFullType(),
- inst->getOperand(0),
+ ptr,
memoryScope,
memorySemantics,
- inst->getOperand(1));
+ val);
ensureAtomicCapability(inst, SpvOpAtomicExchange);
}
else
{
- result = emitStoreMaybeCoherent(parent, inst);
+ result = emitStore(parent, inst, ptr, val);
}
}
break;
@@ -7082,6 +7082,8 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
SpvInst* emitGetOffsetPtr(SpvInstParent* parent, IRInst* inst)
{
+ requireVariableBufferCapabilityIfNeeded(inst->getDataType());
+
return emitOpPtrAccessChain(
parent,
inst,
@@ -7174,54 +7176,100 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
}
}
- SpvInst* emitLoad(SpvInstParent* parent, IRLoad* inst)
+ enum class MemoryAccessType
{
- requireVariableBufferCapabilityIfNeeded(inst->getDataType());
+ Load,
+ Store
+ };
+
+ template<MemoryAccessType memoryAccessType>
+ void getMemoryAccessOperandsOfLoadStore(
+ IRInst* inst,
+ IRInst* ptr,
+ int& memoryAccessMaskOut,
+ int& alignmentOut,
+ MemoryScope& memoryScopeOut)
+ {
+ IRAlignedAttr* alignedAttr = nullptr;
+ IRMemoryScopeAttr* memoryScopeAttr = nullptr;
- auto ptrType = as<IRPtrTypeBase>(inst->getPtr()->getDataType());
- if (ptrType && addressSpaceToStorageClass(ptrType->getAddressSpace()) ==
- SpvStorageClassPhysicalStorageBuffer)
+ for (auto attr : inst->getAllAttrs())
{
- IRSizeAndAlignment sizeAndAlignment;
- if (auto alignedAttr = inst->findAttr<IRAlignedAttr>())
+ if (auto foundAlignedAttr = as<IRAlignedAttr>(attr))
+ alignedAttr = foundAlignedAttr;
+ else if (auto foundMemoryScopeAttr = as<IRMemoryScopeAttr>(attr))
+ memoryScopeAttr = foundMemoryScopeAttr;
+ }
+
+ // Determine coherence
+ {
+ bool isCoherent = false;
+ if (memoryScopeAttr)
{
- sizeAndAlignment.alignment = (int)getIntVal(alignedAttr->getAlignment());
+ memoryScopeOut = (MemoryScope)getIntVal(memoryScopeAttr->getMemoryScope());
+ if (m_memoryModel != SpvMemoryModelVulkan)
+ SLANG_ASSERT_FAILURE(
+ "Explicit coherent operations require vulkan-memory-model, "
+ "specify the capability 'vk_mem_model'");
+ isCoherent = true;
}
else
{
- getNaturalSizeAndAlignment(
- m_targetProgram->getOptionSet(),
- ptrType->getValueType(),
- &sizeAndAlignment);
+ if (NeedToUseCoherentLoadOrStore(ptr))
+ {
+ memoryScopeOut = MemoryScope::Device;
+ isCoherent = true;
+ }
+ }
+ if (isCoherent)
+ {
+
+ memoryAccessMaskOut |= SpvMemoryAccessNonPrivatePointerMask;
+ if constexpr (memoryAccessType == MemoryAccessType::Load)
+ memoryAccessMaskOut |= SpvMemoryAccessMakePointerVisibleMask;
+ else
+ memoryAccessMaskOut |= SpvMemoryAccessMakePointerAvailableMask;
+ if (memoryScopeOut == MemoryScope::Device)
+ requireSPIRVCapability(SpvCapabilityVulkanMemoryModelDeviceScope);
}
- return emitOpLoadAligned(
- parent,
- inst,
- inst->getDataType(),
- inst->getPtr(),
- SpvLiteralInteger::from32(sizeAndAlignment.alignment));
}
- else
+
+ // Determine alignment
{
- return emitLoadMaybeCoherent(parent, inst);
+ auto ptrType = as<IRPtrTypeBase>(ptr->getDataType());
+ if (ptrType && addressSpaceToStorageClass(ptrType->getAddressSpace()) ==
+ SpvStorageClassPhysicalStorageBuffer)
+ {
+ IRSizeAndAlignment sizeAndAlignment;
+ if (alignedAttr)
+ sizeAndAlignment.alignment = (int)getIntVal(alignedAttr->getAlignment());
+ else
+ getNaturalSizeAndAlignment(
+ m_targetProgram->getOptionSet(),
+ ptrType->getValueType(),
+ &sizeAndAlignment);
+
+ alignmentOut = sizeAndAlignment.alignment;
+ if (alignmentOut != -1)
+ memoryAccessMaskOut |= SpvMemoryAccessAlignedMask;
+ }
}
}
- SpvInst* emitLoadMaybeCoherent(SpvInstParent* parent, IRInst* inst)
+ SpvInst* emitLoad(SpvInstParent* parent, IRInst* inst, IRInst* ptr)
{
- IRBuilder builder{inst};
- builder.setInsertBefore(inst);
-
- SpvInst* deviceScope = nullptr;
- IRInst* pointer = inst->getOperand(0);
-
- bool coherentPointer = NeedToUseCoherentLoadOrStore(pointer);
- if (coherentPointer)
- {
- requireSPIRVCapability(SpvCapabilityVulkanMemoryModelDeviceScope);
- deviceScope = emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType());
- }
+ requireVariableBufferCapabilityIfNeeded(inst->getDataType());
+ IRBuilder builder(inst);
+ int memoryAccessMask = 0;
+ int alignment = -1;
+ MemoryScope memoryScope{};
+ getMemoryAccessOperandsOfLoadStore<MemoryAccessType::Load>(
+ inst,
+ ptr,
+ memoryAccessMask,
+ alignment,
+ memoryScope);
return emitInstCustomOperandFunc(
parent,
inst,
@@ -7230,85 +7278,61 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
{
emitOperand(inst->getFullType());
emitOperand(kResultID);
- emitOperand(pointer);
-
- if (coherentPointer)
+ emitOperand(ptr);
+ if (memoryAccessMask)
{
- emitOperand(
- SpvMemoryAccessMakePointerVisibleMask |
- SpvMemoryAccessNonPrivatePointerMask);
-
- emitOperand(deviceScope);
+ emitOperand(SpvLiteralInteger::from32(memoryAccessMask));
+ if (memoryAccessMask & SpvMemoryAccessAlignedMask)
+ emitOperand(SpvLiteralInteger::from32((uint32_t)alignment));
+ if (memoryAccessMask & SpvMemoryAccessMakePointerVisibleMask)
+ emitOperand(
+ emitIntConstant((IRIntegerValue)memoryScope, builder.getIntType()));
}
});
}
- SpvInst* emitStore(SpvInstParent* parent, IRStore* inst)
+ SpvInst* emitLoad(SpvInstParent* parent, IRLoad* inst)
{
- auto ptrType = as<IRPtrTypeBase>(inst->getPtr()->getDataType());
- if (ptrType && addressSpaceToStorageClass(ptrType->getAddressSpace()) ==
- SpvStorageClassPhysicalStorageBuffer)
- {
- IRSizeAndAlignment sizeAndAlignment;
- if (auto alignedAttr = inst->findAttr<IRAlignedAttr>())
- {
- sizeAndAlignment.alignment = (int)getIntVal(alignedAttr->getAlignment());
- }
- else
- {
- getNaturalSizeAndAlignment(
- m_targetProgram->getOptionSet(),
- ptrType->getValueType(),
- &sizeAndAlignment);
- }
- return emitOpStoreAligned(
- parent,
- inst,
- inst->getPtr(),
- inst->getVal(),
- SpvLiteralInteger::from32(sizeAndAlignment.alignment));
- }
- else
- {
- return emitStoreMaybeCoherent(parent, inst);
- }
+ return emitLoad(parent, inst, inst->getPtr());
}
- SpvInst* emitStoreMaybeCoherent(SpvInstParent* parent, IRInst* inst)
+ SpvInst* emitStore(SpvInstParent* parent, IRInst* inst, IRInst* ptr, IRInst* val)
{
- IRBuilder builder{inst};
- builder.setInsertBefore(inst);
-
- SpvInst* deviceScope = nullptr;
- IRInst* pointer = inst->getOperand(0);
- IRInst* object = inst->getOperand(1);
-
- bool coherentPointer = NeedToUseCoherentLoadOrStore(pointer);
- if (coherentPointer)
- {
- requireSPIRVCapability(SpvCapabilityVulkanMemoryModelDeviceScope);
- deviceScope = emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType());
- }
+ requireVariableBufferCapabilityIfNeeded(inst->getDataType());
+ IRBuilder builder(inst);
+ int memoryAccessMask = 0;
+ int alignment = -1;
+ MemoryScope memoryScope{};
+ getMemoryAccessOperandsOfLoadStore<MemoryAccessType::Store>(
+ inst,
+ ptr,
+ memoryAccessMask,
+ alignment,
+ memoryScope);
return emitInstCustomOperandFunc(
parent,
inst,
SpvOpStore,
[&]()
{
- emitOperand(pointer);
- emitOperand(object);
-
- if (coherentPointer)
+ emitOperand(ptr);
+ emitOperand(val);
+ if (memoryAccessMask)
{
- emitOperand(
- SpvMemoryAccessMakePointerAvailableMask |
- SpvMemoryAccessNonPrivatePointerMask);
-
- emitOperand(deviceScope);
+ emitOperand(SpvLiteralInteger::from32(memoryAccessMask));
+ if (memoryAccessMask & SpvMemoryAccessAlignedMask)
+ emitOperand(SpvLiteralInteger::from32((uint32_t)alignment));
+ if (memoryAccessMask & SpvMemoryAccessMakePointerAvailableMask)
+ emitOperand(
+ emitIntConstant((IRIntegerValue)memoryScope, builder.getIntType()));
}
});
}
+ SpvInst* emitStore(SpvInstParent* parent, IRStore* inst)
+ {
+ return emitStore(parent, inst, inst->getPtr(), inst->getVal());
+ }
SpvInst* emitSwizzledStore(SpvInstParent* parent, IRSwizzledStore* inst)
{
@@ -8613,6 +8637,8 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
SpvInst* emitDebugValue(SpvInstParent* parent, IRDebugValue* debugValue)
{
+ auto debugVar = debugValue->getDebugVar();
+ auto debugValueVal = debugValue->getValue();
// We are asked to update the value for a debug variable.
// A debug variable is already emited as a OpDebugVariable +
// OpVariable + OpDebugDeclare. We only need to store the new value
@@ -8628,7 +8654,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
// variable. If it doesn't, we can't emit a store.
//
List<IRInst*> irAccessChain;
- auto rootVar = getRootAddr(debugValue->getDebugVar(), irAccessChain);
+ auto rootVar = getRootAddr(debugVar, irAccessChain);
SpvInst* spvDebugVar = nullptr;
if (!m_mapIRInstToSpvInst.tryGetValue(rootVar, spvDebugVar))
return nullptr;
@@ -8644,7 +8670,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
// be fully static. We will skip emitting the debug inst if the access chain
// isn't static.
//
- auto type = unwrapAttributedType(debugValue->getDebugVar()->getDataType());
+ auto type = unwrapAttributedType(debugVar->getDataType());
List<SpvInst*> accessChain;
bool isConstAccessChain =
translateIRAccessChain(builder, type, irAccessChain, accessChain);
@@ -8657,7 +8683,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
m_voidType,
getNonSemanticDebugInfoExtInst(),
rootVar,
- debugValue->getValue(),
+ debugValueVal,
getDwarfExpr(),
accessChain);
}
@@ -8669,7 +8695,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
// The ordinary case is the debug variable has a backing ordinary variable.
// We can simply emit a store into the backing variable for the DebugValue operation.
//
- return emitStoreMaybeCoherent(parent, debugValue);
+ return emitStore(parent, debugValue, debugVar, debugValueVal);
}
IRInst* getName(IRInst* inst)