OLD | NEW |
(Empty) | |
| 1 ; Tests basics and corner cases of x86-32 sandboxing, using -Om1 in |
| 2 ; the hope that the output will remain stable. When packing bundles, |
| 3 ; we try to limit to a few instructions with well known sizes and |
| 4 ; minimal use of registers and stack slots in the lowering sequence. |
| 5 |
| 6 ; RUN: %p2i -i %s --assemble --disassemble --args -Om1 --verbose none \ |
| 7 ; RUN: -ffunction-sections -sandbox | FileCheck %s |
| 8 |
| 9 declare void @call_target() |
| 10 @global_byte = internal global [1 x i8] zeroinitializer |
| 11 @global_short = internal global [2 x i8] zeroinitializer |
| 12 |
| 13 ; A direct call sequence uses the right mask and register-call sequence. |
| 14 define void @test_direct_call() { |
| 15 entry: |
| 16 call void @call_target() |
| 17 ret void |
| 18 } |
| 19 ; CHECK-LABEL: test_direct_call |
| 20 ; CHECK: nop |
| 21 ; CHECK: 1b: {{.*}} call 1c |
| 22 ; CHECK-NEXT: 20: |
| 23 |
| 24 ; An indirect call sequence uses the right mask and register-call sequence. |
| 25 define void @test_indirect_call(i32 %target) { |
| 26 entry: |
| 27 %__1 = inttoptr i32 %target to void ()* |
| 28 call void %__1() |
| 29 ret void |
| 30 } |
| 31 ; CHECK-LABEL: test_indirect_call |
| 32 ; CHECK: mov [[REG:.*]],DWORD PTR [esp |
| 33 ; CHECK-NEXT: nop |
| 34 ; CHECK: 1b: {{.*}} and [[REG]],0xffffffe0 |
| 35 ; CHECK-NEXT: call [[REG]] |
| 36 ; CHECk-NEXT: 20: |
| 37 |
| 38 ; A return sequences uses the right pop / mask / jmp sequence. |
| 39 define void @test_ret() { |
| 40 entry: |
| 41 ret void |
| 42 } |
| 43 ; CHECK-LABEL: test_ret |
| 44 ; CHECK: pop ecx |
| 45 ; CHECK-NEXT: and ecx,0xffffffe0 |
| 46 ; CHECK-NEXT: jmp ecx |
| 47 |
| 48 ; A perfectly packed bundle should not have nops at the end. |
| 49 define void @packed_bundle() { |
| 50 entry: |
| 51 call void @call_target() |
| 52 ; bundle boundary |
| 53 %addr_byte = bitcast [1 x i8]* @global_byte to i8* |
| 54 %addr_short = bitcast [2 x i8]* @global_short to i16* |
| 55 store i8 0, i8* %addr_byte, align 1 ; 7-byte instruction |
| 56 store i16 0, i16* %addr_short, align 1 ; 9-byte instruction |
| 57 store i8 0, i8* %addr_byte, align 1 ; 7-byte instruction |
| 58 store i16 0, i16* %addr_short, align 1 ; 9-byte instruction |
| 59 ; bundle boundary |
| 60 store i8 0, i8* %addr_byte, align 1 ; 7-byte instruction |
| 61 store i16 0, i16* %addr_short, align 1 ; 9-byte instruction |
| 62 ret void |
| 63 } |
| 64 ; CHECK-LABEL: packed_bundle |
| 65 ; CHECK: call |
| 66 ; CHECK-NEXT: 20: {{.*}} mov BYTE PTR |
| 67 ; CHECK-NEXT: 27: {{.*}} mov WORD PTR |
| 68 ; CHECK-NEXT: 30: {{.*}} mov BYTE PTR |
| 69 ; CHECK-NEXT: 37: {{.*}} mov WORD PTR |
| 70 ; CHECK-NEXT: 40: {{.*}} mov BYTE PTR |
| 71 ; CHECK-NEXT: 47: {{.*}} mov WORD PTR |
| 72 |
| 73 ; An imperfectly packed bundle should have one or more nops at the end. |
| 74 define void @nonpacked_bundle() { |
| 75 entry: |
| 76 call void @call_target() |
| 77 ; bundle boundary |
| 78 %addr_short = bitcast [2 x i8]* @global_short to i16* |
| 79 store i16 0, i16* %addr_short, align 1 ; 9-byte instruction |
| 80 store i16 0, i16* %addr_short, align 1 ; 9-byte instruction |
| 81 store i16 0, i16* %addr_short, align 1 ; 9-byte instruction |
| 82 ; nop padding |
| 83 ; bundle boundary |
| 84 store i16 0, i16* %addr_short, align 1 ; 9-byte instruction |
| 85 ret void |
| 86 } |
| 87 ; CHECK-LABEL: nonpacked_bundle |
| 88 ; CHECK: call |
| 89 ; CHECK-NEXT: 20: {{.*}} mov WORD PTR |
| 90 ; CHECK-NEXT: 29: {{.*}} mov WORD PTR |
| 91 ; CHECK-NEXT: 32: {{.*}} mov WORD PTR |
| 92 ; CHECK-NEXT: 3b: {{.*}} nop |
| 93 ; CHECK: 40: {{.*}} mov WORD PTR |
| 94 |
| 95 ; A zero-byte instruction (e.g. local label definition) at a bundle |
| 96 ; boundary should not trigger nop padding. |
| 97 define void @label_at_boundary(i32 %arg) { |
| 98 entry: |
| 99 call void @call_target() |
| 100 ; bundle boundary |
| 101 %addr_short = bitcast [2 x i8]* @global_short to i16* |
| 102 store i16 0, i16* %addr_short, align 1 ; 9-byte instruction |
| 103 %cmp = icmp eq i32 %arg, 0 ; 23-byte lowering sequence |
| 104 ; label is here |
| 105 store i16 0, i16* %addr_short, align 1 ; 9-byte instruction |
| 106 ret void |
| 107 } |
| 108 ; CHECK-LABEL: label_at_boundary |
| 109 ; CHECK: call |
| 110 ; We rely on the hideous 4-instruction 23-byte Om1 lowering sequence for icmp. |
| 111 ; CHECK-NEXT: 20: {{.*}} mov WORD PTR |
| 112 ; CHECK-NEXT: 29: {{.*}} cmp DWORD PTR |
| 113 ; CHECK-NEXT: 2e: {{.*}} mov DWORD PTR |
| 114 ; CHECK-NEXT: 36: {{.*}} je 40 |
| 115 ; CHECK-NEXT: 38: {{.*}} mov DWORD PTR |
| 116 ; CHECK-NEXT: 40: {{.*}} mov WORD PTR |
| 117 |
| 118 ; Bundle lock without padding. |
| 119 define void @bundle_lock_without_padding() { |
| 120 entry: |
| 121 %addr_short = bitcast [2 x i8]* @global_short to i16* |
| 122 store i16 0, i16* %addr_short, align 1 ; 9-byte instruction |
| 123 ret void |
| 124 } |
| 125 ; CHECK-LABEL: bundle_lock_without_padding |
| 126 ; CHECK: mov WORD PTR |
| 127 ; CHECK-NEXT: pop ecx |
| 128 ; CHECK-NEXT: and ecx,0xffffffe0 |
| 129 ; CHECK-NEXT: jmp ecx |
| 130 |
| 131 ; Bundle lock with padding. |
| 132 define void @bundle_lock_with_padding() { |
| 133 entry: |
| 134 call void @call_target() |
| 135 ; bundle boundary |
| 136 %addr_byte = bitcast [1 x i8]* @global_byte to i8* |
| 137 %addr_short = bitcast [2 x i8]* @global_short to i16* |
| 138 store i8 0, i8* %addr_byte, align 1 ; 7-byte instruction |
| 139 store i16 0, i16* %addr_short, align 1 ; 9-byte instruction |
| 140 store i16 0, i16* %addr_short, align 1 ; 9-byte instruction |
| 141 ret void |
| 142 ; 3 bytes to restore stack pointer |
| 143 ; 1 byte to pop ecx |
| 144 ; bundle_lock |
| 145 ; 3 bytes to mask ecx |
| 146 ; This is now 32 bytes from the beginning of the bundle, so |
| 147 ; a 3-byte nop will need to be emitted before the bundle_lock. |
| 148 ; 2 bytes to jump to ecx |
| 149 ; bundle_unlock |
| 150 } |
| 151 ; CHECK-LABEL: bundle_lock_with_padding |
| 152 ; CHECK: call |
| 153 ; CHECK-NEXT: 20: {{.*}} mov BYTE PTR |
| 154 ; CHECK-NEXT: 27: {{.*}} mov WORD PTR |
| 155 ; CHECK-NEXT: 30: {{.*}} mov WORD PTR |
| 156 ; CHECK-NEXT: 39: {{.*}} add esp, |
| 157 ; CHECK-NEXT: 3c: {{.*}} pop ecx |
| 158 ; CHECK-NEXT: 3d: {{.*}} nop |
| 159 ; CHECK-NEXT: 40: {{.*}} and ecx,0xffffffe0 |
| 160 ; CHECK-NEXT: 43: {{.*}} jmp ecx |
| 161 |
| 162 ; Bundle lock align_to_end without any padding. |
| 163 define void @bundle_lock_align_to_end_padding_0() { |
| 164 entry: |
| 165 call void @call_target() |
| 166 ; bundle boundary |
| 167 %addr_short = bitcast [2 x i8]* @global_short to i16* |
| 168 store i16 0, i16* %addr_short, align 1 ; 9-byte instruction |
| 169 store i16 0, i16* %addr_short, align 1 ; 9-byte instruction |
| 170 store i16 0, i16* %addr_short, align 1 ; 9-byte instruction |
| 171 call void @call_target() ; 5-byte instruction |
| 172 ret void |
| 173 } |
| 174 ; CHECK-LABEL: bundle_lock_align_to_end_padding_0 |
| 175 ; CHECK: call |
| 176 ; CHECK-NEXT: 20: {{.*}} mov WORD PTR |
| 177 ; CHECK-NEXT: 29: {{.*}} mov WORD PTR |
| 178 ; CHECK-NEXT: 32: {{.*}} mov WORD PTR |
| 179 ; CHECK-NEXT: 3b: {{.*}} call |
| 180 |
| 181 ; Bundle lock align_to_end with one bunch of padding. |
| 182 define void @bundle_lock_align_to_end_padding_1() { |
| 183 entry: |
| 184 call void @call_target() |
| 185 ; bundle boundary |
| 186 %addr_byte = bitcast [1 x i8]* @global_byte to i8* |
| 187 store i8 0, i8* %addr_byte, align 1 ; 7-byte instruction |
| 188 store i8 0, i8* %addr_byte, align 1 ; 7-byte instruction |
| 189 store i8 0, i8* %addr_byte, align 1 ; 7-byte instruction |
| 190 call void @call_target() ; 5-byte instruction |
| 191 ret void |
| 192 } |
| 193 ; CHECK-LABEL: bundle_lock_align_to_end_padding_1 |
| 194 ; CHECK: call |
| 195 ; CHECK-NEXT: 20: {{.*}} mov BYTE PTR |
| 196 ; CHECK-NEXT: 27: {{.*}} mov BYTE PTR |
| 197 ; CHECK-NEXT: 2e: {{.*}} mov BYTE PTR |
| 198 ; CHECK-NEXT: 35: {{.*}} nop |
| 199 ; CHECK: 3b: {{.*}} call |
| 200 |
| 201 ; Bundle lock align_to_end with two bunches of padding. |
| 202 define void @bundle_lock_align_to_end_padding_2(i32 %target) { |
| 203 entry: |
| 204 call void @call_target() |
| 205 ; bundle boundary |
| 206 %addr_byte = bitcast [1 x i8]* @global_byte to i8* |
| 207 %addr_short = bitcast [2 x i8]* @global_short to i16* |
| 208 %__1 = inttoptr i32 %target to void ()* |
| 209 store i8 0, i8* %addr_byte, align 1 ; 7-byte instruction |
| 210 store i16 0, i16* %addr_short, align 1 ; 9-byte instruction |
| 211 store i16 0, i16* %addr_short, align 1 ; 9-byte instruction |
| 212 call void %__1() |
| 213 ; 4 bytes to load %target into a register |
| 214 ; bundle_lock align_to_end |
| 215 ; 3 bytes to mask the register |
| 216 ; This is now 32 bytes from the beginning of the bundle, so |
| 217 ; a 3-byte nop will need to be emitted before the bundle_lock, |
| 218 ; followed by a 27-byte nop before the mask/jump. |
| 219 ; 2 bytes to jump to the register |
| 220 ; bundle_unlock |
| 221 ret void |
| 222 } |
| 223 ; CHECK-LABEL: bundle_lock_align_to_end_padding_2 |
| 224 ; CHECK: call |
| 225 ; CHECK-NEXT: 20: {{.*}} mov BYTE PTR |
| 226 ; CHECK-NEXT: 27: {{.*}} mov WORD PTR |
| 227 ; CHECK-NEXT: 30: {{.*}} mov WORD PTR |
| 228 ; CHECK-NEXT: 39: {{.*}} mov [[REG:.*]],DWORD PTR [esp |
| 229 ; CHECK-NEXT: 3d: {{.*}} nop |
| 230 ; CHECK: 40: {{.*}} nop |
| 231 ; CHECK: 5b: {{.*}} and [[REG]],0xffffffe0 |
| 232 ; CHECK-NEXT: 5e: {{.*}} call [[REG]] |
OLD | NEW |