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