xref: /llvm-project/llvm/test/CodeGen/X86/callbr-asm-outputs.ll (revision e3cf80c5c1fe55efd8216575ccadea0ab087e79c)
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc -mtriple=i686-- -verify-machineinstrs < %s | FileCheck %s
3
4; A test for asm-goto output
5
6define i32 @test1(i32 %x) {
7; CHECK-LABEL: test1:
8; CHECK:       # %bb.0: # %entry
9; CHECK-NEXT:    movl {{[0-9]+}}(%esp), %eax
10; CHECK-NEXT:    addl $4, %eax
11; CHECK-NEXT:    #APP
12; CHECK-NEXT:    xorl %eax, %eax
13; CHECK-NEXT:    jmp .LBB0_2
14; CHECK-NEXT:    #NO_APP
15; CHECK-NEXT:  # %bb.1: # %normal
16; CHECK-NEXT:    retl
17; CHECK-NEXT:  .LBB0_2: # Block address taken
18; CHECK-NEXT:    # %abnormal
19; CHECK-NEXT:    # Label of block must be emitted
20; CHECK-NEXT:    movl $1, %eax
21; CHECK-NEXT:    retl
22entry:
23  %add = add nsw i32 %x, 4
24  %ret = callbr i32 asm "xorl $1, $0; jmp ${2:l}", "=r,r,!i"(i32 %add)
25          to label %normal [label %abnormal]
26
27normal:
28  ret i32 %ret
29
30abnormal:
31  ret i32 1
32}
33
34define i32 @test2(i32 %out1, i32 %out2) nounwind {
35; CHECK-LABEL: test2:
36; CHECK:       # %bb.0: # %entry
37; CHECK-NEXT:    pushl %edi
38; CHECK-NEXT:    pushl %esi
39; CHECK-NEXT:    movl {{[0-9]+}}(%esp), %edi
40; CHECK-NEXT:    movl {{[0-9]+}}(%esp), %esi
41; CHECK-NEXT:    cmpl %edi, %esi
42; CHECK-NEXT:    jge .LBB1_3
43; CHECK-NEXT:  # %bb.1: # %if.then
44; CHECK-NEXT:    #APP
45; CHECK-NEXT:    testl %esi, %esi
46; CHECK-NEXT:    testl %edi, %esi
47; CHECK-NEXT:    jne .LBB1_2
48; CHECK-NEXT:    #NO_APP
49; CHECK-NEXT:    jmp .LBB1_4
50; CHECK-NEXT:  .LBB1_2: # Block address taken
51; CHECK-NEXT:    # %if.then.label_true_crit_edge
52; CHECK-NEXT:    # Label of block must be emitted
53; CHECK-NEXT:    jmp .LBB1_9
54; CHECK-NEXT:  .LBB1_3: # %if.else
55; CHECK-NEXT:    #APP
56; CHECK-NEXT:    testl %esi, %edi
57; CHECK-NEXT:    testl %esi, %edi
58; CHECK-NEXT:    jne .LBB1_7
59; CHECK-NEXT:    #NO_APP
60; CHECK-NEXT:  .LBB1_4:
61; CHECK-NEXT:    movl %esi, %eax
62; CHECK-NEXT:    addl %edi, %eax
63; CHECK-NEXT:  .LBB1_5: # %return
64; CHECK-NEXT:    popl %esi
65; CHECK-NEXT:    popl %edi
66; CHECK-NEXT:    retl
67; CHECK-NEXT:  .LBB1_6: # Block address taken
68; CHECK-NEXT:    # %if.then.return_crit_edge
69; CHECK-NEXT:    # Label of block must be emitted
70; CHECK-NEXT:  .LBB1_7: # Block address taken
71; CHECK-NEXT:    # %if.else.return_crit_edge
72; CHECK-NEXT:    # Label of block must be emitted
73; CHECK-NEXT:    movl $-1, %eax
74; CHECK-NEXT:    jmp .LBB1_5
75; CHECK-NEXT:  .LBB1_8: # Block address taken
76; CHECK-NEXT:    # %if.else.label_true_crit_edge
77; CHECK-NEXT:    # Label of block must be emitted
78; CHECK-NEXT:  .LBB1_9: # %label_true
79; CHECK-NEXT:    movl $-2, %eax
80; CHECK-NEXT:    jmp .LBB1_5
81entry:
82  %cmp = icmp slt i32 %out1, %out2
83  br i1 %cmp, label %if.then, label %if.else
84
85if.then:                                          ; preds = %entry
86  %0 = callbr { i32, i32 } asm sideeffect "testl $0, $0; testl $1, $2; jne ${3:l}", "={si},={di},r,!i,!i,0,1"(i32 %out1, i32 %out1, i32 %out2)
87          to label %if.end [label %label_true, label %return]
88
89if.else:                                          ; preds = %entry
90  %1 = callbr { i32, i32 } asm sideeffect "testl $0, $1; testl $2, $3; jne ${5:l}", "={si},={di},r,r,!i,!i,0,1"(i32 %out1, i32 %out2, i32 %out1, i32 %out2)
91          to label %if.end [label %label_true, label %return]
92
93if.end:                                           ; preds = %if.else, %if.then
94  %.sink11 = phi { i32, i32 } [ %0, %if.then ], [ %1, %if.else ]
95  %asmresult3 = extractvalue { i32, i32 } %.sink11, 0
96  %asmresult4 = extractvalue { i32, i32 } %.sink11, 1
97  %add = add nsw i32 %asmresult4, %asmresult3
98  br label %return
99
100label_true:                                       ; preds = %if.else, %if.then
101  br label %return
102
103return:                                           ; preds = %if.then, %if.else, %label_true, %if.end
104  %retval.0 = phi i32 [ %add, %if.end ], [ -2, %label_true ], [ -1, %if.else ], [ -1, %if.then ]
105  ret i32 %retval.0
106}
107
108define i32 @test3(i1 %cmp) nounwind {
109; CHECK-LABEL: test3:
110; CHECK:       # %bb.0: # %entry
111; CHECK-NEXT:    pushl %edi
112; CHECK-NEXT:    pushl %esi
113; CHECK-NEXT:    testb $1, {{[0-9]+}}(%esp)
114; CHECK-NEXT:    je .LBB2_3
115; CHECK-NEXT:  # %bb.1: # %true
116; CHECK-NEXT:    #APP
117; CHECK-NEXT:    .short %esi
118; CHECK-NEXT:    .short %edi
119; CHECK-NEXT:    #NO_APP
120; CHECK-NEXT:  # %bb.2:
121; CHECK-NEXT:    movl %edi, %eax
122; CHECK-NEXT:    jmp .LBB2_4
123; CHECK-NEXT:  .LBB2_3: # %false
124; CHECK-NEXT:    #APP
125; CHECK-NEXT:    .short %eax
126; CHECK-NEXT:    .short %edx
127; CHECK-NEXT:    #NO_APP
128; CHECK-NEXT:    movl %edx, %eax
129; CHECK-NEXT:  .LBB2_4: # %asm.fallthrough
130; CHECK-NEXT:    popl %esi
131; CHECK-NEXT:    popl %edi
132; CHECK-NEXT:    retl
133; CHECK-NEXT:  .LBB2_5: # Block address taken
134; CHECK-NEXT:    # %true.indirect_crit_edge
135; CHECK-NEXT:    # Label of block must be emitted
136; CHECK-NEXT:  .LBB2_6: # Block address taken
137; CHECK-NEXT:    # %false.indirect_crit_edge
138; CHECK-NEXT:    # Label of block must be emitted
139; CHECK-NEXT:    movl $42, %eax
140; CHECK-NEXT:    jmp .LBB2_4
141entry:
142  br i1 %cmp, label %true, label %false
143
144true:
145  %0 = callbr { i32, i32 } asm sideeffect ".word $0, $1", "={si},={di},!i" () to label %asm.fallthrough [label %indirect]
146
147false:
148  %1 = callbr { i32, i32 } asm sideeffect ".word $0, $1", "={ax},={dx},!i" () to label %asm.fallthrough [label %indirect]
149
150asm.fallthrough:
151  %vals = phi { i32, i32 } [ %0, %true ], [ %1, %false ]
152  %v = extractvalue { i32, i32 } %vals, 1
153  ret i32 %v
154
155indirect:
156  ret i32 42
157}
158
159; Test 4 - asm-goto with output constraints.
160define i32 @test4(i32 %out1, i32 %out2) {
161; CHECK-LABEL: test4:
162; CHECK:       # %bb.0: # %entry
163; CHECK-NEXT:    movl {{[0-9]+}}(%esp), %eax
164; CHECK-NEXT:    #APP
165; CHECK-NEXT:    testl %eax, %eax
166; CHECK-NEXT:    testl %ecx, %eax
167; CHECK-NEXT:    jne .LBB3_5
168; CHECK-NEXT:    #NO_APP
169; CHECK-NEXT:  # %bb.1: # %asm.fallthrough
170; CHECK-NEXT:    #APP
171; CHECK-NEXT:    testl %eax, %ecx
172; CHECK-NEXT:    testl %eax, %ecx
173; CHECK-NEXT:    jne .LBB3_4
174; CHECK-NEXT:    #NO_APP
175; CHECK-NEXT:  # %bb.2: # %asm.fallthrough2
176; CHECK-NEXT:    addl %ecx, %eax
177; CHECK-NEXT:    retl
178; CHECK-NEXT:  .LBB3_3: # Block address taken
179; CHECK-NEXT:    # %entry.return_crit_edge
180; CHECK-NEXT:    # Label of block must be emitted
181; CHECK-NEXT:  .LBB3_4: # Block address taken
182; CHECK-NEXT:    # %asm.fallthrough.return_crit_edge
183; CHECK-NEXT:    # Label of block must be emitted
184; CHECK-NEXT:    movl $-1, %eax
185; CHECK-NEXT:    retl
186; CHECK-NEXT:  .LBB3_5: # Block address taken
187; CHECK-NEXT:    # %entry.label_true_crit_edge
188; CHECK-NEXT:    # Label of block must be emitted
189; CHECK-NEXT:  .LBB3_6: # Block address taken
190; CHECK-NEXT:    # %asm.fallthrough.label_true_crit_edge
191; CHECK-NEXT:    # Label of block must be emitted
192; CHECK-NEXT:    movl $-2, %eax
193; CHECK-NEXT:    retl
194entry:
195  %0 = callbr { i32, i32 } asm sideeffect "testl $0, $0; testl $1, $2; jne ${3:l}", "=r,=r,r,!i,!i"(i32 %out1)
196          to label %asm.fallthrough [label %label_true, label %return]
197
198asm.fallthrough:                                  ; preds = %entry
199  %asmresult = extractvalue { i32, i32 } %0, 0
200  %asmresult1 = extractvalue { i32, i32 } %0, 1
201  %1 = callbr { i32, i32 } asm sideeffect "testl $0, $1; testl $2, $3; jne ${5:l}", "=r,=r,r,r,!i,!i"(i32 %asmresult, i32 %asmresult1)
202          to label %asm.fallthrough2 [label %label_true, label %return]
203
204asm.fallthrough2:                                 ; preds = %asm.fallthrough
205  %asmresult3 = extractvalue { i32, i32 } %1, 0
206  %asmresult4 = extractvalue { i32, i32 } %1, 1
207  %add = add nsw i32 %asmresult3, %asmresult4
208  br label %return
209
210label_true:                                       ; preds = %asm.fallthrough, %entry
211  br label %return
212
213return:                                           ; preds = %entry, %asm.fallthrough, %label_true, %asm.fallthrough2
214  %retval.0 = phi i32 [ %add, %asm.fallthrough2 ], [ -2, %label_true ], [ -1, %asm.fallthrough ], [ -1, %entry ]
215  ret i32 %retval.0
216}
217
218; Test5 - test that we don't rely on a positional constraint. ie. +r in
219; GCCAsmStmt being turned into "={esp},0" since after D87279 they're turned
220; into "={esp},{esp}". This previously caused an ICE; this test is more so
221; about avoiding another ICE than what the actual output is.
222define dso_local void @test5() {
223; CHECK-LABEL: test5:
224; CHECK:       # %bb.0:
225; CHECK-NEXT:    #APP
226; CHECK-NEXT:    #NO_APP
227; CHECK-NEXT:  # %bb.1:
228; CHECK-NEXT:    retl
229; CHECK-NEXT:  .LBB4_2: # Block address taken
230; CHECK-NEXT:    # %._crit_edge
231; CHECK-NEXT:    # Label of block must be emitted
232; CHECK-NEXT:    retl
233  %1 = call i32 @llvm.read_register.i32(metadata !3)
234  %2 = callbr i32 asm "", "={esp},!i,{esp}"(i32 %1)
235          to label %3 [label %4]
236
2373:
238  call void @llvm.write_register.i32(metadata !3, i32 %2)
239  br label %4
240
2414:
242  ret void
243}
244
245declare i32 @llvm.read_register.i32(metadata)
246declare void @llvm.write_register.i32(metadata, i32)
247!3 = !{!"esp"}
248