[llvm] llvm-reduce: Support exotic terminators in instructions-to-return (PR #134794)
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Fri May 2 11:19:17 PDT 2025
https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/134794
>From 0141187b692206e3a19fd6aea6f7e2bd03c3cb4f Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Tue, 8 Apr 2025 11:16:01 +0700
Subject: [PATCH 1/2] llvm-reduce: Support exotic terminators in
instructions-to-return
Use splitBasicBlock and avoid directly dealing with the specific of
how to trim the existing terminators. We just need to deal with
unconditional branch to return.
---
.../reduce-values-to-return-callbr.ll | 54 ++++++++++++++++++
.../reduce-values-to-return-invoke.ll | 56 +++++++++++++++++++
.../llvm-reduce/remove-bb-switch-default.ll | 6 +-
.../deltas/ReduceValuesToReturn.cpp | 49 ++++------------
llvm/tools/llvm-reduce/deltas/Utils.cpp | 2 +-
5 files changed, 126 insertions(+), 41 deletions(-)
create mode 100644 llvm/test/tools/llvm-reduce/reduce-values-to-return-callbr.ll
create mode 100644 llvm/test/tools/llvm-reduce/reduce-values-to-return-invoke.ll
diff --git a/llvm/test/tools/llvm-reduce/reduce-values-to-return-callbr.ll b/llvm/test/tools/llvm-reduce/reduce-values-to-return-callbr.ll
new file mode 100644
index 0000000000000..da2f225f0405b
--- /dev/null
+++ b/llvm/test/tools/llvm-reduce/reduce-values-to-return-callbr.ll
@@ -0,0 +1,54 @@
+; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=instructions-to-return --test FileCheck --test-arg --check-prefix=INTERESTING --test-arg %s --test-arg --input-file %s -o %t
+; RUN: FileCheck --check-prefix=RESULT %s < %t
+
+ at gv = global i32 0, align 4
+
+; INTERESTING-LABEL: @callbr0(
+; INTERESTING: %load0 = load i32, ptr %arg0
+; INTERESTING: store i32 %load0, ptr @gv
+
+; RESULT-LABEL: define void @callbr0(ptr %arg0) {
+; RESULT: %load0 = load i32, ptr %arg0, align 4
+; RESULT-NEXT: %callbr = callbr i32 asm
+define void @callbr0(ptr %arg0) {
+entry:
+ %load0 = load i32, ptr %arg0
+ %callbr = callbr i32 asm "", "=r,r,!i,!i"(i32 %load0)
+ to label %one [label %two, label %three]
+one:
+ store i32 %load0, ptr @gv
+ ret void
+
+two:
+ store i32 %load0, ptr @gv
+ ret void
+
+three:
+ store i32 %load0, ptr @gv
+ ret void
+}
+
+; INTERESTING-LABEL: @callbr1(
+; INTERESTING: %load0 = load i32, ptr %arg0
+
+; RESULT-LABEL: define i32 @callbr1(ptr %arg0) {
+; RESULT-NEXT: entry:
+; RESULT-NEXT: %load0 = load i32, ptr %arg0
+; RESULT-NEXT: ret i32 %load0
+define void @callbr1(ptr %arg0) {
+entry:
+ %load0 = load i32, ptr %arg0
+ %callbr = callbr i32 asm "", "=r,r,!i,!i"(i32 %load0)
+ to label %one [label %two, label %three]
+one:
+ store i32 %load0, ptr @gv
+ ret void
+
+two:
+ store i32 %load0, ptr @gv
+ ret void
+
+three:
+ store i32 %load0, ptr @gv
+ ret void
+}
diff --git a/llvm/test/tools/llvm-reduce/reduce-values-to-return-invoke.ll b/llvm/test/tools/llvm-reduce/reduce-values-to-return-invoke.ll
new file mode 100644
index 0000000000000..efa1e5377160e
--- /dev/null
+++ b/llvm/test/tools/llvm-reduce/reduce-values-to-return-invoke.ll
@@ -0,0 +1,56 @@
+; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=instructions-to-return --test FileCheck --test-arg --check-prefix=INTERESTING --test-arg %s --test-arg --input-file %s -o %t
+; RUN: FileCheck --check-prefix=RESULT %s < %t
+
+ at gv = global i32 0, align 4
+
+
+define i32 @has_invoke_user(ptr %arg) {
+ %load = load i32, ptr %arg
+ store i32 %load, ptr @gv
+ ret i32 9
+}
+
+declare i32 @__gxx_personality_v0(...)
+
+; INTERESTING-LABEL: @invoker_keep_invoke(
+; INTERESTING: %invoke
+; RESULT: %invoke = invoke i32 @has_invoke_user(ptr %arg)
+define void @invoker_keep_invoke(ptr %arg) personality ptr @__gxx_personality_v0 {
+bb:
+ %invoke = invoke i32 @has_invoke_user(ptr %arg)
+ to label %bb3 unwind label %bb1
+
+bb1:
+ landingpad { ptr, i32 }
+ catch ptr null
+ ret void
+
+bb3:
+ store i32 %invoke, ptr null
+ ret void
+}
+
+; INTERESTING-LABEL: @invoker_drop_invoke(
+; INTERESTING: %add = add i32
+
+; RESULT-LABEL: define i32 @invoker_drop_invoke(i32 %arg0, ptr %arg1) personality ptr @__gxx_personality_v0 {
+; RESULT-NEXT: bb:
+; RESULT-NEXT: %add = add i32 %arg0, 9
+; RESULT-NEXT: ret i32 %add
+; RESULT-NEXT: }
+define void @invoker_drop_invoke(i32 %arg0, ptr %arg1) personality ptr @__gxx_personality_v0 {
+bb:
+ %add = add i32 %arg0, 9
+ %invoke = invoke i32 @has_invoke_user(ptr %arg1)
+ to label %bb3 unwind label %bb1
+
+bb1:
+ landingpad { ptr, i32 }
+ catch ptr null
+ br label %bb3
+
+bb3:
+ %phi = phi i32 [ %invoke, %bb ], [ %add, %bb1 ]
+ store i32 %phi, ptr null
+ ret void
+}
diff --git a/llvm/test/tools/llvm-reduce/remove-bb-switch-default.ll b/llvm/test/tools/llvm-reduce/remove-bb-switch-default.ll
index b509d1181f74d..27e599e45e9a3 100644
--- a/llvm/test/tools/llvm-reduce/remove-bb-switch-default.ll
+++ b/llvm/test/tools/llvm-reduce/remove-bb-switch-default.ll
@@ -16,13 +16,14 @@
; RESULT0-NEXT: br i1 %arg0, label %bb1, label %bb2
; RESULT0: bb1:
-; RESULT0: %bb1.phi = phi i32 [ %bb.load, %bb ], [ %bb.load, %bb2 ], [ %bb.load, %bb2 ]
+; RESULT0: %bb1.phi = phi i32 [ %bb.load, %bb ], [ %bb2.phi, %bb2 ], [ %bb2.phi, %bb2 ]
; RESULT0-NEXT: store i32 1, ptr null, align 4
; RESULT0-NEXT: ret void
; RESULT0: bb2: ; preds = %bb
+; RESULT0-NEXT: %bb2.phi = phi i32 [ %bb.load, %bb ]
; RESULT0-NEXT: store i32 2, ptr null, align 4
-; RESULT0-NEXT: switch i32 %bb.load, label %bb1 [
+; RESULT0-NEXT: switch i32 %bb2.phi, label %bb1 [
; RESULT0-NEXT: i32 0, label %bb1
; RESULT0-NEXT: ]
@@ -33,6 +34,7 @@
; RESULT1-NEXT: br label %bb2
; RESULT1: bb2:
+; RESULT1-NEXT: %bb2.phi = phi i32 [ %bb.load, %bb ]
; RESULT1-NEXT: store i32 2, ptr null, align 4
; RESULT1-NEXT: ret void
define void @main(i1 %arg0) {
diff --git a/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp b/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
index 4ef2f50a68371..e22e2f684248e 100644
--- a/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
+++ b/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
@@ -55,7 +55,7 @@ static void rewriteFuncWithReturnType(Function &OldF, Value *NewRetValue) {
BasicBlock *NewRetBlock = NewRetI ? NewRetI->getParent() : &EntryBB;
BasicBlock::iterator NewValIt =
- NewRetI ? NewRetI->getIterator() : EntryBB.end();
+ NewRetI ? std::next(NewRetI->getIterator()) : EntryBB.begin();
Type *OldRetTy = OldFuncTy->getReturnType();
@@ -73,28 +73,16 @@ static void rewriteFuncWithReturnType(Function &OldF, Value *NewRetValue) {
}
}
- // Now prune any CFG edges we have to deal with.
- //
- // Use KeepOneInputPHIs in case the instruction we are using for the return is
- // that phi.
- // TODO: Could avoid this with fancier iterator management.
- for (BasicBlock *Succ : successors(NewRetBlock))
- Succ->removePredecessor(NewRetBlock, /*KeepOneInputPHIs=*/true);
-
- // Now delete the tail of this block, in reverse to delete uses before defs.
- for (Instruction &I : make_early_inc_range(
- make_range(NewRetBlock->rbegin(), NewValIt.getReverse()))) {
- Value *Replacement = getDefaultValue(I.getType());
- I.replaceAllUsesWith(Replacement);
- I.eraseFromParent();
- }
+ // If we're returning an instruction, split the basic block so we can let
+ // EliminateUnreachableBlocks cleanup the successors.
+ BasicBlock *TailBB = NewRetBlock->splitBasicBlock(NewValIt);
+ // Replace the unconditional branch splitBasicBlock created
+ NewRetBlock->getTerminator()->eraseFromParent();
ReturnInst::Create(Ctx, NewRetValue, NewRetBlock);
- // TODO: We may be eliminating blocks that were originally unreachable. We
- // probably ought to only be pruning blocks that became dead directly as a
- // result of our pruning here.
- EliminateUnreachableBlocks(OldF);
+ // Now prune any CFG edges we have to deal with.
+ simpleSimplifyCFG(OldF, {TailBB}, /*FoldBlockIntoPredecessor=*/false);
// Drop the incompatible attributes before we copy over to the new function.
if (OldRetTy != NewRetTy) {
@@ -196,20 +184,6 @@ static bool shouldReplaceNonVoidReturnValue(const BasicBlock &BB,
return true;
}
-static bool canHandleSuccessors(const BasicBlock &BB) {
- // TODO: Handle invoke and other exotic terminators
- if (!isa<ReturnInst, UnreachableInst, BranchInst, SwitchInst>(
- BB.getTerminator()))
- return false;
-
- for (const BasicBlock *Succ : successors(&BB)) {
- if (!Succ->canSplitPredecessors())
- return false;
- }
-
- return true;
-}
-
static bool shouldForwardValueToReturn(const BasicBlock &BB, const Value *V,
Type *RetTy) {
if (!isReallyValidReturnType(V->getType()))
@@ -228,10 +202,9 @@ static bool tryForwardingInstructionsToReturn(
Type *RetTy = F.getReturnType();
for (BasicBlock &BB : F) {
- if (!canHandleSuccessors(BB))
- continue;
-
- for (Instruction &I : BB) {
+ // Skip the terminator, we can't insert a second terminator to return its
+ // value.
+ for (Instruction &I : make_range(BB.begin(), std::prev(BB.end()))) {
if (shouldForwardValueToReturn(BB, &I, RetTy) && !O.shouldKeep()) {
FuncsToReplace.emplace_back(&F, &I);
return true;
diff --git a/llvm/tools/llvm-reduce/deltas/Utils.cpp b/llvm/tools/llvm-reduce/deltas/Utils.cpp
index ce3d282d0eac5..bc9c4c4d41948 100644
--- a/llvm/tools/llvm-reduce/deltas/Utils.cpp
+++ b/llvm/tools/llvm-reduce/deltas/Utils.cpp
@@ -73,7 +73,7 @@ void llvm::simpleSimplifyCFG(Function &F, ArrayRef<BasicBlock *> BBs,
for (BasicBlock *BB : Unreachable) {
for (BasicBlock *Successor : successors(&*BB))
if (Visited.count(Successor))
- Successor->removePredecessor(&*BB);
+ Successor->removePredecessor(&*BB, /*KeepOneInputPHIs=*/true);
BB->dropAllReferences();
}
>From c8967661b082c665cca3f3b60dac0045eccb461c Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Fri, 2 May 2025 14:50:59 +0200
Subject: [PATCH 2/2] Update
llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
Co-authored-by: Nikita Popov <npopov at redhat.com>
---
llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp b/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
index e22e2f684248e..e3a3b987bcc65 100644
--- a/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
+++ b/llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp
@@ -74,7 +74,7 @@ static void rewriteFuncWithReturnType(Function &OldF, Value *NewRetValue) {
}
// If we're returning an instruction, split the basic block so we can let
- // EliminateUnreachableBlocks cleanup the successors.
+ // simpleSimplifyCFG cleanup the successors.
BasicBlock *TailBB = NewRetBlock->splitBasicBlock(NewValIt);
// Replace the unconditional branch splitBasicBlock created
More information about the llvm-commits
mailing list