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