Skip to content

Commit 0047df9

Browse files
[SPIR-V] reqd_work_group_size and work_group_size_hint metadata are correctly converted to the LocalSize and LocalSizeHint execution mode (#92552)
The goal of this PR is to ensure that reqd_work_group_size and work_group_size_hint metadata are correctly converted to the LocalSize and LocalSizeHint execution mode. reqd_work_group_size and work_group_size_hint require 3 operands (see https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#Execution_Mode), if metadata contains less operands, just add a default value (1).
1 parent d71f30a commit 0047df9

File tree

3 files changed

+83
-6
lines changed

3 files changed

+83
-6
lines changed

llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ class SPIRVAsmPrinter : public AsmPrinter {
6969
void outputOpFunctionEnd();
7070
void outputExtFuncDecls();
7171
void outputExecutionModeFromMDNode(Register Reg, MDNode *Node,
72-
SPIRV::ExecutionMode::ExecutionMode EM);
72+
SPIRV::ExecutionMode::ExecutionMode EM,
73+
unsigned ExpectMDOps, int64_t DefVal);
7374
void outputExecutionModeFromNumthreadsAttribute(
7475
const Register &Reg, const Attribute &Attr,
7576
SPIRV::ExecutionMode::ExecutionMode EM);
@@ -422,12 +423,19 @@ static void addOpsFromMDNode(MDNode *MDN, MCInst &Inst,
422423
}
423424

424425
void SPIRVAsmPrinter::outputExecutionModeFromMDNode(
425-
Register Reg, MDNode *Node, SPIRV::ExecutionMode::ExecutionMode EM) {
426+
Register Reg, MDNode *Node, SPIRV::ExecutionMode::ExecutionMode EM,
427+
unsigned ExpectMDOps, int64_t DefVal) {
426428
MCInst Inst;
427429
Inst.setOpcode(SPIRV::OpExecutionMode);
428430
Inst.addOperand(MCOperand::createReg(Reg));
429431
Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(EM)));
430432
addOpsFromMDNode(Node, Inst, MAI);
433+
// reqd_work_group_size and work_group_size_hint require 3 operands,
434+
// if metadata contains less operands, just add a default value
435+
unsigned NodeSz = Node->getNumOperands();
436+
if (ExpectMDOps > 0 && NodeSz < ExpectMDOps)
437+
for (unsigned i = NodeSz; i < ExpectMDOps; ++i)
438+
Inst.addOperand(MCOperand::createImm(DefVal));
431439
outputMCInst(Inst);
432440
}
433441

@@ -473,17 +481,17 @@ void SPIRVAsmPrinter::outputExecutionMode(const Module &M) {
473481
Register FReg = MAI->getFuncReg(&F);
474482
assert(FReg.isValid());
475483
if (MDNode *Node = F.getMetadata("reqd_work_group_size"))
476-
outputExecutionModeFromMDNode(FReg, Node,
477-
SPIRV::ExecutionMode::LocalSize);
484+
outputExecutionModeFromMDNode(FReg, Node, SPIRV::ExecutionMode::LocalSize,
485+
3, 1);
478486
if (Attribute Attr = F.getFnAttribute("hlsl.numthreads"); Attr.isValid())
479487
outputExecutionModeFromNumthreadsAttribute(
480488
FReg, Attr, SPIRV::ExecutionMode::LocalSize);
481489
if (MDNode *Node = F.getMetadata("work_group_size_hint"))
482490
outputExecutionModeFromMDNode(FReg, Node,
483-
SPIRV::ExecutionMode::LocalSizeHint);
491+
SPIRV::ExecutionMode::LocalSizeHint, 3, 1);
484492
if (MDNode *Node = F.getMetadata("intel_reqd_sub_group_size"))
485493
outputExecutionModeFromMDNode(FReg, Node,
486-
SPIRV::ExecutionMode::SubgroupSize);
494+
SPIRV::ExecutionMode::SubgroupSize, 0, 0);
487495
if (MDNode *Node = F.getMetadata("vec_type_hint")) {
488496
MCInst Inst;
489497
Inst.setOpcode(SPIRV::OpExecutionMode);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
; From Khronos Translator's test case: test/reqd_work_group_size_md.ll
2+
3+
; The purpose of this test is to check that the reqd_work_group_size metadata
4+
; is correctly converted to the LocalSize execution mode for the kernels it is
5+
; applied to.
6+
7+
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
8+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
9+
10+
; CHECK: OpMemoryModel
11+
; CHECK-DAG: OpEntryPoint Kernel %[[#ENTRY1:]] "test1"
12+
; CHECK-DAG: OpEntryPoint Kernel %[[#ENTRY2:]] "test2"
13+
; CHECK-DAG: OpEntryPoint Kernel %[[#ENTRY3:]] "test3"
14+
; CHECK-DAG: OpExecutionMode %[[#ENTRY1]] LocalSize 1 2 3
15+
; CHECK-DAG: OpExecutionMode %[[#ENTRY2]] LocalSize 2 3 1
16+
; CHECK-DAG: OpExecutionMode %[[#ENTRY3]] LocalSize 3 1 1
17+
18+
define spir_kernel void @test1() !reqd_work_group_size !1 {
19+
entry:
20+
ret void
21+
}
22+
23+
define spir_kernel void @test2() !reqd_work_group_size !2 {
24+
entry:
25+
ret void
26+
}
27+
28+
define spir_kernel void @test3() !reqd_work_group_size !3 {
29+
entry:
30+
ret void
31+
}
32+
33+
!1 = !{i32 1, i32 2, i32 3}
34+
!2 = !{i32 2, i32 3}
35+
!3 = !{i32 3}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
; From Khronos Translator's test case: test/reqd_work_group_size_md.ll
2+
3+
; The purpose of this test is to check that the work_group_size_hint metadata
4+
; is correctly converted to the LocalSizeHint execution mode.
5+
6+
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
7+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
8+
9+
; CHECK: OpMemoryModel
10+
; CHECK-DAG: OpEntryPoint Kernel %[[#ENTRY1:]] "test1"
11+
; CHECK-DAG: OpEntryPoint Kernel %[[#ENTRY2:]] "test2"
12+
; CHECK-DAG: OpEntryPoint Kernel %[[#ENTRY3:]] "test3"
13+
; CHECK-DAG: OpExecutionMode %[[#ENTRY1]] LocalSizeHint 1 2 3
14+
; CHECK-DAG: OpExecutionMode %[[#ENTRY2]] LocalSizeHint 2 3 1
15+
; CHECK-DAG: OpExecutionMode %[[#ENTRY3]] LocalSizeHint 3 1 1
16+
17+
define spir_kernel void @test1() !work_group_size_hint !1 {
18+
entry:
19+
ret void
20+
}
21+
22+
define spir_kernel void @test2() !work_group_size_hint !2 {
23+
entry:
24+
ret void
25+
}
26+
27+
define spir_kernel void @test3() !work_group_size_hint !3 {
28+
entry:
29+
ret void
30+
}
31+
32+
!1 = !{i32 1, i32 2, i32 3}
33+
!2 = !{i32 2, i32 3}
34+
!3 = !{i32 3}

0 commit comments

Comments
 (0)