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,X,~{dirflag},~{fpsr},~{flags}"(i32 %0, i8* blockaddress(@test1, %fail)) to label %normal [label %fail] 27 28normal: 29 ret i32 0 30 31fail: 32 ret i32 1 33} 34 35; Test 2 - callbr terminates an unreachable block, function gets simplified 36; to a trivial zero return. 37define i32 @test2(i32 %a) { 38; CHECK-LABEL: test2: 39; CHECK: # %bb.0: # %entry 40; CHECK-NEXT: xorl %eax, %eax 41; CHECK-NEXT: retl 42entry: 43 br label %normal 44 45unreachableasm: 46 %0 = add i32 %a, 4 47 callbr void asm sideeffect "xorl $0, $0; jmp ${1:l}", "r,X,~{dirflag},~{fpsr},~{flags}"(i32 %0, i8* blockaddress(@test2, %fail)) to label %normal [label %fail] 48 49normal: 50 ret i32 0 51 52fail: 53 ret i32 1 54} 55 56; Test 3 - asm-goto implements a loop. The loop gets recognized, but many loop 57; transforms fail due to canonicalization having callbr exceptions. Trivial 58; blocks at labels 1 and 3 also don't get simplified due to callbr. 59define i32 @test3(i32 %a) { 60; CHECK-LABEL: test3: 61; CHECK: # %bb.0: # %entry 62; CHECK-NEXT: .Ltmp1: # Block address taken 63; CHECK-NEXT: .LBB2_1: # %label01 64; CHECK-NEXT: # =>This Loop Header: Depth=1 65; CHECK-NEXT: # Child Loop BB2_2 Depth 2 66; CHECK-NEXT: # Child Loop BB2_3 Depth 3 67; CHECK-NEXT: # Child Loop BB2_4 Depth 4 68; CHECK-NEXT: .Ltmp2: # Block address taken 69; CHECK-NEXT: .LBB2_2: # %label02 70; CHECK-NEXT: # Parent Loop BB2_1 Depth=1 71; CHECK-NEXT: # => This Loop Header: Depth=2 72; CHECK-NEXT: # Child Loop BB2_3 Depth 3 73; CHECK-NEXT: # Child Loop BB2_4 Depth 4 74; CHECK-NEXT: addl $4, {{[0-9]+}}(%esp) 75; CHECK-NEXT: .Ltmp3: # Block address taken 76; CHECK-NEXT: .LBB2_3: # %label03 77; CHECK-NEXT: # Parent Loop BB2_1 Depth=1 78; CHECK-NEXT: # Parent Loop BB2_2 Depth=2 79; CHECK-NEXT: # => This Loop Header: Depth=3 80; CHECK-NEXT: # Child Loop BB2_4 Depth 4 81; CHECK-NEXT: .Ltmp4: # Block address taken 82; CHECK-NEXT: .LBB2_4: # %label04 83; CHECK-NEXT: # Parent Loop BB2_1 Depth=1 84; CHECK-NEXT: # Parent Loop BB2_2 Depth=2 85; CHECK-NEXT: # Parent Loop BB2_3 Depth=3 86; CHECK-NEXT: # => This Inner Loop Header: Depth=4 87; CHECK-NEXT: #APP 88; CHECK-NEXT: jmp .Ltmp1 89; CHECK-NEXT: jmp .Ltmp2 90; CHECK-NEXT: jmp .Ltmp3 91; CHECK-NEXT: #NO_APP 92; CHECK-NEXT: # %bb.5: # %normal0 93; CHECK-NEXT: # in Loop: Header=BB2_4 Depth=4 94; CHECK-NEXT: #APP 95; CHECK-NEXT: jmp .Ltmp1 96; CHECK-NEXT: jmp .Ltmp2 97; CHECK-NEXT: jmp .Ltmp3 98; CHECK-NEXT: jmp .Ltmp4 99; CHECK-NEXT: #NO_APP 100; CHECK-NEXT: # %bb.6: # %normal1 101; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax 102; CHECK-NEXT: retl 103entry: 104 %a.addr = alloca i32, align 4 105 store i32 %a, i32* %a.addr, align 4 106 br label %label01 107 108label01: ; preds = %normal0, %label04, %entry 109 br label %label02 110 111label02: ; preds = %normal0, %label04, %label01 112 %0 = load i32, i32* %a.addr, align 4 113 %add = add nsw i32 %0, 4 114 store i32 %add, i32* %a.addr, align 4 115 br label %label03 116 117label03: ; preds = %normal0, %label04, %label02 118 br label %label04 119 120label04: ; preds = %normal0, %label03 121 callbr void asm sideeffect "jmp ${0:l}; jmp ${1:l}; jmp ${2:l}", "X,X,X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@test3, %label01), i8* blockaddress(@test3, %label02), i8* blockaddress(@test3, %label03)) 122 to label %normal0 [label %label01, label %label02, label %label03] 123 124normal0: ; preds = %label04 125 callbr void asm sideeffect "jmp ${0:l}; jmp ${1:l}; jmp ${2:l}; jmp ${3:l}", "X,X,X,X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@test3, %label01), i8* blockaddress(@test3, %label02), i8* blockaddress(@test3, %label03), i8* blockaddress(@test3, %label04)) 126 to label %normal1 [label %label01, label %label02, label %label03, label %label04] 127 128normal1: ; preds = %normal0 129 %1 = load i32, i32* %a.addr, align 4 130 ret i32 %1 131} 132 133; Test 4 - asm-goto referenced with the 'l' (ell) modifier and not. 134define void @test4() { 135; CHECK-LABEL: test4: 136; CHECK: # %bb.0: # %entry 137; CHECK-NEXT: #APP 138; CHECK-NEXT: ja .Ltmp5 139; CHECK-NEXT: #NO_APP 140; CHECK-NEXT: # %bb.1: # %asm.fallthrough 141; CHECK-NEXT: #APP 142; CHECK-NEXT: ja .Ltmp5 143; CHECK-NEXT: #NO_APP 144; CHECK-NEXT: .Ltmp5: # Block address taken 145; CHECK-NEXT: .LBB3_3: # %quux 146; CHECK-NEXT: retl 147entry: 148 callbr void asm sideeffect "ja $0", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@test4, %quux)) 149 to label %asm.fallthrough [label %quux] 150 151asm.fallthrough: ; preds = %entry 152 callbr void asm sideeffect "ja ${0:l}", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@test4, %quux)) 153 to label %cleanup [label %quux] 154 155quux: ; preds = %asm.fallthrough, %entry 156 br label %cleanup 157 158cleanup: ; preds = %asm.fallthrough, %quux 159 ret void 160} 161