Skip to content

Commit f836555

Browse files
[spirv] Add Vk::RawBufferLoad intrinsic (#4069)
* Only support raw buffer (i.e. HLSL ByteAddressBuffer) style loads of single uint-s * Always use 4 byte alignment for loads (same as HLSL ByteAddressBuffer) * Add PhysicalStorageBufferAddresses capability and KHR_physical_storage_buffer extension when needed * Promote memory addressing model to PhysicalStorageBuffer64 when needed * Add custom alignment support to SpirvLoad * Add createUnaryOp() overload that takes SpirvType * Add getPhysicalStorageBufferType() * Add documentation and a test case for the new intrinsic
1 parent b780185 commit f836555

18 files changed

Lines changed: 206 additions & 5 deletions

docs/SPIR-V.rst

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3714,6 +3714,7 @@ implicit ``vk`` namepsace.
37143714
const uint QueueFamilyScope = 5;
37153715
37163716
uint64_t ReadClock(in uint scope);
3717+
uint RawBufferLoad(in uint64_t deviceAddress);
37173718
} // end namespace
37183719
37193720
@@ -3751,6 +3752,35 @@ For example:
37513752
37523753
uint64_t clock = vk::ReadClock(vk::SubgroupScope);
37533754
3755+
RawBufferLoad
3756+
~~~~~~~~~~~~~
3757+
This intrinsic funcion has the following signature:
3758+
3759+
.. code:: hlsl
3760+
3761+
uint RawBufferLoad(in uint64_t deviceAddress);
3762+
3763+
This exposes a subset of the `VK_KHR_buffer_device_address <https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_buffer_device_address.html>`_
3764+
and `SPV_KHR_physical_storage_buffer <https://github.com/KhronosGroup/SPIRV-Registry/blob/main/extensions/KHR/SPV_KHR_physical_storage_buffer.asciidoc>`_
3765+
functionality to HLSL.
3766+
3767+
It allows the shader program to load a single 32 bit value from a GPU
3768+
accessible memory at given address, similar to ``ByteAddressBuffer.Load()``.
3769+
Like ``ByteAddressBuffer``, this intrinsic requires a 4 byte aligned address.
3770+
3771+
Using this intrinsic adds ``PhysicalStorageBufferAddresses`` capability and
3772+
``SPV_KHR_physical_storage_buffer`` extension requirements as well as changing
3773+
the addressing model to ``PhysicalStorageBuffer64``.
3774+
3775+
Example:
3776+
3777+
.. code:: hlsl
3778+
3779+
uint64_t Address;
3780+
float4 main() : SV_Target0 {
3781+
uint Value = vk::RawBufferLoad(Address);
3782+
return asfloat(Value);
3783+
}
37543784
37553785
Supported Command-line Options
37563786
==============================

include/dxc/HlslIntrinsicOp.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,9 @@ enum class IntrinsicOp { IOP_AcceptHitAndEndSearch,
221221
IOP_unpack_s8s32,
222222
IOP_unpack_u8u16,
223223
IOP_unpack_u8u32,
224+
#ifdef ENABLE_SPIRV_CODEGEN
225+
IOP_VkRawBufferLoad,
226+
#endif // ENABLE_SPIRV_CODEGEN
224227
#ifdef ENABLE_SPIRV_CODEGEN
225228
IOP_VkReadClock,
226229
#endif // ENABLE_SPIRV_CODEGEN

lib/HLSL/HLOperationLower.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5661,6 +5661,7 @@ IntrinsicLower gLowerTable[] = {
56615661
{IntrinsicOp::IOP_unpack_u8u32, TranslateUnpack, DXIL::OpCode::Unpack4x8},
56625662
#ifdef ENABLE_SPIRV_CODEGEN
56635663
{ IntrinsicOp::IOP_VkReadClock, UnsupportedVulkanIntrinsic, DXIL::OpCode::NumOpCodes },
5664+
{ IntrinsicOp::IOP_VkRawBufferLoad, UnsupportedVulkanIntrinsic, DXIL::OpCode::NumOpCodes },
56645665
#endif // ENABLE_SPIRV_CODEGEN
56655666
{IntrinsicOp::MOP_Append, StreamOutputLower, DXIL::OpCode::EmitStream},
56665667
{IntrinsicOp::MOP_RestartStrip, StreamOutputLower, DXIL::OpCode::CutStream},

tools/clang/include/clang/SPIRV/FeatureManager.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ enum class Extension {
5252
NV_mesh_shader,
5353
KHR_ray_query,
5454
EXT_shader_image_int64,
55+
KHR_physical_storage_buffer,
5556
Unknown,
5657
};
5758

tools/clang/include/clang/SPIRV/SpirvBuilder.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,8 @@ class SpirvBuilder {
212212
/// the instruction pointer for the result.
213213
SpirvUnaryOp *createUnaryOp(spv::Op op, QualType resultType,
214214
SpirvInstruction *operand, SourceLocation loc);
215+
SpirvUnaryOp *createUnaryOp(spv::Op op, const SpirvType *resultType,
216+
SpirvInstruction *operand, SourceLocation loc);
215217

216218
/// \brief Creates a binary operation with the given SPIR-V opcode. Returns
217219
/// the instruction pointer for the result.
@@ -689,6 +691,10 @@ class SpirvBuilder {
689691

690692
SpirvString *getString(llvm::StringRef str);
691693

694+
const HybridPointerType *getPhysicalStorageBufferType(QualType pointee);
695+
const SpirvPointerType *
696+
getPhysicalStorageBufferType(const SpirvType *pointee);
697+
692698
public:
693699
std::vector<uint32_t> takeModule();
694700

@@ -793,8 +799,14 @@ class SpirvBuilder {
793799

794800
void SpirvBuilder::requireCapability(spv::Capability cap, SourceLocation loc) {
795801
auto *capability = new (context) SpirvCapability(loc, cap);
796-
if (!mod->addCapability(capability))
802+
if (mod->addCapability(capability)) {
803+
if (cap == spv::Capability::PhysicalStorageBufferAddresses) {
804+
mod->promoteAddressingModel(
805+
spv::AddressingModel::PhysicalStorageBuffer64);
806+
}
807+
} else {
797808
capability->releaseMemory();
809+
}
798810
}
799811

800812
void SpirvBuilder::requireExtension(llvm::StringRef ext, SourceLocation loc) {

tools/clang/include/clang/SPIRV/SpirvInstruction.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,9 @@ class SpirvMemoryModel : public SpirvInstruction {
332332

333333
spv::AddressingModel getAddressingModel() const { return addressModel; }
334334
spv::MemoryModel getMemoryModel() const { return memoryModel; }
335+
void setAddressingModel(spv::AddressingModel addrModel) {
336+
addressModel = addrModel;
337+
}
335338

336339
private:
337340
spv::AddressingModel addressModel;
@@ -1669,9 +1672,14 @@ class SpirvLoad : public SpirvInstruction {
16691672
return memoryAccess.getValue();
16701673
}
16711674

1675+
void setAlignment(uint32_t alignment);
1676+
bool hasAlignment() const { return memoryAlignment.hasValue(); }
1677+
uint32_t getAlignment() const { return memoryAlignment.getValue(); }
1678+
16721679
private:
16731680
SpirvInstruction *pointer;
16741681
llvm::Optional<spv::MemoryAccessMask> memoryAccess;
1682+
llvm::Optional<uint32_t> memoryAlignment;
16751683
};
16761684

16771685
/// \brief OpCopyObject instruction
@@ -1869,6 +1877,9 @@ class SpirvUnaryOp : public SpirvInstruction {
18691877
SpirvUnaryOp(spv::Op opcode, QualType resultType, SourceLocation loc,
18701878
SpirvInstruction *op);
18711879

1880+
SpirvUnaryOp(spv::Op opcode, const SpirvType *resultType, SourceLocation loc,
1881+
SpirvInstruction *op);
1882+
18721883
DEFINE_RELEASE_MEMORY_FOR_CLASS(SpirvUnaryOp)
18731884

18741885
// For LLVM-style RTTI

tools/clang/include/clang/SPIRV/SpirvModule.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ class SpirvModule {
105105
// Set the memory model of the module.
106106
void setMemoryModel(SpirvMemoryModel *model);
107107

108+
// Increases addressing model requirement for the module:
109+
// Logical -> Physical32 -> Physical64 -> PhysicalStorageBuffer64.
110+
// Requires setMemoryModel() to be called first to set the base memory model.
111+
// Returns true if addressing model was changed.
112+
bool promoteAddressingModel(spv::AddressingModel addrModel);
113+
108114
// Add an entry point to the module.
109115
void addEntryPoint(SpirvEntryPoint *);
110116

tools/clang/lib/SPIRV/CapabilityVisitor.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,11 @@ void CapabilityVisitor::addCapabilityForType(const SpirvType *type,
189189
// Pointer type
190190
else if (const auto *ptrType = dyn_cast<SpirvPointerType>(type)) {
191191
addCapabilityForType(ptrType->getPointeeType(), loc, sc);
192+
if (sc == spv::StorageClass::PhysicalStorageBuffer) {
193+
addExtension(Extension::KHR_physical_storage_buffer,
194+
"SPV_KHR_physical_storage_buffer", loc);
195+
addCapability(spv::Capability::PhysicalStorageBufferAddresses);
196+
}
192197
}
193198
// Struct type
194199
else if (const auto *structType = dyn_cast<StructType>(type)) {
@@ -525,8 +530,7 @@ bool CapabilityVisitor::visitInstruction(SpirvInstruction *instr) {
525530
case spv::Op::OpRayQueryInitializeKHR: {
526531
auto rayQueryInst = dyn_cast<SpirvRayQueryOpKHR>(instr);
527532
if (rayQueryInst->hasCullFlags()) {
528-
addCapability(
529-
spv::Capability::RayTraversalPrimitiveCullingKHR);
533+
addCapability(spv::Capability::RayTraversalPrimitiveCullingKHR);
530534
}
531535

532536
break;
@@ -581,6 +585,7 @@ bool CapabilityVisitor::visit(SpirvEntryPoint *entryPoint) {
581585
llvm_unreachable("found unknown shader model");
582586
break;
583587
}
588+
584589
return true;
585590
}
586591

tools/clang/lib/SPIRV/EmitVisitor.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,8 +1201,15 @@ bool EmitVisitor::visit(SpirvLoad *inst) {
12011201
curInst.push_back(inst->getResultTypeId());
12021202
curInst.push_back(getOrAssignResultId<SpirvInstruction>(inst));
12031203
curInst.push_back(getOrAssignResultId<SpirvInstruction>(inst->getPointer()));
1204-
if (inst->hasMemoryAccessSemantics())
1205-
curInst.push_back(static_cast<uint32_t>(inst->getMemoryAccess()));
1204+
if (inst->hasMemoryAccessSemantics()) {
1205+
spv::MemoryAccessMask memoryAccess = inst->getMemoryAccess();
1206+
curInst.push_back(static_cast<uint32_t>(memoryAccess));
1207+
if (inst->hasAlignment()) {
1208+
assert(static_cast<uint32_t>(memoryAccess) &
1209+
static_cast<uint32_t>(spv::MemoryAccessMask::Aligned));
1210+
curInst.push_back(inst->getAlignment());
1211+
}
1212+
}
12061213
finalizeInstruction(&mainBinary);
12071214
emitDebugNameForInstruction(getOrAssignResultId<SpirvInstruction>(inst),
12081215
inst->getDebugName());

tools/clang/lib/SPIRV/FeatureManager.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ Extension FeatureManager::getExtensionSymbol(llvm::StringRef name) {
143143
.Case("SPV_KHR_fragment_shading_rate",
144144
Extension::KHR_fragment_shading_rate)
145145
.Case("SPV_EXT_shader_image_int64", Extension::EXT_shader_image_int64)
146+
.Case("SPV_KHR_physical_storage_buffer",
147+
Extension::KHR_physical_storage_buffer)
146148
.Default(Extension::Unknown);
147149
}
148150

@@ -196,6 +198,8 @@ const char *FeatureManager::getExtensionName(Extension symbol) {
196198
return "SPV_KHR_fragment_shading_rate";
197199
case Extension::EXT_shader_image_int64:
198200
return "SPV_EXT_shader_image_int64";
201+
case Extension::KHR_physical_storage_buffer:
202+
return "SPV_KHR_physical_storage_buffer";
199203
default:
200204
break;
201205
}

0 commit comments

Comments
 (0)