Skip to content

Commit a7f6d27

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 579ac18 commit a7f6d27

File tree

5 files changed

+126
-41
lines changed

5 files changed

+126
-41
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/test/tools/llvm-reduce/remove-bb-switch-default.ll

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@
1616
; RESULT0-NEXT: br i1 %arg0, label %bb1, label %bb2
1717

1818
; RESULT0: bb1:
19-
; RESULT0: %bb1.phi = phi i32 [ %bb.load, %bb ], [ %bb.load, %bb2 ], [ %bb.load, %bb2 ]
19+
; RESULT0: %bb1.phi = phi i32 [ %bb.load, %bb ], [ %bb2.phi, %bb2 ], [ %bb2.phi, %bb2 ]
2020
; RESULT0-NEXT: store i32 1, ptr null, align 4
2121
; RESULT0-NEXT: ret void
2222

2323
; RESULT0: bb2: ; preds = %bb
24+
; RESULT0-NEXT: %bb2.phi = phi i32 [ %bb.load, %bb ]
2425
; RESULT0-NEXT: store i32 2, ptr null, align 4
25-
; RESULT0-NEXT: switch i32 %bb.load, label %bb1 [
26+
; RESULT0-NEXT: switch i32 %bb2.phi, label %bb1 [
2627
; RESULT0-NEXT: i32 0, label %bb1
2728
; RESULT0-NEXT: ]
2829

@@ -33,6 +34,7 @@
3334
; RESULT1-NEXT: br label %bb2
3435

3536
; RESULT1: bb2:
37+
; RESULT1-NEXT: %bb2.phi = phi i32 [ %bb.load, %bb ]
3638
; RESULT1-NEXT: store i32 2, ptr null, align 4
3739
; RESULT1-NEXT: ret void
3840
define void @main(i1 %arg0) {

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

Lines changed: 11 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ static void rewriteFuncWithReturnType(Function &OldF, Value *NewRetValue) {
5656
BasicBlock *NewRetBlock = NewRetI ? NewRetI->getParent() : &EntryBB;
5757

5858
BasicBlock::iterator NewValIt =
59-
NewRetI ? NewRetI->getIterator() : EntryBB.end();
59+
NewRetI ? std::next(NewRetI->getIterator()) : EntryBB.begin();
6060

6161
Type *OldRetTy = OldFuncTy->getReturnType();
6262

@@ -74,28 +74,16 @@ static void rewriteFuncWithReturnType(Function &OldF, Value *NewRetValue) {
7474
}
7575
}
7676

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

81+
// Replace the unconditional branch splitBasicBlock created
82+
NewRetBlock->getTerminator()->eraseFromParent();
9383
ReturnInst::Create(Ctx, NewRetValue, NewRetBlock);
9484

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

10088
// Drop the incompatible attributes before we copy over to the new function.
10189
if (OldRetTy != NewRetTy) {
@@ -200,20 +188,6 @@ static bool shouldReplaceNonVoidReturnValue(const BasicBlock &BB,
200188
return true;
201189
}
202190

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

234208
for (BasicBlock &BB : F) {
235-
if (!canHandleSuccessors(BB))
236-
continue;
237-
238-
for (Instruction &I : BB) {
209+
// Skip the terminator, we can't insert a second terminator to return its
210+
// value.
211+
for (Instruction &I : make_range(BB.begin(), std::prev(BB.end()))) {
239212
if (shouldForwardValueToReturn(BB, &I, RetTy) && !O.shouldKeep()) {
240213
FuncsToReplace.emplace_back(&F, &I);
241214
return true;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ void llvm::simpleSimplifyCFG(Function &F, ArrayRef<BasicBlock *> BBs,
7373
for (BasicBlock *BB : Unreachable) {
7474
for (BasicBlock *Successor : successors(&*BB))
7575
if (Visited.count(Successor))
76-
Successor->removePredecessor(&*BB);
76+
Successor->removePredecessor(&*BB, /*KeepOneInputPHIs=*/true);
7777
BB->dropAllReferences();
7878
}
7979

0 commit comments

Comments
 (0)