aboutsummaryrefslogtreecommitdiff
path: root/llvm/test/CodeGen/X86/callbr-asm.ll
blob: 16b23fa81e3414a4ee487b819d1cb0b417f8c3a4 (plain)
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
191
192
193
194
195
196
197
; 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 .LBB0_2
; CHECK-NEXT:    #NO_APP
; CHECK-NEXT:  # %bb.1: # %normal
; CHECK-NEXT:    xorl %eax, %eax
; CHECK-NEXT:    retl
; CHECK-NEXT:  .LBB0_2: # Inline asm indirect target
; CHECK-NEXT:    # %fail
; CHECK-NEXT:    # Label of block must be emitted
; 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) 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 .LBB1_2
; CHECK-EMPTY:
; CHECK-NEXT:    #NO_APP
; CHECK-NEXT:  # %bb.1: # %normal
; CHECK-NEXT:    xorl %eax, %eax
; CHECK-NEXT:    retl
; CHECK-NEXT:  .LBB1_2: # Inline asm indirect target
; CHECK-NEXT:    # %fail
; CHECK-NEXT:    # Label of block must be emitted
; 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) 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) 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:  .LBB3_1: # Inline asm indirect target
; CHECK-NEXT:    # %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:    # Label of block must be emitted
; CHECK-NEXT:  .LBB3_2: # Inline asm indirect target
; CHECK-NEXT:    # %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:    # Label of block must be emitted
; CHECK-NEXT:    addl $4, {{[0-9]+}}(%esp)
; CHECK-NEXT:  .LBB3_3: # Inline asm indirect target
; CHECK-NEXT:    # %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:    # Label of block must be emitted
; CHECK-NEXT:  .LBB3_4: # Inline asm indirect target
; CHECK-NEXT:    # %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:    # Label of block must be emitted
; CHECK-NEXT:    #APP
; CHECK-NEXT:    jmp .LBB3_1
; CHECK-NEXT:    jmp .LBB3_2
; CHECK-NEXT:    jmp .LBB3_3
; CHECK-NEXT:    #NO_APP
; CHECK-NEXT:  # %bb.5: # %normal0
; CHECK-NEXT:    # in Loop: Header=BB3_4 Depth=4
; CHECK-NEXT:    #APP
; CHECK-NEXT:    jmp .LBB3_1
; CHECK-NEXT:    jmp .LBB3_2
; CHECK-NEXT:    jmp .LBB3_3
; CHECK-NEXT:    jmp .LBB3_4
; 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, ptr %a.addr, align 4
  br label %label01

label01:                                          ; preds = %normal0, %label04, %entry
  br label %label02

label02:                                          ; preds = %normal0, %label04, %label01
  %0 = load i32, ptr %a.addr, align 4
  %add = add nsw i32 %0, 4
  store i32 %add, ptr %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}"()
          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}"()
          to label %normal1 [label %label01, label %label02, label %label03, label %label04]

normal1:                                          ; preds = %normal0
  %1 = load i32, ptr %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 .LBB4_3
; CHECK-NEXT:    #NO_APP
; CHECK-NEXT:  # %bb.1: # %asm.fallthrough
; CHECK-NEXT:    #APP
; CHECK-NEXT:    ja .LBB4_3
; CHECK-NEXT:    #NO_APP
; CHECK-NEXT:  .LBB4_3: # Inline asm indirect target
; CHECK-NEXT:    # %quux
; CHECK-NEXT:    # Label of block must be emitted
; CHECK-NEXT:    retl
entry:
  callbr void asm sideeffect "ja $0", "!i,~{dirflag},~{fpsr},~{flags}"()
          to label %asm.fallthrough [label %quux]

asm.fallthrough:                                  ; preds = %entry
  callbr void asm sideeffect "ja ${0:l}", "!i,~{dirflag},~{fpsr},~{flags}"()
          to label %cleanup [label %quux]

quux:                                             ; preds = %asm.fallthrough, %entry
  br label %cleanup

cleanup:                                          ; preds = %asm.fallthrough, %quux
  ret void
}