• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; Tests various aspects of x86 branch encodings (near vs far,
2; forward vs backward, using CFG labels, or local labels).
3
4; Use -ffunction-sections so that the offsets reset for each function.
5; RUN: %p2i --filetype=obj --disassemble -i %s --args -O2 \
6; RUN:   -ffunction-sections | FileCheck %s
7
8; Use atomic ops as filler, which shouldn't get optimized out.
9declare void @llvm.nacl.atomic.store.i32(i32, i32*, i32)
10declare i32 @llvm.nacl.atomic.load.i32(i32*, i32)
11declare i32 @llvm.nacl.atomic.rmw.i32(i32, i32*, i32, i32)
12
13define internal void @test_near_backward(i32 %iptr, i32 %val) {
14entry:
15  br label %next
16next:
17  %ptr = inttoptr i32 %iptr to i32*
18  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
19  br label %next2
20next2:
21  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
22  %cmp = icmp ult i32 %val, 1
23  br i1 %cmp, label %next2, label %next
24}
25
26; CHECK-LABEL: test_near_backward
27; CHECK:      8: {{.*}}  mov DWORD PTR
28; CHECK-NEXT: a: {{.*}}  mfence
29; CHECK-NEXT: d: {{.*}}  mov DWORD PTR
30; CHECK-NEXT: f: {{.*}}  mfence
31; CHECK-NEXT: 12: {{.*}} cmp
32; CHECK-NEXT: 15: 72 f6 jb d
33; CHECK-NEXT: 17: eb ef jmp 8
34
35; Test one of the backward branches being too large for 8 bits
36; and one being just okay.
37define internal void @test_far_backward1(i32 %iptr, i32 %val) {
38entry:
39  br label %next
40next:
41  %ptr = inttoptr i32 %iptr to i32*
42  %tmp = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6)
43  br label %next2
44next2:
45  call void @llvm.nacl.atomic.store.i32(i32 %tmp, i32* %ptr, i32 6)
46  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
47  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
48  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
49  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
50  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
51  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
52  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
53  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
54  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
55  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
56  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
57  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
58  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
59  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
60  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
61  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
62  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
63  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
64  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
65  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
66  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
67  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
68  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
69  %cmp = icmp ugt i32 %val, 0
70  br i1 %cmp, label %next2, label %next
71}
72
73; CHECK-LABEL: test_far_backward1
74; CHECK:      8: {{.*}}  mov {{.*}},DWORD PTR [e{{[^s]}}
75; CHECK-NEXT: a: {{.*}}  mov DWORD PTR
76; CHECK-NEXT: c: {{.*}}  mfence
77; CHECK: 85: 77 83 ja a
78; CHECK-NEXT: 87: e9 7c ff ff ff jmp 8
79
80; Same as test_far_backward1, but with the conditional branch being
81; the one that is too far.
82define internal void @test_far_backward2(i32 %iptr, i32 %val) {
83entry:
84  br label %next
85next:
86  %ptr = inttoptr i32 %iptr to i32*
87  %tmp = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6)
88  %tmp2 = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6)
89  %tmp3 = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6)
90  %tmp4 = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6)
91  %tmp5 = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6)
92  br label %next2
93next2:
94  call void @llvm.nacl.atomic.store.i32(i32 %tmp, i32* %ptr, i32 6)
95  call void @llvm.nacl.atomic.store.i32(i32 %tmp2, i32* %ptr, i32 6)
96  call void @llvm.nacl.atomic.store.i32(i32 %tmp3, i32* %ptr, i32 6)
97  call void @llvm.nacl.atomic.store.i32(i32 %tmp4, i32* %ptr, i32 6)
98  call void @llvm.nacl.atomic.store.i32(i32 %tmp5, i32* %ptr, i32 6)
99  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
100  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
101  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
102  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
103  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
104  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
105  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
106  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
107  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
108  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
109  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
110  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
111  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
112  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
113  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
114  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
115  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
116  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
117  %cmp = icmp sle i32 %val, 0
118  br i1 %cmp, label %next, label %next2
119}
120
121; CHECK-LABEL: test_far_backward2
122; CHECK:      c:  {{.*}}  mov {{.*}},DWORD PTR [e{{[^s]}}
123; CHECK:      14: {{.*}}  mov {{.*}},DWORD PTR
124; CHECK-NEXT: 16: {{.*}}  mov DWORD PTR
125; CHECK-NEXT: 18: {{.*}}  mfence
126; CHECK: 8c: 0f 8e 7a ff ff ff jle c
127; CHECK-NEXT: 92: eb 82 jmp 16
128
129define internal void @test_near_forward(i32 %iptr, i32 %val) {
130entry:
131  br label %next1
132next1:
133  %ptr = inttoptr i32 %iptr to i32*
134  %cmp = icmp ult i32 %val, 1
135  br i1 %cmp, label %next3, label %next2
136next2:
137  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
138  br label %next3
139next3:
140  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
141  br label %next1
142}
143; Note: forward branches for non-local labels in Subzero currently use the fully
144; relaxed form (4-byte offset) to avoid needing a relaxation pass.  When we use
145; llvm-mc, it performs the relaxation pass and uses a 1-byte offset.
146; CHECK-LABEL: test_near_forward
147; CHECK:      [[BACKLABEL:[0-9a-f]+]]: {{.*}} cmp
148; CHECK-NEXT: {{.*}} jb [[FORWARDLABEL:[0-9a-f]+]]
149; CHECK-NEXT: {{.*}} mov DWORD PTR
150; CHECK-NEXT: {{.*}} mfence
151; CHECK-NEXT: [[FORWARDLABEL]]: {{.*}} mov DWORD PTR
152; CHECK:      {{.*}} jmp [[BACKLABEL]]
153
154
155; Unlike forward branches to cfg nodes, "local" forward branches
156; always use a 1 byte displacement.
157; Check local forward branches, followed by a near backward branch
158; to make sure that the instruction size accounting for the forward
159; branches are correct, by the time the backward branch is hit.
160; A 64-bit compare happens to use local forward branches.
161define internal void @test_local_forward_then_back(i64 %val64, i32 %iptr,
162                                                   i32 %val) {
163entry:
164  br label %next
165next:
166  %ptr = inttoptr i32 %iptr to i32*
167  call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6)
168  br label %next2
169next2:
170  %cmp = icmp ult i64 %val64, 1
171  br i1 %cmp, label %next, label %next2
172}
173; CHECK-LABEL: test_local_forward_then_back
174; CHECK:      {{.*}} mov DWORD PTR
175; CHECK-NEXT: {{.*}} mfence
176; CHECK-NEXT: [[LABEL:[0-9a-f]+]]: {{.*}} cmp
177; CHECK-NEXT: {{.*}} jb
178; CHECK-NEXT: {{.*}} ja
179; CHECK-NEXT: {{.*}} cmp
180; CHECK-NEXT: {{.*}} jb
181; CHECK-NEXT: {{.*}} jmp [[LABEL]]
182
183
184; Test that backward local branches also work and are small.
185; Some of the atomic instructions use a cmpxchg loop.
186define internal void @test_local_backward(i64 %val64, i32 %iptr, i32 %val) {
187entry:
188  br label %next
189next:
190  %ptr = inttoptr i32 %iptr to i32*
191  %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 5, i32* %ptr, i32 %val, i32 6)
192  br label %next2
193next2:
194  %success = icmp eq i32 1, %a
195  br i1 %success, label %next, label %next2
196}
197; CHECK-LABEL: test_local_backward
198; CHECK:       9: {{.*}} mov {{.*}},DWORD
199; CHECK:       b: {{.*}} mov
200; CHECK-NEXT:  d: {{.*}} xor
201; CHECK-NEXT:  f: {{.*}} lock cmpxchg
202; CHECK-NEXT: 13: 75 f6 jne b
203; CHECK:      1c: 74 eb je 9
204