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