Skip to content

Commit 144ff03

Browse files
committed
Allow variable number of operands in work-group metadata (intel#1726)
The reqd_work_group_size and work_group_size_hint metadata nodes are currently expected to have exactly 3 operands which are in turn translated to the 3 operands of their corresponding SPIR-V execution modes. This commit relaxes this requirement by allowing the metadata to have 1-3 operands, where the missing dimensions are padded with 1's in the corresponding execution mode. Note that the information about the dimensionality of the original metadata is lost after translation, so reverse translation will always result in the metadata having all three operands. Motivation comes from intel#7450 where instead of doing the implicit padding during LLVM IR generation we want to simplify the metadata to only have the operands specified. Not only does it relax the requirements, it also lets us preserve information about dimensionality up until it is translated into SPIR-V.
1 parent 9a2c4fe commit 144ff03

File tree

5 files changed

+103
-21
lines changed

5 files changed

+103
-21
lines changed

llvm-spirv/lib/SPIRV/OCLUtil.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -791,12 +791,15 @@ unsigned getOCLVersion(Module *M, bool AllowMulti) {
791791
return encodeOCLVer(Ver.first, Ver.second, 0);
792792
}
793793

794-
void decodeMDNode(MDNode *N, unsigned &X, unsigned &Y, unsigned &Z) {
794+
SmallVector<unsigned, 3> decodeMDNode(MDNode *N) {
795795
if (N == NULL)
796-
return;
797-
X = getMDOperandAsInt(N, 0);
798-
Y = getMDOperandAsInt(N, 1);
799-
Z = getMDOperandAsInt(N, 2);
796+
return {};
797+
size_t NumOperands = N->getNumOperands();
798+
SmallVector<unsigned, 3> ReadVals;
799+
ReadVals.reserve(NumOperands);
800+
for (unsigned I = 0; I < NumOperands; ++I)
801+
ReadVals.push_back(getMDOperandAsInt(N, I));
802+
return ReadVals;
800803
}
801804

802805
/// Encode LLVM type by SPIR-V execution mode VecTypeHint

llvm-spirv/lib/SPIRV/OCLUtil.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ std::tuple<unsigned short, unsigned char, unsigned char>
444444
decodeOCLVer(unsigned Ver);
445445

446446
/// Decode a MDNode assuming it contains three integer constants.
447-
void decodeMDNode(MDNode *N, unsigned &X, unsigned &Y, unsigned &Z);
447+
SmallVector<unsigned, 3> decodeMDNode(MDNode *N);
448448

449449
/// Get full path from debug info metadata
450450
/// Return empty string if the path is not available.

llvm-spirv/lib/SPIRV/PreprocessMetadata.cpp

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -129,27 +129,30 @@ void PreprocessMetadataBase::visit(Module *M) {
129129

130130
// !{void (i32 addrspace(1)*)* @kernel, i32 17, i32 X, i32 Y, i32 Z}
131131
if (MDNode *WGSize = Kernel.getMetadata(kSPIR2MD::WGSize)) {
132-
unsigned X, Y, Z;
133-
decodeMDNode(WGSize, X, Y, Z);
132+
assert(WGSize->getNumOperands() >= 1 && WGSize->getNumOperands() <= 3 &&
133+
"reqd_work_group_size does not have between 1 and 3 operands.");
134+
SmallVector<unsigned, 3> DecodedVals = decodeMDNode(WGSize);
134135
EM.addOp()
135136
.add(&Kernel)
136137
.add(spv::ExecutionModeLocalSize)
137-
.add(X)
138-
.add(Y)
139-
.add(Z)
138+
.add(DecodedVals[0])
139+
.add(DecodedVals.size() >= 2 ? DecodedVals[1] : 1)
140+
.add(DecodedVals.size() == 3 ? DecodedVals[2] : 1)
140141
.done();
141142
}
142143

143144
// !{void (i32 addrspace(1)*)* @kernel, i32 18, i32 X, i32 Y, i32 Z}
144145
if (MDNode *WGSizeHint = Kernel.getMetadata(kSPIR2MD::WGSizeHint)) {
145-
unsigned X, Y, Z;
146-
decodeMDNode(WGSizeHint, X, Y, Z);
146+
assert(WGSizeHint->getNumOperands() >= 1 &&
147+
WGSizeHint->getNumOperands() <= 3 &&
148+
"work_group_size_hint does not have between 1 and 3 operands.");
149+
SmallVector<unsigned, 3> DecodedVals = decodeMDNode(WGSizeHint);
147150
EM.addOp()
148151
.add(&Kernel)
149152
.add(spv::ExecutionModeLocalSizeHint)
150-
.add(X)
151-
.add(Y)
152-
.add(Z)
153+
.add(DecodedVals[0])
154+
.add(DecodedVals.size() >= 2 ? DecodedVals[1] : 1)
155+
.add(DecodedVals.size() == 3 ? DecodedVals[2] : 1)
153156
.done();
154157
}
155158

@@ -175,14 +178,16 @@ void PreprocessMetadataBase::visit(Module *M) {
175178
// i32 Y, i32 Z}
176179
if (MDNode *MaxWorkgroupSizeINTEL =
177180
Kernel.getMetadata(kSPIR2MD::MaxWGSize)) {
178-
unsigned X, Y, Z;
179-
decodeMDNode(MaxWorkgroupSizeINTEL, X, Y, Z);
181+
assert(MaxWorkgroupSizeINTEL->getNumOperands() == 3 &&
182+
"max_work_group_size does not have 3 operands.");
183+
SmallVector<unsigned, 3> DecodedVals =
184+
decodeMDNode(MaxWorkgroupSizeINTEL);
180185
EM.addOp()
181186
.add(&Kernel)
182187
.add(spv::ExecutionModeMaxWorkgroupSizeINTEL)
183-
.add(X)
184-
.add(Y)
185-
.add(Z)
188+
.add(DecodedVals[0])
189+
.add(DecodedVals[1])
190+
.add(DecodedVals[2])
186191
.done();
187192
}
188193

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
; RUN: llvm-as %s -o %t.bc
2+
; RUN: llvm-spirv %t.bc -o %t.spv
3+
; RUN: llvm-spirv -to-text %t.spv -o %t.spt
4+
; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
5+
;
6+
; The purpose of this test is to check that the reqd_work_group_size metadata
7+
; is correctly converted to the LocalSize execution mode for the kernels it is
8+
; applied to.
9+
;
10+
; CHECK-SPIRV: EntryPoint 6 [[TEST1:[0-9]+]] "test1"
11+
; CHECK-SPIRV: EntryPoint 6 [[TEST2:[0-9]+]] "test2"
12+
; CHECK-SPIRV: EntryPoint 6 [[TEST3:[0-9]+]] "test3"
13+
; CHECK-SPIRV: ExecutionMode [[TEST1]] 17 1 2 3
14+
; CHECK-SPIRV: ExecutionMode [[TEST2]] 17 2 3 1
15+
; CHECK-SPIRV: ExecutionMode [[TEST3]] 17 3 1 1
16+
17+
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
18+
target triple = "spir64-unknown-unknown"
19+
20+
define spir_kernel void @test1() !reqd_work_group_size !1 {
21+
entry:
22+
ret void
23+
}
24+
25+
define spir_kernel void @test2() !reqd_work_group_size !2 {
26+
entry:
27+
ret void
28+
}
29+
30+
define spir_kernel void @test3() !reqd_work_group_size !3 {
31+
entry:
32+
ret void
33+
}
34+
35+
!1 = !{i32 1, i32 2, i32 3}
36+
!2 = !{i32 2, i32 3}
37+
!3 = !{i32 3}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
; RUN: llvm-as %s -o %t.bc
2+
; RUN: llvm-spirv %t.bc -o %t.spv
3+
; RUN: llvm-spirv -to-text %t.spv -o %t.spt
4+
; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
5+
;
6+
; The purpose of this test is to check that the work_group_size_hint metadata
7+
; is correctly converted to the LocalSizeHint execution mode for the kernels it
8+
; is applied to.
9+
;
10+
; CHECK-SPIRV: EntryPoint 6 [[TEST1:[0-9]+]] "test1"
11+
; CHECK-SPIRV: EntryPoint 6 [[TEST2:[0-9]+]] "test2"
12+
; CHECK-SPIRV: EntryPoint 6 [[TEST3:[0-9]+]] "test3"
13+
; CHECK-SPIRV: ExecutionMode [[TEST1]] 18 1 2 3
14+
; CHECK-SPIRV: ExecutionMode [[TEST2]] 18 2 3 1
15+
; CHECK-SPIRV: ExecutionMode [[TEST3]] 18 3 1 1
16+
17+
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
18+
target triple = "spir64-unknown-unknown"
19+
20+
define spir_kernel void @test1() !work_group_size_hint !1 {
21+
entry:
22+
ret void
23+
}
24+
25+
define spir_kernel void @test2() !work_group_size_hint !2 {
26+
entry:
27+
ret void
28+
}
29+
30+
define spir_kernel void @test3() !work_group_size_hint !3 {
31+
entry:
32+
ret void
33+
}
34+
35+
!1 = !{i32 1, i32 2, i32 3}
36+
!2 = !{i32 2, i32 3}
37+
!3 = !{i32 3}

0 commit comments

Comments
 (0)