10b57cec5SDimitry Andric//===-- X86InstrExtension.td - Sign and Zero Extensions ----*- tablegen -*-===//
20b57cec5SDimitry Andric//
30b57cec5SDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric// See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric//
70b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric//
90b57cec5SDimitry Andric// This file describes the sign and zero extension operations.
100b57cec5SDimitry Andric//
110b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andriclet hasSideEffects = 0 in {
140b57cec5SDimitry Andric  let Defs = [AX], Uses = [AL] in // AX = signext(AL)
150b57cec5SDimitry Andric  def CBW : I<0x98, RawFrm, (outs), (ins),
160b57cec5SDimitry Andric              "{cbtw|cbw}", []>, OpSize16, Sched<[WriteALU]>;
170b57cec5SDimitry Andric  let Defs = [EAX], Uses = [AX] in // EAX = signext(AX)
180b57cec5SDimitry Andric  def CWDE : I<0x98, RawFrm, (outs), (ins),
190b57cec5SDimitry Andric              "{cwtl|cwde}", []>, OpSize32, Sched<[WriteALU]>;
208bcb0991SDimitry Andric  let Defs = [RAX], Uses = [EAX] in // RAX = signext(EAX)
218bcb0991SDimitry Andric  def CDQE : RI<0x98, RawFrm, (outs), (ins),
228bcb0991SDimitry Andric               "{cltq|cdqe}", []>, Sched<[WriteALU]>, Requires<[In64BitMode]>;
230b57cec5SDimitry Andric
248bcb0991SDimitry Andric  // FIXME: CWD/CDQ/CQO shouldn't Def the A register, but the fast register
258bcb0991SDimitry Andric  // allocator crashes if you remove it.
260b57cec5SDimitry Andric  let Defs = [AX,DX], Uses = [AX] in // DX:AX = signext(AX)
270b57cec5SDimitry Andric  def CWD : I<0x99, RawFrm, (outs), (ins),
280b57cec5SDimitry Andric              "{cwtd|cwd}", []>, OpSize16, Sched<[WriteALU]>;
290b57cec5SDimitry Andric  let Defs = [EAX,EDX], Uses = [EAX] in // EDX:EAX = signext(EAX)
300b57cec5SDimitry Andric  def CDQ : I<0x99, RawFrm, (outs), (ins),
310b57cec5SDimitry Andric              "{cltd|cdq}", []>, OpSize32, Sched<[WriteALU]>;
320b57cec5SDimitry Andric  let Defs = [RAX,RDX], Uses = [RAX] in // RDX:RAX = signext(RAX)
330b57cec5SDimitry Andric  def CQO  : RI<0x99, RawFrm, (outs), (ins),
340b57cec5SDimitry Andric                "{cqto|cqo}", []>, Sched<[WriteALU]>, Requires<[In64BitMode]>;
350b57cec5SDimitry Andric}
360b57cec5SDimitry Andric
370b57cec5SDimitry Andric// Sign/Zero extenders
380b57cec5SDimitry Andriclet hasSideEffects = 0 in {
390b57cec5SDimitry Andricdef MOVSX16rr8 : I<0xBE, MRMSrcReg, (outs GR16:$dst), (ins GR8:$src),
400b57cec5SDimitry Andric                   "movs{bw|x}\t{$src, $dst|$dst, $src}", []>,
410b57cec5SDimitry Andric                   TB, OpSize16, Sched<[WriteALU]>;
420b57cec5SDimitry Andriclet mayLoad = 1 in
430b57cec5SDimitry Andricdef MOVSX16rm8 : I<0xBE, MRMSrcMem, (outs GR16:$dst), (ins i8mem:$src),
440b57cec5SDimitry Andric                   "movs{bw|x}\t{$src, $dst|$dst, $src}", []>,
45bdd1243dSDimitry Andric                   TB, OpSize16, Sched<[WriteLoad]>;
460b57cec5SDimitry Andric} // hasSideEffects = 0
470b57cec5SDimitry Andricdef MOVSX32rr8 : I<0xBE, MRMSrcReg, (outs GR32:$dst), (ins GR8:$src),
480b57cec5SDimitry Andric                   "movs{bl|x}\t{$src, $dst|$dst, $src}",
490b57cec5SDimitry Andric                   [(set GR32:$dst, (sext GR8:$src))]>, TB,
500b57cec5SDimitry Andric                   OpSize32, Sched<[WriteALU]>;
510b57cec5SDimitry Andricdef MOVSX32rm8 : I<0xBE, MRMSrcMem, (outs GR32:$dst), (ins i8mem :$src),
520b57cec5SDimitry Andric                   "movs{bl|x}\t{$src, $dst|$dst, $src}",
530b57cec5SDimitry Andric                   [(set GR32:$dst, (sextloadi32i8 addr:$src))]>, TB,
54bdd1243dSDimitry Andric                   OpSize32, Sched<[WriteLoad]>;
550b57cec5SDimitry Andricdef MOVSX32rr16: I<0xBF, MRMSrcReg, (outs GR32:$dst), (ins GR16:$src),
560b57cec5SDimitry Andric                   "movs{wl|x}\t{$src, $dst|$dst, $src}",
570b57cec5SDimitry Andric                   [(set GR32:$dst, (sext GR16:$src))]>, TB,
580b57cec5SDimitry Andric                   OpSize32, Sched<[WriteALU]>;
590b57cec5SDimitry Andricdef MOVSX32rm16: I<0xBF, MRMSrcMem, (outs GR32:$dst), (ins i16mem:$src),
600b57cec5SDimitry Andric                   "movs{wl|x}\t{$src, $dst|$dst, $src}",
610b57cec5SDimitry Andric                   [(set GR32:$dst, (sextloadi32i16 addr:$src))]>,
62bdd1243dSDimitry Andric                   OpSize32, TB, Sched<[WriteLoad]>;
630b57cec5SDimitry Andric
640b57cec5SDimitry Andriclet hasSideEffects = 0 in {
650b57cec5SDimitry Andricdef MOVZX16rr8 : I<0xB6, MRMSrcReg, (outs GR16:$dst), (ins GR8:$src),
660b57cec5SDimitry Andric                   "movz{bw|x}\t{$src, $dst|$dst, $src}", []>,
670b57cec5SDimitry Andric                   TB, OpSize16, Sched<[WriteALU]>;
680b57cec5SDimitry Andriclet mayLoad = 1 in
690b57cec5SDimitry Andricdef MOVZX16rm8 : I<0xB6, MRMSrcMem, (outs GR16:$dst), (ins i8mem:$src),
700b57cec5SDimitry Andric                   "movz{bw|x}\t{$src, $dst|$dst, $src}", []>,
71bdd1243dSDimitry Andric                   TB, OpSize16, Sched<[WriteLoad]>;
720b57cec5SDimitry Andric} // hasSideEffects = 0
730b57cec5SDimitry Andricdef MOVZX32rr8 : I<0xB6, MRMSrcReg, (outs GR32:$dst), (ins GR8 :$src),
740b57cec5SDimitry Andric                   "movz{bl|x}\t{$src, $dst|$dst, $src}",
750b57cec5SDimitry Andric                   [(set GR32:$dst, (zext GR8:$src))]>, TB,
760b57cec5SDimitry Andric                   OpSize32, Sched<[WriteALU]>;
770b57cec5SDimitry Andricdef MOVZX32rm8 : I<0xB6, MRMSrcMem, (outs GR32:$dst), (ins i8mem :$src),
780b57cec5SDimitry Andric                   "movz{bl|x}\t{$src, $dst|$dst, $src}",
790b57cec5SDimitry Andric                   [(set GR32:$dst, (zextloadi32i8 addr:$src))]>, TB,
80bdd1243dSDimitry Andric                   OpSize32, Sched<[WriteLoad]>;
810b57cec5SDimitry Andricdef MOVZX32rr16: I<0xB7, MRMSrcReg, (outs GR32:$dst), (ins GR16:$src),
820b57cec5SDimitry Andric                   "movz{wl|x}\t{$src, $dst|$dst, $src}",
830b57cec5SDimitry Andric                   [(set GR32:$dst, (zext GR16:$src))]>, TB,
840b57cec5SDimitry Andric                   OpSize32, Sched<[WriteALU]>;
850b57cec5SDimitry Andricdef MOVZX32rm16: I<0xB7, MRMSrcMem, (outs GR32:$dst), (ins i16mem:$src),
860b57cec5SDimitry Andric                   "movz{wl|x}\t{$src, $dst|$dst, $src}",
870b57cec5SDimitry Andric                   [(set GR32:$dst, (zextloadi32i16 addr:$src))]>,
88bdd1243dSDimitry Andric                   TB, OpSize32, Sched<[WriteLoad]>;
890b57cec5SDimitry Andric
900b57cec5SDimitry Andric// These instructions exist as a consequence of operand size prefix having
910b57cec5SDimitry Andric// control of the destination size, but not the input size. Only support them
920b57cec5SDimitry Andric// for the disassembler.
930b57cec5SDimitry Andriclet isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0 in {
940b57cec5SDimitry Andricdef MOVSX16rr16: I<0xBF, MRMSrcReg, (outs GR16:$dst), (ins GR16:$src),
950b57cec5SDimitry Andric                   "movs{ww|x}\t{$src, $dst|$dst, $src}",
9606c3fb27SDimitry Andric                   []>, TB, OpSize16, Sched<[WriteALU]>;
970b57cec5SDimitry Andricdef MOVZX16rr16: I<0xB7, MRMSrcReg, (outs GR16:$dst), (ins GR16:$src),
980b57cec5SDimitry Andric                   "movz{ww|x}\t{$src, $dst|$dst, $src}",
9906c3fb27SDimitry Andric                   []>, TB, OpSize16, Sched<[WriteALU]>;
1000b57cec5SDimitry Andriclet mayLoad = 1 in {
1010b57cec5SDimitry Andricdef MOVSX16rm16: I<0xBF, MRMSrcMem, (outs GR16:$dst), (ins i16mem:$src),
1020b57cec5SDimitry Andric                   "movs{ww|x}\t{$src, $dst|$dst, $src}",
10306c3fb27SDimitry Andric                   []>, OpSize16, TB, Sched<[WriteLoad]>;
1040b57cec5SDimitry Andricdef MOVZX16rm16: I<0xB7, MRMSrcMem, (outs GR16:$dst), (ins i16mem:$src),
1050b57cec5SDimitry Andric                   "movz{ww|x}\t{$src, $dst|$dst, $src}",
10606c3fb27SDimitry Andric                   []>, TB, OpSize16, Sched<[WriteLoad]>;
1070b57cec5SDimitry Andric} // mayLoad = 1
1080b57cec5SDimitry Andric} // isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0
1090b57cec5SDimitry Andric
1100b57cec5SDimitry Andric// These are the same as the regular MOVZX32rr8 and MOVZX32rm8
1110b57cec5SDimitry Andric// except that they use GR32_NOREX for the output operand register class
1120b57cec5SDimitry Andric// instead of GR32. This allows them to operate on h registers on x86-64.
1130b57cec5SDimitry Andriclet hasSideEffects = 0, isCodeGenOnly = 1 in {
1140b57cec5SDimitry Andricdef MOVZX32rr8_NOREX : I<0xB6, MRMSrcReg,
1150b57cec5SDimitry Andric                         (outs GR32_NOREX:$dst), (ins GR8_NOREX:$src),
1160b57cec5SDimitry Andric                         "movz{bl|x}\t{$src, $dst|$dst, $src}",
1170b57cec5SDimitry Andric                         []>, TB, OpSize32, Sched<[WriteALU]>;
1180b57cec5SDimitry Andriclet mayLoad = 1 in
1190b57cec5SDimitry Andricdef MOVZX32rm8_NOREX : I<0xB6, MRMSrcMem,
1200b57cec5SDimitry Andric                         (outs GR32_NOREX:$dst), (ins i8mem_NOREX:$src),
1210b57cec5SDimitry Andric                         "movz{bl|x}\t{$src, $dst|$dst, $src}",
122bdd1243dSDimitry Andric                         []>, TB, OpSize32, Sched<[WriteLoad]>;
1230b57cec5SDimitry Andric
1240b57cec5SDimitry Andricdef MOVSX32rr8_NOREX : I<0xBE, MRMSrcReg,
1250b57cec5SDimitry Andric                         (outs GR32_NOREX:$dst), (ins GR8_NOREX:$src),
1260b57cec5SDimitry Andric                         "movs{bl|x}\t{$src, $dst|$dst, $src}",
1270b57cec5SDimitry Andric                         []>, TB, OpSize32, Sched<[WriteALU]>;
1280b57cec5SDimitry Andriclet mayLoad = 1 in
1290b57cec5SDimitry Andricdef MOVSX32rm8_NOREX : I<0xBE, MRMSrcMem,
1300b57cec5SDimitry Andric                         (outs GR32_NOREX:$dst), (ins i8mem_NOREX:$src),
1310b57cec5SDimitry Andric                         "movs{bl|x}\t{$src, $dst|$dst, $src}",
132bdd1243dSDimitry Andric                         []>, TB, OpSize32, Sched<[WriteLoad]>;
1330b57cec5SDimitry Andric}
1340b57cec5SDimitry Andric
1350b57cec5SDimitry Andric// MOVSX64rr8 always has a REX prefix and it has an 8-bit register
1360b57cec5SDimitry Andric// operand, which makes it a rare instruction with an 8-bit register
1370b57cec5SDimitry Andric// operand that can never access an h register. If support for h registers
1380b57cec5SDimitry Andric// were generalized, this would require a special register class.
1390b57cec5SDimitry Andricdef MOVSX64rr8 : RI<0xBE, MRMSrcReg, (outs GR64:$dst), (ins GR8 :$src),
1400b57cec5SDimitry Andric                    "movs{bq|x}\t{$src, $dst|$dst, $src}",
1410b57cec5SDimitry Andric                    [(set GR64:$dst, (sext GR8:$src))]>, TB,
1420b57cec5SDimitry Andric                    Sched<[WriteALU]>;
1430b57cec5SDimitry Andricdef MOVSX64rm8 : RI<0xBE, MRMSrcMem, (outs GR64:$dst), (ins i8mem :$src),
1440b57cec5SDimitry Andric                    "movs{bq|x}\t{$src, $dst|$dst, $src}",
1450b57cec5SDimitry Andric                    [(set GR64:$dst, (sextloadi64i8 addr:$src))]>,
146bdd1243dSDimitry Andric                    TB, Sched<[WriteLoad]>;
1470b57cec5SDimitry Andricdef MOVSX64rr16: RI<0xBF, MRMSrcReg, (outs GR64:$dst), (ins GR16:$src),
1480b57cec5SDimitry Andric                    "movs{wq|x}\t{$src, $dst|$dst, $src}",
1490b57cec5SDimitry Andric                    [(set GR64:$dst, (sext GR16:$src))]>, TB,
1500b57cec5SDimitry Andric                    Sched<[WriteALU]>;
1510b57cec5SDimitry Andricdef MOVSX64rm16: RI<0xBF, MRMSrcMem, (outs GR64:$dst), (ins i16mem:$src),
1520b57cec5SDimitry Andric                    "movs{wq|x}\t{$src, $dst|$dst, $src}",
1530b57cec5SDimitry Andric                    [(set GR64:$dst, (sextloadi64i16 addr:$src))]>,
154bdd1243dSDimitry Andric                    TB, Sched<[WriteLoad]>;
1550b57cec5SDimitry Andricdef MOVSX64rr32: RI<0x63, MRMSrcReg, (outs GR64:$dst), (ins GR32:$src),
1560b57cec5SDimitry Andric                    "movs{lq|xd}\t{$src, $dst|$dst, $src}",
1570b57cec5SDimitry Andric                    [(set GR64:$dst, (sext GR32:$src))]>,
1580b57cec5SDimitry Andric                    Sched<[WriteALU]>, Requires<[In64BitMode]>;
1590b57cec5SDimitry Andricdef MOVSX64rm32: RI<0x63, MRMSrcMem, (outs GR64:$dst), (ins i32mem:$src),
1600b57cec5SDimitry Andric                    "movs{lq|xd}\t{$src, $dst|$dst, $src}",
1610b57cec5SDimitry Andric                    [(set GR64:$dst, (sextloadi64i32 addr:$src))]>,
162bdd1243dSDimitry Andric                    Sched<[WriteLoad]>, Requires<[In64BitMode]>;
1630b57cec5SDimitry Andric
1640b57cec5SDimitry Andric// These instructions exist as a consequence of operand size prefix having
1650b57cec5SDimitry Andric// control of the destination size, but not the input size. Only support them
1660b57cec5SDimitry Andric// for the disassembler.
1670b57cec5SDimitry Andriclet isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0 in {
1680b57cec5SDimitry Andricdef MOVSX16rr32: I<0x63, MRMSrcReg, (outs GR16:$dst), (ins GR32:$src),
1690b57cec5SDimitry Andric                   "movs{lq|xd}\t{$src, $dst|$dst, $src}", []>,
1700b57cec5SDimitry Andric                   Sched<[WriteALU]>, OpSize16, Requires<[In64BitMode]>;
1710b57cec5SDimitry Andricdef MOVSX32rr32: I<0x63, MRMSrcReg, (outs GR32:$dst), (ins GR32:$src),
1720b57cec5SDimitry Andric                   "movs{lq|xd}\t{$src, $dst|$dst, $src}", []>,
1730b57cec5SDimitry Andric                   Sched<[WriteALU]>, OpSize32, Requires<[In64BitMode]>;
1740b57cec5SDimitry Andriclet mayLoad = 1 in {
1750b57cec5SDimitry Andricdef MOVSX16rm32: I<0x63, MRMSrcMem, (outs GR16:$dst), (ins i32mem:$src),
1760b57cec5SDimitry Andric                   "movs{lq|xd}\t{$src, $dst|$dst, $src}", []>,
177bdd1243dSDimitry Andric                   Sched<[WriteLoad]>, OpSize16, Requires<[In64BitMode]>;
1780b57cec5SDimitry Andricdef MOVSX32rm32: I<0x63, MRMSrcMem, (outs GR32:$dst), (ins i32mem:$src),
1790b57cec5SDimitry Andric                   "movs{lq|xd}\t{$src, $dst|$dst, $src}", []>,
180bdd1243dSDimitry Andric                   Sched<[WriteLoad]>, OpSize32, Requires<[In64BitMode]>;
1810b57cec5SDimitry Andric} // mayLoad = 1
1820b57cec5SDimitry Andric} // isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0
1830b57cec5SDimitry Andric
1840b57cec5SDimitry Andric// movzbq and movzwq encodings for the disassembler
1850b57cec5SDimitry Andriclet hasSideEffects = 0 in {
1860b57cec5SDimitry Andricdef MOVZX64rr8 : RI<0xB6, MRMSrcReg, (outs GR64:$dst), (ins GR8:$src),
1870b57cec5SDimitry Andric                     "movz{bq|x}\t{$src, $dst|$dst, $src}", []>,
1880b57cec5SDimitry Andric                     TB, Sched<[WriteALU]>;
1890b57cec5SDimitry Andriclet mayLoad = 1 in
1900b57cec5SDimitry Andricdef MOVZX64rm8 : RI<0xB6, MRMSrcMem, (outs GR64:$dst), (ins i8mem:$src),
1910b57cec5SDimitry Andric                     "movz{bq|x}\t{$src, $dst|$dst, $src}", []>,
192bdd1243dSDimitry Andric                     TB, Sched<[WriteLoad]>;
1930b57cec5SDimitry Andricdef MOVZX64rr16 : RI<0xB7, MRMSrcReg, (outs GR64:$dst), (ins GR16:$src),
1940b57cec5SDimitry Andric                     "movz{wq|x}\t{$src, $dst|$dst, $src}", []>,
1950b57cec5SDimitry Andric                     TB, Sched<[WriteALU]>;
1960b57cec5SDimitry Andriclet mayLoad = 1 in
1970b57cec5SDimitry Andricdef MOVZX64rm16 : RI<0xB7, MRMSrcMem, (outs GR64:$dst), (ins i16mem:$src),
1980b57cec5SDimitry Andric                     "movz{wq|x}\t{$src, $dst|$dst, $src}", []>,
199bdd1243dSDimitry Andric                     TB, Sched<[WriteLoad]>;
2000b57cec5SDimitry Andric}
2010b57cec5SDimitry Andric
2020b57cec5SDimitry Andric// 64-bit zero-extension patterns use SUBREG_TO_REG and an operation writing a
2030b57cec5SDimitry Andric// 32-bit register.
2040b57cec5SDimitry Andricdef : Pat<(i64 (zext GR8:$src)),
2050b57cec5SDimitry Andric          (SUBREG_TO_REG (i64 0), (MOVZX32rr8 GR8:$src), sub_32bit)>;
2060b57cec5SDimitry Andricdef : Pat<(zextloadi64i8 addr:$src),
2070b57cec5SDimitry Andric          (SUBREG_TO_REG (i64 0), (MOVZX32rm8 addr:$src), sub_32bit)>;
2080b57cec5SDimitry Andric
2090b57cec5SDimitry Andricdef : Pat<(i64 (zext GR16:$src)),
2100b57cec5SDimitry Andric          (SUBREG_TO_REG (i64 0), (MOVZX32rr16 GR16:$src), sub_32bit)>;
2110b57cec5SDimitry Andricdef : Pat<(zextloadi64i16 addr:$src),
2120b57cec5SDimitry Andric          (SUBREG_TO_REG (i64 0), (MOVZX32rm16 addr:$src), sub_32bit)>;
2130b57cec5SDimitry Andric
2140b57cec5SDimitry Andric// The preferred way to do 32-bit-to-64-bit zero extension on x86-64 is to use a
2150b57cec5SDimitry Andric// SUBREG_TO_REG to utilize implicit zero-extension, however this isn't possible
2160b57cec5SDimitry Andric// when the 32-bit value is defined by a truncate or is copied from something
2170b57cec5SDimitry Andric// where the high bits aren't necessarily all zero. In such cases, we fall back
2180b57cec5SDimitry Andric// to these explicit zext instructions.
2190b57cec5SDimitry Andricdef : Pat<(i64 (zext GR32:$src)),
2200b57cec5SDimitry Andric          (SUBREG_TO_REG (i64 0), (MOV32rr GR32:$src), sub_32bit)>;
2210b57cec5SDimitry Andricdef : Pat<(i64 (zextloadi64i32 addr:$src)),
2220b57cec5SDimitry Andric          (SUBREG_TO_REG (i64 0), (MOV32rm addr:$src), sub_32bit)>;
223