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. 9 declare void @llvm.nacl.atomic.store.i32(i32, i32*, i32) 10 declare i32 @llvm.nacl.atomic.load.i32(i32*, i32) 11 declare i32 @llvm.nacl.atomic.rmw.i32(i32, i32*, i32, i32) 12 13 define internal void @test_near_backward(i32 %iptr, i32 %val) { 14 entry: 15 br label %next 16 next: 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 20 next2: 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. 37 define internal void @test_far_backward1(i32 %iptr, i32 %val) { 38 entry: 39 br label %next 40 next: 41 %ptr = inttoptr i32 %iptr to i32* 42 %tmp = call i32 @llvm.nacl.atomic.load.i32(i32* %ptr, i32 6) 43 br label %next2 44 next2: 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. 82 define internal void @test_far_backward2(i32 %iptr, i32 %val) { 83 entry: 84 br label %next 85 next: 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 93 next2: 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 129 define internal void @test_near_forward(i32 %iptr, i32 %val) { 130 entry: 131 br label %next1 132 next1: 133 %ptr = inttoptr i32 %iptr to i32* 134 %cmp = icmp ult i32 %val, 1 135 br i1 %cmp, label %next3, label %next2 136 next2: 137 call void @llvm.nacl.atomic.store.i32(i32 %val, i32* %ptr, i32 6) 138 br label %next3 139 next3: 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. 161 define internal void @test_local_forward_then_back(i64 %val64, i32 %iptr, 162 i32 %val) { 163 entry: 164 br label %next 165 next: 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 169 next2: 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. 186 define internal void @test_local_backward(i64 %val64, i32 %iptr, i32 %val) { 187 entry: 188 br label %next 189 next: 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 193 next2: 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