Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit f3470b1

Browse files
committed
[BranchFolding] Tail common all identical unreachable blocks
Summary: Blocks ending in unreachable are typically cold because they end the program or throw an exception, so merging them with other identical blocks is usually profitable because it reduces the size of cold code. MachineBlockPlacement generally does not arrange to fall through to such blocks, so commoning these blocks will not introduce additional unconditional branches. Reviewers: hans, iteratee, haicheng Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D29153 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@295105 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 07fb294 commit f3470b1

File tree

3 files changed

+175
-16
lines changed

3 files changed

+175
-16
lines changed

lib/CodeGen/BranchFolding.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,17 @@ static unsigned CountTerminators(MachineBasicBlock *MBB,
523523
return NumTerms;
524524
}
525525

526+
/// A no successor, non-return block probably ends in unreachable and is cold.
527+
/// Also consider a block that ends in an indirect branch to be a return block,
528+
/// since many targets use plain indirect branches to return.
529+
static bool blockEndsInUnreachable(const MachineBasicBlock *MBB) {
530+
if (!MBB->succ_empty())
531+
return false;
532+
if (MBB->empty())
533+
return true;
534+
return !(MBB->back().isReturn() || MBB->back().isIndirectBranch());
535+
}
536+
526537
/// ProfitableToMerge - Check if two machine basic blocks have a common tail
527538
/// and decide if it would be profitable to merge those tails. Return the
528539
/// length of the common tail and iterators to the first common instruction
@@ -577,6 +588,15 @@ ProfitableToMerge(MachineBasicBlock *MBB1, MachineBasicBlock *MBB2,
577588
return true;
578589
}
579590

591+
// If these are identical non-return blocks with no successors, merge them.
592+
// Such blocks are typically cold calls to noreturn functions like abort, and
593+
// are unlikely to become a fallthrough target after machine block placement.
594+
// Tail merging these blocks is unlikely to create additional unconditional
595+
// branches, and will reduce the size of this cold code.
596+
if (I1 == MBB1->begin() && I2 == MBB2->begin() &&
597+
blockEndsInUnreachable(MBB1) && blockEndsInUnreachable(MBB2))
598+
return true;
599+
580600
// If one of the blocks can be completely merged and happens to be in
581601
// a position where the other could fall through into it, merge any number
582602
// of instructions, because it can be done without a branch.

test/CodeGen/ARM/tail-opts.ll

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,55 @@ altret:
6565
call void @far(i32 1001)
6666
ret void
6767
}
68+
69+
; Use alternating abort functions so that the blocks we wish to merge are not
70+
; layout successors during branch folding.
71+
72+
; CHECK-LABEL: merge_alternating_aborts:
73+
; CHECK-NOT: _abort
74+
; CHECK-NOT: _alt_abort
75+
; CHECK: bxne lr
76+
; CHECK-NOT: _abort
77+
; CHECK-NOT: _alt_abort
78+
; CHECK: LBB{{.*}}:
79+
; CHECK: mov lr, pc
80+
; CHECK: b _alt_abort
81+
; CHECK-NOT: _abort
82+
; CHECK-NOT: _alt_abort
83+
; CHECK: LBB{{.*}}:
84+
; CHECK: mov lr, pc
85+
; CHECK: b _abort
86+
; CHECK-NOT: _abort
87+
; CHECK-NOT: _alt_abort
88+
89+
declare void @abort()
90+
declare void @alt_abort()
91+
92+
define void @merge_alternating_aborts() {
93+
entry:
94+
%c1 = call i1 @qux()
95+
br i1 %c1, label %cont1, label %abort1
96+
abort1:
97+
call void @abort()
98+
unreachable
99+
cont1:
100+
%c2 = call i1 @qux()
101+
br i1 %c2, label %cont2, label %abort2
102+
abort2:
103+
call void @alt_abort()
104+
unreachable
105+
cont2:
106+
%c3 = call i1 @qux()
107+
br i1 %c3, label %cont3, label %abort3
108+
abort3:
109+
call void @abort()
110+
unreachable
111+
cont3:
112+
%c4 = call i1 @qux()
113+
br i1 %c4, label %cont4, label %abort4
114+
abort4:
115+
call void @alt_abort()
116+
unreachable
117+
cont4:
118+
ret void
119+
}

test/CodeGen/X86/tail-opts.ll

Lines changed: 103 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -299,33 +299,35 @@ declare void @func()
299299
; one - One instruction may be tail-duplicated even with optsize.
300300

301301
; CHECK-LABEL: one:
302-
; CHECK: movl $0, XYZ(%rip)
303-
; CHECK: movl $0, XYZ(%rip)
302+
; CHECK: j{{.*}} tail_call_me
303+
; CHECK: j{{.*}} tail_call_me
304304

305305
@XYZ = external global i32
306306

307-
define void @one() nounwind optsize {
307+
declare void @tail_call_me()
308+
309+
define void @one(i32 %v) nounwind optsize {
308310
entry:
309-
%0 = icmp eq i32 undef, 0
311+
%0 = icmp eq i32 %v, 0
310312
br i1 %0, label %bbx, label %bby
311313

312314
bby:
313-
switch i32 undef, label %bb7 [
315+
switch i32 %v, label %bb7 [
314316
i32 16, label %return
315317
]
316318

317319
bb7:
318-
store volatile i32 0, i32* @XYZ
319-
unreachable
320+
tail call void @tail_call_me()
321+
ret void
320322

321323
bbx:
322-
switch i32 undef, label %bb12 [
324+
switch i32 %v, label %bb12 [
323325
i32 128, label %return
324326
]
325327

326328
bb12:
327-
store volatile i32 0, i32* @XYZ
328-
unreachable
329+
tail call void @tail_call_me()
330+
ret void
329331

330332
return:
331333
ret void
@@ -414,9 +416,9 @@ return:
414416

415417
; CHECK-LABEL: two_nosize:
416418
; CHECK: movl $0, XYZ(%rip)
417-
; CHECK: movl $1, XYZ(%rip)
419+
; CHECK: jmp tail_call_me
418420
; CHECK: movl $0, XYZ(%rip)
419-
; CHECK: movl $1, XYZ(%rip)
421+
; CHECK: jmp tail_call_me
420422

421423
define void @two_nosize() nounwind {
422424
entry:
@@ -430,8 +432,8 @@ bby:
430432

431433
bb7:
432434
store volatile i32 0, i32* @XYZ
433-
store volatile i32 1, i32* @XYZ
434-
unreachable
435+
tail call void @tail_call_me()
436+
ret void
435437

436438
bbx:
437439
switch i32 undef, label %bb12 [
@@ -440,8 +442,8 @@ bbx:
440442

441443
bb12:
442444
store volatile i32 0, i32* @XYZ
443-
store volatile i32 1, i32* @XYZ
444-
unreachable
445+
tail call void @tail_call_me()
446+
ret void
445447

446448
return:
447449
ret void
@@ -469,3 +471,88 @@ bb.nph: ; preds = %entry
469471
for.end: ; preds = %entry
470472
ret i64 %varx.0
471473
}
474+
475+
; We should tail merge small blocks that don't end in a tail call or return
476+
; instruction. Those blocks are typically unreachable and will be placed
477+
; out-of-line after the main return, so we should try to eliminate as many of
478+
; them as possible.
479+
480+
; CHECK-LABEL: merge_aborts:
481+
; CHECK-NOT: callq abort
482+
; CHECK: ret
483+
; CHECK: callq abort
484+
; CHECK-NOT: callq abort
485+
; CHECK: .Lfunc_end{{.*}}:
486+
487+
declare void @abort()
488+
define void @merge_aborts() {
489+
entry:
490+
%c1 = call i1 @qux()
491+
br i1 %c1, label %cont1, label %abort1
492+
abort1:
493+
call void @abort()
494+
unreachable
495+
cont1:
496+
%c2 = call i1 @qux()
497+
br i1 %c2, label %cont2, label %abort2
498+
abort2:
499+
call void @abort()
500+
unreachable
501+
cont2:
502+
%c3 = call i1 @qux()
503+
br i1 %c3, label %cont3, label %abort3
504+
abort3:
505+
call void @abort()
506+
unreachable
507+
cont3:
508+
%c4 = call i1 @qux()
509+
br i1 %c4, label %cont4, label %abort4
510+
abort4:
511+
call void @abort()
512+
unreachable
513+
cont4:
514+
ret void
515+
}
516+
517+
; Use alternating abort functions so that the blocks we wish to merge are not
518+
; layout successors during branch folding.
519+
520+
; CHECK-LABEL: merge_alternating_aborts:
521+
; CHECK-NOT: callq abort
522+
; CHECK: ret
523+
; CHECK: callq abort
524+
; CHECK: callq alt_abort
525+
; CHECK-NOT: callq abort
526+
; CHECK-NOT: callq alt_abort
527+
; CHECK: .Lfunc_end{{.*}}:
528+
529+
declare void @alt_abort()
530+
531+
define void @merge_alternating_aborts() {
532+
entry:
533+
%c1 = call i1 @qux()
534+
br i1 %c1, label %cont1, label %abort1
535+
abort1:
536+
call void @abort()
537+
unreachable
538+
cont1:
539+
%c2 = call i1 @qux()
540+
br i1 %c2, label %cont2, label %abort2
541+
abort2:
542+
call void @alt_abort()
543+
unreachable
544+
cont2:
545+
%c3 = call i1 @qux()
546+
br i1 %c3, label %cont3, label %abort3
547+
abort3:
548+
call void @abort()
549+
unreachable
550+
cont3:
551+
%c4 = call i1 @qux()
552+
br i1 %c4, label %cont4, label %abort4
553+
abort4:
554+
call void @alt_abort()
555+
unreachable
556+
cont4:
557+
ret void
558+
}

0 commit comments

Comments
 (0)