Skip to content

Commit d6c0f78

Browse files
vmaksimojsji
authored andcommitted
Support subgroup block read/write builtins translation with untyped pointers (#3458)
`SPV_KHR_untyped_pointers` does not modify [`SPV_INTEL_subgroups`](https://github.khronos.org/SPIRV-Registry/extensions/INTEL/SPV_INTEL_subgroups.html) extension, meaning we should preserve typed logic for the pointers used in subgroup instructions (pointers are used only in `OpSubgroupBlockReadINTEL` and `OpSubgroupBlockWriteINTEL`). Original commit: KhronosGroup/SPIRV-LLVM-Translator@81d49784bc32658
1 parent fb37b05 commit d6c0f78

File tree

4 files changed

+154
-7
lines changed

4 files changed

+154
-7
lines changed

llvm-spirv/lib/SPIRV/SPIRVReader.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2415,13 +2415,18 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F,
24152415
BaseSPVTy->isTypeCooperativeMatrixKHR())) {
24162416
return mapValue(BV, transSPIRVBuiltinFromInst(AC, BB));
24172417
}
2418-
Type *BaseTy =
2419-
BaseSPVTy->isTypeVector()
2420-
? transType(
2421-
BaseSPVTy->getVectorComponentType()->getPointerElementType())
2422-
: BaseSPVTy->isTypePointer()
2423-
? transType(BaseSPVTy->getPointerElementType())
2424-
: transType(BaseSPVTy);
2418+
Type *BaseTy = nullptr;
2419+
if (BaseSPVTy->isTypeVector()) {
2420+
auto *VecCompTy = BaseSPVTy->getVectorComponentType();
2421+
if (VecCompTy->isTypePointer())
2422+
BaseTy = transType(VecCompTy->getPointerElementType());
2423+
else
2424+
BaseTy = transType(VecCompTy);
2425+
} else if (BaseSPVTy->isTypePointer()) {
2426+
BaseTy = transType(BaseSPVTy->getPointerElementType());
2427+
} else {
2428+
BaseTy = transType(BaseSPVTy);
2429+
}
24252430
auto Index = transValue(AC->getIndices(), F, BB);
24262431
if (!AC->hasPtrIndex())
24272432
Index.insert(Index.begin(), getInt32(M, 0));

llvm-spirv/lib/SPIRV/SPIRVWriter.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7181,6 +7181,18 @@ LLVMToSPIRVBase::transBuiltinToInstWithoutDecoration(Op OC, CallInst *CI,
71817181
return BM->addBinaryInst(OC, transScavengedType(CI),
71827182
transValue(CI->getArgOperand(0), BB),
71837183
transValue(CI->getArgOperand(1), BB), BB);
7184+
} else if (OC == OpSubgroupBlockReadINTEL) {
7185+
SPIRVType *RetTy = transScavengedType(CI);
7186+
SPIRVValue *Ptr = transValue(CI->getArgOperand(0), BB);
7187+
7188+
if (Ptr->getType()->getPointerElementType() != RetTy &&
7189+
Ptr->getType()->getPointerElementType()->isTypeUntypedPointerKHR()) {
7190+
// Bitcast untyped pointer to typed pointer.
7191+
SPIRVType *ExpectedType = BM->addPointerType(
7192+
Ptr->getType()->getPointerStorageClass(), RetTy->getScalarType());
7193+
Ptr = BM->addUnaryInst(OpBitcast, ExpectedType, Ptr, BB);
7194+
}
7195+
return BM->addUnaryInst(OC, RetTy, Ptr, BB);
71847196
} else if (CI->arg_size() == 1 && !CI->getType()->isVoidTy() &&
71857197
!hasExecScope(OC) && !isAtomicOpCode(OC)) {
71867198
return BM->addUnaryInst(OC, transScavengedType(CI),
@@ -7232,6 +7244,22 @@ LLVMToSPIRVBase::transBuiltinToInstWithoutDecoration(Op OC, CallInst *CI,
72327244
SPArgs.push_back(cast<ConstantInt>(Args[I])->getZExtValue());
72337245
}
72347246
}
7247+
if (OC == OpSubgroupBlockWriteINTEL) {
7248+
// First argument should be a pointer to the same scalar type as the
7249+
// second argument's component type is. Do the bitcast if the pointer is
7250+
// untyped.
7251+
if (BM->getValue(SPArgs[0])->getType()->isTypeUntypedPointerKHR()) {
7252+
// TODO: rewrite vector of IDs to vector of values?
7253+
SPIRVType *ScalarTy =
7254+
BM->getValue(SPArgs[1])->getType()->getScalarType();
7255+
SPIRVType *NewPtrTy = BM->addPointerType(
7256+
BM->getValue(SPArgs[0])->getType()->getPointerStorageClass(),
7257+
ScalarTy);
7258+
SPIRVValue *NewPtr = BM->addUnaryInst(OpBitcast, NewPtrTy,
7259+
BM->getValue(SPArgs[0]), BB);
7260+
SPArgs[0] = NewPtr->getId();
7261+
}
7262+
}
72357263
BM->addInstTemplate(SPI, SPArgs, BB, SPRetTy);
72367264
if (!SPRetTy || !SPRetTy->isTypeStruct())
72377265
return SPI;

llvm-spirv/test/extensions/INTEL/SPV_INTEL_subgroups/cl_intel_sub_groups.ll

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@
5252
; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM-SPIRV
5353
; RUN: llvm-spirv %t.rev.bc -o - -spirv-text --spirv-ext=+SPV_INTEL_subgroups | FileCheck %s --check-prefix=CHECK-SPIRV
5454

55+
; Verify the mangling works correctly with the untyped pointers enabled.
56+
; RUN: llvm-spirv %s -o %t.spv --spirv-ext=+SPV_INTEL_subgroups,+SPV_KHR_untyped_pointers
57+
; RUN: llvm-spirv -r %t.spv -o %t.rev.bc
58+
; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM-UNTYPED
59+
; RUN: llvm-spirv -r %t.spv -o %t.rev.bc --spirv-target-env=SPV-IR
60+
; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM-SPIRV
61+
5562
; CHECK-SPIRV: Capability SubgroupShuffleINTEL
5663
; CHECK-SPIRV: Capability SubgroupBufferBlockIOINTEL
5764
; CHECK-SPIRV: Capability SubgroupImageBlockIOINTEL
@@ -138,6 +145,36 @@ define spir_kernel void @test(<2 x float> %x, i32 %c, ptr addrspace(1) %image_in
138145
; CHECK-LLVM-NEXT: call spir_func void @_Z32intel_sub_group_block_write_us16PU3AS1tDv16_t(ptr addrspace(1) [[SP]], <16 x i16> [[CALL15]])
139146
; CHECK-LLVM-NEXT: ret void
140147

148+
; The checks are the same as above, just skipping function parameters name check (because bitcasts in between instructions are involved).
149+
; CHECK-LLVM-UNTYPED: call spir_func <2 x float> @_Z23intel_sub_group_shuffleDv2_fj(<2 x float> [[X:%.*]], i32 [[C:%.*]])
150+
; CHECK-LLVM-UNTYPED: call spir_func <2 x float> @_Z28intel_sub_group_shuffle_downDv2_fS_j(<2 x float> [[X]], <2 x float> [[X]], i32 [[C]])
151+
; CHECK-LLVM-UNTYPED: call spir_func <2 x float> @_Z26intel_sub_group_shuffle_upDv2_fS_j(<2 x float> [[X]], <2 x float> [[X]], i32 [[C]])
152+
; CHECK-LLVM-UNTYPED: call spir_func <2 x float> @_Z27intel_sub_group_shuffle_xorDv2_fj(<2 x float> [[X]], i32 [[C]])
153+
; CHECK-LLVM-UNTYPED: call spir_func <2 x i32> @_Z27intel_sub_group_block_read214ocl_image2d_roDv2_i(target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 0) [[IMAGE_IN:%.*]], <2 x i32> [[COORD:%.*]])
154+
; CHECK-LLVM-UNTYPED: call spir_func void @_Z28intel_sub_group_block_write214ocl_image2d_woDv2_iDv2_j(target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 1) [[IMAGE_OUT:%.*]], <2 x i32> [[COORD]], <2 x i32> {{%.*}})
155+
; CHECK-LLVM-UNTYPED: call spir_func <2 x i32> @_Z27intel_sub_group_block_read2PU3AS1Kj(ptr addrspace(1) {{%.*}})
156+
; CHECK-LLVM-UNTYPED: call spir_func void @_Z28intel_sub_group_block_write2PU3AS1jDv2_j(ptr addrspace(1) {{%.*}}, <2 x i32> {{%.*}})
157+
; CHECK-LLVM-UNTYPED: call spir_func <2 x i16> @_Z30intel_sub_group_block_read_us214ocl_image2d_roDv2_i(target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 0) [[IMAGE_IN]], <2 x i32> [[COORD]])
158+
; CHECK-LLVM-UNTYPED: call spir_func void @_Z31intel_sub_group_block_write_us214ocl_image2d_woDv2_iDv2_t(target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 1) [[IMAGE_OUT]], <2 x i32> [[COORD]], <2 x i16> {{%.*}})
159+
; CHECK-LLVM-UNTYPED: call spir_func <2 x i16> @_Z30intel_sub_group_block_read_us2PU3AS1Kt(ptr addrspace(1) {{%.*}})
160+
; CHECK-LLVM-UNTYPED: call spir_func void @_Z31intel_sub_group_block_write_us2PU3AS1tDv2_t(ptr addrspace(1) {{%.*}}, <2 x i16> {{%.*}})
161+
; CHECK-LLVM-UNTYPED: call spir_func <2 x i8> @_Z30intel_sub_group_block_read_uc214ocl_image2d_roDv2_i(target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 0) [[IMAGE_IN]], <2 x i32> [[COORD]])
162+
; CHECK-LLVM-UNTYPED: call spir_func void @_Z31intel_sub_group_block_write_uc214ocl_image2d_woDv2_iDv2_h(target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 1) [[IMAGE_OUT]], <2 x i32> [[COORD]], <2 x i8> {{%.*}})
163+
; CHECK-LLVM-UNTYPED: call spir_func <2 x i8> @_Z30intel_sub_group_block_read_uc2PU3AS1Kh(ptr addrspace(1) {{%.*}})
164+
; CHECK-LLVM-UNTYPED: call spir_func void @_Z31intel_sub_group_block_write_uc2PU3AS1hDv2_h(ptr addrspace(1) {{%.*}}, <2 x i8> {{%.*}})
165+
; CHECK-LLVM-UNTYPED: call spir_func <2 x i64> @_Z30intel_sub_group_block_read_ul214ocl_image2d_roDv2_i(target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 0) [[IMAGE_IN]], <2 x i32> [[COORD]])
166+
; CHECK-LLVM-UNTYPED: call spir_func void @_Z31intel_sub_group_block_write_ul214ocl_image2d_woDv2_iDv2_m(target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 1) [[IMAGE_OUT]], <2 x i32> [[COORD]], <2 x i64> {{%.*}})
167+
; CHECK-LLVM-UNTYPED: call spir_func <2 x i64> @_Z30intel_sub_group_block_read_ul2PU3AS1Km(ptr addrspace(1) {{%.*}})
168+
; CHECK-LLVM-UNTYPED: call spir_func void @_Z31intel_sub_group_block_write_ul2PU3AS1mDv2_m(ptr addrspace(1) {{%.*}}, <2 x i64> {{%.*}})
169+
; CHECK-LLVM-UNTYPED: call spir_func <16 x i8> @_Z31intel_sub_group_block_read_uc1614ocl_image2d_roDv2_i(target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 0) [[IMAGE_IN]], <2 x i32> [[COORD]])
170+
; CHECK-LLVM-UNTYPED: call spir_func void @_Z32intel_sub_group_block_write_uc1614ocl_image2d_woDv2_iDv16_h(target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 1) [[IMAGE_OUT]], <2 x i32> [[COORD]], <16 x i8> {{%.*}})
171+
; CHECK-LLVM-UNTYPED: call spir_func <16 x i8> @_Z31intel_sub_group_block_read_uc16PU3AS1Kh(ptr addrspace(1) {{%.*}})
172+
; CHECK-LLVM-UNTYPED: call spir_func void @_Z32intel_sub_group_block_write_uc16PU3AS1hDv16_h(ptr addrspace(1) {{%.*}}, <16 x i8> {{%.*}})
173+
; CHECK-LLVM-UNTYPED: call spir_func <16 x i16> @_Z31intel_sub_group_block_read_us1614ocl_image2d_roDv2_i(target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 0) [[IMAGE_IN]], <2 x i32> [[COORD]])
174+
; CHECK-LLVM-UNTYPED: call spir_func void @_Z32intel_sub_group_block_write_us1614ocl_image2d_woDv2_iDv16_t(target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 1) [[IMAGE_OUT]], <2 x i32> [[COORD]], <16 x i16> {{%.*}})
175+
; CHECK-LLVM-UNTYPED: call spir_func <16 x i16> @_Z31intel_sub_group_block_read_us16PU3AS1Kt(ptr addrspace(1) {{%.*}})
176+
; CHECK-LLVM-UNTYPED: call spir_func void @_Z32intel_sub_group_block_write_us16PU3AS1tDv16_t(ptr addrspace(1) {{%.*}}, <16 x i16> {{%.*}})
177+
141178
; CHECK-LLVM-SPIRV: call spir_func <2 x float> @_Z28__spirv_SubgroupShuffleINTELDv2_fj(
142179
; CHECK-LLVM-SPIRV: call spir_func <2 x float> @_Z32__spirv_SubgroupShuffleDownINTELDv2_fS_j(
143180
; CHECK-LLVM-SPIRV: call spir_func <2 x float> @_Z30__spirv_SubgroupShuffleUpINTELDv2_fS_j(
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
; This test checks the translation of SPV_INTEL_subgroups extension with the SPV_KHR_untyped_pointers extension.
2+
; It verifies instructions validity and mangling even if the pointer is fortified with other instructions like bitcast and addrspacecast.
3+
4+
; RUN: llvm-spirv %s -o %t.spt -spirv-text --spirv-ext=+SPV_INTEL_subgroups,+SPV_KHR_untyped_pointers
5+
; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
6+
; RUN: llvm-spirv %s -o %t.spv --spirv-ext=+SPV_INTEL_subgroups,+SPV_KHR_untyped_pointers
7+
; RUN: spirv-val %t.spv
8+
; RUN: llvm-spirv -r %t.spv -o %t.rev.bc
9+
; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM
10+
; RUN: llvm-spirv -r %t.spv -o %t.rev.bc --spirv-target-env=SPV-IR
11+
; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM-SPIRV
12+
13+
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
14+
target triple = "spir64"
15+
16+
; CHECK-SPIRV: Capability SubgroupBufferBlockIOINTEL
17+
; CHECK-SPIRV: Extension "SPV_INTEL_subgroups"
18+
19+
; CHECK-SPIRV: TypeInt [[#Int32:]] 32 0
20+
; CHECK-SPIRV-DAG: TypeVector [[#IntVec2:]] [[#Int32]] 2
21+
; CHECK-SPIRV-DAG: TypeUntypedPointerKHR [[#PtrTy:]] 5
22+
; CHECK-SPIRV-DAG: TypePointer [[#Int32Ptr:]] 5 [[#Int32]]
23+
24+
; CHECK-SPIRV: Function
25+
; CHECK-SPIRV: FunctionParameter [[#PtrTy]] [[#ParamPtr:]]
26+
27+
; CHECK-SPIRV: Bitcast [[#Int32Ptr]] [[#TypedPtr:]] [[#]]
28+
; CHECK-SPIRV: SubgroupBlockReadINTEL [[#IntVec2]] [[#Res:]] [[#TypedPtr]]
29+
; CHECK-SPIRV: Bitcast [[#Int32Ptr]] [[#TypedPtr:]] [[#ParamPtr]]
30+
; CHECK-SPIRV: SubgroupBlockWriteINTEL [[#TypedPtr]] [[#Res]]
31+
32+
; CHECK-SPIRV: SubgroupBlockReadINTEL
33+
; CHECK-SPIRV: SubgroupBlockWriteINTEL
34+
35+
; CHECK-LLVM: %[[#IntVec:]] = call spir_func <2 x i32> @_Z27intel_sub_group_block_read2PU3AS1Kj(ptr addrspace(1) %[[#]])
36+
; CHECK-LLVM: %[[#P:]] = bitcast ptr addrspace(1) %p0 to ptr addrspace(1)
37+
; CHECK-LLVM: call spir_func void @_Z28intel_sub_group_block_write2PU3AS1jDv2_j(ptr addrspace(1) %[[#P]], <2 x i32> %[[#IntVec]])
38+
39+
; CHECK-LLVM: %[[#CP:]] = bitcast ptr addrspace(1) %p1 to ptr addrspace(1)
40+
; CHECK-LLVM: %[[#CharVec:]] = call spir_func <16 x i8> @_Z31intel_sub_group_block_read_uc16PU3AS1Kh(ptr addrspace(1) %[[#CP]])
41+
; CHECK-LLVM: %[[#CP1:]] = bitcast ptr addrspace(1) %p1 to ptr addrspace(1)
42+
; CHECK-LLVM: call spir_func void @_Z32intel_sub_group_block_write_uc16PU3AS1hDv16_h(ptr addrspace(1) %[[#CP1]], <16 x i8> %[[#CharVec]])
43+
44+
; CHECK-LLVM-SPIRV: call spir_func <2 x i32> @_Z36__spirv_SubgroupBlockReadINTEL_Rint2PU3AS1Kj(
45+
; CHECK-LLVM-SPIRV: call spir_func void @_Z31__spirv_SubgroupBlockWriteINTELPU3AS1jDv2_j(
46+
; CHECK-LLVM-SPIRV: call spir_func <16 x i8> @_Z38__spirv_SubgroupBlockReadINTEL_Rchar16PU3AS1Kh(
47+
; CHECK-LLVM-SPIRV: call spir_func void @_Z31__spirv_SubgroupBlockWriteINTELPU3AS1hDv16_h(
48+
49+
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
50+
target triple = "spir64"
51+
52+
define spir_kernel void @test_subgroup_block_read_write(ptr addrspace(1) %p0, ptr addrspace(1) %p1) {
53+
54+
entry:
55+
%0 = addrspacecast ptr addrspace(1) %p0 to ptr addrspace(4)
56+
%1 = call spir_func ptr addrspace(1) @__to_global(ptr addrspace(4) %0)
57+
%2 = tail call spir_func <2 x i32> @_Z27intel_sub_group_block_read2PU3AS1Kj(ptr addrspace(1) %1)
58+
tail call spir_func void @_Z28intel_sub_group_block_write2PU3AS1jDv2_j(ptr addrspace(1) %p0, <2 x i32> %2)
59+
60+
%3 = tail call spir_func <16 x i8> @_Z31intel_sub_group_block_read_uc16PU3AS1Kh(ptr addrspace(1) %p1)
61+
tail call spir_func void @_Z32intel_sub_group_block_write_uc16PU3AS1hDv16_h(ptr addrspace(1) %p1, <16 x i8> %3)
62+
63+
ret void
64+
}
65+
66+
declare spir_func <2 x i32> @_Z27intel_sub_group_block_read2PU3AS1Kj(ptr addrspace(1))
67+
declare spir_func <16 x i8> @_Z31intel_sub_group_block_read_uc16PU3AS1Kh(ptr addrspace(1))
68+
69+
declare spir_func void @_Z28intel_sub_group_block_write2PU3AS1jDv2_j(ptr addrspace(1), <2 x i32>)
70+
declare spir_func void @_Z32intel_sub_group_block_write_uc16PU3AS1hDv16_h(ptr addrspace(1), <16 x i8>)
71+
72+
declare spir_func ptr addrspace(1) @__to_global(ptr addrspace(4))
73+
74+
!opencl.ocl.version = !{!0}
75+
!opencl.spir.version = !{!0}
76+
77+
!0 = !{i32 1, i32 2}

0 commit comments

Comments
 (0)