[llvm] [SPIRV] Requires SCFG for Vulkan's SPIR-V (PR #67441)

Nathan Gauër via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 26 08:21:57 PDT 2023


https://github.com/Keenuts created https://github.com/llvm/llvm-project/pull/67441

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.

>From 45c020bd997a16bbb9172d01f5349f128762c495 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Tue, 26 Sep 2023 14:54:44 +0200
Subject: [PATCH] [SPIRV] Requires SCFG for Vulkan's SPIR-V
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

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 at google.com>
---
 llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp |  3 ++
 llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp |  2 +-
 llvm/test/CodeGen/SPIRV/scfg-basic.ll        | 43 ++++++++++++++++++++
 3 files changed, 47 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/CodeGen/SPIRV/scfg-basic.ll

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 }



More information about the llvm-commits mailing list