1; RUN: llc < %s -mtriple=arm-apple-darwin -relocation-model=dynamic-no-pic -mcpu=cortex-a8 -asm-verbose=false | FileCheck %s
2
3declare void @bar(i32)
4declare void @car(i32)
5declare void @dar(i32)
6declare void @ear(i32)
7declare void @far(i32)
8declare i1 @qux()
9
10@GHJK = global i32 0
11
12declare i8* @choose(i8*, i8*)
13
14; BranchFolding should tail-duplicate the indirect jump to avoid
15; redundant branching.
16
17; CHECK-LABEL: tail_duplicate_me:
18; CHECK:      qux
19; CHECK:      movw r{{[0-9]+}}, :lower16:_GHJK
20; CHECK:      movt r{{[0-9]+}}, :upper16:_GHJK
21; CHECK:      str r
22; CHECK-NEXT: bx r
23; CHECK:      qux
24; CHECK:      movw r{{[0-9]+}}, :lower16:_GHJK
25; CHECK:      movt r{{[0-9]+}}, :upper16:_GHJK
26; CHECK:      str r
27; CHECK-NEXT: bx r
28; CHECK:      movw r{{[0-9]+}}, :lower16:_GHJK
29; CHECK:      movt r{{[0-9]+}}, :upper16:_GHJK
30; CHECK:      str r
31; CHECK-NEXT: bx r
32
33define void @tail_duplicate_me() nounwind {
34entry:
35  %a = call i1 @qux()
36  %c = call i8* @choose(i8* blockaddress(@tail_duplicate_me, %return),
37                        i8* blockaddress(@tail_duplicate_me, %altret))
38  br i1 %a, label %A, label %next
39next:
40  %b = call i1 @qux()
41  br i1 %b, label %B, label %C
42
43A:
44  call void @bar(i32 0)
45  store i32 0, i32* @GHJK
46  br label %M
47
48B:
49  call void @car(i32 1)
50  store i32 0, i32* @GHJK
51  br label %M
52
53C:
54  call void @dar(i32 2)
55  store i32 0, i32* @GHJK
56  br label %M
57
58M:
59  indirectbr i8* %c, [label %return, label %altret]
60
61return:
62  call void @ear(i32 1000)
63  ret void
64altret:
65  call void @far(i32 1001)
66  ret void
67}
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
89declare void @abort()
90declare void @alt_abort()
91
92define void @merge_alternating_aborts() {
93entry:
94  %c1 = call i1 @qux()
95  br i1 %c1, label %cont1, label %abort1
96abort1:
97  call void @abort()
98  unreachable
99cont1:
100  %c2 = call i1 @qux()
101  br i1 %c2, label %cont2, label %abort2
102abort2:
103  call void @alt_abort()
104  unreachable
105cont2:
106  %c3 = call i1 @qux()
107  br i1 %c3, label %cont3, label %abort3
108abort3:
109  call void @abort()
110  unreachable
111cont3:
112  %c4 = call i1 @qux()
113  br i1 %c4, label %cont4, label %abort4
114abort4:
115  call void @alt_abort()
116  unreachable
117cont4:
118  ret void
119}
120