[llvm] [SPIR-V] Add pre-headers to loops. (PR #75844)
Nathan Gauër via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 2 02:52:02 PST 2024
https://github.com/Keenuts updated https://github.com/llvm/llvm-project/pull/75844
>From 8bdf4bf33f3349d333ccf62e6d18925018a81b7a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Mon, 18 Dec 2023 19:51:14 +0100
Subject: [PATCH 1/4] [SPIR-V] Add pre-headers to loops.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This is the first of the 7 steps outlined in #75801.
This PR explicitely calls the SimplifyLoops pass. Directly following
this pass should follow the 6 others required to structurize the IR.
Running this pass could generate empty basic-blocks, which are
implicit fallthrough to the successor BB.
There was a specific condition in the SPIR-V ISel which handled
implicit fallthrough, but it couldn't work on empty basic-blocks.
This commits removes the old logic, and adds this new logic, which
checks all basic-blocks for implicit fallthroughs, including empty ones.
Signed-off-by: Nathan Gauër <brioche at google.com>
---
llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp | 35 ++++++++++
llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp | 6 ++
llvm/lib/Target/SPIRV/SPIRVUtils.cpp | 4 +-
llvm/lib/Target/SPIRV/SPIRVUtils.h | 2 +-
.../CodeGen/SPIRV/scfg-add-pre-headers.ll | 67 +++++++++++++++++++
5 files changed, 111 insertions(+), 3 deletions(-)
create mode 100644 llvm/test/CodeGen/SPIRV/scfg-add-pre-headers.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
index f4076be2a7b778..275c24e22c3025 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
@@ -587,6 +587,40 @@ static void processSwitches(MachineFunction &MF, SPIRVGlobalRegistry *GR,
}
}
+static bool isImplicitFallthrough(MachineBasicBlock &MBB) {
+ if (MBB.empty())
+ return true;
+
+ // Branching spirv intrinsics are not detected by this generic method.
+ // Thus, we can only trust negative result.
+ if (!MBB.canFallThrough())
+ return false;
+
+ // Otherwise, we must manually check if we have a spirv intrinsic which
+ // prevent an implicit fallthrough.
+ for (MachineBasicBlock::reverse_iterator It = MBB.rbegin(), E = MBB.rend();
+ It != E; ++It) {
+ if (isSpvIntrinsic(*It, Intrinsic::spv_switch))
+ return false;
+ }
+ return true;
+}
+
+static void removeImplicitFallthroughs(MachineFunction &MF,
+ MachineIRBuilder MIB) {
+ // It is valid for MachineBasicBlocks to not finish with a branch instruction.
+ // In such cases, they will simply fallthrough their immediate successor.
+ for (MachineBasicBlock &MBB : MF) {
+ if (!isImplicitFallthrough(MBB))
+ continue;
+
+ assert(std::distance(MBB.successors().begin(), MBB.successors().end()) ==
+ 1);
+ MIB.setInsertPt(MBB, MBB.end());
+ MIB.buildBr(**MBB.successors().begin());
+ }
+}
+
bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) {
// Initialize the type registry.
const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>();
@@ -599,6 +633,7 @@ bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) {
generateAssignInstrs(MF, GR, MIB);
processSwitches(MF, GR, MIB);
processInstrsWithTypeFolding(MF, GR, MIB);
+ removeImplicitFallthroughs(MF, MIB);
return true;
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
index 1503f263e42c0d..517174b356f059 100644
--- a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
@@ -29,6 +29,7 @@
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Pass.h"
#include "llvm/Target/TargetOptions.h"
+#include "llvm/Transforms/Utils.h"
#include <optional>
using namespace llvm;
@@ -151,6 +152,11 @@ TargetPassConfig *SPIRVTargetMachine::createPassConfig(PassManagerBase &PM) {
}
void SPIRVPassConfig::addIRPasses() {
+ // Once legalized, we need to structurize the CFG to follow the spec.
+ // This is done through the following 8 steps.
+ // TODO(#75801): add the remaining steps.
+ addPass(createLoopSimplifyPass());
+
TargetPassConfig::addIRPasses();
addPass(createSPIRVRegularizerPass());
addPass(createSPIRVPrepareFunctionsPass(TM));
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index 1c0e8d84e2fd10..d4f7d8e89af5e4 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -228,8 +228,8 @@ uint64_t getIConstVal(Register ConstReg, const MachineRegisterInfo *MRI) {
return MI->getOperand(1).getCImm()->getValue().getZExtValue();
}
-bool isSpvIntrinsic(MachineInstr &MI, Intrinsic::ID IntrinsicID) {
- if (auto *GI = dyn_cast<GIntrinsic>(&MI))
+bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID) {
+ if (const auto *GI = dyn_cast<GIntrinsic>(&MI))
return GI->is(IntrinsicID);
return false;
}
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.h b/llvm/lib/Target/SPIRV/SPIRVUtils.h
index 30fae6c7de479f..60742e2f272808 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.h
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.h
@@ -79,7 +79,7 @@ MachineInstr *getDefInstrMaybeConstant(Register &ConstReg,
uint64_t getIConstVal(Register ConstReg, const MachineRegisterInfo *MRI);
// Check if MI is a SPIR-V specific intrinsic call.
-bool isSpvIntrinsic(MachineInstr &MI, Intrinsic::ID IntrinsicID);
+bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID);
// Get type of i-th operand of the metadata node.
Type *getMDOperandAsType(const MDNode *N, unsigned I);
diff --git a/llvm/test/CodeGen/SPIRV/scfg-add-pre-headers.ll b/llvm/test/CodeGen/SPIRV/scfg-add-pre-headers.ll
new file mode 100644
index 00000000000000..eccf3301002ae7
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/scfg-add-pre-headers.ll
@@ -0,0 +1,67 @@
+; RUN: llc -mtriple=spirv-unknown-unknown -O0 %s -o - | FileCheck %s
+
+; CHECK-DAG: [[bool:%[0-9]+]] = OpTypeBool
+; CHECK-DAG: [[uint:%[0-9]+]] = OpTypeInt 32 0
+; CHECK-DAG: [[uint_0:%[0-9]+]] = OpConstant [[uint]] 0
+
+define i32 @main(i32 noundef %0) #1 {
+ %2 = icmp ne i32 %0, 0
+ br i1 %2, label %l1, label %l2
+
+; CHECK: [[param_0:%[0-9]+]] = OpFunctionParameter [[uint]]
+; CHECK: [[cond:%[0-9]+]] = OpINotEqual [[bool]] [[param_0]] [[uint_0]]
+; CHECK: OpBranchConditional [[cond]] [[l1_pre:%[0-9]+]] [[l2_pre:%[0-9]+]]
+
+; CHECK-DAG: [[l2_pre]] = OpLabel
+; CHECK-NEXT: OpBranch [[l2_header:%[0-9]+]]
+
+; CHECK-DAG: [[l1_pre]] = OpLabel
+; CHECK-NEXT: OpBranch [[l1_header:%[0-9]+]]
+
+l1:
+ br i1 %2, label %l1_body, label %l1_end
+; CHECK-DAG: [[l1_header]] = OpLabel
+; CHECK-NEXT: OpBranchConditional [[cond]] [[l1_body:%[0-9]+]] [[l1_end:%[0-9]+]]
+
+l1_body:
+ br label %l1_continue
+; CHECK-DAG: [[l1_body]] = OpLabel
+; CHECK-NEXT: OpBranch [[l1_continue:%[0-9]+]]
+
+l1_continue:
+ br label %l1
+; CHECK-DAG: [[l1_continue]] = OpLabel
+; CHECK-NEXT: OpBranch [[l1_header]]
+
+l1_end:
+ br label %end
+; CHECK-DAG: [[l1_end]] = OpLabel
+; CHECK-NEXT: OpBranch [[end:%[0-9]+]]
+
+l2:
+ br i1 %2, label %l2_body, label %l2_end
+; CHECK-DAG: [[l2_header]] = OpLabel
+; CHECK-NEXT: OpBranchConditional [[cond]] [[l2_body:%[0-9]+]] [[l2_end:%[0-9]+]]
+
+l2_body:
+ br label %l2_continue
+; CHECK-DAG: [[l2_body]] = OpLabel
+; CHECK-NEXT: OpBranch [[l2_continue:%[0-9]+]]
+
+l2_continue:
+ br label %l2
+; CHECK-DAG: [[l2_continue]] = OpLabel
+; CHECK-NEXT: OpBranch [[l2_header]]
+
+l2_end:
+ br label %end
+; CHECK-DAG: [[l2_end]] = OpLabel
+; CHECK-NEXT: OpBranch [[end:%[0-9]+]]
+
+end:
+ ret i32 1
+; CHECK-DAG: [[end]] = OpLabel
+; CHECK-NEXT: OpReturn
+}
+
+attributes #1 = { "hlsl.numthreads"="4,8,16" "hlsl.shader"="compute" convergent }
>From 28be748baa885a5c2b2af11debfc0d91e9966f36 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Tue, 19 Dec 2023 13:51:41 +0100
Subject: [PATCH 2/4] fixup! [SPIR-V] Add pre-headers to loops.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
only allow pass for Vulkan
Signed-off-by: Nathan Gauër <brioche at google.com>
---
llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
index 517174b356f059..52b174f4e0c294 100644
--- a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
@@ -152,10 +152,12 @@ TargetPassConfig *SPIRVTargetMachine::createPassConfig(PassManagerBase &PM) {
}
void SPIRVPassConfig::addIRPasses() {
- // Once legalized, we need to structurize the CFG to follow the spec.
- // This is done through the following 8 steps.
- // TODO(#75801): add the remaining steps.
- addPass(createLoopSimplifyPass());
+ if (TM.getSubtargetImpl()->isVulkanEnv()) {
+ // Once legalized, we need to structurize the CFG to follow the spec.
+ // This is done through the following 8 steps.
+ // TODO(#75801): add the remaining steps.
+ addPass(createLoopSimplifyPass());
+ }
TargetPassConfig::addIRPasses();
addPass(createSPIRVRegularizerPass());
>From ec501822239e9b1d3acd51b050be9408fdedeb7c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Tue, 2 Jan 2024 11:40:34 +0100
Subject: [PATCH 3/4] fixup! fixup! [SPIR-V] Add pre-headers to loops.
fix test format
---
.../CodeGen/SPIRV/scfg-add-pre-headers.ll | 56 +++++++++----------
1 file changed, 28 insertions(+), 28 deletions(-)
diff --git a/llvm/test/CodeGen/SPIRV/scfg-add-pre-headers.ll b/llvm/test/CodeGen/SPIRV/scfg-add-pre-headers.ll
index eccf3301002ae7..73efde8d17bb9c 100644
--- a/llvm/test/CodeGen/SPIRV/scfg-add-pre-headers.ll
+++ b/llvm/test/CodeGen/SPIRV/scfg-add-pre-headers.ll
@@ -1,67 +1,67 @@
; RUN: llc -mtriple=spirv-unknown-unknown -O0 %s -o - | FileCheck %s
-; CHECK-DAG: [[bool:%[0-9]+]] = OpTypeBool
-; CHECK-DAG: [[uint:%[0-9]+]] = OpTypeInt 32 0
-; CHECK-DAG: [[uint_0:%[0-9]+]] = OpConstant [[uint]] 0
+; CHECK-DAG: [[#bool:]] = OpTypeBool
+; CHECK-DAG: [[#uint:]] = OpTypeInt 32 0
+; CHECK-DAG: [[#uint_0:]] = OpConstant [[#uint]] 0
define i32 @main(i32 noundef %0) #1 {
%2 = icmp ne i32 %0, 0
br i1 %2, label %l1, label %l2
-; CHECK: [[param_0:%[0-9]+]] = OpFunctionParameter [[uint]]
-; CHECK: [[cond:%[0-9]+]] = OpINotEqual [[bool]] [[param_0]] [[uint_0]]
-; CHECK: OpBranchConditional [[cond]] [[l1_pre:%[0-9]+]] [[l2_pre:%[0-9]+]]
+; CHECK: [[#param_0:]] = OpFunctionParameter [[#uint]]
+; CHECK: [[#cond:]] = OpINotEqual [[#bool]] [[#param_0]] [[#uint_0]]
+; CHECK: OpBranchConditional [[#cond]] [[#l1_pre:]] [[#l2_pre:]]
-; CHECK-DAG: [[l2_pre]] = OpLabel
-; CHECK-NEXT: OpBranch [[l2_header:%[0-9]+]]
+; CHECK-DAG: [[#l2_pre]] = OpLabel
+; CHECK-NEXT: OpBranch [[#l2_header:]]
-; CHECK-DAG: [[l1_pre]] = OpLabel
-; CHECK-NEXT: OpBranch [[l1_header:%[0-9]+]]
+; CHECK-DAG: [[#l1_pre]] = OpLabel
+; CHECK-NEXT: OpBranch [[#l1_header:]]
l1:
br i1 %2, label %l1_body, label %l1_end
-; CHECK-DAG: [[l1_header]] = OpLabel
-; CHECK-NEXT: OpBranchConditional [[cond]] [[l1_body:%[0-9]+]] [[l1_end:%[0-9]+]]
+; CHECK-DAG: [[#l1_header]] = OpLabel
+; CHECK-NEXT: OpBranchConditional [[#cond]] [[#l1_body:]] [[#l1_end:]]
l1_body:
br label %l1_continue
-; CHECK-DAG: [[l1_body]] = OpLabel
-; CHECK-NEXT: OpBranch [[l1_continue:%[0-9]+]]
+; CHECK-DAG: [[#l1_body]] = OpLabel
+; CHECK-NEXT: OpBranch [[#l1_continue:]]
l1_continue:
br label %l1
-; CHECK-DAG: [[l1_continue]] = OpLabel
-; CHECK-NEXT: OpBranch [[l1_header]]
+; CHECK-DAG: [[#l1_continue]] = OpLabel
+; CHECK-NEXT: OpBranch [[#l1_header]]
l1_end:
br label %end
-; CHECK-DAG: [[l1_end]] = OpLabel
-; CHECK-NEXT: OpBranch [[end:%[0-9]+]]
+; CHECK-DAG: [[#l1_end]] = OpLabel
+; CHECK-NEXT: OpBranch [[#end:]]
l2:
br i1 %2, label %l2_body, label %l2_end
-; CHECK-DAG: [[l2_header]] = OpLabel
-; CHECK-NEXT: OpBranchConditional [[cond]] [[l2_body:%[0-9]+]] [[l2_end:%[0-9]+]]
+; CHECK-DAG: [[#l2_header]] = OpLabel
+; CHECK-NEXT: OpBranchConditional [[#cond]] [[#l2_body:]] [[#l2_end:]]
l2_body:
br label %l2_continue
-; CHECK-DAG: [[l2_body]] = OpLabel
-; CHECK-NEXT: OpBranch [[l2_continue:%[0-9]+]]
+; CHECK-DAG: [[#l2_body]] = OpLabel
+; CHECK-NEXT: OpBranch [[#l2_continue:]]
l2_continue:
br label %l2
-; CHECK-DAG: [[l2_continue]] = OpLabel
-; CHECK-NEXT: OpBranch [[l2_header]]
+; CHECK-DAG: [[#l2_continue]] = OpLabel
+; CHECK-NEXT: OpBranch [[#l2_header]]
l2_end:
br label %end
-; CHECK-DAG: [[l2_end]] = OpLabel
-; CHECK-NEXT: OpBranch [[end:%[0-9]+]]
+; CHECK-DAG: [[#l2_end]] = OpLabel
+; CHECK-NEXT: OpBranch [[#end:]]
end:
ret i32 1
-; CHECK-DAG: [[end]] = OpLabel
-; CHECK-NEXT: OpReturn
+; CHECK-DAG: [[#end]] = OpLabel
+; CHECK-NEXT: OpReturn
}
attributes #1 = { "hlsl.numthreads"="4,8,16" "hlsl.shader"="compute" convergent }
>From b1f3b2e003bd04d63ad78e1d3a882c42786b9e7f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= <brioche at google.com>
Date: Tue, 2 Jan 2024 11:51:41 +0100
Subject: [PATCH 4/4] fixup! [SPIR-V] Add pre-headers to loops.
fix test format
---
.../CodeGen/SPIRV/scfg-add-pre-headers.ll | 54 +++++++++----------
1 file changed, 27 insertions(+), 27 deletions(-)
diff --git a/llvm/test/CodeGen/SPIRV/scfg-add-pre-headers.ll b/llvm/test/CodeGen/SPIRV/scfg-add-pre-headers.ll
index 73efde8d17bb9c..46f6e03303bcb4 100644
--- a/llvm/test/CodeGen/SPIRV/scfg-add-pre-headers.ll
+++ b/llvm/test/CodeGen/SPIRV/scfg-add-pre-headers.ll
@@ -1,66 +1,66 @@
; RUN: llc -mtriple=spirv-unknown-unknown -O0 %s -o - | FileCheck %s
-; CHECK-DAG: [[#bool:]] = OpTypeBool
-; CHECK-DAG: [[#uint:]] = OpTypeInt 32 0
-; CHECK-DAG: [[#uint_0:]] = OpConstant [[#uint]] 0
+; CHECK-DAG: %[[#bool:]] = OpTypeBool
+; CHECK-DAG: %[[#uint:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#uint_0:]] = OpConstant %[[#uint]] 0
define i32 @main(i32 noundef %0) #1 {
%2 = icmp ne i32 %0, 0
br i1 %2, label %l1, label %l2
-; CHECK: [[#param_0:]] = OpFunctionParameter [[#uint]]
-; CHECK: [[#cond:]] = OpINotEqual [[#bool]] [[#param_0]] [[#uint_0]]
-; CHECK: OpBranchConditional [[#cond]] [[#l1_pre:]] [[#l2_pre:]]
+; CHECK: %[[#param_0:]] = OpFunctionParameter %[[#uint]]
+; CHECK: %[[#cond:]] = OpINotEqual %[[#bool]] %[[#param_0]] %[[#uint_0]]
+; CHECK: OpBranchConditional %[[#cond]] %[[#l1_pre:]] %[[#l2_pre:]]
-; CHECK-DAG: [[#l2_pre]] = OpLabel
-; CHECK-NEXT: OpBranch [[#l2_header:]]
+; CHECK-DAG: %[[#l2_pre]] = OpLabel
+; CHECK-NEXT: OpBranch %[[#l2_header:]]
-; CHECK-DAG: [[#l1_pre]] = OpLabel
-; CHECK-NEXT: OpBranch [[#l1_header:]]
+; CHECK-DAG: %[[#l1_pre]] = OpLabel
+; CHECK-NEXT: OpBranch %[[#l1_header:]]
l1:
br i1 %2, label %l1_body, label %l1_end
-; CHECK-DAG: [[#l1_header]] = OpLabel
-; CHECK-NEXT: OpBranchConditional [[#cond]] [[#l1_body:]] [[#l1_end:]]
+; CHECK-DAG: %[[#l1_header]] = OpLabel
+; CHECK-NEXT: OpBranchConditional %[[#cond]] %[[#l1_body:]] %[[#l1_end:]]
l1_body:
br label %l1_continue
-; CHECK-DAG: [[#l1_body]] = OpLabel
-; CHECK-NEXT: OpBranch [[#l1_continue:]]
+; CHECK-DAG: %[[#l1_body]] = OpLabel
+; CHECK-NEXT: OpBranch %[[#l1_continue:]]
l1_continue:
br label %l1
-; CHECK-DAG: [[#l1_continue]] = OpLabel
-; CHECK-NEXT: OpBranch [[#l1_header]]
+; CHECK-DAG: %[[#l1_continue]] = OpLabel
+; CHECK-NEXT: OpBranch %[[#l1_header]]
l1_end:
br label %end
-; CHECK-DAG: [[#l1_end]] = OpLabel
-; CHECK-NEXT: OpBranch [[#end:]]
+; CHECK-DAG: %[[#l1_end]] = OpLabel
+; CHECK-NEXT: OpBranch %[[#end:]]
l2:
br i1 %2, label %l2_body, label %l2_end
-; CHECK-DAG: [[#l2_header]] = OpLabel
-; CHECK-NEXT: OpBranchConditional [[#cond]] [[#l2_body:]] [[#l2_end:]]
+; CHECK-DAG: %[[#l2_header]] = OpLabel
+; CHECK-NEXT: OpBranchConditional %[[#cond]] %[[#l2_body:]] %[[#l2_end:]]
l2_body:
br label %l2_continue
-; CHECK-DAG: [[#l2_body]] = OpLabel
-; CHECK-NEXT: OpBranch [[#l2_continue:]]
+; CHECK-DAG: %[[#l2_body]] = OpLabel
+; CHECK-NEXT: OpBranch %[[#l2_continue:]]
l2_continue:
br label %l2
-; CHECK-DAG: [[#l2_continue]] = OpLabel
-; CHECK-NEXT: OpBranch [[#l2_header]]
+; CHECK-DAG: %[[#l2_continue]] = OpLabel
+; CHECK-NEXT: OpBranch %[[#l2_header]]
l2_end:
br label %end
-; CHECK-DAG: [[#l2_end]] = OpLabel
-; CHECK-NEXT: OpBranch [[#end:]]
+; CHECK-DAG: %[[#l2_end]] = OpLabel
+; CHECK-NEXT: OpBranch %[[#end:]]
end:
ret i32 1
-; CHECK-DAG: [[#end]] = OpLabel
+; CHECK-DAG: %[[#end]] = OpLabel
; CHECK-NEXT: OpReturn
}
More information about the llvm-commits
mailing list