https://github.com/arsenm updated 
https://github.com/llvm/llvm-project/pull/134794

>From a1b1e097648b8d0f14452291db4d7951c1144eaf Mon Sep 17 00:00:00 2001
From: Matt Arsenault <matthew.arsena...@amd.com>
Date: Tue, 8 Apr 2025 11:16:01 +0700
Subject: [PATCH] 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
+
+@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
+
+@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 caa77b7009282..0fe8bc5b365cb 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();
   }
 

_______________________________________________
llvm-branch-commits mailing list
llvm-branch-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to