summaryrefslogtreecommitdiff
path: root/test/CodeGen/X86/tail-opts.ll
diff options
context:
space:
mode:
Diffstat (limited to 'test/CodeGen/X86/tail-opts.ll')
-rw-r--r--test/CodeGen/X86/tail-opts.ll126
1 files changed, 106 insertions, 20 deletions
diff --git a/test/CodeGen/X86/tail-opts.ll b/test/CodeGen/X86/tail-opts.ll
index 12c90c1a5fa9..96ff33ff5f7d 100644
--- a/test/CodeGen/X86/tail-opts.ll
+++ b/test/CodeGen/X86/tail-opts.ll
@@ -113,16 +113,15 @@ altret:
; CHECK-NEXT: jbe .LBB2_3
; CHECK-NEXT: ucomiss %xmm{{[0-2]}}, %xmm{{[0-2]}}
; CHECK-NEXT: ja .LBB2_4
-; CHECK-NEXT: jmp .LBB2_2
+; CHECK-NEXT: .LBB2_2:
+; CHECK-NEXT: movb $1, %al
+; CHECK-NEXT: ret
; CHECK-NEXT: .LBB2_3:
; CHECK-NEXT: ucomiss %xmm{{[0-2]}}, %xmm{{[0-2]}}
; CHECK-NEXT: jbe .LBB2_2
; CHECK-NEXT: .LBB2_4:
; CHECK-NEXT: xorl %eax, %eax
; CHECK-NEXT: ret
-; CHECK-NEXT: .LBB2_2:
-; CHECK-NEXT: movb $1, %al
-; CHECK-NEXT: ret
define i1 @dont_merge_oddly(float* %result) nounwind {
entry:
@@ -299,33 +298,35 @@ declare void @func()
; one - One instruction may be tail-duplicated even with optsize.
; CHECK-LABEL: one:
-; CHECK: movl $0, XYZ(%rip)
-; CHECK: movl $0, XYZ(%rip)
+; CHECK: j{{.*}} tail_call_me
+; CHECK: j{{.*}} tail_call_me
@XYZ = external global i32
-define void @one() nounwind optsize {
+declare void @tail_call_me()
+
+define void @one(i32 %v) nounwind optsize {
entry:
- %0 = icmp eq i32 undef, 0
+ %0 = icmp eq i32 %v, 0
br i1 %0, label %bbx, label %bby
bby:
- switch i32 undef, label %bb7 [
+ switch i32 %v, label %bb7 [
i32 16, label %return
]
bb7:
- store volatile i32 0, i32* @XYZ
- unreachable
+ tail call void @tail_call_me()
+ ret void
bbx:
- switch i32 undef, label %bb12 [
+ switch i32 %v, label %bb12 [
i32 128, label %return
]
bb12:
- store volatile i32 0, i32* @XYZ
- unreachable
+ tail call void @tail_call_me()
+ ret void
return:
ret void
@@ -414,9 +415,9 @@ return:
; CHECK-LABEL: two_nosize:
; CHECK: movl $0, XYZ(%rip)
-; CHECK: movl $1, XYZ(%rip)
+; CHECK: jmp tail_call_me
; CHECK: movl $0, XYZ(%rip)
-; CHECK: movl $1, XYZ(%rip)
+; CHECK: jmp tail_call_me
define void @two_nosize() nounwind {
entry:
@@ -430,8 +431,8 @@ bby:
bb7:
store volatile i32 0, i32* @XYZ
- store volatile i32 1, i32* @XYZ
- unreachable
+ tail call void @tail_call_me()
+ ret void
bbx:
switch i32 undef, label %bb12 [
@@ -440,8 +441,8 @@ bbx:
bb12:
store volatile i32 0, i32* @XYZ
- store volatile i32 1, i32* @XYZ
- unreachable
+ tail call void @tail_call_me()
+ ret void
return:
ret void
@@ -469,3 +470,88 @@ bb.nph: ; preds = %entry
for.end: ; preds = %entry
ret i64 %varx.0
}
+
+; We should tail merge small blocks that don't end in a tail call or return
+; instruction. Those blocks are typically unreachable and will be placed
+; out-of-line after the main return, so we should try to eliminate as many of
+; them as possible.
+
+; CHECK-LABEL: merge_aborts:
+; CHECK-NOT: callq abort
+; CHECK: ret
+; CHECK: callq abort
+; CHECK-NOT: callq abort
+; CHECK: .Lfunc_end{{.*}}:
+
+declare void @abort()
+define void @merge_aborts() {
+entry:
+ %c1 = call i1 @qux()
+ br i1 %c1, label %cont1, label %abort1
+abort1:
+ call void @abort()
+ unreachable
+cont1:
+ %c2 = call i1 @qux()
+ br i1 %c2, label %cont2, label %abort2
+abort2:
+ call void @abort()
+ unreachable
+cont2:
+ %c3 = call i1 @qux()
+ br i1 %c3, label %cont3, label %abort3
+abort3:
+ call void @abort()
+ unreachable
+cont3:
+ %c4 = call i1 @qux()
+ br i1 %c4, label %cont4, label %abort4
+abort4:
+ call void @abort()
+ unreachable
+cont4:
+ ret void
+}
+
+; Use alternating abort functions so that the blocks we wish to merge are not
+; layout successors during branch folding.
+
+; CHECK-LABEL: merge_alternating_aborts:
+; CHECK-NOT: callq abort
+; CHECK: ret
+; CHECK: callq abort
+; CHECK: callq alt_abort
+; CHECK-NOT: callq abort
+; CHECK-NOT: callq alt_abort
+; CHECK: .Lfunc_end{{.*}}:
+
+declare void @alt_abort()
+
+define void @merge_alternating_aborts() {
+entry:
+ %c1 = call i1 @qux()
+ br i1 %c1, label %cont1, label %abort1
+abort1:
+ call void @abort()
+ unreachable
+cont1:
+ %c2 = call i1 @qux()
+ br i1 %c2, label %cont2, label %abort2
+abort2:
+ call void @alt_abort()
+ unreachable
+cont2:
+ %c3 = call i1 @qux()
+ br i1 %c3, label %cont3, label %abort3
+abort3:
+ call void @abort()
+ unreachable
+cont3:
+ %c4 = call i1 @qux()
+ br i1 %c4, label %cont4, label %abort4
+abort4:
+ call void @alt_abort()
+ unreachable
+cont4:
+ ret void
+}