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