[llvm] [SPIR-V] Emit builtin variable OpVariable into entry block (PR #189958)
Arseniy Obolenskiy via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 1 09:20:30 PDT 2026
https://github.com/aobolensk updated https://github.com/llvm/llvm-project/pull/189958
>From 51ebeca2ea6ba10a0ba16eebcb8e4f2533a51586 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Wed, 1 Apr 2026 15:25:39 +0200
Subject: [PATCH 1/3] [SPIR-V] Emit builtin variable OpVariable into entry
block
Move the OpVariable and decoration emission for builtin variables into the first MBB so that VReg definition dependencies remain valid across all BBs
---
llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp | 10 ++++++++--
.../test/CodeGen/SPIRV/transcoding/OpGroupAsyncCopy.ll | 6 ++----
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
index db5218ec73bb7..4c5c37e6d7ddc 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
@@ -518,11 +518,17 @@ static Register buildBuiltinVariableLoad(
VariableType, MIRBuilder, SPIRV::StorageClass::Input);
GR->assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF());
- // Set up the global OpVariable with the necessary builtin decorations.
+ // Emit the OpVariable and its decorations into the first MBB to ensure
+ // VReg definition dependencies are valid across all MBBs.
+ MachineBasicBlock &EntryBB = MIRBuilder.getMF().front();
+ MachineIRBuilder FirstBlockBuilder;
+ FirstBlockBuilder.setMF(MIRBuilder.getMF());
+ FirstBlockBuilder.setMBB(EntryBB);
+
Register Variable = GR->buildGlobalVariable(
NewRegister, PtrType, getLinkStringForBuiltIn(BuiltinValue), nullptr,
SPIRV::StorageClass::Input, nullptr, /* isConst= */ isConst, LinkageTy,
- MIRBuilder, false);
+ FirstBlockBuilder, false);
// Load the value from the global variable.
Register LoadedRegister =
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpGroupAsyncCopy.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpGroupAsyncCopy.ll
index 3e68161105cc1..0c5b03895f579 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/OpGroupAsyncCopy.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/OpGroupAsyncCopy.ll
@@ -1,7 +1,5 @@
-; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-
-; TODO: This test currently fails with LLVM_ENABLE_EXPENSIVE_CHECKS enabled
-; XFAIL: expensive_checks
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: %if spirv-tools %{ llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK-SPIRV-DAG: %[[#]] = OpGroupAsyncCopy %[[#]] %[[#Scope:]]
; CHECK-SPIRV-DAG: %[[#Scope]] = OpConstant %[[#]]
>From fc61b8d39ff5171b38be2b57013afa05a247e22f Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Wed, 1 Apr 2026 16:53:56 +0200
Subject: [PATCH 2/3] add spir-val todo
---
llvm/test/CodeGen/SPIRV/transcoding/OpGroupAsyncCopy.ll | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/OpGroupAsyncCopy.ll b/llvm/test/CodeGen/SPIRV/transcoding/OpGroupAsyncCopy.ll
index 0c5b03895f579..facab89b1ad1e 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/OpGroupAsyncCopy.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/OpGroupAsyncCopy.ll
@@ -1,5 +1,6 @@
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
-; RUN: %if spirv-tools %{ llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; TODO: enable spirv-val: OpGroupAsyncCopy event arg needs OpTypeEvent, not OpTypePointer
+; RUNx: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK-SPIRV-DAG: %[[#]] = OpGroupAsyncCopy %[[#]] %[[#Scope:]]
; CHECK-SPIRV-DAG: %[[#Scope]] = OpConstant %[[#]]
>From 082b75606132a682d27d33bc69c4f782b3596dcd Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Wed, 1 Apr 2026 18:20:18 +0200
Subject: [PATCH 3/3] Address review comments
---
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 26 ++++++---
.../CodeGen/SPIRV/builtin_intrinsics_32.ll | 56 +++++++++---------
.../CodeGen/SPIRV/builtin_intrinsics_64.ll | 58 +++++++++----------
.../hlsl-intrinsics/builtin-var-dominance.ll | 48 +++++++++++++++
.../transcoding/builtin-var-dominance.ll | 33 +++++++++++
5 files changed, 156 insertions(+), 65 deletions(-)
create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/builtin-var-dominance.ll
create mode 100644 llvm/test/CodeGen/SPIRV/transcoding/builtin-var-dominance.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 9e75932b20f59..b3be6543a8f72 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -6114,12 +6114,17 @@ bool SPIRVInstructionSelector::loadVec3BuiltinInputID(
MIRBuilder.getMRI()->setType(NewRegister, LLT::pointer(0, 64));
GR.assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF());
- // Build global variable with the necessary decorations for the input ID
- // builtin variable.
+ // Emit the OpVariable into the first MBB before its terminator to ensure
+ // the def dominates all uses across all MBBs.
+ MachineBasicBlock &EntryBB = MIRBuilder.getMF().front();
+ MachineIRBuilder FirstBlockBuilder;
+ FirstBlockBuilder.setMF(MIRBuilder.getMF());
+ FirstBlockBuilder.setInsertPt(EntryBB, EntryBB.getFirstTerminator());
+
Register Variable = GR.buildGlobalVariable(
NewRegister, PtrType, getLinkStringForBuiltIn(BuiltInValue), nullptr,
- SPIRV::StorageClass::Input, nullptr, true, std::nullopt, MIRBuilder,
- false);
+ SPIRV::StorageClass::Input, nullptr, true, std::nullopt,
+ FirstBlockBuilder, false);
// Create new register for loading value.
MachineRegisterInfo *MRI = MIRBuilder.getMRI();
@@ -6167,12 +6172,17 @@ bool SPIRVInstructionSelector::loadBuiltinInputID(
GR.getPointerSize()));
GR.assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF());
- // Build global variable with the necessary decorations for the input ID
- // builtin variable.
+ // Emit the OpVariable into the first MBB to ensure the def dominates all
+ // uses across all MBBs.
+ MachineBasicBlock &EntryBB = MIRBuilder.getMF().front();
+ MachineIRBuilder FirstBlockBuilder;
+ FirstBlockBuilder.setMF(MIRBuilder.getMF());
+ FirstBlockBuilder.setInsertPt(EntryBB, EntryBB.getFirstTerminator());
+
Register Variable = GR.buildGlobalVariable(
NewRegister, PtrType, getLinkStringForBuiltIn(BuiltInValue), nullptr,
- SPIRV::StorageClass::Input, nullptr, true, std::nullopt, MIRBuilder,
- false);
+ SPIRV::StorageClass::Input, nullptr, true, std::nullopt,
+ FirstBlockBuilder, false);
// Load uint value from the global variable.
auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpLoad))
diff --git a/llvm/test/CodeGen/SPIRV/builtin_intrinsics_32.ll b/llvm/test/CodeGen/SPIRV/builtin_intrinsics_32.ll
index c348c934e85ff..6abe8ce53bb98 100644
--- a/llvm/test/CodeGen/SPIRV/builtin_intrinsics_32.ll
+++ b/llvm/test/CodeGen/SPIRV/builtin_intrinsics_32.ll
@@ -4,34 +4,34 @@
target datalayout = "e-p:32:32-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"
target triple = "spirv32-unknown-unknown"
-; CHECK: OpDecorate [[NumWorkgroups:%[0-9]*]] BuiltIn NumWorkgroups
-; CHECK: OpDecorate [[WorkgroupSize:%[0-9]*]] BuiltIn WorkgroupSize
-; CHECK: OpDecorate [[WorkgroupId:%[0-9]*]] BuiltIn WorkgroupId
-; CHECK: OpDecorate [[LocalInvocationId:%[0-9]*]] BuiltIn LocalInvocationId
-; CHECK: OpDecorate [[GlobalInvocationId:%[0-9]*]] BuiltIn GlobalInvocationId
-; CHECK: OpDecorate [[GlobalSize:%[0-9]*]] BuiltIn GlobalSize
-; CHECK: OpDecorate [[GlobalOffset:%[0-9]*]] BuiltIn GlobalOffset
-; CHECK: OpDecorate [[SubgroupSize:%[0-9]*]] BuiltIn SubgroupSize
-; CHECK: OpDecorate [[SubgroupMaxSize:%[0-9]*]] BuiltIn SubgroupMaxSize
-; CHECK: OpDecorate [[NumSubgroups:%[0-9]*]] BuiltIn NumSubgroups
-; CHECK: OpDecorate [[SubgroupId:%[0-9]*]] BuiltIn SubgroupId
-; CHECK: OpDecorate [[SubgroupLocalInvocationId:%[0-9]*]] BuiltIn SubgroupLocalInvocationId
-; CHECK: [[I32:%[0-9]*]] = OpTypeInt 32 0
-; CHECK: [[I32PTR:%[0-9]*]] = OpTypePointer Input [[I32]]
-; CHECK: [[I32V3:%[0-9]*]] = OpTypeVector [[I32]] 3
-; CHECK: [[I32V3PTR:%[0-9]*]] = OpTypePointer Input [[I32V3]]
-; CHECK: [[NumWorkgroups]] = OpVariable [[I32V3PTR]] Input
-; CHECK: [[WorkgroupSize]] = OpVariable [[I32V3PTR]] Input
-; CHECK: [[WorkgroupId]] = OpVariable [[I32V3PTR]] Input
-; CHECK: [[LocalInvocationId]] = OpVariable [[I32V3PTR]] Input
-; CHECK: [[GlobalInvocationId]] = OpVariable [[I32V3PTR]] Input
-; CHECK: [[GlobalSize]] = OpVariable [[I32V3PTR]] Input
-; CHECK: [[GlobalOffset]] = OpVariable [[I32V3PTR]] Input
-; CHECK: [[SubgroupSize]] = OpVariable [[I32PTR]] Input
-; CHECK: [[SubgroupMaxSize]] = OpVariable [[I32PTR]] Input
-; CHECK: [[NumSubgroups]] = OpVariable [[I32PTR]] Input
-; CHECK: [[SubgroupId]] = OpVariable [[I32PTR]] Input
-; CHECK: [[SubgroupLocalInvocationId]] = OpVariable [[I32PTR]] Input
+; CHECK-DAG: OpDecorate [[NumWorkgroups:%[0-9]*]] BuiltIn NumWorkgroups
+; CHECK-DAG: OpDecorate [[WorkgroupSize:%[0-9]*]] BuiltIn WorkgroupSize
+; CHECK-DAG: OpDecorate [[WorkgroupId:%[0-9]*]] BuiltIn WorkgroupId
+; CHECK-DAG: OpDecorate [[LocalInvocationId:%[0-9]*]] BuiltIn LocalInvocationId
+; CHECK-DAG: OpDecorate [[GlobalInvocationId:%[0-9]*]] BuiltIn GlobalInvocationId
+; CHECK-DAG: OpDecorate [[GlobalSize:%[0-9]*]] BuiltIn GlobalSize
+; CHECK-DAG: OpDecorate [[GlobalOffset:%[0-9]*]] BuiltIn GlobalOffset
+; CHECK-DAG: OpDecorate [[SubgroupSize:%[0-9]*]] BuiltIn SubgroupSize
+; CHECK-DAG: OpDecorate [[SubgroupMaxSize:%[0-9]*]] BuiltIn SubgroupMaxSize
+; CHECK-DAG: OpDecorate [[NumSubgroups:%[0-9]*]] BuiltIn NumSubgroups
+; CHECK-DAG: OpDecorate [[SubgroupId:%[0-9]*]] BuiltIn SubgroupId
+; CHECK-DAG: OpDecorate [[SubgroupLocalInvocationId:%[0-9]*]] BuiltIn SubgroupLocalInvocationId
+; CHECK-DAG: [[I32:%[0-9]*]] = OpTypeInt 32 0
+; CHECK-DAG: [[I32PTR:%[0-9]*]] = OpTypePointer Input [[I32]]
+; CHECK-DAG: [[I32V3:%[0-9]*]] = OpTypeVector [[I32]] 3
+; CHECK-DAG: [[I32V3PTR:%[0-9]*]] = OpTypePointer Input [[I32V3]]
+; CHECK-DAG: [[NumWorkgroups]] = OpVariable [[I32V3PTR]] Input
+; CHECK-DAG: [[WorkgroupSize]] = OpVariable [[I32V3PTR]] Input
+; CHECK-DAG: [[WorkgroupId]] = OpVariable [[I32V3PTR]] Input
+; CHECK-DAG: [[LocalInvocationId]] = OpVariable [[I32V3PTR]] Input
+; CHECK-DAG: [[GlobalInvocationId]] = OpVariable [[I32V3PTR]] Input
+; CHECK-DAG: [[GlobalSize]] = OpVariable [[I32V3PTR]] Input
+; CHECK-DAG: [[GlobalOffset]] = OpVariable [[I32V3PTR]] Input
+; CHECK-DAG: [[SubgroupSize]] = OpVariable [[I32PTR]] Input
+; CHECK-DAG: [[SubgroupMaxSize]] = OpVariable [[I32PTR]] Input
+; CHECK-DAG: [[NumSubgroups]] = OpVariable [[I32PTR]] Input
+; CHECK-DAG: [[SubgroupId]] = OpVariable [[I32PTR]] Input
+; CHECK-DAG: [[SubgroupLocalInvocationId]] = OpVariable [[I32PTR]] Input
@G_spv_num_workgroups_0 = global i32 0
@G_spv_num_workgroups_1 = global i32 0
diff --git a/llvm/test/CodeGen/SPIRV/builtin_intrinsics_64.ll b/llvm/test/CodeGen/SPIRV/builtin_intrinsics_64.ll
index 45227c31c6ad8..f9b703e681cf5 100644
--- a/llvm/test/CodeGen/SPIRV/builtin_intrinsics_64.ll
+++ b/llvm/test/CodeGen/SPIRV/builtin_intrinsics_64.ll
@@ -4,35 +4,35 @@
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"
target triple = "spirv64-unknown-unknown"
-; CHECK: OpDecorate [[NumWorkgroups:%[0-9]*]] BuiltIn NumWorkgroups
-; CHECK: OpDecorate [[WorkgroupSize:%[0-9]*]] BuiltIn WorkgroupSize
-; CHECK: OpDecorate [[WorkgroupId:%[0-9]*]] BuiltIn WorkgroupId
-; CHECK: OpDecorate [[LocalInvocationId:%[0-9]*]] BuiltIn LocalInvocationId
-; CHECK: OpDecorate [[GlobalInvocationId:%[0-9]*]] BuiltIn GlobalInvocationId
-; CHECK: OpDecorate [[GlobalSize:%[0-9]*]] BuiltIn GlobalSize
-; CHECK: OpDecorate [[GlobalOffset:%[0-9]*]] BuiltIn GlobalOffset
-; CHECK: OpDecorate [[SubgroupSize:%[0-9]*]] BuiltIn SubgroupSize
-; CHECK: OpDecorate [[SubgroupMaxSize:%[0-9]*]] BuiltIn SubgroupMaxSize
-; CHECK: OpDecorate [[NumSubgroups:%[0-9]*]] BuiltIn NumSubgroups
-; CHECK: OpDecorate [[SubgroupId:%[0-9]*]] BuiltIn SubgroupId
-; CHECK: OpDecorate [[SubgroupLocalInvocationId:%[0-9]*]] BuiltIn SubgroupLocalInvocationId
-; CHECK: [[I32:%[0-9]*]] = OpTypeInt 32 0
-; CHECK: [[I64:%[0-9]*]] = OpTypeInt 64 0
-; CHECK: [[I32PTR:%[0-9]*]] = OpTypePointer Input [[I32]]
-; CHECK: [[I64V3:%[0-9]*]] = OpTypeVector [[I64]] 3
-; CHECK: [[I64V3PTR:%[0-9]*]] = OpTypePointer Input [[I64V3]]
-; CHECK: [[NumWorkgroups]] = OpVariable [[I64V3PTR]] Input
-; CHECK: [[WorkgroupSize]] = OpVariable [[I64V3PTR]] Input
-; CHECK: [[WorkgroupId]] = OpVariable [[I64V3PTR]] Input
-; CHECK: [[LocalInvocationId]] = OpVariable [[I64V3PTR]] Input
-; CHECK: [[GlobalInvocationId]] = OpVariable [[I64V3PTR]] Input
-; CHECK: [[GlobalSize]] = OpVariable [[I64V3PTR]] Input
-; CHECK: [[GlobalOffset]] = OpVariable [[I64V3PTR]] Input
-; CHECK: [[SubgroupSize]] = OpVariable [[I32PTR]] Input
-; CHECK: [[SubgroupMaxSize]] = OpVariable [[I32PTR]] Input
-; CHECK: [[NumSubgroups]] = OpVariable [[I32PTR]] Input
-; CHECK: [[SubgroupId]] = OpVariable [[I32PTR]] Input
-; CHECK: [[SubgroupLocalInvocationId]] = OpVariable [[I32PTR]] Input
+; CHECK-DAG: OpDecorate [[NumWorkgroups:%[0-9]*]] BuiltIn NumWorkgroups
+; CHECK-DAG: OpDecorate [[WorkgroupSize:%[0-9]*]] BuiltIn WorkgroupSize
+; CHECK-DAG: OpDecorate [[WorkgroupId:%[0-9]*]] BuiltIn WorkgroupId
+; CHECK-DAG: OpDecorate [[LocalInvocationId:%[0-9]*]] BuiltIn LocalInvocationId
+; CHECK-DAG: OpDecorate [[GlobalInvocationId:%[0-9]*]] BuiltIn GlobalInvocationId
+; CHECK-DAG: OpDecorate [[GlobalSize:%[0-9]*]] BuiltIn GlobalSize
+; CHECK-DAG: OpDecorate [[GlobalOffset:%[0-9]*]] BuiltIn GlobalOffset
+; CHECK-DAG: OpDecorate [[SubgroupSize:%[0-9]*]] BuiltIn SubgroupSize
+; CHECK-DAG: OpDecorate [[SubgroupMaxSize:%[0-9]*]] BuiltIn SubgroupMaxSize
+; CHECK-DAG: OpDecorate [[NumSubgroups:%[0-9]*]] BuiltIn NumSubgroups
+; CHECK-DAG: OpDecorate [[SubgroupId:%[0-9]*]] BuiltIn SubgroupId
+; CHECK-DAG: OpDecorate [[SubgroupLocalInvocationId:%[0-9]*]] BuiltIn SubgroupLocalInvocationId
+; CHECK-DAG: [[I32:%[0-9]*]] = OpTypeInt 32 0
+; CHECK-DAG: [[I64:%[0-9]*]] = OpTypeInt 64 0
+; CHECK-DAG: [[I32PTR:%[0-9]*]] = OpTypePointer Input [[I32]]
+; CHECK-DAG: [[I64V3:%[0-9]*]] = OpTypeVector [[I64]] 3
+; CHECK-DAG: [[I64V3PTR:%[0-9]*]] = OpTypePointer Input [[I64V3]]
+; CHECK-DAG: [[NumWorkgroups]] = OpVariable [[I64V3PTR]] Input
+; CHECK-DAG: [[WorkgroupSize]] = OpVariable [[I64V3PTR]] Input
+; CHECK-DAG: [[WorkgroupId]] = OpVariable [[I64V3PTR]] Input
+; CHECK-DAG: [[LocalInvocationId]] = OpVariable [[I64V3PTR]] Input
+; CHECK-DAG: [[GlobalInvocationId]] = OpVariable [[I64V3PTR]] Input
+; CHECK-DAG: [[GlobalSize]] = OpVariable [[I64V3PTR]] Input
+; CHECK-DAG: [[GlobalOffset]] = OpVariable [[I64V3PTR]] Input
+; CHECK-DAG: [[SubgroupSize]] = OpVariable [[I32PTR]] Input
+; CHECK-DAG: [[SubgroupMaxSize]] = OpVariable [[I32PTR]] Input
+; CHECK-DAG: [[NumSubgroups]] = OpVariable [[I32PTR]] Input
+; CHECK-DAG: [[SubgroupId]] = OpVariable [[I32PTR]] Input
+; CHECK-DAG: [[SubgroupLocalInvocationId]] = OpVariable [[I32PTR]] Input
@G_spv_num_workgroups_0 = global i64 0
@G_spv_num_workgroups_1 = global i64 0
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/builtin-var-dominance.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/builtin-var-dominance.ll
new file mode 100644
index 0000000000000..12912236d2942
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/builtin-var-dominance.ll
@@ -0,0 +1,48 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-vulkan-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-unknown %s -o - -filetype=obj | spirv-val %}
+
+;; Verify that builtin variable OpVariable is emitted in the entry block
+;; on the shader (ISel) path, so its def dominates all uses when the
+;; same builtin is accessed in multiple non-entry blocks.
+
+; CHECK-DAG: OpDecorate %[[#VarID:]] BuiltIn LocalInvocationId
+; CHECK-DAG: %[[#VarID]] = OpVariable %[[#]] Input
+
+define internal spir_func void @main_inner(<3 x i32> noundef %ID) {
+entry:
+ ret void
+}
+
+define void @main.1() #0 {
+entry:
+ %cmp = icmp sgt i32 1, 0
+ br i1 %cmp, label %then, label %else
+
+then:
+ %0 = call i32 @llvm.spv.thread.id.in.group.i32(i32 0)
+ %1 = insertelement <3 x i32> poison, i32 %0, i64 0
+ %2 = call i32 @llvm.spv.thread.id.in.group.i32(i32 1)
+ %3 = insertelement <3 x i32> %1, i32 %2, i64 1
+ %4 = call i32 @llvm.spv.thread.id.in.group.i32(i32 2)
+ %5 = insertelement <3 x i32> %3, i32 %4, i64 2
+ call void @main_inner(<3 x i32> %5)
+ br label %exit
+
+else:
+ %6 = call i32 @llvm.spv.thread.id.in.group.i32(i32 0)
+ %7 = insertelement <3 x i32> poison, i32 %6, i64 0
+ %8 = call i32 @llvm.spv.thread.id.in.group.i32(i32 1)
+ %9 = insertelement <3 x i32> %7, i32 %8, i64 1
+ %10 = call i32 @llvm.spv.thread.id.in.group.i32(i32 2)
+ %11 = insertelement <3 x i32> %9, i32 %10, i64 2
+ call void @main_inner(<3 x i32> %11)
+ br label %exit
+
+exit:
+ ret void
+}
+
+declare i32 @llvm.spv.thread.id.in.group.i32(i32) #1
+
+attributes #0 = { norecurse "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
+attributes #1 = { nounwind willreturn memory(none) }
diff --git a/llvm/test/CodeGen/SPIRV/transcoding/builtin-var-dominance.ll b/llvm/test/CodeGen/SPIRV/transcoding/builtin-var-dominance.ll
new file mode 100644
index 0000000000000..f6046be91d96c
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/transcoding/builtin-var-dominance.ll
@@ -0,0 +1,33 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+;; Verify that builtin variable OpVariable is emitted in the entry block
+;; so its def dominates all uses, even when the same builtin is called
+;; in multiple non-entry blocks.
+
+; CHECK-DAG: OpDecorate %[[#VarID:]] BuiltIn LocalInvocationId
+; CHECK-DAG: %[[#VarID]] = OpVariable %[[#]] Input
+
+define spir_kernel void @test(ptr addrspace(1) %out, i32 %n) {
+entry:
+ %cmp = icmp sgt i32 %n, 0
+ br i1 %cmp, label %then, label %else
+
+then:
+ %id0 = call spir_func i32 @_Z12get_local_idj(i32 0)
+ store i32 %id0, ptr addrspace(1) %out, align 4
+ br label %exit
+
+else:
+ %id1 = call spir_func i32 @_Z12get_local_idj(i32 0)
+ %neg = sub i32 0, %id1
+ store i32 %neg, ptr addrspace(1) %out, align 4
+ br label %exit
+
+exit:
+ ret void
+}
+
+declare spir_func i32 @_Z12get_local_idj(i32)
More information about the llvm-commits
mailing list