OLD | NEW |
1 ; Tests various aspects of x86 branch encodings (near vs far, | 1 ; Tests various aspects of x86 branch encodings (near vs far, |
2 ; forward vs backward, using CFG labels, or local labels). | 2 ; forward vs backward, using CFG labels, or local labels). |
3 | 3 |
4 ; Use -ffunction-sections so that the offsets reset for each function. | 4 ; Use -ffunction-sections so that the offsets reset for each function. |
5 ; RUN: %p2i -i %s --args -O2 --verbose none -ffunction-sections \ | 5 ; RUN: %p2i --assemble --disassemble -i %s --args -O2 --verbose none \ |
6 ; RUN: | llvm-mc -triple=i686-none-nacl -filetype=obj \ | 6 ; RUN: -ffunction-sections | FileCheck %s |
7 ; RUN: | llvm-objdump -d --symbolize -x86-asm-syntax=intel - | FileCheck %s | |
8 | 7 |
9 ; Use atomic ops as filler, which shouldn't get optimized out. | 8 ; Use atomic ops as filler, which shouldn't get optimized out. |
10 declare void @llvm.nacl.atomic.store.i32(i32, i32*, i32) | 9 declare void @llvm.nacl.atomic.store.i32(i32, i32*, i32) |
11 declare i32 @llvm.nacl.atomic.load.i32(i32*, i32) | 10 declare i32 @llvm.nacl.atomic.load.i32(i32*, i32) |
12 declare i32 @llvm.nacl.atomic.rmw.i32(i32, i32*, i32, i32) | 11 declare i32 @llvm.nacl.atomic.rmw.i32(i32, i32*, i32, i32) |
13 | 12 |
14 define void @test_near_backward(i32 %iptr, i32 %val) { | 13 define void @test_near_backward(i32 %iptr, i32 %val) { |
15 entry: | 14 entry: |
16 br label %next | 15 br label %next |
17 next: | 16 next: |
18 %ptr = inttoptr i32 %iptr to i32* | 17 %ptr = inttoptr i32 %iptr to i32* |
19 call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6) | 18 call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6) |
20 br label %next2 | 19 br label %next2 |
21 next2: | 20 next2: |
22 call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6) | 21 call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6) |
23 %cmp = icmp ult i32 %val, 0 | 22 %cmp = icmp ult i32 %val, 0 |
24 br i1 %cmp, label %next2, label %next | 23 br i1 %cmp, label %next2, label %next |
25 } | 24 } |
26 | 25 |
27 ; CHECK-LABEL: test_near_backward | 26 ; CHECK-LABEL: test_near_backward |
28 ; CHECK: 8: {{.*}} mov dword ptr | 27 ; CHECK: 8: {{.*}} mov DWORD PTR |
29 ; CHECK-NEXT: a: {{.*}} mfence | 28 ; CHECK-NEXT: a: {{.*}} mfence |
30 ; CHECK-NEXT: d: {{.*}} mov dword ptr | 29 ; CHECK-NEXT: d: {{.*}} mov DWORD PTR |
31 ; CHECK-NEXT: f: {{.*}} mfence | 30 ; CHECK-NEXT: f: {{.*}} mfence |
32 ; CHECK-NEXT: 12: {{.*}} cmp | 31 ; CHECK-NEXT: 12: {{.*}} cmp |
33 ; (0x15 + 2) - 10 == 0xd | 32 ; CHECK-NEXT: 15: 72 f6 jb d |
34 ; CHECK-NEXT: 15: 72 f6 jb -10 | 33 ; CHECK-NEXT: 17: eb ef jmp 8 |
35 ; (0x17 + 2) - 17 == 0x8 | |
36 ; CHECK-NEXT: 17: eb ef jmp -17 | |
37 | 34 |
38 ; Test one of the backward branches being too large for 8 bits | 35 ; Test one of the backward branches being too large for 8 bits |
39 ; and one being just okay. | 36 ; and one being just okay. |
40 define void @test_far_backward1(i32 %iptr, i32 %val) { | 37 define void @test_far_backward1(i32 %iptr, i32 %val) { |
41 entry: | 38 entry: |
42 br label %next | 39 br label %next |
43 next: | 40 next: |
44 %ptr = inttoptr i32 %iptr to i32* | 41 %ptr = inttoptr i32 %iptr to i32* |
45 %tmp = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) | 42 %tmp = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) |
46 br label %next2 | 43 br label %next2 |
(...skipping 20 matching lines...) Expand all Loading... |
67 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) |
68 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) |
69 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) |
70 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) |
71 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) |
72 %cmp = icmp ugt i32 %val, 0 | 69 %cmp = icmp ugt i32 %val, 0 |
73 br i1 %cmp, label %next2, label %next | 70 br i1 %cmp, label %next2, label %next |
74 } | 71 } |
75 | 72 |
76 ; CHECK-LABEL: test_far_backward1 | 73 ; CHECK-LABEL: test_far_backward1 |
77 ; CHECK: 8: {{.*}} mov {{.*}}, dword ptr [e{{[^s]}} | 74 ; CHECK: 8: {{.*}} mov {{.*}},DWORD PTR [e{{[^s]}} |
78 ; CHECK-NEXT: a: {{.*}} mov dword ptr | 75 ; CHECK-NEXT: a: {{.*}} mov DWORD PTR |
79 ; CHECK-NEXT: c: {{.*}} mfence | 76 ; CHECK-NEXT: c: {{.*}} mfence |
80 ; (0x85 + 2) - 125 == 0xa | 77 ; CHECK: 85: 77 83 ja a |
81 ; CHECK: 85: 77 83 ja -125 | 78 ; CHECK-NEXT: 87: e9 7c ff ff ff jmp 8 |
82 ; (0x87 + 5) - 132 == 0x8 | |
83 ; CHECK-NEXT: 87: e9 7c ff ff ff jmp -132 | |
84 | 79 |
85 ; Same as test_far_backward1, but with the conditional branch being | 80 ; Same as test_far_backward1, but with the conditional branch being |
86 ; the one that is too far. | 81 ; the one that is too far. |
87 define void @test_far_backward2(i32 %iptr, i32 %val) { | 82 define void @test_far_backward2(i32 %iptr, i32 %val) { |
88 entry: | 83 entry: |
89 br label %next | 84 br label %next |
90 next: | 85 next: |
91 %ptr = inttoptr i32 %iptr to i32* | 86 %ptr = inttoptr i32 %iptr to i32* |
92 %tmp = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) | 87 %tmp = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) |
93 %tmp2 = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) | 88 %tmp2 = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) |
(...skipping 23 matching lines...) Expand all Loading... |
117 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) |
118 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) |
119 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) |
120 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) |
121 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) |
122 %cmp = icmp sle i32 %val, 0 | 117 %cmp = icmp sle i32 %val, 0 |
123 br i1 %cmp, label %next, label %next2 | 118 br i1 %cmp, label %next, label %next2 |
124 } | 119 } |
125 | 120 |
126 ; CHECK-LABEL: test_far_backward2 | 121 ; CHECK-LABEL: test_far_backward2 |
127 ; CHECK: c: {{.*}} mov {{.*}}, dword ptr [e{{[^s]}} | 122 ; CHECK: c: {{.*}} mov {{.*}},DWORD PTR [e{{[^s]}} |
128 ; CHECK: 14: {{.*}} mov {{.*}}, dword ptr | 123 ; CHECK: 14: {{.*}} mov {{.*}},DWORD PTR |
129 ; CHECK-NEXT: 16: {{.*}} mov dword ptr | 124 ; CHECK-NEXT: 16: {{.*}} mov DWORD PTR |
130 ; CHECK-NEXT: 18: {{.*}} mfence | 125 ; CHECK-NEXT: 18: {{.*}} mfence |
131 ; (0x8c + 6) - 134 == 0xc | 126 ; CHECK: 8c: 0f 8e 7a ff ff ff jle c |
132 ; CHECK: 8c: 0f 8e 7a ff ff ff jle -134 | 127 ; CHECK-NEXT: 92: eb 82 jmp 16 |
133 ; (0x92 + 2) - 126 == 0x16 | |
134 ; CHECK-NEXT: 92: eb 82 jmp -126 | |
135 | 128 |
136 define void @test_near_forward(i32 %iptr, i32 %val) { | 129 define void @test_near_forward(i32 %iptr, i32 %val) { |
137 entry: | 130 entry: |
138 br label %next1 | 131 br label %next1 |
139 next1: | 132 next1: |
140 %ptr = inttoptr i32 %iptr to i32* | 133 %ptr = inttoptr i32 %iptr to i32* |
141 %cmp = icmp ult i32 %val, 0 | 134 %cmp = icmp ult i32 %val, 0 |
142 br i1 %cmp, label %next3, label %next2 | 135 br i1 %cmp, label %next3, label %next2 |
143 next2: | 136 next2: |
144 call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6) | 137 call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6) |
145 br label %next3 | 138 br label %next3 |
146 next3: | 139 next3: |
147 call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6) | 140 call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6) |
148 br label %next1 | 141 br label %next1 |
149 } | 142 } |
150 ; Forward branches for non-local labels currently use the fully relaxed | 143 ; Forward branches for non-local labels currently use the fully relaxed |
151 ; form to avoid needing a relaxation pass. | 144 ; form to avoid needing a relaxation pass. |
152 ; CHECK-LABEL: test_near_forward | 145 ; CHECK-LABEL: test_near_forward |
153 ; CHECK: 8: {{.*}} cmp | 146 ; CHECK: 8: {{.*}} cmp |
154 ; CHECK-NEXT: b: 0f 82 05 00 00 00 jb 5 | 147 ; CHECK-NEXT: b: 0f 82 05 00 00 00 jb 16 |
155 ; CHECK-NEXT: 11: {{.*}} mov dword ptr | 148 ; CHECK-NEXT: 11: {{.*}} mov DWORD PTR |
156 ; CHECK-NEXT: 13: {{.*}} mfence | 149 ; CHECK-NEXT: 13: {{.*}} mfence |
157 ; Forward branch is 5 bytes ahead to here. | 150 ; CHECK-NEXT: 16: {{.*}} mov DWORD PTR |
158 ; CHECK-NEXT: 16: {{.*}} mov dword ptr | 151 ; CHECK: 1b: eb eb jmp 8 |
159 ; Jumps back to (0x1b + 2) - 21 == 0x8 (to before the forward branch, | |
160 ; therefore knowing that the forward branch was indeed 6 bytes). | |
161 ; CHECK: 1b: eb eb jmp -21 | |
162 | 152 |
163 | 153 |
164 ; Unlike forward branches to cfg nodes, "local" forward branches | 154 ; Unlike forward branches to cfg nodes, "local" forward branches |
165 ; always use a 1 byte displacement. | 155 ; always use a 1 byte displacement. |
166 ; Check local forward branches, followed by a near backward branch | 156 ; Check local forward branches, followed by a near backward branch |
167 ; to make sure that the instruction size accounting for the forward | 157 ; to make sure that the instruction size accounting for the forward |
168 ; branches are correct, by the time the backward branch is hit. | 158 ; branches are correct, by the time the backward branch is hit. |
169 ; A 64-bit compare happens to use local forward branches. | 159 ; A 64-bit compare happens to use local forward branches. |
170 define void @test_local_forward_then_back(i64 %val64, i32 %iptr, i32 %val) { | 160 define void @test_local_forward_then_back(i64 %val64, i32 %iptr, i32 %val) { |
171 entry: | 161 entry: |
172 br label %next | 162 br label %next |
173 next: | 163 next: |
174 %ptr = inttoptr i32 %iptr to i32* | 164 %ptr = inttoptr i32 %iptr to i32* |
175 call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6) | 165 call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6) |
176 br label %next2 | 166 br label %next2 |
177 next2: | 167 next2: |
178 %cmp = icmp ult i64 %val64, 0 | 168 %cmp = icmp ult i64 %val64, 0 |
179 br i1 %cmp, label %next, label %next2 | 169 br i1 %cmp, label %next, label %next2 |
180 } | 170 } |
181 ; CHECK-LABEL: test_local_forward_then_back | 171 ; CHECK-LABEL: test_local_forward_then_back |
182 ; CHECK: 14: {{.*}} mov dword ptr | 172 ; CHECK: 14: {{.*}} mov DWORD PTR |
183 ; CHECK-NEXT: 16: {{.*}} mfence | 173 ; CHECK-NEXT: 16: {{.*}} mfence |
184 ; CHECK-NEXT: 19: {{.*}} mov dword ptr {{.*}}, 1 | 174 ; CHECK-NEXT: 19: {{.*}} mov DWORD PTR {{.*}},0x1 |
185 ; CHECK-NEXT: 20: {{.*}} cmp | 175 ; CHECK-NEXT: 20: {{.*}} cmp |
186 ; CHECK-NEXT: 23: {{.*}} jb 14 | 176 ; CHECK-NEXT: 23: {{.*}} jb 33 |
187 ; (0x37 + 2) - 37 == 0x14 | 177 ; CHECK: 37: {{.*}} jne 14 |
188 ; CHECK: 37: {{.*}} jne -37 | 178 ; CHECK: 39: {{.*}} jmp 19 |
189 ; (0x39 + 2) - 34 == 0x19 | |
190 ; CHECK: 39: {{.*}} jmp -34 | |
191 | 179 |
192 | 180 |
193 ; Test that backward local branches also work and are small. | 181 ; Test that backward local branches also work and are small. |
194 ; Some of the atomic instructions use a cmpxchg loop. | 182 ; Some of the atomic instructions use a cmpxchg loop. |
195 define void @test_local_backward(i64 %val64, i32 %iptr, i32 %val) { | 183 define void @test_local_backward(i64 %val64, i32 %iptr, i32 %val) { |
196 entry: | 184 entry: |
197 br label %next | 185 br label %next |
198 next: | 186 next: |
199 %ptr = inttoptr i32 %iptr to i32* | 187 %ptr = inttoptr i32 %iptr to i32* |
200 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 5, i32* %ptr, i32 %val, i32 6) | 188 %a = call i32 @llvm.nacl.atomic.rmw.i32(i32 5, i32* %ptr, i32 %val, i32 6) |
201 br label %next2 | 189 br label %next2 |
202 next2: | 190 next2: |
203 %success = icmp eq i32 1, %a | 191 %success = icmp eq i32 1, %a |
204 br i1 %success, label %next, label %next2 | 192 br i1 %success, label %next, label %next2 |
205 } | 193 } |
206 ; CHECK-LABEL: test_local_backward | 194 ; CHECK-LABEL: test_local_backward |
207 ; CHECK: 9: {{.*}} mov {{.*}}, dword | 195 ; CHECK: 9: {{.*}} mov {{.*}},DWORD |
208 ; CHECK: b: {{.*}} mov | 196 ; CHECK: b: {{.*}} mov |
209 ; CHECK-NEXT: d: {{.*}} xor | 197 ; CHECK-NEXT: d: {{.*}} xor |
210 ; CHECK-NEXT: f: {{.*}} lock | 198 ; CHECK-NEXT: f: {{.*}} lock cmpxchg |
211 ; CHECK-NEXT: 10: {{.*}} cmpxchg | 199 ; CHECK-NEXT: 13: 75 f6 jne b |
212 ; (0x13 + 2) - 10 == 0xb | 200 ; CHECK: 1c: 74 eb je 9 |
213 ; CHECK-NEXT: 13: 75 f6 jne -10 | |
214 ; (0x1c + 2) - 21 == 0x9 | |
215 ; CHECK: 1c: 74 eb je -21 | |
OLD | NEW |