; 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 }