Skip to content

Commit c1e5029

Browse files
committed
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.
1 parent f86430f commit c1e5029

File tree

4 files changed

+122
-40
lines changed

4 files changed

+122
-40
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
; 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
2+
; RUN: FileCheck --check-prefix=RESULT %s < %t
3+
4+
@gv = global i32 0, align 4
5+
6+
; INTERESTING-LABEL: @callbr0(
7+
; INTERESTING: %load0 = load i32, ptr %arg0
8+
; INTERESTING: store i32 %load0, ptr @gv
9+
10+
; RESULT-LABEL: define void @callbr0(ptr %arg0) {
11+
; RESULT: %load0 = load i32, ptr %arg0, align 4
12+
; RESULT-NEXT: %callbr = callbr i32 asm
13+
define void @callbr0(ptr %arg0) {
14+
entry:
15+
%load0 = load i32, ptr %arg0
16+
%callbr = callbr i32 asm "", "=r,r,!i,!i"(i32 %load0)
17+
to label %one [label %two, label %three]
18+
one:
19+
store i32 %load0, ptr @gv
20+
ret void
21+
22+
two:
23+
store i32 %load0, ptr @gv
24+
ret void
25+
26+
three:
27+
store i32 %load0, ptr @gv
28+
ret void
29+
}
30+
31+
; INTERESTING-LABEL: @callbr1(
32+
; INTERESTING: %load0 = load i32, ptr %arg0
33+
34+
; RESULT-LABEL: define i32 @callbr1(ptr %arg0) {
35+
; RESULT-NEXT: entry:
36+
; RESULT-NEXT: %load0 = load i32, ptr %arg0
37+
; RESULT-NEXT: ret i32 %load0
38+
define void @callbr1(ptr %arg0) {
39+
entry:
40+
%load0 = load i32, ptr %arg0
41+
%callbr = callbr i32 asm "", "=r,r,!i,!i"(i32 %load0)
42+
to label %one [label %two, label %three]
43+
one:
44+
store i32 %load0, ptr @gv
45+
ret void
46+
47+
two:
48+
store i32 %load0, ptr @gv
49+
ret void
50+
51+
three:
52+
store i32 %load0, ptr @gv
53+
ret void
54+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
; 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
2+
; RUN: FileCheck --check-prefix=RESULT %s < %t
3+
4+
@gv = global i32 0, align 4
5+
6+
7+
define i32 @has_invoke_user(ptr %arg) {
8+
%load = load i32, ptr %arg
9+
store i32 %load, ptr @gv
10+
ret i32 9
11+
}
12+
13+
declare i32 @__gxx_personality_v0(...)
14+
15+
; INTERESTING-LABEL: @invoker_keep_invoke(
16+
; INTERESTING: %invoke
17+
; RESULT: %invoke = invoke i32 @has_invoke_user(ptr %arg)
18+
define void @invoker_keep_invoke(ptr %arg) personality ptr @__gxx_personality_v0 {
19+
bb:
20+
%invoke = invoke i32 @has_invoke_user(ptr %arg)
21+
to label %bb3 unwind label %bb1
22+
23+
bb1:
24+
landingpad { ptr, i32 }
25+
catch ptr null
26+
ret void
27+
28+
bb3:
29+
store i32 %invoke, ptr null
30+
ret void
31+
}
32+
33+
; INTERESTING-LABEL: @invoker_drop_invoke(
34+
; INTERESTING: %add = add i32
35+
36+
; RESULT-LABEL: define i32 @invoker_drop_invoke(i32 %arg0, ptr %arg1) personality ptr @__gxx_personality_v0 {
37+
; RESULT-NEXT: bb:
38+
; RESULT-NEXT: %add = add i32 %arg0, 9
39+
; RESULT-NEXT: ret i32 %add
40+
; RESULT-NEXT: }
41+
define void @invoker_drop_invoke(i32 %arg0, ptr %arg1) personality ptr @__gxx_personality_v0 {
42+
bb:
43+
%add = add i32 %arg0, 9
44+
%invoke = invoke i32 @has_invoke_user(ptr %arg1)
45+
to label %bb3 unwind label %bb1
46+
47+
bb1:
48+
landingpad { ptr, i32 }
49+
catch ptr null
50+
br label %bb3
51+
52+
bb3:
53+
%phi = phi i32 [ %invoke, %bb ], [ %add, %bb1 ]
54+
store i32 %phi, ptr null
55+
ret void
56+
}

llvm/tools/llvm-reduce/deltas/ReduceValuesToReturn.cpp

Lines changed: 11 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
#include "llvm/IR/Attributes.h"
2323
#include "llvm/IR/CFG.h"
2424
#include "llvm/IR/Instructions.h"
25-
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
2625
#include "llvm/Transforms/Utils/Cloning.h"
2726

2827
using namespace llvm;
@@ -55,7 +54,7 @@ static void rewriteFuncWithReturnType(Function &OldF, Value *NewRetValue) {
5554
BasicBlock *NewRetBlock = NewRetI ? NewRetI->getParent() : &EntryBB;
5655

5756
BasicBlock::iterator NewValIt =
58-
NewRetI ? NewRetI->getIterator() : EntryBB.end();
57+
NewRetI ? std::next(NewRetI->getIterator()) : EntryBB.begin();
5958

6059
Type *OldRetTy = OldFuncTy->getReturnType();
6160

@@ -73,28 +72,16 @@ static void rewriteFuncWithReturnType(Function &OldF, Value *NewRetValue) {
7372
}
7473
}
7574

76-
// Now prune any CFG edges we have to deal with.
77-
//
78-
// Use KeepOneInputPHIs in case the instruction we are using for the return is
79-
// that phi.
80-
// TODO: Could avoid this with fancier iterator management.
81-
for (BasicBlock *Succ : successors(NewRetBlock))
82-
Succ->removePredecessor(NewRetBlock, /*KeepOneInputPHIs=*/true);
83-
84-
// Now delete the tail of this block, in reverse to delete uses before defs.
85-
for (Instruction &I : make_early_inc_range(
86-
make_range(NewRetBlock->rbegin(), NewValIt.getReverse()))) {
87-
Value *Replacement = getDefaultValue(I.getType());
88-
I.replaceAllUsesWith(Replacement);
89-
I.eraseFromParent();
90-
}
75+
// If we're returning an instruction, split the basic block so we can let
76+
// EliminateUnreachableBlocks cleanup the successors.
77+
BasicBlock *TailBB = NewRetBlock->splitBasicBlock(NewValIt);
9178

79+
// Replace the unconditional branch splitBasicBlock created
80+
NewRetBlock->getTerminator()->eraseFromParent();
9281
ReturnInst::Create(Ctx, NewRetValue, NewRetBlock);
9382

94-
// TODO: We may be eliminating blocks that were originally unreachable. We
95-
// probably ought to only be pruning blocks that became dead directly as a
96-
// result of our pruning here.
97-
EliminateUnreachableBlocks(OldF);
83+
// Now prune any CFG edges we have to deal with.
84+
simpleSimplifyCFG(OldF, {TailBB}, /*FoldBlockIntoPredecessor=*/false);
9885

9986
// Drop the incompatible attributes before we copy over to the new function.
10087
if (OldRetTy != NewRetTy) {
@@ -199,20 +186,6 @@ static bool shouldReplaceNonVoidReturnValue(const BasicBlock &BB,
199186
return true;
200187
}
201188

202-
static bool canHandleSuccessors(const BasicBlock &BB) {
203-
// TODO: Handle invoke and other exotic terminators
204-
if (!isa<ReturnInst, UnreachableInst, BranchInst, SwitchInst>(
205-
BB.getTerminator()))
206-
return false;
207-
208-
for (const BasicBlock *Succ : successors(&BB)) {
209-
if (!Succ->canSplitPredecessors())
210-
return false;
211-
}
212-
213-
return true;
214-
}
215-
216189
static bool shouldForwardValueToReturn(const BasicBlock &BB, const Value *V,
217190
Type *RetTy) {
218191
if (!isReallyValidReturnType(V->getType()))
@@ -231,10 +204,9 @@ static bool tryForwardingInstructionsToReturn(
231204
Type *RetTy = F.getReturnType();
232205

233206
for (BasicBlock &BB : F) {
234-
if (!canHandleSuccessors(BB))
235-
continue;
236-
237-
for (Instruction &I : BB) {
207+
// Skip the terminator, we can't insert a second terminator to return its
208+
// value.
209+
for (Instruction &I : make_range(BB.begin(), std::prev(BB.end()))) {
238210
if (shouldForwardValueToReturn(BB, &I, RetTy) && !O.shouldKeep()) {
239211
FuncsToReplace.emplace_back(&F, &I);
240212
return true;

llvm/tools/llvm-reduce/deltas/Utils.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ void llvm::simpleSimplifyCFG(Function &F, ArrayRef<BasicBlock *> BBs,
7979
for (BasicBlock *BB : Unreachable) {
8080
for (BasicBlock *Successor : successors(&*BB))
8181
if (Visited.count(Successor))
82-
Successor->removePredecessor(&*BB);
82+
Successor->removePredecessor(&*BB, /*KeepOneInputPHIs=*/true);
8383
BB->dropAllReferences();
8484
}
8585

0 commit comments

Comments
 (0)