[clang] [llvm] [SPIRV] Implement spv_resource_getbasepointer for Vulkan buffers (PR #195152)
Steven Perron via cfe-commits
cfe-commits at lists.llvm.org
Wed May 6 06:17:17 PDT 2026
https://github.com/s-perron updated https://github.com/llvm/llvm-project/pull/195152
>From e9a060b390e43adae9dd2ad491379647b148af96 Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at google.com>
Date: Wed, 8 Apr 2026 15:00:16 -0400
Subject: [PATCH 1/2] [HLSL] Allow __builtin_hlsl_resource_getpointer to take
no indices
In preperation for adding ConstnatBuffer<T>, we will need to be able to
access the base pointer for the data constat buffer resource handle is pointingto
to. This is done by:
1. Making the index operand in __builtin_hlsl_resource_getpointer
optional.
2. Modifing the codegen for __builtin_hlsl_resource_getpointer to emit a
call to resource.getbasepointer when no index is provided.
3. Add the resource.getbasepointer for the dx and spv targets.
Another issue is that the address space for the pointer returned by
__builtin_hlsl_resource_getpointer is not always hlsl_device any more.
Changes are made to get the correct address space based on the resource
class of the handle.
Note that we cannot implement codegen for
__builtin_hlsl_resource_getpointer directly. The tests for the codegen
changes will be in a follow up PR that add ConstnatBuffer<T>.
Assisted-by: Gemini
---
clang/lib/CodeGen/CGHLSLBuiltins.cpp | 14 +++++++--
clang/lib/CodeGen/CGHLSLRuntime.h | 2 ++
clang/lib/Sema/SemaHLSL.cpp | 30 ++++++++++++++-----
.../BuiltIns/resource_getpointer-errors.hlsl | 10 +++----
llvm/include/llvm/IR/IntrinsicsDirectX.td | 4 +++
llvm/include/llvm/IR/IntrinsicsSPIRV.td | 4 +++
6 files changed, 49 insertions(+), 15 deletions(-)
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index b82a237ecefca..82b03d7d5f069 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -571,12 +571,20 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
case Builtin::BI__builtin_hlsl_resource_getpointer:
case Builtin::BI__builtin_hlsl_resource_getpointer_typed: {
Value *HandleOp = EmitScalarExpr(E->getArg(0));
- Value *IndexOp = EmitScalarExpr(E->getArg(1));
+ bool IsIndexed =
+ BuiltinID == Builtin::BI__builtin_hlsl_resource_getpointer_typed ||
+ E->getNumArgs() > 1;
llvm::Type *RetTy = ConvertType(E->getType());
+ if (IsIndexed) {
+ Value *IndexOp = EmitScalarExpr(E->getArg(1));
+ return Builder.CreateIntrinsic(
+ RetTy, CGM.getHLSLRuntime().getCreateResourceGetPointerIntrinsic(),
+ ArrayRef<Value *>{HandleOp, IndexOp});
+ }
return Builder.CreateIntrinsic(
- RetTy, CGM.getHLSLRuntime().getCreateResourceGetPointerIntrinsic(),
- ArrayRef<Value *>{HandleOp, IndexOp});
+ RetTy, CGM.getHLSLRuntime().getCreateResourceGetBasePointerIntrinsic(),
+ ArrayRef<Value *>{HandleOp});
}
case Builtin::BI__builtin_hlsl_resource_sample: {
Value *HandleOp = EmitScalarExpr(E->getArg(0));
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index b54cbab906056..d7ac2346f2428 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -167,6 +167,8 @@ class CGHLSLRuntime {
GENERATE_HLSL_INTRINSIC_FUNCTION(SClamp, sclamp)
GENERATE_HLSL_INTRINSIC_FUNCTION(UClamp, uclamp)
+ GENERATE_HLSL_INTRINSIC_FUNCTION(CreateResourceGetBasePointer,
+ resource_getbasepointer)
GENERATE_HLSL_INTRINSIC_FUNCTION(CreateResourceGetPointer,
resource_getpointer)
GENERATE_HLSL_INTRINSIC_FUNCTION(Sample, resource_sample)
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index aba1c5072a5fc..7788d777edf1c 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -77,6 +77,19 @@ static RegisterType getRegisterType(const HLSLAttributedResourceType *ResTy) {
return getRegisterType(ResTy->getAttrs().ResourceClass);
}
+static LangAS getLangASFromResourceClass(ResourceClass RC) {
+ switch (RC) {
+ case ResourceClass::SRV:
+ case ResourceClass::UAV:
+ return LangAS::hlsl_device;
+ case ResourceClass::CBuffer:
+ return LangAS::hlsl_constant;
+ case ResourceClass::Sampler:
+ return LangAS::hlsl_device;
+ }
+ llvm_unreachable("unexpected ResourceClass value");
+}
+
// Converts the first letter of string Slot to RegisterType.
// Returns false if the letter does not correspond to a valid register type.
static bool convertToRegisterType(StringRef Slot, RegisterType *RT) {
@@ -3891,19 +3904,19 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
break;
}
case Builtin::BI__builtin_hlsl_resource_getpointer: {
- if (SemaRef.checkArgCount(TheCall, 2) ||
+ if (SemaRef.checkArgCountRange(TheCall, 1, 2) ||
CheckResourceHandle(&SemaRef, TheCall, 0) ||
- CheckIndexType(&SemaRef, TheCall, 1))
+ (TheCall->getNumArgs() == 2 && CheckIndexType(&SemaRef, TheCall, 1)))
return true;
auto *ResourceTy =
TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
QualType ContainedTy = ResourceTy->getContainedType();
- auto ReturnType =
- SemaRef.Context.getAddrSpaceQualType(ContainedTy, LangAS::hlsl_device);
+ auto ReturnType = SemaRef.Context.getAddrSpaceQualType(
+ ContainedTy,
+ getLangASFromResourceClass(ResourceTy->getAttrs().ResourceClass));
ReturnType = SemaRef.Context.getPointerType(ReturnType);
TheCall->setType(ReturnType);
- TheCall->setValueKind(VK_LValue);
break;
}
@@ -3924,8 +3937,11 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
cast<FunctionDecl>(SemaRef.CurContext)->getPointOfInstantiation(),
diag::err_invalid_use_of_array_type);
- auto ReturnType =
- SemaRef.Context.getAddrSpaceQualType(ElementTy, LangAS::hlsl_device);
+ auto *ResourceTy =
+ TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
+ auto ReturnType = SemaRef.Context.getAddrSpaceQualType(
+ ElementTy,
+ getLangASFromResourceClass(ResourceTy->getAttrs().ResourceClass));
ReturnType = SemaRef.Context.getPointerType(ReturnType);
TheCall->setType(ReturnType);
diff --git a/clang/test/SemaHLSL/BuiltIns/resource_getpointer-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/resource_getpointer-errors.hlsl
index 20de0773a1742..7dde4dcf6c149 100644
--- a/clang/test/SemaHLSL/BuiltIns/resource_getpointer-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/resource_getpointer-errors.hlsl
@@ -5,17 +5,17 @@ using handle_t = __hlsl_resource_t
[[hlsl::resource_class(UAV)]] [[hlsl::contained_type(int)]];
void test_args(unsigned int x) {
- // expected-error at +1 {{too few arguments to function call, expected 2, have 1}}
+ // expected-error at +1 {{used type 'unsigned int' where __hlsl_resource_t is required}}
__builtin_hlsl_resource_getpointer(x);
- // expected-error at +1 {{too many arguments to function call, expected 2, have 3}}
+ // expected-error at +1 {{too many arguments to function call, expected at most 2, have 3}}
__builtin_hlsl_resource_getpointer(x, x, x);
- // expected-error at +1 {{used type 'unsigned int' where __hlsl_resource_t is required}}
- __builtin_hlsl_resource_getpointer(x, x);
-
handle_t res;
+ // no error
+ __builtin_hlsl_resource_getpointer(res);
+
// expected-error at +1 {{used type 'const char *' where integer is required}}
__builtin_hlsl_resource_getpointer(res, "1");
diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index f37180ce9084a..f55996234aea5 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -40,6 +40,10 @@ def int_dx_resource_getpointer
: DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty, llvm_any_ty],
[IntrReadMem, IntrInaccessibleMemOnly]>;
+def int_dx_resource_getbasepointer
+ : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty],
+ [IntrReadMem, IntrInaccessibleMemOnly]>;
+
def int_dx_resource_nonuniformindex
: DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_i32_ty], [IntrNoMem]>;
diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index 44e31a1410523..6157947ad2318 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -318,6 +318,10 @@ def int_spv_rsqrt : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty]
: DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty, llvm_any_ty],
[IntrNoMem]>;
+ def int_spv_resource_getbasepointer
+ : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty],
+ [IntrNoMem]>;
+
def int_spv_pushconstant_getpointer
: DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty], [IntrNoMem]>;
>From 1c1f1a5c185935682dbf87723723dcaafc741e8b Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at google.com>
Date: Wed, 29 Apr 2026 16:19:35 -0400
Subject: [PATCH 2/2] [SPIRV] Implement spv_resource_getbasepointer for Vulkan
buffers
The new intrinsic spv_resource_getbasepointer allows retrieving the base
pointer of a resource without an index. This is necessary for resources
like ConstantBuffer<T> where you can access the top level struct of type
T.
Assisted-by: Gemini
---
llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 19 ++++---
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 30 +++++++----
.../SPIRV/hlsl-resources/getbasepointer.ll | 54 +++++++++++++++++++
3 files changed, 86 insertions(+), 17 deletions(-)
create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-resources/getbasepointer.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
index 180a0f45874e1..cfded9596c094 100644
--- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp
@@ -411,6 +411,7 @@ bool isConvergenceIntrinsic(const Instruction *I) {
bool expectIgnoredInIRTranslation(const Instruction *I) {
return match(I, m_AnyIntrinsic<Intrinsic::invariant_start,
Intrinsic::spv_resource_handlefrombinding,
+ Intrinsic::spv_resource_getbasepointer,
Intrinsic::spv_resource_getpointer>());
}
@@ -1022,7 +1023,8 @@ Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
// TODO: maybe improve performance by caching demangled names
auto *II = dyn_cast<IntrinsicInst>(I);
- if (II && II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
+ if (II && (II->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
+ II->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
auto *HandleType = cast<TargetExtType>(II->getOperand(0)->getType());
if (HandleType->getTargetExtName() == "spirv.Image" ||
HandleType->getTargetExtName() == "spirv.SignedImage") {
@@ -1034,12 +1036,15 @@ Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
} else if (HandleType->getTargetExtName() == "spirv.VulkanBuffer") {
// This call is supposed to index into an array
Ty = HandleType->getTypeParameter(0);
- if (Ty->isArrayTy())
- Ty = Ty->getArrayElementType();
- else {
- assert(Ty && Ty->isStructTy());
- uint32_t Index = cast<ConstantInt>(II->getOperand(1))->getZExtValue();
- Ty = cast<StructType>(Ty)->getElementType(Index);
+ if (II->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
+ if (Ty->isArrayTy())
+ Ty = Ty->getArrayElementType();
+ else {
+ assert(Ty && Ty->isStructTy());
+ uint32_t Index =
+ cast<ConstantInt>(II->getOperand(1))->getZExtValue();
+ Ty = cast<StructType>(Ty)->getElementType(Index);
+ }
}
Ty = reconstitutePeeledArrayType(Ty);
} else {
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index aee3a29c6e42b..5b0204d5a2e8b 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -700,6 +700,7 @@ static bool intrinsicHasSideEffects(Intrinsic::ID ID) {
case Intrinsic::spv_radians:
case Intrinsic::spv_reflect:
case Intrinsic::spv_refract:
+ case Intrinsic::spv_resource_getbasepointer:
case Intrinsic::spv_resource_getpointer:
case Intrinsic::spv_resource_handlefrombinding:
case Intrinsic::spv_resource_handlefromimplicitbinding:
@@ -1887,7 +1888,9 @@ bool SPIRVInstructionSelector::selectLoad(Register ResVReg,
auto *PtrDef = getVRegDef(*MRI, Ptr);
auto *IntPtrDef = dyn_cast<GIntrinsic>(PtrDef);
if (IntPtrDef &&
- IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
+ (IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
+ IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
+
Register HandleReg = IntPtrDef->getOperand(2).getReg();
SPIRVTypeInst HandleType = GR.getSPIRVTypeForVReg(HandleReg);
if (HandleType->getOpcode() == SPIRV::OpTypeImage) {
@@ -1979,7 +1982,9 @@ bool SPIRVInstructionSelector::selectStore(MachineInstr &I) const {
auto *PtrDef = getVRegDef(*MRI, Ptr);
auto *IntPtrDef = dyn_cast<GIntrinsic>(PtrDef);
if (IntPtrDef &&
- IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getpointer) {
+ (IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getbasepointer ||
+ IntPtrDef->getIntrinsicID() == Intrinsic::spv_resource_getpointer)) {
+
Register HandleReg = IntPtrDef->getOperand(2).getReg();
Register NewHandleReg =
MRI->createVirtualRegister(MRI->getRegClass(HandleReg));
@@ -5094,6 +5099,7 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
case Intrinsic::spv_resource_gather:
case Intrinsic::spv_resource_gather_cmp:
return selectGatherIntrinsic(ResVReg, ResType, I);
+ case Intrinsic::spv_resource_getbasepointer:
case Intrinsic::spv_resource_getpointer: {
return selectResourceGetPointer(ResVReg, ResType, I);
}
@@ -5890,16 +5896,20 @@ bool SPIRVInstructionSelector::selectResourceGetPointer(Register &ResVReg,
assert(ResType->getOpcode() == SPIRV::OpTypePointer);
MachineIRBuilder MIRBuilder(I);
- Register IndexReg = I.getOperand(3).getReg();
Register ZeroReg =
buildZerosVal(GR.getOrCreateSPIRVIntegerType(32, I, TII), I);
- BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpAccessChain))
- .addDef(ResVReg)
- .addUse(GR.getSPIRVTypeID(ResType))
- .addUse(ResourcePtr)
- .addUse(ZeroReg)
- .addUse(IndexReg)
- .constrainAllUses(TII, TRI, RBI);
+ auto MIB =
+ BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpAccessChain))
+ .addDef(ResVReg)
+ .addUse(GR.getSPIRVTypeID(ResType))
+ .addUse(ResourcePtr)
+ .addUse(ZeroReg);
+
+ if (I.getNumExplicitOperands() > 3) {
+ Register IndexReg = I.getOperand(3).getReg();
+ MIB.addUse(IndexReg);
+ }
+ MIB.constrainAllUses(TII, TRI, RBI);
return true;
}
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-resources/getbasepointer.ll b/llvm/test/CodeGen/SPIRV/hlsl-resources/getbasepointer.ll
new file mode 100644
index 0000000000000..aefeea0981871
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-resources/getbasepointer.ll
@@ -0,0 +1,54 @@
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv1.6-vulkan1.3-library %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv1.6-vulkan1.3-library %s -o - -filetype=obj | spirv-val %}
+
+target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64-G1"
+
+ at .str.1 = private unnamed_addr constant [2 x i8] c"B\00", align 1
+ at .str.2 = private unnamed_addr constant [2 x i8] c"S\00", align 1
+
+; CHECK-DAG: [[int:%[0-9]+]] = OpTypeInt 32 0
+; CHECK-DAG: [[zero:%[0-9]+]] = OpConstant [[int]] 0
+
+; CHECK-DAG: [[ArrayType:%.+]] = OpTypeRuntimeArray [[int]]
+; CHECK-DAG: [[BufferType:%.+]] = OpTypeStruct [[ArrayType]]
+; CHECK-DAG: [[BufferPtrType:%.+]] = OpTypePointer StorageBuffer [[BufferType]]
+; CHECK-DAG: [[BufferVar:%.+]] = OpVariable [[BufferPtrType]] StorageBuffer
+
+; CHECK-DAG: [[StructType:%.+]] = OpTypeStruct [[int]] [[int]]
+; CHECK-DAG: [[StructWrapper:%.+]] = OpTypeStruct [[StructType]]
+; CHECK-DAG: [[StructPtrType:%.+]] = OpTypePointer StorageBuffer [[StructWrapper]]
+; CHECK-DAG: [[StructVar:%.+]] = OpVariable [[StructPtrType]] StorageBuffer
+
+define i32 @main() local_unnamed_addr {
+entry:
+; CHECK-DAG: [[BufferHandle:%.+]] = OpCopyObject [[BufferPtrType]] [[BufferVar]]
+; CHECK-DAG: [[StructHandle:%.+]] = OpCopyObject [[StructPtrType]] [[StructVar]]
+
+ %BufferHandle = tail call target("spirv.VulkanBuffer", [0 x i32], 12, 0) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer(i32 0, i32 1, i32 1, i32 0, ptr nonnull @.str.1)
+ %StructHandle = tail call target("spirv.VulkanBuffer", {i32, i32}, 12, 0) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBufferStruct(i32 0, i32 2, i32 1, i32 0, ptr nonnull @.str.2)
+
+; CHECK: [[AC2:%.+]] = OpAccessChain {{.*}} [[BufferHandle]] [[zero]]
+; CHECK-NOT: [[AC2]] = OpAccessChain {{.*}} [[BufferHandle]] [[zero]] %
+ %2 = tail call noundef nonnull align 4 dereferenceable(4) ptr addrspace(11) @llvm.spv.resource.getbasepointer.p11.tspirv.VulkanBuffer(target("spirv.VulkanBuffer", [0 x i32], 12, 0) %BufferHandle)
+ %load2 = load i32, ptr addrspace(11) %2
+
+; CHECK: [[AC3:%.+]] = OpAccessChain {{.*}} [[BufferHandle]] [[zero]] [[index:%[0-9]+]]
+ %3 = tail call noundef nonnull align 4 dereferenceable(4) ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer(target("spirv.VulkanBuffer", [0 x i32], 12, 0) %BufferHandle, i32 42)
+ %load3 = load i32, ptr addrspace(11) %3
+
+; CHECK: [[AC4:%.+]] = OpAccessChain {{.*}} [[StructHandle]] [[zero]]
+; CHECK-NOT: [[AC4]] = OpAccessChain {{.*}} [[StructHandle]] [[zero]] %
+ %4 = tail call noundef nonnull align 4 dereferenceable(4) ptr addrspace(11) @llvm.spv.resource.getbasepointer.p11.tspirv.VulkanBufferStruct(target("spirv.VulkanBuffer", {i32, i32}, 12, 0) %StructHandle)
+ %load4 = load i32, ptr addrspace(11) %4
+
+ %res1 = add i32 %load2, %load3
+ %res2 = add i32 %res1, %load4
+ ret i32 %res2
+}
+
+declare target("spirv.VulkanBuffer", [0 x i32], 12, 0) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer(i32, i32, i32, i32, ptr)
+declare target("spirv.VulkanBuffer", {i32, i32}, 12, 0) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBufferStruct(i32, i32, i32, i32, ptr)
+
+declare ptr addrspace(11) @llvm.spv.resource.getbasepointer.p11.tspirv.VulkanBuffer(target("spirv.VulkanBuffer", [0 x i32], 12, 0))
+declare ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer(target("spirv.VulkanBuffer", [0 x i32], 12, 0), i32)
+declare ptr addrspace(11) @llvm.spv.resource.getbasepointer.p11.tspirv.VulkanBufferStruct(target("spirv.VulkanBuffer", {i32, i32}, 12, 0))
More information about the cfe-commits
mailing list