1 ; Tests various aspects of i1 related lowering. 2 3 ; RUN: %if --need=target_X8632 --command %p2i --filetype=obj --disassemble \ 4 ; RUN: --target x8632 -i %s --args -O2 \ 5 ; RUN: | %if --need=target_X8632 --command FileCheck %s 6 7 ; RUN: %if --need=target_X8632 --command %p2i --filetype=obj --disassemble \ 8 ; RUN: --target x8632 -i %s --args -Om1 \ 9 ; RUN: | %if --need=target_X8632 --command FileCheck %s 10 11 ; TODO(jpp): Switch to --filetype=obj when possible. 12 ; RUN: %if --need=target_ARM32 --need=allow_dump \ 13 ; RUN: --command %p2i --filetype=asm --assemble \ 14 ; RUN: --disassemble --target arm32 -i %s --args -O2 \ 15 ; RUN: | %if --need=target_ARM32 --need=allow_dump \ 16 ; RUN: --command FileCheck --check-prefix ARM32 %s 17 18 ; RUN: %if --need=target_MIPS32 --need=allow_dump \ 19 ; RUN: --command %p2i --filetype=asm --assemble --disassemble --target \ 20 ; RUN: mips32 -i %s --args -O2 -allow-externally-defined-symbols \ 21 ; RUN: | %if --need=target_MIPS32 --need=allow_dump \ 22 ; RUN: --command FileCheck --check-prefix MIPS32 %s 23 24 ; Test that and with true uses immediate 1, not -1. 25 define internal i32 @testAndTrue(i32 %arg) { 26 entry: 27 %arg_i1 = trunc i32 %arg to i1 28 %result_i1 = and i1 %arg_i1, true 29 %result = zext i1 %result_i1 to i32 30 ret i32 %result 31 } 32 ; CHECK-LABEL: testAndTrue 33 ; CHECK: and {{.*}},0x1 34 ; ARM32-LABEL: testAndTrue 35 ; ARM32: and {{.*}}, #1 36 ; MIPS32-LABEL: testAndTrue 37 ; MIPS32: andi {{.*}},0x1 38 39 ; Test that or with true uses immediate 1, not -1. 40 define internal i32 @testOrTrue(i32 %arg) { 41 entry: 42 %arg_i1 = trunc i32 %arg to i1 43 %result_i1 = or i1 %arg_i1, true 44 %result = zext i1 %result_i1 to i32 45 ret i32 %result 46 } 47 ; CHECK-LABEL: testOrTrue 48 ; CHECK: or {{.*}},0x1 49 ; ARM32-LABEL: testOrTrue 50 ; ARM32: orr {{.*}}, #1 51 ; MIPS32-LABEL: testOrTrue 52 ; MIPS32: ori {{.*}},0x1 53 54 ; Test that xor with true uses immediate 1, not -1. 55 define internal i32 @testXorTrue(i32 %arg) { 56 entry: 57 %arg_i1 = trunc i32 %arg to i1 58 %result_i1 = xor i1 %arg_i1, true 59 %result = zext i1 %result_i1 to i32 60 ret i32 %result 61 } 62 ; CHECK-LABEL: testXorTrue 63 ; CHECK: xor {{.*}},0x1 64 ; ARM32-LABEL: testXorTrue 65 ; ARM32: eor {{.*}}, #1 66 ; MIPS32-LABEL: testXorTrue 67 ; MIPS32: xori {{.*}},0x1 68 69 ; Test that trunc to i1 masks correctly. 70 define internal i32 @testTrunc(i32 %arg) { 71 entry: 72 %arg_i1 = trunc i32 %arg to i1 73 %result = zext i1 %arg_i1 to i32 74 ret i32 %result 75 } 76 ; CHECK-LABEL: testTrunc 77 ; CHECK: and {{.*}},0x1 78 ; ARM32-LABEL: testTrunc 79 ; ARM32: and {{.*}}, #1 80 ; MIPS32-LABEL: testTrunc 81 ; MIPS32: andi {{.*}},0x1 82 83 ; Test zext to i8. 84 define internal i32 @testZextI8(i32 %arg) { 85 entry: 86 %arg_i1 = trunc i32 %arg to i1 87 %result_i8 = zext i1 %arg_i1 to i8 88 %result = zext i8 %result_i8 to i32 89 ret i32 %result 90 } 91 ; CHECK-LABEL: testZextI8 92 ; match the trunc instruction 93 ; CHECK: and {{.*}},0x1 94 ; match the zext i1 instruction (NOTE: no mov need between i1 and i8). 95 ; CHECK-NOT: and {{.*}},0x1 96 ; ARM32-LABEL: testZextI8 97 ; ARM32: {{.*}}, #1 98 ; ARM32: uxtb 99 ; MIPS32-LABEL: testZextI8 100 ; MIPS32: andi {{.*}},0x1 101 ; MIPS32: andi {{.*}},0xff 102 103 ; Test zext to i16. 104 define internal i32 @testZextI16(i32 %arg) { 105 entry: 106 %arg_i1 = trunc i32 %arg to i1 107 %result_i16 = zext i1 %arg_i1 to i16 108 %result = zext i16 %result_i16 to i32 109 ret i32 %result 110 } 111 ; CHECK-LABEL: testZextI16 112 ; match the trunc instruction 113 ; CHECK: and {{.*}},0x1 114 ; match the zext i1 instruction (note 32-bit reg is used because it's shorter). 115 ; CHECK: movzx [[REG:e.*]],{{[a-d]l|BYTE PTR}} 116 ; CHECK-NOT: and [[REG]],0x1 117 118 ; ARM32-LABEL: testZextI16 119 ; ARM32: and {{.*}}, #1 120 ; ARM32: uxth 121 122 ; MIPS32-LABEL: testZextI16 123 ; MIPS32: andi {{.*}},0x1 124 ; MIPS32: andi {{.*}},0xffff 125 126 ; Test zext to i32. 127 define internal i32 @testZextI32(i32 %arg) { 128 entry: 129 %arg_i1 = trunc i32 %arg to i1 130 %result_i32 = zext i1 %arg_i1 to i32 131 ret i32 %result_i32 132 } 133 ; CHECK-LABEL: testZextI32 134 ; match the trunc instruction 135 ; CHECK: and {{.*}},0x1 136 ; match the zext i1 instruction 137 ; CHECK: movzx 138 ; CHECK-NOT: and {{.*}},0x1 139 ; ARM32-LABEL: testZextI32 140 ; ARM32: and {{.*}}, #1 141 ; MIPS32-LABEL: testZextI32 142 ; MIPS32: andi {{.*}},0x1 143 144 ; Test zext to i64. 145 define internal i64 @testZextI64(i32 %arg) { 146 entry: 147 %arg_i1 = trunc i32 %arg to i1 148 %result_i64 = zext i1 %arg_i1 to i64 149 ret i64 %result_i64 150 } 151 ; CHECK-LABEL: testZextI64 152 ; match the trunc instruction 153 ; CHECK: and {{.*}},0x1 154 ; match the zext i1 instruction 155 ; CHECK: movzx 156 ; CHECK: mov {{.*}},0x0 157 ; ARM32-LABEL: testZextI64 158 ; ARM32: and {{.*}}, #1 159 ; ARM32: mov {{.*}}, #0 160 ; MIPS32-LABEL: testZextI64 161 ; MIPS32: andi {{.*}},0x1 162 ; MIPS32: li {{.*}},0 163 ; MIPS32: move 164 ; MIPS32: move 165 166 ; Test sext to i8. 167 define internal i32 @testSextI8(i32 %arg) { 168 entry: 169 %arg_i1 = trunc i32 %arg to i1 170 %result_i8 = sext i1 %arg_i1 to i8 171 %result = sext i8 %result_i8 to i32 172 ret i32 %result 173 } 174 ; CHECK-LABEL: testSextI8 175 ; match the trunc instruction 176 ; CHECK: and {{.*}},0x1 177 ; match the sext i1 instruction 178 ; CHECK: shl [[REG:.*]],0x7 179 ; CHECK-NEXT: sar [[REG]],0x7 180 ; 181 ; ARM32-LABEL: testSextI8 182 ; ARM32: mov {{.*}}, #0 183 ; ARM32: tst {{.*}}, #1 184 ; ARM32: mvn {{.*}}, #0 185 ; ARM32: movne 186 ; ARM32: sxtb 187 ; 188 ; MIPS32-LABEL: testSextI8 189 ; MIPS32: sll {{.*}},0x1f 190 ; MIPS32: sra {{.*}},0x1f 191 ; MIPS32: sll {{.*}},0x18 192 ; MIPS32: sra {{.*}},0x18 193 194 ; Test sext to i16. 195 define internal i32 @testSextI16(i32 %arg) { 196 entry: 197 %arg_i1 = trunc i32 %arg to i1 198 %result_i16 = sext i1 %arg_i1 to i16 199 %result = sext i16 %result_i16 to i32 200 ret i32 %result 201 } 202 ; CHECK-LABEL: testSextI16 203 ; match the trunc instruction 204 ; CHECK: and {{.*}},0x1 205 ; match the sext i1 instruction 206 ; CHECK: movzx {{e*}}[[REG:.*]],{{[a-d]l|BYTE PTR}} 207 ; CHECK-NEXT: shl [[REG]],0xf 208 ; CHECK-NEXT: sar [[REG]],0xf 209 210 ; ARM32-LABEL: testSextI16 211 ; ARM32: mov {{.*}}, #0 212 ; ARM32: tst {{.*}}, #1 213 ; ARM32: mvn {{.*}}, #0 214 ; ARM32: movne 215 ; ARM32: sxth 216 217 ; MIPS32-LABEL: testSextI16 218 ; MIPS32: sll {{.*}},0x1f 219 ; MIPS32: sra {{.*}},0x1f 220 ; MIPS32: sll {{.*}},0x10 221 ; MIPS32: sra {{.*}},0x10 222 223 ; Test sext to i32. 224 define internal i32 @testSextI32(i32 %arg) { 225 entry: 226 %arg_i1 = trunc i32 %arg to i1 227 %result_i32 = sext i1 %arg_i1 to i32 228 ret i32 %result_i32 229 } 230 ; CHECK-LABEL: testSextI32 231 ; match the trunc instruction 232 ; CHECK: and {{.*}},0x1 233 ; match the sext i1 instruction 234 ; CHECK: movzx [[REG:.*]], 235 ; CHECK-NEXT: shl [[REG]],0x1f 236 ; CHECK-NEXT: sar [[REG]],0x1f 237 238 ; ARM32-LABEL: testSextI32 239 ; ARM32: mov {{.*}}, #0 240 ; ARM32: tst {{.*}}, #1 241 ; ARM32: mvn {{.*}}, #0 242 ; ARM32: movne 243 244 ; MIPS32-LABEL: testSextI32 245 ; MIPS32: sll {{.*}},0x1f 246 ; MIPS32: sra {{.*}},0x1f 247 248 ; Test sext to i64. 249 define internal i64 @testSextI64(i32 %arg) { 250 entry: 251 %arg_i1 = trunc i32 %arg to i1 252 %result_i64 = sext i1 %arg_i1 to i64 253 ret i64 %result_i64 254 } 255 ; CHECK-LABEL: testSextI64 256 ; match the trunc instruction 257 ; CHECK: and {{.*}},0x1 258 ; match the sext i1 instruction 259 ; CHECK: movzx [[REG:.*]], 260 ; CHECK-NEXT: shl [[REG]],0x1f 261 ; CHECK-NEXT: sar [[REG]],0x1f 262 263 ; ARM32-LABEL: testSextI64 264 ; ARM32: mov {{.*}}, #0 265 ; ARM32: tst {{.*}}, #1 266 ; ARM32: mvn {{.*}}, #0 267 ; ARM32: movne [[REG:r[0-9]+]] 268 ; ARM32: mov {{.*}}, [[REG]] 269 270 ; MIPS32-LABEL: testSextI64 271 ; MIPS32: sll {{.*}},0x1f 272 ; MIPS32: sra {{.*}},0x1f 273 ; MIPS32: move 274 ; MIPS32: move 275 276 ; Kind of like sext i1 to i32, but with an immediate source. On ARM, 277 ; sxtb cannot take an immediate operand, so make sure it's using a reg. 278 ; If we had optimized constants, this could just be mov dst, 0xffffffff 279 ; or mvn dst, #0. 280 define internal i32 @testSextTrue() { 281 %result = sext i1 true to i32 282 ret i32 %result 283 } 284 ; CHECK-LABEL: testSextTrue 285 ; CHECK: movzx 286 ; CHECK-NEXT: shl 287 ; CHECK-NEXT: sar 288 ; ARM32-LABEL: testSextTrue 289 ; ARM32: mov {{.*}}, #0 290 ; ARM32: tst {{.*}}, #1 291 ; ARM32: mvn {{.*}}, #0 292 ; ARM32: movne 293 ; MIPS32-LABEL: testSextTrue 294 ; MIPS32: li {{.*}},1 295 ; MIPS32: sll {{.*}},0x1f 296 ; MIPS32: sra {{.*}},0x1f 297 298 define internal i32 @testZextTrue() { 299 %result = zext i1 true to i32 300 ret i32 %result 301 } 302 ; CHECK-LABEL: testZextTrue 303 ; CHECK: movzx 304 ; CHECK-NOT: and {{.*}},0x1 305 ; ARM32-LABEL: testZextTrue 306 ; ARM32: mov{{.*}}, #1 307 ; ARM32: and {{.*}}, #1 308 ; MIPS32-LABEL: testZextTrue 309 ; MIPS32: li {{.*}},1 310 ; MIPS32: andi {{.*}},0x1 311 312 ; Test fptosi float to i1. 313 define internal i32 @testFptosiFloat(float %arg) { 314 entry: 315 %arg_i1 = fptosi float %arg to i1 316 %result = sext i1 %arg_i1 to i32 317 ret i32 %result 318 } 319 ; CHECK-LABEL: testFptosiFloat 320 ; CHECK: cvttss2si 321 ; CHECK: and {{.*}},0x1 322 ; CHECK: movzx [[REG:.*]], 323 ; CHECK-NEXT: shl [[REG]],0x1f 324 ; CHECK-NEXT: sar [[REG]],0x1f 325 ; MIPS32-LABEL: testFptosiFloat 326 ; MIPS32: trunc.w.s 327 ; MIPS32: mfc1 328 ; MIPS32: sll {{.*}},0x1f 329 ; MIPS32: sra {{.*}},0x1f 330 331 ; Test fptosi double to i1. 332 define internal i32 @testFptosiDouble(double %arg) { 333 entry: 334 %arg_i1 = fptosi double %arg to i1 335 %result = sext i1 %arg_i1 to i32 336 ret i32 %result 337 } 338 ; CHECK-LABEL: testFptosiDouble 339 ; CHECK: cvttsd2si 340 ; CHECK: and {{.*}},0x1 341 ; CHECK: movzx [[REG:.*]], 342 ; CHECK-NEXT: shl [[REG]],0x1f 343 ; CHECK-NEXT: sar [[REG]],0x1f 344 ; MIPS32-LABEL: testFptosiDouble 345 ; MIPS32: trunc.w.d 346 ; MIPS32: mfc1 347 ; MIPS32: sll {{.*}},0x1f 348 ; MIPS32: sra {{.*}},0x1f 349