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