Home | History | Annotate | Download | only in x86
      1 ; Tests various aspects of x86 immediate encoding. Some encodings are shorter.
      2 ; For example, the encoding is shorter for 8-bit immediates or when using EAX.
      3 ; This assumes that EAX is chosen as the first free register in O2 mode.
      4 
      5 ; RUN: %p2i --filetype=obj --disassemble -i %s --args -O2 | FileCheck %s
      6 
      7 define internal i32 @testXor8Imm8(i32 %arg) {
      8 entry:
      9   %arg_i8 = trunc i32 %arg to i8
     10   %result_i8 = xor i8 %arg_i8, 127
     11   %result = zext i8 %result_i8 to i32
     12   ret i32 %result
     13 }
     14 ; CHECK-LABEL: testXor8Imm8
     15 ; CHECK: 34 7f   xor al
     16 
     17 define internal i32 @testXor8Imm8Neg(i32 %arg) {
     18 entry:
     19   %arg_i8 = trunc i32 %arg to i8
     20   %result_i8 = xor i8 %arg_i8, -128
     21   %result = zext i8 %result_i8 to i32
     22   ret i32 %result
     23 }
     24 ; CHECK-LABEL: testXor8Imm8Neg
     25 ; CHECK: 34 80   xor al
     26 
     27 define internal i32 @testXor8Imm8NotEAX(i32 %arg, i32 %arg2, i32 %arg3) {
     28 entry:
     29   %arg_i8 = trunc i32 %arg to i8
     30   %arg2_i8 = trunc i32 %arg2 to i8
     31   %arg3_i8 = trunc i32 %arg3 to i8
     32   %x1 = xor i8 %arg_i8, 127
     33   %x2 = xor i8 %arg2_i8, 127
     34   %x3 = xor i8 %arg3_i8, 127
     35   %x4 = add i8 %x1, %x2
     36   %x5 = add i8 %x4, %x3
     37   %result = zext i8 %x5 to i32
     38   ret i32 %result
     39 }
     40 ; CHECK-LABEL: testXor8Imm8NotEAX
     41 ; CHECK: 80 f{{[1-3]}} 7f xor {{[^a]}}l
     42 
     43 define internal i32 @testXor16Imm8(i32 %arg) {
     44 entry:
     45   %arg_i16 = trunc i32 %arg to i16
     46   %result_i16 = xor i16 %arg_i16, 127
     47   %result = zext i16 %result_i16 to i32
     48   ret i32 %result
     49 }
     50 ; CHECK-LABEL: testXor16Imm8
     51 ; CHECK: 66 83 f0 7f  xor ax
     52 
     53 define internal i32 @testXor16Imm8Neg(i32 %arg) {
     54 entry:
     55   %arg_i16 = trunc i32 %arg to i16
     56   %result_i16 = xor i16 %arg_i16, -128
     57   %result = zext i16 %result_i16 to i32
     58   ret i32 %result
     59 }
     60 ; CHECK-LABEL: testXor16Imm8Neg
     61 ; CHECK: 66 83 f0 80  xor ax
     62 
     63 define internal i32 @testXor16Imm16Eax(i32 %arg) {
     64 entry:
     65   %arg_i16 = trunc i32 %arg to i16
     66   %tmp = xor i16 %arg_i16, 1024
     67   %result_i16 = add i16 %tmp, 1
     68   %result = zext i16 %result_i16 to i32
     69   ret i32 %result
     70 }
     71 ; CHECK-LABEL: testXor16Imm16Eax
     72 ; CHECK: 66 35 00 04  xor ax
     73 ; CHECK-NEXT: add ax,0x1
     74 
     75 define internal i32 @testXor16Imm16NegEax(i32 %arg) {
     76 entry:
     77   %arg_i16 = trunc i32 %arg to i16
     78   %tmp = xor i16 %arg_i16, -256
     79   %result_i16 = add i16 %tmp, 1
     80   %result = zext i16 %result_i16 to i32
     81   ret i32 %result
     82 }
     83 ; CHECK-LABEL: testXor16Imm16NegEax
     84 ; CHECK: 66 35 00 ff  xor ax
     85 ; CHECK-NEXT: add ax,0x1
     86 
     87 define internal i32 @testXor16Imm16NotEAX(i32 %arg_i32, i32 %arg2_i32, i32 %arg3_i32) {
     88 entry:
     89   %arg = trunc i32 %arg_i32 to i16
     90   %arg2 = trunc i32 %arg2_i32 to i16
     91   %arg3 = trunc i32 %arg3_i32 to i16
     92   %x = xor i16 %arg, 32767
     93   %x2 = xor i16 %arg2, 32767
     94   %x3 = xor i16 %arg3, 32767
     95   %add1 = add i16 %x, %x2
     96   %add2 = add i16 %add1, %x3
     97   %result = zext i16 %add2 to i32
     98   ret i32 %result
     99 }
    100 ; CHECK-LABEL: testXor16Imm16NotEAX
    101 ; CHECK: 66 81 f{{[1-3]}} ff 7f  xor {{[^a]}}x
    102 ; CHECK-NEXT: 66 81 f{{[1-3]}} ff 7f  xor {{[^a]}}x
    103 
    104 define internal i32 @testXor32Imm8(i32 %arg) {
    105 entry:
    106   %result = xor i32 %arg, 127
    107   ret i32 %result
    108 }
    109 ; CHECK-LABEL: testXor32Imm8
    110 ; CHECK: 83 f0 7f   xor eax
    111 
    112 define internal i32 @testXor32Imm8Neg(i32 %arg) {
    113 entry:
    114   %result = xor i32 %arg, -128
    115   ret i32 %result
    116 }
    117 ; CHECK-LABEL: testXor32Imm8Neg
    118 ; CHECK: 83 f0 80   xor eax
    119 
    120 define internal i32 @testXor32Imm32Eax(i32 %arg) {
    121 entry:
    122   %result = xor i32 %arg, 16777216
    123   ret i32 %result
    124 }
    125 ; CHECK-LABEL: testXor32Imm32Eax
    126 ; CHECK: 35 00 00 00 01   xor eax
    127 
    128 define internal i32 @testXor32Imm32NegEax(i32 %arg) {
    129 entry:
    130   %result = xor i32 %arg, -256
    131   ret i32 %result
    132 }
    133 ; CHECK-LABEL: testXor32Imm32NegEax
    134 ; CHECK: 35 00 ff ff ff   xor eax
    135 
    136 define internal i32 @testXor32Imm32NotEAX(i32 %arg, i32 %arg2, i32 %arg3) {
    137 entry:
    138   %x = xor i32 %arg, 32767
    139   %x2 = xor i32 %arg2, 32767
    140   %x3 = xor i32 %arg3, 32767
    141   %add1 = add i32 %x, %x2
    142   %add2 = add i32 %add1, %x3
    143   ret i32 %add2
    144 }
    145 ; CHECK-LABEL: testXor32Imm32NotEAX
    146 ; CHECK: 81 f{{[1-3]}} ff 7f 00 00   xor e{{[^a]}}x,
    147 
    148 ; Should be similar for add, sub, etc., so sample a few.
    149 
    150 define internal i32 @testAdd8Imm8(i32 %arg) {
    151 entry:
    152   %arg_i8 = trunc i32 %arg to i8
    153   %result_i8 = add i8 %arg_i8, 126
    154   %result = zext i8 %result_i8 to i32
    155   ret i32 %result
    156 }
    157 ; CHECK-LABEL: testAdd8Imm8
    158 ; CHECK: 04 7e   add al
    159 
    160 define internal i32 @testSub8Imm8(i32 %arg) {
    161 entry:
    162   %arg_i8 = trunc i32 %arg to i8
    163   %result_i8 = sub i8 %arg_i8, 125
    164   %result = zext i8 %result_i8 to i32
    165   ret i32 %result
    166 }
    167 ; CHECK-LABEL: testSub8Imm8
    168 ; CHECK: 2c 7d  sub al
    169 
    170 ; imul has some shorter 8-bit immediate encodings.
    171 ; It also has a shorter encoding for eax, but we don't do that yet.
    172 
    173 define internal i32 @testMul16Imm8(i32 %arg) {
    174 entry:
    175   %arg_i16 = trunc i32 %arg to i16
    176   %tmp = mul i16 %arg_i16, 99
    177   %result_i16 = add i16 %tmp, 1
    178   %result = zext i16 %result_i16 to i32
    179   ret i32 %result
    180 }
    181 ; CHECK-LABEL: testMul16Imm8
    182 ; CHECK: 66 6b c0 63  imul ax,ax
    183 ; CHECK-NEXT: add ax,0x1
    184 
    185 define internal i32 @testMul16Imm8Neg(i32 %arg) {
    186 entry:
    187   %arg_i16 = trunc i32 %arg to i16
    188   %tmp = mul i16 %arg_i16, -111
    189   %result_i16 = add i16 %tmp, 1
    190   %result = zext i16 %result_i16 to i32
    191   ret i32 %result
    192 }
    193 ; CHECK-LABEL: testMul16Imm8Neg
    194 ; CHECK: 66 6b c0 91  imul ax,ax
    195 ; CHECK-NEXT: add ax,0x1
    196 
    197 define internal i32 @testMul16Imm16(i32 %arg) {
    198 entry:
    199   %arg_i16 = trunc i32 %arg to i16
    200   %tmp = mul i16 %arg_i16, 1025
    201   %result_i16 = add i16 %tmp, 1
    202   %result = zext i16 %result_i16 to i32
    203   ret i32 %result
    204 }
    205 ; CHECK-LABEL: testMul16Imm16
    206 ; CHECK: 66 69 c0 01 04  imul ax,ax
    207 ; CHECK-NEXT: add ax,0x1
    208 
    209 define internal i32 @testMul16Imm16Neg(i32 %arg) {
    210 entry:
    211   %arg_i16 = trunc i32 %arg to i16
    212   %tmp = mul i16 %arg_i16, -255
    213   %result_i16 = add i16 %tmp, 1
    214   %result = zext i16 %result_i16 to i32
    215   ret i32 %result
    216 }
    217 ; CHECK-LABEL: testMul16Imm16Neg
    218 ; CHECK: 66 69 c0 01 ff  imul ax,ax,0xff01
    219 ; CHECK-NEXT: add ax,0x1
    220 
    221 define internal i32 @testMul32Imm8(i32 %arg) {
    222 entry:
    223   %result = mul i32 %arg, 99
    224   ret i32 %result
    225 }
    226 ; CHECK-LABEL: testMul32Imm8
    227 ; CHECK: 6b c0 63  imul eax,eax
    228 
    229 define internal i32 @testMul32Imm8Neg(i32 %arg) {
    230 entry:
    231   %result = mul i32 %arg, -111
    232   ret i32 %result
    233 }
    234 ; CHECK-LABEL: testMul32Imm8Neg
    235 ; CHECK: 6b c0 91  imul eax,eax
    236 
    237 define internal i32 @testMul32Imm16(i32 %arg) {
    238 entry:
    239   %result = mul i32 %arg, 1025
    240   ret i32 %result
    241 }
    242 ; CHECK-LABEL: testMul32Imm16
    243 ; CHECK: 69 c0 01 04 00 00  imul eax,eax
    244 
    245 define internal i32 @testMul32Imm16Neg(i32 %arg) {
    246 entry:
    247   %result = mul i32 %arg, -255
    248   ret i32 %result
    249 }
    250 ; CHECK-LABEL: testMul32Imm16Neg
    251 ; CHECK: 69 c0 01 ff ff ff  imul eax,eax,0xffffff01
    252 
    253 define internal i32 @testMul32Imm32ThreeAddress(i32 %a) {
    254 entry:
    255   %mul = mul i32 232, %a
    256   %add = add i32 %mul, %a
    257   ret i32 %add
    258 }
    259 ; CHECK-LABEL: testMul32Imm32ThreeAddress
    260 ; CHECK: 69 c8 e8 00 00 00  imul ecx,eax,0xe8
    261 
    262 define internal i32 @testMul32Mem32Imm32ThreeAddress(i32 %addr_arg) {
    263 entry:
    264   %__1 = inttoptr i32 %addr_arg to i32*
    265   %a = load i32, i32* %__1, align 1
    266   %mul = mul i32 232, %a
    267   ret i32 %mul
    268 }
    269 ; CHECK-LABEL: testMul32Mem32Imm32ThreeAddress
    270 ; CHECK: 69 00 e8 00 00 00  imul eax,DWORD PTR [eax],0xe8
    271 
    272 define internal i32 @testMul32Imm8ThreeAddress(i32 %a) {
    273 entry:
    274   %mul = mul i32 127, %a
    275   %add = add i32 %mul, %a
    276   ret i32 %add
    277 }
    278 ; CHECK-LABEL: testMul32Imm8ThreeAddress
    279 ; CHECK: 6b c8 7f imul ecx,eax,0x7f
    280 
    281 define internal i32 @testMul32Mem32Imm8ThreeAddress(i32 %addr_arg) {
    282 entry:
    283   %__1 = inttoptr i32 %addr_arg to i32*
    284   %a = load i32, i32* %__1, align 1
    285   %mul = mul i32 127, %a
    286   ret i32 %mul
    287 }
    288 ; CHECK-LABEL: testMul32Mem32Imm8ThreeAddress
    289 ; CHECK: 6b 00 7f imul eax,DWORD PTR [eax],0x7f
    290 
    291 define internal i32 @testMul16Imm16ThreeAddress(i32 %a) {
    292 entry:
    293   %arg_i16 = trunc i32 %a to i16
    294   %mul = mul i16 232, %arg_i16
    295   %add = add i16 %mul, %arg_i16
    296   %result = zext i16 %add to i32
    297   ret i32 %result
    298 }
    299 ; CHECK-LABEL: testMul16Imm16ThreeAddress
    300 ; CHECK: 66 69 c8 e8 00 imul cx,ax,0xe8
    301 
    302 define internal i32 @testMul16Mem16Imm16ThreeAddress(i32 %addr_arg) {
    303 entry:
    304   %__1 = inttoptr i32 %addr_arg to i16*
    305   %a = load i16, i16* %__1, align 1
    306   %mul = mul i16 232, %a
    307   %result = zext i16 %mul to i32
    308   ret i32 %result
    309 }
    310 ; CHECK-LABEL: testMul16Mem16Imm16ThreeAddress
    311 ; CHECK: 66 69 00 e8 00 imul ax,WORD PTR [eax],0xe8
    312 
    313 define internal i32 @testMul16Imm8ThreeAddress(i32 %a) {
    314 entry:
    315   %arg_i16 = trunc i32 %a to i16
    316   %mul = mul i16 127, %arg_i16
    317   %add = add i16 %mul, %arg_i16
    318   %result = zext i16 %add to i32
    319   ret i32 %result
    320 }
    321 ; CHECK-LABEL: testMul16Imm8ThreeAddress
    322 ; CHECK: 66 6b c8 7f imul cx,ax,0x7f
    323 
    324 define internal i32 @testMul16Mem16Imm8ThreeAddress(i32 %addr_arg) {
    325 entry:
    326   %__1 = inttoptr i32 %addr_arg to i16*
    327   %a = load i16, i16* %__1, align 1
    328   %mul = mul i16 127, %a
    329   %result = zext i16 %mul to i32
    330   ret i32 %result
    331 }
    332 ; CHECK-LABEL: testMul16Mem16Imm8ThreeAddress
    333 ; CHECK: 66 6b 00 7f imul ax,WORD PTR [eax],0x7f
    334 
    335 ; The GPR shift instructions either allow an 8-bit immediate or
    336 ; have a special encoding for "1".
    337 define internal i32 @testShl16Imm8(i32 %arg) {
    338 entry:
    339   %arg_i16 = trunc i32 %arg to i16
    340   %tmp = shl i16 %arg_i16, 13
    341   %result = zext i16 %tmp to i32
    342   ret i32 %result
    343 }
    344 ; CHECK-LABEL: testShl16Imm8
    345 ; CHECK: 66 c1 e0 0d shl ax,0xd
    346 
    347 define internal i32 @testShl16Imm1(i32 %arg) {
    348 entry:
    349   %arg_i16 = trunc i32 %arg to i16
    350   %tmp = shl i16 %arg_i16, 1
    351   %result = zext i16 %tmp to i32
    352   ret i32 %result
    353 }
    354 ; CHECK-LABEL: testShl16Imm1
    355 ; CHECK: 66 d1 e0 shl ax
    356 
    357 ; Currently the "test" instruction is used for 64-bit shifts, and
    358 ; for ctlz 64-bit, so we use those to test the "test" instruction.
    359 ; One optimization for "test": the "test" instruction is essentially a
    360 ; bitwise AND that doesn't modify the two source operands, so for immediates
    361 ; under 8-bits and registers with 8-bit variants we can use the shorter form.
    362 
    363 define internal i64 @test_via_shl64Bit(i64 %a, i64 %b) {
    364 entry:
    365   %shl = shl i64 %a, %b
    366   ret i64 %shl
    367 }
    368 ; CHECK-LABEL: test_via_shl64Bit
    369 ; CHECK: 0f a5 c2  shld edx,eax,cl
    370 ; CHECK: d3 e0     shl eax,cl
    371 ; CHECK: f6 c1 20  test cl,0x20
    372 
    373 ; Test a few register encodings of "test".
    374 declare i64 @llvm.ctlz.i64(i64, i1)
    375 
    376 define internal i64 @test_via_ctlz_64(i64 %x, i64 %y, i64 %z, i64 %w) {
    377 entry:
    378   %r = call i64 @llvm.ctlz.i64(i64 %x, i1 false)
    379   %r2 = call i64 @llvm.ctlz.i64(i64 %y, i1 false)
    380   %r3 = call i64 @llvm.ctlz.i64(i64 %z, i1 false)
    381   %r4 = call i64 @llvm.ctlz.i64(i64 %w, i1 false)
    382   %res1 = add i64 %r, %r2
    383   %res2 = add i64 %r3, %r4
    384   %res = add i64 %res1, %res2
    385   ret i64 %res
    386 }
    387 ; CHECK-LABEL: test_via_ctlz_64
    388 ; CHECK-DAG: 85 c0 test eax,eax
    389 ; CHECK-DAG: 85 db test ebx,ebx
    390 ; CHECK-DAG: 85 f6 test esi,esi
    391