1//===-- X86InstrExtension.td - Sign and Zero Extensions ----*- tablegen -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file describes the sign and zero extension operations.
11//
12//===----------------------------------------------------------------------===//
13
14let hasSideEffects = 0 in {
15  let Defs = [AX], Uses = [AL] in // AX = signext(AL)
16  def CBW : I<0x98, RawFrm, (outs), (ins),
17              "{cbtw|cbw}", []>, OpSize16, Sched<[WriteALU]>;
18  let Defs = [EAX], Uses = [AX] in // EAX = signext(AX)
19  def CWDE : I<0x98, RawFrm, (outs), (ins),
20              "{cwtl|cwde}", []>, OpSize32, Sched<[WriteALU]>;
21
22  let Defs = [AX,DX], Uses = [AX] in // DX:AX = signext(AX)
23  def CWD : I<0x99, RawFrm, (outs), (ins),
24              "{cwtd|cwd}", []>, OpSize16, Sched<[WriteALU]>;
25  let Defs = [EAX,EDX], Uses = [EAX] in // EDX:EAX = signext(EAX)
26  def CDQ : I<0x99, RawFrm, (outs), (ins),
27              "{cltd|cdq}", []>, OpSize32, Sched<[WriteALU]>;
28
29
30  let Defs = [RAX], Uses = [EAX] in // RAX = signext(EAX)
31  def CDQE : RI<0x98, RawFrm, (outs), (ins),
32               "{cltq|cdqe}", []>, Sched<[WriteALU]>;
33
34  let Defs = [RAX,RDX], Uses = [RAX] in // RDX:RAX = signext(RAX)
35  def CQO  : RI<0x99, RawFrm, (outs), (ins),
36                "{cqto|cqo}", []>, Sched<[WriteALU]>;
37}
38
39// Sign/Zero extenders
40let hasSideEffects = 0 in {
41def MOVSX16rr8 : I<0xBE, MRMSrcReg, (outs GR16:$dst), (ins GR8:$src),
42                   "movs{bw|x}\t{$src, $dst|$dst, $src}", []>,
43                   TB, OpSize16, Sched<[WriteALU]>;
44let mayLoad = 1 in
45def MOVSX16rm8 : I<0xBE, MRMSrcMem, (outs GR16:$dst), (ins i8mem:$src),
46                   "movs{bw|x}\t{$src, $dst|$dst, $src}", []>,
47                   TB, OpSize16, Sched<[WriteALULd]>;
48} // hasSideEffects = 0
49def MOVSX32rr8 : I<0xBE, MRMSrcReg, (outs GR32:$dst), (ins GR8:$src),
50                   "movs{bl|x}\t{$src, $dst|$dst, $src}",
51                   [(set GR32:$dst, (sext GR8:$src))]>, TB,
52                   OpSize32, Sched<[WriteALU]>;
53def MOVSX32rm8 : I<0xBE, MRMSrcMem, (outs GR32:$dst), (ins i8mem :$src),
54                   "movs{bl|x}\t{$src, $dst|$dst, $src}",
55                   [(set GR32:$dst, (sextloadi32i8 addr:$src))]>, TB,
56                   OpSize32, Sched<[WriteALULd]>;
57def MOVSX32rr16: I<0xBF, MRMSrcReg, (outs GR32:$dst), (ins GR16:$src),
58                   "movs{wl|x}\t{$src, $dst|$dst, $src}",
59                   [(set GR32:$dst, (sext GR16:$src))]>, TB,
60                   OpSize32, Sched<[WriteALU]>;
61def MOVSX32rm16: I<0xBF, MRMSrcMem, (outs GR32:$dst), (ins i16mem:$src),
62                   "movs{wl|x}\t{$src, $dst|$dst, $src}",
63                   [(set GR32:$dst, (sextloadi32i16 addr:$src))]>,
64                   OpSize32, TB, Sched<[WriteALULd]>;
65
66let hasSideEffects = 0 in {
67def MOVZX16rr8 : I<0xB6, MRMSrcReg, (outs GR16:$dst), (ins GR8:$src),
68                   "movz{bw|x}\t{$src, $dst|$dst, $src}", []>,
69                   TB, OpSize16, Sched<[WriteALU]>;
70let mayLoad = 1 in
71def MOVZX16rm8 : I<0xB6, MRMSrcMem, (outs GR16:$dst), (ins i8mem:$src),
72                   "movz{bw|x}\t{$src, $dst|$dst, $src}", []>,
73                   TB, OpSize16, Sched<[WriteALULd]>;
74} // hasSideEffects = 0
75def MOVZX32rr8 : I<0xB6, MRMSrcReg, (outs GR32:$dst), (ins GR8 :$src),
76                   "movz{bl|x}\t{$src, $dst|$dst, $src}",
77                   [(set GR32:$dst, (zext GR8:$src))]>, TB,
78                   OpSize32, Sched<[WriteALU]>;
79def MOVZX32rm8 : I<0xB6, MRMSrcMem, (outs GR32:$dst), (ins i8mem :$src),
80                   "movz{bl|x}\t{$src, $dst|$dst, $src}",
81                   [(set GR32:$dst, (zextloadi32i8 addr:$src))]>, TB,
82                   OpSize32, Sched<[WriteALULd]>;
83def MOVZX32rr16: I<0xB7, MRMSrcReg, (outs GR32:$dst), (ins GR16:$src),
84                   "movz{wl|x}\t{$src, $dst|$dst, $src}",
85                   [(set GR32:$dst, (zext GR16:$src))]>, TB,
86                   OpSize32, Sched<[WriteALU]>;
87def MOVZX32rm16: I<0xB7, MRMSrcMem, (outs GR32:$dst), (ins i16mem:$src),
88                   "movz{wl|x}\t{$src, $dst|$dst, $src}",
89                   [(set GR32:$dst, (zextloadi32i16 addr:$src))]>,
90                   TB, OpSize32, Sched<[WriteALULd]>;
91
92// These instructions exist as a consequence of operand size prefix having
93// control of the destination size, but not the input size. Only support them
94// for the disassembler.
95let isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0 in {
96def MOVSX16rr16: I<0xBF, MRMSrcReg, (outs GR16:$dst), (ins GR16:$src),
97                   "movs{ww|x}\t{$src, $dst|$dst, $src}",
98                   []>, TB, OpSize16, Sched<[WriteALU]>, NotMemoryFoldable;
99def MOVZX16rr16: I<0xB7, MRMSrcReg, (outs GR16:$dst), (ins GR16:$src),
100                   "movz{ww|x}\t{$src, $dst|$dst, $src}",
101                   []>, TB, OpSize16, Sched<[WriteALU]>, NotMemoryFoldable;
102let mayLoad = 1 in {
103def MOVSX16rm16: I<0xBF, MRMSrcMem, (outs GR16:$dst), (ins i16mem:$src),
104                   "movs{ww|x}\t{$src, $dst|$dst, $src}",
105                   []>, OpSize16, TB, Sched<[WriteALULd]>, NotMemoryFoldable;
106def MOVZX16rm16: I<0xB7, MRMSrcMem, (outs GR16:$dst), (ins i16mem:$src),
107                   "movz{ww|x}\t{$src, $dst|$dst, $src}",
108                   []>, TB, OpSize16, Sched<[WriteALULd]>, NotMemoryFoldable;
109} // mayLoad = 1
110} // isCodeGenOnly = 1, ForceDisassemble = 1, hasSideEffects = 0
111
112// These are the same as the regular MOVZX32rr8 and MOVZX32rm8
113// except that they use GR32_NOREX for the output operand register class
114// instead of GR32. This allows them to operate on h registers on x86-64.
115let hasSideEffects = 0, isCodeGenOnly = 1 in {
116def MOVZX32rr8_NOREX : I<0xB6, MRMSrcReg,
117                         (outs GR32_NOREX:$dst), (ins GR8_NOREX:$src),
118                         "movz{bl|x}\t{$src, $dst|$dst, $src}",
119                         []>, TB, OpSize32, Sched<[WriteALU]>;
120let mayLoad = 1 in
121def MOVZX32rm8_NOREX : I<0xB6, MRMSrcMem,
122                         (outs GR32_NOREX:$dst), (ins i8mem_NOREX:$src),
123                         "movz{bl|x}\t{$src, $dst|$dst, $src}",
124                         []>, TB, OpSize32, Sched<[WriteALULd]>;
125
126def MOVSX32rr8_NOREX : I<0xBE, MRMSrcReg,
127                         (outs GR32_NOREX:$dst), (ins GR8_NOREX:$src),
128                         "movs{bl|x}\t{$src, $dst|$dst, $src}",
129                         []>, TB, OpSize32, Sched<[WriteALU]>;
130let mayLoad = 1 in
131def MOVSX32rm8_NOREX : I<0xBE, MRMSrcMem,
132                         (outs GR32_NOREX:$dst), (ins i8mem_NOREX:$src),
133                         "movs{bl|x}\t{$src, $dst|$dst, $src}",
134                         []>, TB, OpSize32, Sched<[WriteALULd]>;
135}
136
137// MOVSX64rr8 always has a REX prefix and it has an 8-bit register
138// operand, which makes it a rare instruction with an 8-bit register
139// operand that can never access an h register. If support for h registers
140// were generalized, this would require a special register class.
141def MOVSX64rr8 : RI<0xBE, MRMSrcReg, (outs GR64:$dst), (ins GR8 :$src),
142                    "movs{bq|x}\t{$src, $dst|$dst, $src}",
143                    [(set GR64:$dst, (sext GR8:$src))]>, TB,
144                    Sched<[WriteALU]>;
145def MOVSX64rm8 : RI<0xBE, MRMSrcMem, (outs GR64:$dst), (ins i8mem :$src),
146                    "movs{bq|x}\t{$src, $dst|$dst, $src}",
147                    [(set GR64:$dst, (sextloadi64i8 addr:$src))]>,
148                    TB, Sched<[WriteALULd]>;
149def MOVSX64rr16: RI<0xBF, MRMSrcReg, (outs GR64:$dst), (ins GR16:$src),
150                    "movs{wq|x}\t{$src, $dst|$dst, $src}",
151                    [(set GR64:$dst, (sext GR16:$src))]>, TB,
152                    Sched<[WriteALU]>;
153def MOVSX64rm16: RI<0xBF, MRMSrcMem, (outs GR64:$dst), (ins i16mem:$src),
154                    "movs{wq|x}\t{$src, $dst|$dst, $src}",
155                    [(set GR64:$dst, (sextloadi64i16 addr:$src))]>,
156                    TB, Sched<[WriteALULd]>;
157def MOVSX64rr32: RI<0x63, MRMSrcReg, (outs GR64:$dst), (ins GR32:$src),
158                    "movs{lq|xd}\t{$src, $dst|$dst, $src}",
159                    [(set GR64:$dst, (sext GR32:$src))]>,
160                    Sched<[WriteALU]>, Requires<[In64BitMode]>;
161def MOVSX64rm32: RI<0x63, MRMSrcMem, (outs GR64:$dst), (ins i32mem:$src),
162                    "movs{lq|xd}\t{$src, $dst|$dst, $src}",
163                    [(set GR64:$dst, (sextloadi64i32 addr:$src))]>,
164                    Sched<[WriteALULd]>, Requires<[In64BitMode]>;
165
166// movzbq and movzwq encodings for the disassembler
167let hasSideEffects = 0 in {
168def MOVZX64rr8 : RI<0xB6, MRMSrcReg, (outs GR64:$dst), (ins GR8:$src),
169                     "movz{bq|x}\t{$src, $dst|$dst, $src}", []>,
170                     TB, Sched<[WriteALU]>;
171let mayLoad = 1 in
172def MOVZX64rm8 : RI<0xB6, MRMSrcMem, (outs GR64:$dst), (ins i8mem:$src),
173                     "movz{bq|x}\t{$src, $dst|$dst, $src}", []>,
174                     TB, Sched<[WriteALULd]>;
175def MOVZX64rr16 : RI<0xB7, MRMSrcReg, (outs GR64:$dst), (ins GR16:$src),
176                     "movz{wq|x}\t{$src, $dst|$dst, $src}", []>,
177                     TB, Sched<[WriteALU]>;
178let mayLoad = 1 in
179def MOVZX64rm16 : RI<0xB7, MRMSrcMem, (outs GR64:$dst), (ins i16mem:$src),
180                     "movz{wq|x}\t{$src, $dst|$dst, $src}", []>,
181                     TB, Sched<[WriteALULd]>;
182}
183
184// 64-bit zero-extension patterns use SUBREG_TO_REG and an operation writing a
185// 32-bit register.
186def : Pat<(i64 (zext GR8:$src)),
187          (SUBREG_TO_REG (i64 0), (MOVZX32rr8 GR8:$src), sub_32bit)>;
188def : Pat<(zextloadi64i8 addr:$src),
189          (SUBREG_TO_REG (i64 0), (MOVZX32rm8 addr:$src), sub_32bit)>;
190
191def : Pat<(i64 (zext GR16:$src)),
192          (SUBREG_TO_REG (i64 0), (MOVZX32rr16 GR16:$src), sub_32bit)>;
193def : Pat<(zextloadi64i16 addr:$src),
194          (SUBREG_TO_REG (i64 0), (MOVZX32rm16 addr:$src), sub_32bit)>;
195
196// The preferred way to do 32-bit-to-64-bit zero extension on x86-64 is to use a
197// SUBREG_TO_REG to utilize implicit zero-extension, however this isn't possible
198// when the 32-bit value is defined by a truncate or is copied from something
199// where the high bits aren't necessarily all zero. In such cases, we fall back
200// to these explicit zext instructions.
201def : Pat<(i64 (zext GR32:$src)),
202          (SUBREG_TO_REG (i64 0), (MOV32rr GR32:$src), sub_32bit)>;
203def : Pat<(i64 (zextloadi64i32 addr:$src)),
204          (SUBREG_TO_REG (i64 0), (MOV32rm addr:$src), sub_32bit)>;
205