| 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 |