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