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