summaryrefslogtreecommitdiff
path: root/source/slang
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang')
-rw-r--r--source/slang/slang-capabilities.capdef14
-rw-r--r--source/slang/slang-emit-spirv.cpp462
-rw-r--r--source/slang/slang-ir-spirv-legalize.cpp13
-rw-r--r--source/slang/slang-ir-spirv-legalize.h2
4 files changed, 411 insertions, 80 deletions
diff --git a/source/slang/slang-capabilities.capdef b/source/slang/slang-capabilities.capdef
index 9a1a89bfe..1799d4bfc 100644
--- a/source/slang/slang-capabilities.capdef
+++ b/source/slang/slang-capabilities.capdef
@@ -587,6 +587,7 @@ def SPV_NV_tensor_addressing : _spirv_1_6;
/// [EXT]
def SPV_NV_cooperative_matrix2 : SPV_NV_tensor_addressing + SPV_KHR_cooperative_matrix;
+
// SPIRV Capabilities.
/// Represents the SPIR-V capability for atomic float 32 add operations.
@@ -781,6 +782,14 @@ def spvMaximalReconvergenceKHR : SPV_KHR_maximal_reconvergence;
/// [EXT]
def spvQuadControlKHR : SPV_KHR_quad_control;
+/// Represents the SPIR-V capability for vulkan memory model.
+/// [EXT]
+def spvVulkanMemoryModelKHR : SPV_KHR_vulkan_memory_model;
+
+/// Represents the SPIR-V capability for vulkan memory model.
+/// [EXT]
+def spvVulkanMemoryModelDeviceScopeKHR : SPV_KHR_vulkan_memory_model;
+
// The following capabilities all pertain to how ray tracing shaders are translated
// to GLSL, where there are two different extensions that can provide the core
// functionality of `TraceRay` and the related operations.
@@ -1169,6 +1178,7 @@ alias cooperative_vector = _sm_6_9 | cpp | _cuda_sm_9_0 | spvCooperativeVectorNV
alias cooperative_vector_training = spvCooperativeVectorTrainingNV;
/// Capabilities needed to use cooperative matrices
+/// [Compound]
alias cooperative_matrix = spvCooperativeMatrixKHR;
/// Capabilities needed to use reduction operations with cooperative matrix
/// [Compound]
@@ -1192,6 +1202,10 @@ alias tensor_addressing = spvTensorAddressingNV;
/// [Compound]
alias cooperative_matrix_2 = spvCooperativeMatrixKHR + spvCooperativeMatrixReductionsNV + spvCooperativeMatrixConversionsNV + spvCooperativeMatrixPerElementOperationsNV + spvCooperativeMatrixTensorAddressingNV + spvCooperativeMatrixBlockLoadsNV + spvTensorAddressingNV;
+/// Capabilities needed to use vulkan memory model
+/// [Compound]
+alias vk_mem_model = spvVulkanMemoryModelKHR + spvVulkanMemoryModelDeviceScopeKHR;
+
// Non-internal shader stages
//
/// Pixel shader stage
diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp
index 54417899c..5c1ccaf36 100644
--- a/source/slang/slang-emit-spirv.cpp
+++ b/source/slang/slang-emit-spirv.cpp
@@ -1507,7 +1507,104 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
getSection(SpvLogicalSectionID::MemoryModel),
nullptr,
m_addressingMode,
- SpvMemoryModelGLSL450);
+ m_memoryModel);
+
+ if (m_memoryModel == SpvMemoryModelVulkan)
+ {
+ requireSPIRVCapability(SpvCapabilityVulkanMemoryModel);
+ ensureExtensionDeclaration(UnownedStringSlice("SPV_KHR_vulkan_memory_model"));
+
+ auto targetCaps = m_targetProgram->getTargetReq()->getTargetCaps();
+ if (targetCaps.implies(CapabilityAtom::spvVulkanMemoryModelDeviceScopeKHR))
+ {
+ requireSPIRVCapability(SpvCapabilityVulkanMemoryModelDeviceScope);
+ }
+ }
+ }
+
+ bool NeedToUseCoherentLoadOrStore(IRInst* pointer)
+ {
+ if (m_memoryModel != SpvMemoryModelVulkan)
+ return false;
+
+ auto ptrType = as<IRPtrTypeBase>(pointer->getFullType());
+ if (!ptrType)
+ return false;
+
+ SpvStorageClass storageClass = SpvStorageClassFunction;
+ if (ptrType->hasAddressSpace())
+ storageClass = addressSpaceToStorageClass(ptrType->getAddressSpace());
+
+ // "NonPrivatePointerKHR requires a pointer in Uniform, Workgroup, CrossWorkgroup, Generic,
+ // Image or StorageBuffer storage classes."
+ switch (storageClass)
+ {
+ case SpvStorageClassUniform:
+ case SpvStorageClassWorkgroup:
+ case SpvStorageClassCrossWorkgroup:
+ case SpvStorageClassGeneric:
+ case SpvStorageClassImage:
+ case SpvStorageClassStorageBuffer:
+ break;
+ default:
+ return false;
+ }
+
+ IRInst* baseObj = pointer;
+ while (baseObj)
+ {
+ baseObj = getRootAddr(baseObj);
+ switch (baseObj->getOp())
+ {
+ case kIROp_RWStructuredBufferGetElementPtr:
+ baseObj = baseObj->getOperand(0);
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+
+ if (baseObj == nullptr)
+ return false;
+
+ for (auto decoration : baseObj->getDecorations())
+ {
+ if (decoration->getOp() == kIROp_MemoryQualifierSetDecoration)
+ {
+ auto collection = as<IRMemoryQualifierSetDecoration>(decoration);
+ IRIntegerValue flags = collection->getMemoryQualifierBit();
+ if (flags & MemoryQualifierSetModifier::Flags::kCoherent)
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ bool NeedToUseCoherentImageLoadOrStore(IRInst* image)
+ {
+ if (m_memoryModel != SpvMemoryModelVulkan)
+ return false;
+
+ if (auto opLoad = as<IRLoad>(image->getOperand(0)))
+ {
+ auto texPtr = opLoad->getPtr();
+ for (auto decoration : texPtr->getDecorations())
+ {
+ if (decoration->getOp() == kIROp_MemoryQualifierSetDecoration)
+ {
+ auto collection = as<IRMemoryQualifierSetDecoration>(decoration);
+ IRIntegerValue flags = collection->getMemoryQualifierBit();
+ if (flags & MemoryQualifierSetModifier::Flags::kCoherent)
+ {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
}
IRInst* m_defaultDebugSource = nullptr;
@@ -4208,6 +4305,9 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
break;
case kIROp_AtomicInc:
{
+ if (m_memoryModel == SpvMemoryModelVulkan)
+ requireSPIRVCapability(SpvCapabilityVulkanMemoryModelDeviceScope);
+
IRBuilder builder{inst};
const auto memoryScope =
emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType());
@@ -4225,6 +4325,9 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
break;
case kIROp_AtomicDec:
{
+ if (m_memoryModel == SpvMemoryModelVulkan)
+ requireSPIRVCapability(SpvCapabilityVulkanMemoryModelDeviceScope);
+
IRBuilder builder{inst};
const auto memoryScope =
emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType());
@@ -4245,6 +4348,9 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
IRBuilder builder{inst};
if (isAtomicableAddressSpace(inst->getOperand(0)->getDataType()))
{
+ if (m_memoryModel == SpvMemoryModelVulkan)
+ requireSPIRVCapability(SpvCapabilityVulkanMemoryModelDeviceScope);
+
const auto memoryScope =
emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType());
const auto memorySemantics =
@@ -4260,7 +4366,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
}
else
{
- result = emitOpLoad(parent, inst, inst->getFullType(), inst->getOperand(0));
+ result = emitLoadMaybeCoherent(parent, inst);
}
}
break;
@@ -4269,6 +4375,9 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
IRBuilder builder{inst};
if (isAtomicableAddressSpace(inst->getOperand(0)->getDataType()))
{
+ if (m_memoryModel == SpvMemoryModelVulkan)
+ requireSPIRVCapability(SpvCapabilityVulkanMemoryModelDeviceScope);
+
const auto memoryScope =
emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType());
const auto memorySemantics =
@@ -4284,7 +4393,7 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
}
else
{
- result = emitOpStore(parent, inst, inst->getOperand(0), inst->getOperand(1));
+ result = emitStoreMaybeCoherent(parent, inst);
}
}
break;
@@ -4293,6 +4402,9 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
IRBuilder builder{inst};
if (isAtomicableAddressSpace(inst->getOperand(0)->getDataType()))
{
+ if (m_memoryModel == SpvMemoryModelVulkan)
+ requireSPIRVCapability(SpvCapabilityVulkanMemoryModelDeviceScope);
+
const auto memoryScope =
emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType());
const auto memorySemantics =
@@ -4309,12 +4421,15 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
}
else
{
- result = emitOpStore(parent, inst, inst->getOperand(0), inst->getOperand(1));
+ result = emitStoreMaybeCoherent(parent, inst);
}
}
break;
case kIROp_AtomicCompareExchange:
{
+ if (m_memoryModel == SpvMemoryModelVulkan)
+ requireSPIRVCapability(SpvCapabilityVulkanMemoryModelDeviceScope);
+
IRBuilder builder{inst};
const auto memoryScope =
emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType());
@@ -4343,6 +4458,9 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
case kIROp_AtomicOr:
case kIROp_AtomicXor:
{
+ if (m_memoryModel == SpvMemoryModelVulkan)
+ requireSPIRVCapability(SpvCapabilityVulkanMemoryModelDeviceScope);
+
IRBuilder builder{inst};
const auto memoryScope =
emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType());
@@ -4443,56 +4561,80 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
SpvInst* emitImageLoad(SpvInstParent* parent, IRImageLoad* load)
{
- if (load->hasAuxCoord1())
- {
- return emitInst(
- parent,
- load,
- SpvOpImageRead,
- load->getDataType(),
- kResultID,
- load->getImage(),
- load->getCoord(),
- SpvImageOperandsSampleMask,
- load->getAuxCoord1());
- }
- else
+ IRBuilder builder(load);
+ builder.setInsertBefore(load);
+
+ SpvInst* memoryScope = nullptr;
+ bool coherentImage = NeedToUseCoherentImageLoadOrStore(load);
+ if (coherentImage)
{
- return emitInst(
- parent,
- load,
- SpvOpImageRead,
- load->getDataType(),
- kResultID,
- load->getImage(),
- load->getCoord());
+ memoryScope = emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType());
}
+
+ return emitInstCustomOperandFunc(
+ parent,
+ load,
+ SpvOpImageRead,
+ [&]()
+ {
+ emitOperand(load->getDataType());
+ emitOperand(kResultID);
+ emitOperand(load->getImage());
+ emitOperand(load->getCoord());
+
+ if (load->hasAuxCoord1())
+ {
+ emitOperand(SpvImageOperandsSampleMask);
+ emitOperand(load->getAuxCoord1());
+ }
+
+ if (coherentImage)
+ {
+ emitOperand(
+ SpvImageOperandsMakeTexelVisibleMask | SpvImageOperandsNonPrivateTexelMask);
+
+ emitOperand(memoryScope);
+ }
+ });
}
SpvInst* emitImageStore(SpvInstParent* parent, IRImageStore* store)
{
- if (store->hasAuxCoord1())
- {
- return emitInst(
- parent,
- store,
- SpvOpImageWrite,
- store->getImage(),
- store->getCoord(),
- store->getValue(),
- SpvImageOperandsSampleMask,
- store->getAuxCoord1());
- }
- else
+ IRBuilder builder(store);
+ builder.setInsertBefore(store);
+
+ SpvInst* memoryScope = nullptr;
+ bool coherentImage = NeedToUseCoherentImageLoadOrStore(store);
+ if (coherentImage)
{
- return emitInst(
- parent,
- store,
- SpvOpImageWrite,
- store->getImage(),
- store->getCoord(),
- store->getValue());
+ memoryScope = emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType());
}
+
+ return emitInstCustomOperandFunc(
+ parent,
+ store,
+ SpvOpImageWrite,
+ [&]()
+ {
+ emitOperand(store->getImage());
+ emitOperand(store->getCoord());
+ emitOperand(store->getValue());
+
+ if (store->hasAuxCoord1())
+ {
+ emitOperand(SpvImageOperandsSampleMask);
+ emitOperand(store->getAuxCoord1());
+ }
+
+ if (coherentImage)
+ {
+ emitOperand(
+ SpvImageOperandsMakeTexelAvailableMask |
+ SpvImageOperandsNonPrivateTexelMask);
+
+ emitOperand(memoryScope);
+ }
+ });
}
SpvInst* emitImageSubscript(SpvInstParent* parent, IRImageSubscript* subscript)
@@ -5194,21 +5336,28 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
{
auto collection = as<IRMemoryQualifierSetDecoration>(decoration);
IRIntegerValue flags = collection->getMemoryQualifierBit();
- if (flags & MemoryQualifierSetModifier::Flags::kCoherent)
- {
- emitOpDecorate(
- getSection(SpvLogicalSectionID::Annotations),
- nullptr,
- dstID,
- SpvDecorationCoherent);
- }
- if (flags & MemoryQualifierSetModifier::Flags::kVolatile)
+
+ // https://github.khronos.org/SPIRV-Registry/extensions/KHR/SPV_KHR_vulkan_memory_model.html#_modifications_to_the_spir_v_specification_version_1_3
+ // "Coherent is not allowed when the declared memory model is VulkanKHR."
+ // "Volatile is not allowed when the declared memory model is VulkanKHR"
+ if (m_memoryModel != SpvMemoryModelVulkan)
{
- emitOpDecorate(
- getSection(SpvLogicalSectionID::Annotations),
- nullptr,
- dstID,
- SpvDecorationVolatile);
+ if (flags & MemoryQualifierSetModifier::Flags::kCoherent)
+ {
+ emitOpDecorate(
+ getSection(SpvLogicalSectionID::Annotations),
+ nullptr,
+ dstID,
+ SpvDecorationCoherent);
+ }
+ if (flags & MemoryQualifierSetModifier::Flags::kVolatile)
+ {
+ emitOpDecorate(
+ getSection(SpvLogicalSectionID::Annotations),
+ nullptr,
+ dstID,
+ SpvDecorationVolatile);
+ }
}
if (flags & MemoryQualifierSetModifier::Flags::kRestrict)
{
@@ -5389,23 +5538,29 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
else if (auto collection = as<IRMemoryQualifierSetDecoration>(decor))
{
IRIntegerValue flags = collection->getMemoryQualifierBit();
- if (flags & MemoryQualifierSetModifier::Flags::kCoherent)
- {
- emitOpMemberDecorate(
- getSection(SpvLogicalSectionID::Annotations),
- nullptr,
- spvStructID,
- SpvLiteralInteger::from32(id),
- SpvDecorationCoherent);
- }
- if (flags & MemoryQualifierSetModifier::Flags::kVolatile)
+ // https://github.khronos.org/SPIRV-Registry/extensions/KHR/SPV_KHR_vulkan_memory_model.html#_modifications_to_the_spir_v_specification_version_1_3
+ // "Coherent is not allowed when the declared memory model is VulkanKHR."
+ // "Volatile is not allowed when the declared memory model is VulkanKHR"
+ if (m_memoryModel != SpvMemoryModelVulkan)
{
- emitOpMemberDecorate(
- getSection(SpvLogicalSectionID::Annotations),
- nullptr,
- spvStructID,
- SpvLiteralInteger::from32(id),
- SpvDecorationVolatile);
+ if (flags & MemoryQualifierSetModifier::Flags::kCoherent)
+ {
+ emitOpMemberDecorate(
+ getSection(SpvLogicalSectionID::Annotations),
+ nullptr,
+ spvStructID,
+ SpvLiteralInteger::from32(id),
+ SpvDecorationCoherent);
+ }
+ if (flags & MemoryQualifierSetModifier::Flags::kVolatile)
+ {
+ emitOpMemberDecorate(
+ getSection(SpvLogicalSectionID::Annotations),
+ nullptr,
+ spvStructID,
+ SpvLiteralInteger::from32(id),
+ SpvDecorationVolatile);
+ }
}
if (flags & MemoryQualifierSetModifier::Flags::kRestrict)
{
@@ -6718,10 +6873,46 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
}
else
{
- return emitOpLoad(parent, inst, inst->getDataType(), inst->getPtr());
+ return emitLoadMaybeCoherent(parent, inst);
}
}
+ SpvInst* emitLoadMaybeCoherent(SpvInstParent* parent, IRInst* inst)
+ {
+ 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());
+ }
+
+ return emitInstCustomOperandFunc(
+ parent,
+ inst,
+ SpvOpLoad,
+ [&]()
+ {
+ emitOperand(inst->getFullType());
+ emitOperand(kResultID);
+ emitOperand(pointer);
+
+ if (coherentPointer)
+ {
+ emitOperand(
+ SpvMemoryAccessMakePointerVisibleMask |
+ SpvMemoryAccessNonPrivatePointerMask);
+
+ emitOperand(deviceScope);
+ }
+ });
+ }
+
SpvInst* emitStore(SpvInstParent* parent, IRStore* inst)
{
auto ptrType = as<IRPtrTypeBase>(inst->getPtr()->getDataType());
@@ -6749,10 +6940,46 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
}
else
{
- return emitOpStore(parent, inst, inst->getPtr(), inst->getVal());
+ return emitStoreMaybeCoherent(parent, inst);
}
}
+ SpvInst* emitStoreMaybeCoherent(SpvInstParent* parent, IRInst* inst)
+ {
+ 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());
+ }
+
+ return emitInstCustomOperandFunc(
+ parent,
+ inst,
+ SpvOpStore,
+ [&]()
+ {
+ emitOperand(pointer);
+ emitOperand(object);
+
+ if (coherentPointer)
+ {
+ emitOperand(
+ SpvMemoryAccessMakePointerAvailableMask |
+ SpvMemoryAccessNonPrivatePointerMask);
+
+ emitOperand(deviceScope);
+ }
+ });
+ }
+
SpvInst* emitSwizzledStore(SpvInstParent* parent, IRSwizzledStore* inst)
{
auto sourceVectorType = as<IRVectorType>(inst->getSource()->getDataType());
@@ -7886,8 +8113,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.
//
- builder.setInsertBefore(debugValue);
- return emitOpStore(parent, debugValue, debugValue->getDebugVar(), debugValue->getValue());
+ return emitStoreMaybeCoherent(parent, debugValue);
}
IRInst* getName(IRInst* inst)
@@ -8593,6 +8819,43 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
default:
break;
}
+
+ bool needToUseCoherentLoadOrStore = false;
+ if (m_memoryModel == SpvMemoryModelVulkan)
+ {
+ switch (opcode)
+ {
+ case SpvOpControlBarrier:
+ case SpvOpMemoryBarrier:
+ case SpvOpAtomicLoad:
+ case SpvOpAtomicStore:
+ case SpvOpAtomicExchange:
+ case SpvOpAtomicCompareExchange:
+ case SpvOpAtomicCompareExchangeWeak:
+ case SpvOpAtomicIIncrement:
+ case SpvOpAtomicIDecrement:
+ case SpvOpAtomicIAdd:
+ case SpvOpAtomicISub:
+ case SpvOpAtomicSMin:
+ case SpvOpAtomicUMin:
+ case SpvOpAtomicSMax:
+ case SpvOpAtomicUMax:
+ case SpvOpAtomicAnd:
+ case SpvOpAtomicOr:
+ case SpvOpAtomicXor:
+ requireSPIRVCapability(SpvCapabilityVulkanMemoryModelDeviceScope);
+ break;
+ case SpvOpImageRead:
+ needToUseCoherentLoadOrStore =
+ NeedToUseCoherentImageLoadOrStore(spvInst->getOperand(3));
+ break;
+ case SpvOpImageWrite:
+ needToUseCoherentLoadOrStore =
+ NeedToUseCoherentImageLoadOrStore(spvInst->getOperand(1));
+ break;
+ }
+ }
+
const auto opParent = parentForOpCode(opcode, parent);
const auto opInfo = m_grammarInfo->opInfos.lookup(opcode);
@@ -8642,6 +8905,15 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
}
else
{
+ IRBuilder builder(spvInst);
+ SpvInst* memoryScope = nullptr;
+ if (needToUseCoherentLoadOrStore)
+ {
+ requireSPIRVCapability(SpvCapabilityVulkanMemoryModelDeviceScope);
+ memoryScope =
+ emitIntConstant(IRIntegerValue{SpvScopeDevice}, builder.getUIntType());
+ }
+
last = emitInstCustomOperandFunc(
opParent,
assignedInst,
@@ -8650,6 +8922,36 @@ struct SPIRVEmitContext : public SourceEmitterBase, public SPIRVEmitSharedContex
{
for (const auto operand : spvInst->getSPIRVOperands())
emitSpvAsmOperand(operand);
+
+ if (needToUseCoherentLoadOrStore)
+ {
+ // Check if user specified memory operand explicitly
+ uint32_t usedMask = 0;
+ for (auto operand : spvInst->getSPIRVOperands())
+ {
+ if (operand->getOp() == kIROp_SPIRVAsmOperandLiteral)
+ {
+ if (auto valInst = as<IRIntLit>(operand->getOperand(0)))
+ {
+ usedMask |= uint32_t(valInst->getValue());
+ }
+ }
+ }
+
+ uint32_t requiredMask = SpvImageOperandsNonPrivateTexelMask;
+ if (opcode == SpvOpImageRead)
+ requiredMask |= SpvImageOperandsMakeTexelVisibleMask;
+ else
+ requiredMask |= SpvImageOperandsMakeTexelAvailableMask;
+
+ // If user specified any of the required masks, we cannot specified
+ // anymore.
+ if (usedMask & requiredMask)
+ return;
+
+ emitOperand(requiredMask);
+ emitOperand(memoryScope);
+ }
});
}
}
diff --git a/source/slang/slang-ir-spirv-legalize.cpp b/source/slang/slang-ir-spirv-legalize.cpp
index 3319aa89d..87a6cc4b9 100644
--- a/source/slang/slang-ir-spirv-legalize.cpp
+++ b/source/slang/slang-ir-spirv-legalize.cpp
@@ -1810,6 +1810,14 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
// Scan through the entry points and find the max version required.
auto processInst = [&](IRInst* globalInst)
{
+ switch (globalInst->getOp())
+ {
+ case kIROp_CoopVectorType:
+ case kIROp_CoopMatrixType:
+ m_sharedContext->m_memoryModel = SpvMemoryModelVulkan;
+ break;
+ }
+
for (auto decor : globalInst->getDecorations())
{
switch (decor->getOp())
@@ -1844,6 +1852,11 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
processInst(globalInst);
}
+ if (targetCaps.implies(CapabilityAtom::SPV_KHR_vulkan_memory_model))
+ {
+ m_sharedContext->m_memoryModel = SpvMemoryModelVulkan;
+ }
+
if (m_sharedContext->m_spvVersion < 0x10300)
{
// Direct SPIRV backend does not support generating SPIRV before 1.3,
diff --git a/source/slang/slang-ir-spirv-legalize.h b/source/slang/slang-ir-spirv-legalize.h
index 3c9bdf26a..d2258ffb8 100644
--- a/source/slang/slang-ir-spirv-legalize.h
+++ b/source/slang/slang-ir-spirv-legalize.h
@@ -31,6 +31,8 @@ struct SPIRVEmitSharedContext
unsigned int m_spvVersion = 0x10000;
bool m_useDemoteToHelperInvocationExtension = false;
+ SpvMemoryModel m_memoryModel = SpvMemoryModelGLSL450;
+
bool isSpirv14OrLater() { return m_spvVersion >= 0x10400; }
bool isSpirv15OrLater() { return m_spvVersion >= 0x10500; }
bool isSpirv16OrLater() { return m_spvVersion >= 0x10600; }