1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc < %s -mtriple=i686-- -O3 -verify-machineinstrs | FileCheck %s 3 4; Tests for using callbr as an asm-goto wrapper 5 6; Test 1 - fallthrough label gets removed, but the fallthrough code that is 7; unreachable due to asm ending on a jmp is still left in. 8define i32 @test1(i32 %a) { 9; CHECK-LABEL: test1: 10; CHECK: # %bb.0: # %entry 11; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax 12; CHECK-NEXT: addl $4, %eax 13; CHECK-NEXT: #APP 14; CHECK-NEXT: xorl %eax, %eax 15; CHECK-NEXT: jmp .LBB0_2 16; CHECK-NEXT: #NO_APP 17; CHECK-NEXT: # %bb.1: # %normal 18; CHECK-NEXT: xorl %eax, %eax 19; CHECK-NEXT: retl 20; CHECK-NEXT: .LBB0_2: # Block address taken 21; CHECK-NEXT: # %fail 22; CHECK-NEXT: # Label of block must be emitted 23; CHECK-NEXT: movl $1, %eax 24; CHECK-NEXT: retl 25entry: 26 %0 = add i32 %a, 4 27 callbr void asm "xorl $0, $0; jmp ${1:l}", "r,!i,~{dirflag},~{fpsr},~{flags}"(i32 %0) to label %normal [label %fail] 28 29normal: 30 ret i32 0 31 32fail: 33 ret i32 1 34} 35 36; Test 1b - Like test 1 but using `asm inteldialect`. 37define i32 @test1b(i32 %a) { 38; CHECK-LABEL: test1b: 39; CHECK: # %bb.0: # %entry 40; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax 41; CHECK-NEXT: addl $4, %eax 42; CHECK-NEXT: #APP 43; CHECK-EMPTY: 44; CHECK-NEXT: xorl %eax, %eax 45; CHECK-NEXT: jmp .LBB1_2 46; CHECK-EMPTY: 47; CHECK-NEXT: #NO_APP 48; CHECK-NEXT: # %bb.1: # %normal 49; CHECK-NEXT: xorl %eax, %eax 50; CHECK-NEXT: retl 51; CHECK-NEXT: .LBB1_2: # Block address taken 52; CHECK-NEXT: # %fail 53; CHECK-NEXT: # Label of block must be emitted 54; CHECK-NEXT: movl $1, %eax 55; CHECK-NEXT: retl 56entry: 57 %0 = add i32 %a, 4 58 callbr void asm inteldialect "xor $0, $0; jmp ${1:l}", "r,!i,~{dirflag},~{fpsr},~{flags}"(i32 %0) to label %normal [label %fail] 59 60normal: 61 ret i32 0 62 63fail: 64 ret i32 1 65} 66 67; Test 2 - callbr terminates an unreachable block, function gets simplified 68; to a trivial zero return. 69define i32 @test2(i32 %a) { 70; CHECK-LABEL: test2: 71; CHECK: # %bb.0: # %entry 72; CHECK-NEXT: xorl %eax, %eax 73; CHECK-NEXT: retl 74entry: 75 br label %normal 76 77unreachableasm: 78 %0 = add i32 %a, 4 79 callbr void asm sideeffect "xorl $0, $0; jmp ${1:l}", "r,!i,~{dirflag},~{fpsr},~{flags}"(i32 %0) to label %normal [label %fail] 80 81normal: 82 ret i32 0 83 84fail: 85 ret i32 1 86} 87 88; Test 3 - asm-goto implements a loop. The loop gets recognized, but many loop 89; transforms fail due to canonicalization having callbr exceptions. Trivial 90; blocks at labels 1 and 3 also don't get simplified due to callbr. 91define i32 @test3(i32 %a) { 92; CHECK-LABEL: test3: 93; CHECK: # %bb.0: # %entry 94; CHECK-NEXT: .LBB3_1: # Block address taken 95; CHECK-NEXT: # %label01 96; CHECK-NEXT: # =>This Loop Header: Depth=1 97; CHECK-NEXT: # Child Loop BB3_2 Depth 2 98; CHECK-NEXT: # Child Loop BB3_3 Depth 3 99; CHECK-NEXT: # Child Loop BB3_4 Depth 4 100; CHECK-NEXT: # Label of block must be emitted 101; CHECK-NEXT: .LBB3_2: # Block address taken 102; CHECK-NEXT: # %label02 103; CHECK-NEXT: # Parent Loop BB3_1 Depth=1 104; CHECK-NEXT: # => This Loop Header: Depth=2 105; CHECK-NEXT: # Child Loop BB3_3 Depth 3 106; CHECK-NEXT: # Child Loop BB3_4 Depth 4 107; CHECK-NEXT: # Label of block must be emitted 108; CHECK-NEXT: addl $4, {{[0-9]+}}(%esp) 109; CHECK-NEXT: .LBB3_3: # Block address taken 110; CHECK-NEXT: # %label03 111; CHECK-NEXT: # Parent Loop BB3_1 Depth=1 112; CHECK-NEXT: # Parent Loop BB3_2 Depth=2 113; CHECK-NEXT: # => This Loop Header: Depth=3 114; CHECK-NEXT: # Child Loop BB3_4 Depth 4 115; CHECK-NEXT: # Label of block must be emitted 116; CHECK-NEXT: .LBB3_4: # Block address taken 117; CHECK-NEXT: # %label04 118; CHECK-NEXT: # Parent Loop BB3_1 Depth=1 119; CHECK-NEXT: # Parent Loop BB3_2 Depth=2 120; CHECK-NEXT: # Parent Loop BB3_3 Depth=3 121; CHECK-NEXT: # => This Inner Loop Header: Depth=4 122; CHECK-NEXT: # Label of block must be emitted 123; CHECK-NEXT: #APP 124; CHECK-NEXT: jmp .LBB3_1 125; CHECK-NEXT: jmp .LBB3_2 126; CHECK-NEXT: jmp .LBB3_3 127; CHECK-NEXT: #NO_APP 128; CHECK-NEXT: # %bb.5: # %normal0 129; CHECK-NEXT: # in Loop: Header=BB3_4 Depth=4 130; CHECK-NEXT: #APP 131; CHECK-NEXT: jmp .LBB3_1 132; CHECK-NEXT: jmp .LBB3_2 133; CHECK-NEXT: jmp .LBB3_3 134; CHECK-NEXT: jmp .LBB3_4 135; CHECK-NEXT: #NO_APP 136; CHECK-NEXT: # %bb.6: # %normal1 137; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax 138; CHECK-NEXT: retl 139entry: 140 %a.addr = alloca i32, align 4 141 store i32 %a, ptr %a.addr, align 4 142 br label %label01 143 144label01: ; preds = %normal0, %label04, %entry 145 br label %label02 146 147label02: ; preds = %normal0, %label04, %label01 148 %0 = load i32, ptr %a.addr, align 4 149 %add = add nsw i32 %0, 4 150 store i32 %add, ptr %a.addr, align 4 151 br label %label03 152 153label03: ; preds = %normal0, %label04, %label02 154 br label %label04 155 156label04: ; preds = %normal0, %label03 157 callbr void asm sideeffect "jmp ${0:l}; jmp ${1:l}; jmp ${2:l}", "!i,!i,!i,~{dirflag},~{fpsr},~{flags}"() 158 to label %normal0 [label %label01, label %label02, label %label03] 159 160normal0: ; preds = %label04 161 callbr void asm sideeffect "jmp ${0:l}; jmp ${1:l}; jmp ${2:l}; jmp ${3:l}", "!i,!i,!i,!i,~{dirflag},~{fpsr},~{flags}"() 162 to label %normal1 [label %label01, label %label02, label %label03, label %label04] 163 164normal1: ; preds = %normal0 165 %1 = load i32, ptr %a.addr, align 4 166 ret i32 %1 167} 168 169; Test 4 - asm-goto referenced with the 'l' (ell) modifier and not. 170define void @test4() { 171; CHECK-LABEL: test4: 172; CHECK: # %bb.0: # %entry 173; CHECK-NEXT: #APP 174; CHECK-NEXT: ja .LBB4_3 175; CHECK-NEXT: #NO_APP 176; CHECK-NEXT: # %bb.1: # %asm.fallthrough 177; CHECK-NEXT: #APP 178; CHECK-NEXT: ja .LBB4_3 179; CHECK-NEXT: #NO_APP 180; CHECK-NEXT: .LBB4_3: # Block address taken 181; CHECK-NEXT: # %quux 182; CHECK-NEXT: # Label of block must be emitted 183; CHECK-NEXT: retl 184entry: 185 callbr void asm sideeffect "ja $0", "!i,~{dirflag},~{fpsr},~{flags}"() 186 to label %asm.fallthrough [label %quux] 187 188asm.fallthrough: ; preds = %entry 189 callbr void asm sideeffect "ja ${0:l}", "!i,~{dirflag},~{fpsr},~{flags}"() 190 to label %cleanup [label %quux] 191 192quux: ; preds = %asm.fallthrough, %entry 193 br label %cleanup 194 195cleanup: ; preds = %asm.fallthrough, %quux 196 ret void 197} 198