|  | ; RUN: llc < %s -mtriple=arm-apple-darwin -relocation-model=dynamic-no-pic -mcpu=cortex-a8 -asm-verbose=false | FileCheck %s | 
|  |  | 
|  | declare void @bar(i32) | 
|  | declare void @car(i32) | 
|  | declare void @dar(i32) | 
|  | declare void @ear(i32) | 
|  | declare void @far(i32) | 
|  | declare i1 @qux() | 
|  |  | 
|  | @GHJK = global i32 0 | 
|  |  | 
|  | declare i8* @choose(i8*, i8*) | 
|  |  | 
|  | ; BranchFolding should tail-duplicate the indirect jump to avoid | 
|  | ; redundant branching. | 
|  |  | 
|  | ; CHECK-LABEL: tail_duplicate_me: | 
|  | ; CHECK:      qux | 
|  | ; CHECK:      movw r{{[0-9]+}}, :lower16:_GHJK | 
|  | ; CHECK:      movt r{{[0-9]+}}, :upper16:_GHJK | 
|  | ; CHECK:      str r | 
|  | ; CHECK-NEXT: bx r | 
|  | ; CHECK:      qux | 
|  | ; CHECK:      movw r{{[0-9]+}}, :lower16:_GHJK | 
|  | ; CHECK:      movt r{{[0-9]+}}, :upper16:_GHJK | 
|  | ; CHECK:      str r | 
|  | ; CHECK-NEXT: bx r | 
|  | ; CHECK:      movw r{{[0-9]+}}, :lower16:_GHJK | 
|  | ; CHECK:      movt r{{[0-9]+}}, :upper16:_GHJK | 
|  | ; CHECK:      str r | 
|  | ; CHECK-NEXT: bx r | 
|  |  | 
|  | define void @tail_duplicate_me() nounwind { | 
|  | entry: | 
|  | %a = call i1 @qux() | 
|  | %c = call i8* @choose(i8* blockaddress(@tail_duplicate_me, %return), | 
|  | i8* blockaddress(@tail_duplicate_me, %altret)) | 
|  | br i1 %a, label %A, label %next | 
|  | next: | 
|  | %b = call i1 @qux() | 
|  | br i1 %b, label %B, label %C | 
|  |  | 
|  | A: | 
|  | call void @bar(i32 0) | 
|  | store i32 0, i32* @GHJK | 
|  | br label %M | 
|  |  | 
|  | B: | 
|  | call void @car(i32 1) | 
|  | store i32 0, i32* @GHJK | 
|  | br label %M | 
|  |  | 
|  | C: | 
|  | call void @dar(i32 2) | 
|  | store i32 0, i32* @GHJK | 
|  | br label %M | 
|  |  | 
|  | M: | 
|  | indirectbr i8* %c, [label %return, label %altret] | 
|  |  | 
|  | return: | 
|  | call void @ear(i32 1000) | 
|  | ret void | 
|  | altret: | 
|  | call void @far(i32 1001) | 
|  | 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: _abort | 
|  | ; CHECK-NOT: _alt_abort | 
|  | ; CHECK: bxne lr | 
|  | ; CHECK-NOT: _abort | 
|  | ; CHECK-NOT: _alt_abort | 
|  | ; CHECK: LBB{{.*}}: | 
|  | ; CHECK: mov lr, pc | 
|  | ; CHECK: b _alt_abort | 
|  | ; CHECK-NOT: _abort | 
|  | ; CHECK-NOT: _alt_abort | 
|  | ; CHECK: LBB{{.*}}: | 
|  | ; CHECK: mov lr, pc | 
|  | ; CHECK: b _abort | 
|  | ; CHECK-NOT: _abort | 
|  | ; CHECK-NOT: _alt_abort | 
|  |  | 
|  | declare void @abort() | 
|  | 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 | 
|  | } |