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