Jim Grosbach | 4e0dbee | 2011-09-30 17:41:35 +0000 | [diff] [blame] | 1 | ; RUN: llc < %s -mtriple=arm-apple-darwin -relocation-model=dynamic-no-pic -mcpu=cortex-a8 -asm-verbose=false | FileCheck %s |
Bob Wilson | 108aadf | 2009-11-18 22:52:37 +0000 | [diff] [blame] | 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 | |
Dan Gohman | fb41936 | 2010-01-05 17:55:26 +0000 | [diff] [blame] | 12 | declare i8* @choose(i8*, i8*) |
Bob Wilson | 108aadf | 2009-11-18 22:52:37 +0000 | [diff] [blame] | 13 | |
| 14 | ; BranchFolding should tail-duplicate the indirect jump to avoid |
| 15 | ; redundant branching. |
| 16 | |
Stephen Lin | d24ab20 | 2013-07-14 06:24:09 +0000 | [diff] [blame] | 17 | ; CHECK-LABEL: tail_duplicate_me: |
Bob Wilson | 108aadf | 2009-11-18 22:52:37 +0000 | [diff] [blame] | 18 | ; CHECK: qux |
Evan Cheng | 2f2435d | 2011-01-21 18:55:51 +0000 | [diff] [blame] | 19 | ; CHECK: movw r{{[0-9]+}}, :lower16:_GHJK |
| 20 | ; CHECK: movt r{{[0-9]+}}, :upper16:_GHJK |
Bob Wilson | 108aadf | 2009-11-18 22:52:37 +0000 | [diff] [blame] | 21 | ; CHECK: str r |
| 22 | ; CHECK-NEXT: bx r |
Chandler Carruth | 4190b50 | 2012-04-16 13:49:17 +0000 | [diff] [blame] | 23 | ; CHECK: qux |
Evan Cheng | 2f2435d | 2011-01-21 18:55:51 +0000 | [diff] [blame] | 24 | ; CHECK: movw r{{[0-9]+}}, :lower16:_GHJK |
| 25 | ; CHECK: movt r{{[0-9]+}}, :upper16:_GHJK |
Bob Wilson | 108aadf | 2009-11-18 22:52:37 +0000 | [diff] [blame] | 26 | ; CHECK: str r |
| 27 | ; CHECK-NEXT: bx r |
Evan Cheng | 2f2435d | 2011-01-21 18:55:51 +0000 | [diff] [blame] | 28 | ; CHECK: movw r{{[0-9]+}}, :lower16:_GHJK |
| 29 | ; CHECK: movt r{{[0-9]+}}, :upper16:_GHJK |
Bob Wilson | 108aadf | 2009-11-18 22:52:37 +0000 | [diff] [blame] | 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 | } |
Reid Kleckner | a622fc9 | 2017-02-14 21:02:24 +0000 | [diff] [blame] | 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 | } |