-
Notifications
You must be signed in to change notification settings - Fork 10.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SPIRV] Requires SCFG for Vulkan's SPIR-V #67441
Conversation
This commit sets the target requiresSCFG to true when building Vulkan. This is a first step toward bringing structured control flow to this backend. Now that we have this flag, we can disable a first problematic transformation: removal of branches when it falls through. This is required in the SPIR-V specification: - Each basic block MUST end with a branch instruction. This means it is not valid to just fall-through. note: this commit does not generate valid CFG for graphical SPIR-V. Merge headers are missing, and outside of this specific edge case, we don't generate structured SCFG. Just a first independent step. Signed-off-by: Nathan Gauër <brioche@google.com>
@llvm/pr-subscribers-backend-spir-v @llvm/pr-subscribers-llvm-globalisel ChangesThis commit sets the target requiresSCFG to true when building Vulkan. This is a first step toward bringing structured control flow to this backend. Now that we have this flag, we can disable a first problematic transformation: removal of branches when it falls through. This is required in the SPIR-V specification: note: this commit does not generate valid CFG for graphical SPIR-V. Merge headers are missing, and outside of this specific edge case, we don't generate structured SCFG. Just a first independent step. Full diff: https://github.com/llvm/llvm-project/pull/67441.diff 3 Files Affected:
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index 764567ac7baada6..39278971782a1de 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -578,7 +578,10 @@ bool IRTranslator::translateBr(const User &U, MachineIRBuilder &MIRBuilder) {
if (BrInst.isUnconditional()) {
// If the unconditional target is the layout successor, fallthrough.
+ // Except if the target requires SCFGs. In such case, we should keep the IR
+ // branch.
if (OptLevel == CodeGenOptLevel::None ||
+ MF->getTarget().requiresStructuredCFG() ||
!CurMBB.isLayoutSuccessor(Succ0MBB))
MIRBuilder.buildBr(*Succ0MBB);
diff --git a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
index 14dd429b451910d..dcd7f3c95fded8a 100644
--- a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
@@ -82,7 +82,7 @@ SPIRVTargetMachine::SPIRVTargetMachine(const Target &T, const Triple &TT,
setGlobalISel(true);
setFastISel(false);
setO0WantsFastISel(false);
- setRequiresStructuredCFG(false);
+ setRequiresStructuredCFG(Subtarget.isVulkanEnv());
}
namespace {
diff --git a/llvm/test/CodeGen/SPIRV/scfg-basic.ll b/llvm/test/CodeGen/SPIRV/scfg-basic.ll
new file mode 100644
index 000000000000000..2fd42297999c858
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/scfg-basic.ll
@@ -0,0 +1,43 @@
+; RUN: llc -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
+
+; CHECK-DAG: [[uint:%[0-9]+]] = OpTypeInt 32 0
+; CHECK-DAG: [[bool:%[0-9]+]] = OpTypeBool
+; CHECK-DAG: [[ptr_uint:%[0-9]+]] = OpTypePointer Function [[uint]]
+; CHECK-DAG: [[uint_0:%[0-9]+]] = OpConstant [[uint]] 0
+; CHECK-DAG: [[uint_10:%[0-9]+]] = OpConstant [[uint]] 10
+; CHECK-DAG: [[uint_20:%[0-9]+]] = OpConstant [[uint]] 20
+
+define void @main() #1 {
+ %input = alloca i32, align 4
+ %output = alloca i32, align 4
+; CHECK: [[input:%[0-9]+]] = OpVariable [[ptr_uint]] Function
+; CHECK: [[output:%[0-9]+]] = OpVariable [[ptr_uint]] Function
+
+ %1 = load i32, i32* %input, align 4
+ %2 = icmp ne i32 %1, 0
+ br i1 %2, label %true, label %false
+; CHECK: [[tmp:%[0-9]+]] = OpLoad [[uint]] [[input]]
+; CHECK: [[cond:%[0-9]+]] = OpINotEqual [[bool]] [[tmp]] [[uint_0]]
+; CHECK: OpBranchConditional [[cond]] [[true:%[0-9]+]] [[false:%[0-9]+]]
+
+true:
+ store i32 10, i32* %output, align 4
+ br label %merge
+; CHECK: [[true]] = OpLabel
+; CHECK: OpStore [[output]] [[uint_10]]
+; CHECK: OpBranch [[merge:%[0-9]+]]
+
+false:
+ store i32 20, i32* %output, align 4
+ br label %merge
+; CHECK: [[false]] = OpLabel
+; CHECK: OpStore [[output]] [[uint_20]]
+; CHECK: OpBranch [[merge]]
+
+merge:
+; CHECK: [[merge]] = OpLabel
+; CHECK: OpReturn
+ ret void
+}
+
+attributes #1 = { "hlsl.numthreads"="4,8,16" "hlsl.shader"="compute" convergent }
|
TBH, I am not convinced this is the right solution. Leaving this as draft for now, until we figured out a path forward for a structurizer. |
This commit sets the target requiresSCFG to true when building Vulkan. This is a first step toward bringing structured control flow to this backend.
Now that we have this flag, we can disable a first problematic transformation: removal of branches when it falls through. This is required in the SPIR-V specification:
- Each basic block MUST end with a branch instruction.
This means it is not valid to just fall-through.
note: this commit does not generate valid CFG for graphical SPIR-V. Merge headers are missing, and outside of this specific edge case, we don't generate structured SCFG. Just a first independent step.