1 ; RUN: llc < %s -mtriple=arm-apple-darwin -relocation-model=dynamic-no-pic -mcpu=cortex-a8 -asm-verbose=false | FileCheck %s 2 3 declare void @bar(i32) 4 declare void @car(i32) 5 declare void @dar(i32) 6 declare void @ear(i32) 7 declare void @far(i32) 8 declare i1 @qux() 9 10 @GHJK = global i32 0 11 12 declare 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 33 define void @tail_duplicate_me() nounwind { 34 entry: 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 39 next: 40 %b = call i1 @qux() 41 br i1 %b, label %B, label %C 42 43 A: 44 call void @bar(i32 0) 45 store i32 0, i32* @GHJK 46 br label %M 47 48 B: 49 call void @car(i32 1) 50 store i32 0, i32* @GHJK 51 br label %M 52 53 C: 54 call void @dar(i32 2) 55 store i32 0, i32* @GHJK 56 br label %M 57 58 M: 59 indirectbr i8* %c, [label %return, label %altret] 60 61 return: 62 call void @ear(i32 1000) 63 ret void 64 altret: 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 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 } 120