1 | //===-- X86EncodingOptimization.cpp - X86 Encoding optimization -*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file contains the implementation of the X86 encoding optimization |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "X86EncodingOptimization.h" |
14 | #include "X86BaseInfo.h" |
15 | #include "llvm/MC/MCExpr.h" |
16 | #include "llvm/MC/MCInst.h" |
17 | #include "llvm/MC/MCInstrDesc.h" |
18 | #include "llvm/Support/Casting.h" |
19 | |
20 | using namespace llvm; |
21 | |
22 | bool X86::optimizeInstFromVEX3ToVEX2(MCInst &MI, const MCInstrDesc &Desc) { |
23 | unsigned OpIdx1, OpIdx2; |
24 | unsigned Opcode = MI.getOpcode(); |
25 | unsigned NewOpc = 0; |
26 | #define FROM_TO(FROM, TO, IDX1, IDX2) \ |
27 | case X86::FROM: \ |
28 | NewOpc = X86::TO; \ |
29 | OpIdx1 = IDX1; \ |
30 | OpIdx2 = IDX2; \ |
31 | break; |
32 | #define TO_REV(FROM) FROM_TO(FROM, FROM##_REV, 0, 1) |
33 | switch (Opcode) { |
34 | default: { |
35 | // If the instruction is a commutable arithmetic instruction we might be |
36 | // able to commute the operands to get a 2 byte VEX prefix. |
37 | uint64_t TSFlags = Desc.TSFlags; |
38 | if (!Desc.isCommutable() || (TSFlags & X86II::EncodingMask) != X86II::VEX || |
39 | (TSFlags & X86II::OpMapMask) != X86II::TB || |
40 | (TSFlags & X86II::FormMask) != X86II::MRMSrcReg || |
41 | (TSFlags & X86II::REX_W) || !(TSFlags & X86II::VEX_4V) || |
42 | MI.getNumOperands() != 3) |
43 | return false; |
44 | // These two are not truly commutable. |
45 | if (Opcode == X86::VMOVHLPSrr || Opcode == X86::VUNPCKHPDrr) |
46 | return false; |
47 | OpIdx1 = 1; |
48 | OpIdx2 = 2; |
49 | break; |
50 | } |
51 | case X86::VCMPPDrri: |
52 | case X86::VCMPPDYrri: |
53 | case X86::VCMPPSrri: |
54 | case X86::VCMPPSYrri: |
55 | case X86::VCMPSDrri: |
56 | case X86::VCMPSSrri: { |
57 | switch (MI.getOperand(i: 3).getImm() & 0x7) { |
58 | default: |
59 | return false; |
60 | case 0x00: // EQUAL |
61 | case 0x03: // UNORDERED |
62 | case 0x04: // NOT EQUAL |
63 | case 0x07: // ORDERED |
64 | OpIdx1 = 1; |
65 | OpIdx2 = 2; |
66 | break; |
67 | } |
68 | break; |
69 | } |
70 | // Commute operands to get a smaller encoding by using VEX.R instead of |
71 | // VEX.B if one of the registers is extended, but other isn't. |
72 | FROM_TO(VMOVZPQILo2PQIrr, VMOVPQI2QIrr, 0, 1) |
73 | TO_REV(VMOVAPDrr) |
74 | TO_REV(VMOVAPDYrr) |
75 | TO_REV(VMOVAPSrr) |
76 | TO_REV(VMOVAPSYrr) |
77 | TO_REV(VMOVDQArr) |
78 | TO_REV(VMOVDQAYrr) |
79 | TO_REV(VMOVDQUrr) |
80 | TO_REV(VMOVDQUYrr) |
81 | TO_REV(VMOVUPDrr) |
82 | TO_REV(VMOVUPDYrr) |
83 | TO_REV(VMOVUPSrr) |
84 | TO_REV(VMOVUPSYrr) |
85 | #undef TO_REV |
86 | #define TO_REV(FROM) FROM_TO(FROM, FROM##_REV, 0, 2) |
87 | TO_REV(VMOVSDrr) |
88 | TO_REV(VMOVSSrr) |
89 | #undef TO_REV |
90 | #undef FROM_TO |
91 | } |
92 | if (X86II::isX86_64ExtendedReg(RegNo: MI.getOperand(i: OpIdx1).getReg()) || |
93 | !X86II::isX86_64ExtendedReg(RegNo: MI.getOperand(i: OpIdx2).getReg())) |
94 | return false; |
95 | if (NewOpc) |
96 | MI.setOpcode(NewOpc); |
97 | else |
98 | std::swap(a&: MI.getOperand(i: OpIdx1), b&: MI.getOperand(i: OpIdx2)); |
99 | return true; |
100 | } |
101 | |
102 | // NOTE: We may write this as an InstAlias if it's only used by AsmParser. See |
103 | // validateTargetOperandClass. |
104 | bool X86::optimizeShiftRotateWithImmediateOne(MCInst &MI) { |
105 | unsigned NewOpc; |
106 | #define TO_IMM1(FROM) \ |
107 | case X86::FROM##i: \ |
108 | NewOpc = X86::FROM##1; \ |
109 | break; \ |
110 | case X86::FROM##i_EVEX: \ |
111 | NewOpc = X86::FROM##1_EVEX; \ |
112 | break; \ |
113 | case X86::FROM##i_ND: \ |
114 | NewOpc = X86::FROM##1_ND; \ |
115 | break; |
116 | switch (MI.getOpcode()) { |
117 | default: |
118 | return false; |
119 | TO_IMM1(RCR8r) |
120 | TO_IMM1(RCR16r) |
121 | TO_IMM1(RCR32r) |
122 | TO_IMM1(RCR64r) |
123 | TO_IMM1(RCL8r) |
124 | TO_IMM1(RCL16r) |
125 | TO_IMM1(RCL32r) |
126 | TO_IMM1(RCL64r) |
127 | TO_IMM1(RCR8m) |
128 | TO_IMM1(RCR16m) |
129 | TO_IMM1(RCR32m) |
130 | TO_IMM1(RCR64m) |
131 | TO_IMM1(RCL8m) |
132 | TO_IMM1(RCL16m) |
133 | TO_IMM1(RCL32m) |
134 | TO_IMM1(RCL64m) |
135 | #undef TO_IMM1 |
136 | #define TO_IMM1(FROM) \ |
137 | case X86::FROM##i: \ |
138 | NewOpc = X86::FROM##1; \ |
139 | break; \ |
140 | case X86::FROM##i_EVEX: \ |
141 | NewOpc = X86::FROM##1_EVEX; \ |
142 | break; \ |
143 | case X86::FROM##i_NF: \ |
144 | NewOpc = X86::FROM##1_NF; \ |
145 | break; \ |
146 | case X86::FROM##i_ND: \ |
147 | NewOpc = X86::FROM##1_ND; \ |
148 | break; \ |
149 | case X86::FROM##i_NF_ND: \ |
150 | NewOpc = X86::FROM##1_NF_ND; \ |
151 | break; |
152 | TO_IMM1(ROR8r) |
153 | TO_IMM1(ROR16r) |
154 | TO_IMM1(ROR32r) |
155 | TO_IMM1(ROR64r) |
156 | TO_IMM1(ROL8r) |
157 | TO_IMM1(ROL16r) |
158 | TO_IMM1(ROL32r) |
159 | TO_IMM1(ROL64r) |
160 | TO_IMM1(SAR8r) |
161 | TO_IMM1(SAR16r) |
162 | TO_IMM1(SAR32r) |
163 | TO_IMM1(SAR64r) |
164 | TO_IMM1(SHR8r) |
165 | TO_IMM1(SHR16r) |
166 | TO_IMM1(SHR32r) |
167 | TO_IMM1(SHR64r) |
168 | TO_IMM1(SHL8r) |
169 | TO_IMM1(SHL16r) |
170 | TO_IMM1(SHL32r) |
171 | TO_IMM1(SHL64r) |
172 | TO_IMM1(ROR8m) |
173 | TO_IMM1(ROR16m) |
174 | TO_IMM1(ROR32m) |
175 | TO_IMM1(ROR64m) |
176 | TO_IMM1(ROL8m) |
177 | TO_IMM1(ROL16m) |
178 | TO_IMM1(ROL32m) |
179 | TO_IMM1(ROL64m) |
180 | TO_IMM1(SAR8m) |
181 | TO_IMM1(SAR16m) |
182 | TO_IMM1(SAR32m) |
183 | TO_IMM1(SAR64m) |
184 | TO_IMM1(SHR8m) |
185 | TO_IMM1(SHR16m) |
186 | TO_IMM1(SHR32m) |
187 | TO_IMM1(SHR64m) |
188 | TO_IMM1(SHL8m) |
189 | TO_IMM1(SHL16m) |
190 | TO_IMM1(SHL32m) |
191 | TO_IMM1(SHL64m) |
192 | #undef TO_IMM1 |
193 | } |
194 | MCOperand &LastOp = MI.getOperand(i: MI.getNumOperands() - 1); |
195 | if (!LastOp.isImm() || LastOp.getImm() != 1) |
196 | return false; |
197 | MI.setOpcode(NewOpc); |
198 | MI.erase(I: &LastOp); |
199 | return true; |
200 | } |
201 | |
202 | bool X86::optimizeVPCMPWithImmediateOneOrSix(MCInst &MI) { |
203 | unsigned Opc1; |
204 | unsigned Opc2; |
205 | #define FROM_TO(FROM, TO1, TO2) \ |
206 | case X86::FROM: \ |
207 | Opc1 = X86::TO1; \ |
208 | Opc2 = X86::TO2; \ |
209 | break; |
210 | switch (MI.getOpcode()) { |
211 | default: |
212 | return false; |
213 | FROM_TO(VPCMPBZ128rmi, VPCMPEQBZ128rm, VPCMPGTBZ128rm) |
214 | FROM_TO(VPCMPBZ128rmik, VPCMPEQBZ128rmk, VPCMPGTBZ128rmk) |
215 | FROM_TO(VPCMPBZ128rri, VPCMPEQBZ128rr, VPCMPGTBZ128rr) |
216 | FROM_TO(VPCMPBZ128rrik, VPCMPEQBZ128rrk, VPCMPGTBZ128rrk) |
217 | FROM_TO(VPCMPBZ256rmi, VPCMPEQBZ256rm, VPCMPGTBZ256rm) |
218 | FROM_TO(VPCMPBZ256rmik, VPCMPEQBZ256rmk, VPCMPGTBZ256rmk) |
219 | FROM_TO(VPCMPBZ256rri, VPCMPEQBZ256rr, VPCMPGTBZ256rr) |
220 | FROM_TO(VPCMPBZ256rrik, VPCMPEQBZ256rrk, VPCMPGTBZ256rrk) |
221 | FROM_TO(VPCMPBZrmi, VPCMPEQBZrm, VPCMPGTBZrm) |
222 | FROM_TO(VPCMPBZrmik, VPCMPEQBZrmk, VPCMPGTBZrmk) |
223 | FROM_TO(VPCMPBZrri, VPCMPEQBZrr, VPCMPGTBZrr) |
224 | FROM_TO(VPCMPBZrrik, VPCMPEQBZrrk, VPCMPGTBZrrk) |
225 | FROM_TO(VPCMPDZ128rmi, VPCMPEQDZ128rm, VPCMPGTDZ128rm) |
226 | FROM_TO(VPCMPDZ128rmib, VPCMPEQDZ128rmb, VPCMPGTDZ128rmb) |
227 | FROM_TO(VPCMPDZ128rmibk, VPCMPEQDZ128rmbk, VPCMPGTDZ128rmbk) |
228 | FROM_TO(VPCMPDZ128rmik, VPCMPEQDZ128rmk, VPCMPGTDZ128rmk) |
229 | FROM_TO(VPCMPDZ128rri, VPCMPEQDZ128rr, VPCMPGTDZ128rr) |
230 | FROM_TO(VPCMPDZ128rrik, VPCMPEQDZ128rrk, VPCMPGTDZ128rrk) |
231 | FROM_TO(VPCMPDZ256rmi, VPCMPEQDZ256rm, VPCMPGTDZ256rm) |
232 | FROM_TO(VPCMPDZ256rmib, VPCMPEQDZ256rmb, VPCMPGTDZ256rmb) |
233 | FROM_TO(VPCMPDZ256rmibk, VPCMPEQDZ256rmbk, VPCMPGTDZ256rmbk) |
234 | FROM_TO(VPCMPDZ256rmik, VPCMPEQDZ256rmk, VPCMPGTDZ256rmk) |
235 | FROM_TO(VPCMPDZ256rri, VPCMPEQDZ256rr, VPCMPGTDZ256rr) |
236 | FROM_TO(VPCMPDZ256rrik, VPCMPEQDZ256rrk, VPCMPGTDZ256rrk) |
237 | FROM_TO(VPCMPDZrmi, VPCMPEQDZrm, VPCMPGTDZrm) |
238 | FROM_TO(VPCMPDZrmib, VPCMPEQDZrmb, VPCMPGTDZrmb) |
239 | FROM_TO(VPCMPDZrmibk, VPCMPEQDZrmbk, VPCMPGTDZrmbk) |
240 | FROM_TO(VPCMPDZrmik, VPCMPEQDZrmk, VPCMPGTDZrmk) |
241 | FROM_TO(VPCMPDZrri, VPCMPEQDZrr, VPCMPGTDZrr) |
242 | FROM_TO(VPCMPDZrrik, VPCMPEQDZrrk, VPCMPGTDZrrk) |
243 | FROM_TO(VPCMPQZ128rmi, VPCMPEQQZ128rm, VPCMPGTQZ128rm) |
244 | FROM_TO(VPCMPQZ128rmib, VPCMPEQQZ128rmb, VPCMPGTQZ128rmb) |
245 | FROM_TO(VPCMPQZ128rmibk, VPCMPEQQZ128rmbk, VPCMPGTQZ128rmbk) |
246 | FROM_TO(VPCMPQZ128rmik, VPCMPEQQZ128rmk, VPCMPGTQZ128rmk) |
247 | FROM_TO(VPCMPQZ128rri, VPCMPEQQZ128rr, VPCMPGTQZ128rr) |
248 | FROM_TO(VPCMPQZ128rrik, VPCMPEQQZ128rrk, VPCMPGTQZ128rrk) |
249 | FROM_TO(VPCMPQZ256rmi, VPCMPEQQZ256rm, VPCMPGTQZ256rm) |
250 | FROM_TO(VPCMPQZ256rmib, VPCMPEQQZ256rmb, VPCMPGTQZ256rmb) |
251 | FROM_TO(VPCMPQZ256rmibk, VPCMPEQQZ256rmbk, VPCMPGTQZ256rmbk) |
252 | FROM_TO(VPCMPQZ256rmik, VPCMPEQQZ256rmk, VPCMPGTQZ256rmk) |
253 | FROM_TO(VPCMPQZ256rri, VPCMPEQQZ256rr, VPCMPGTQZ256rr) |
254 | FROM_TO(VPCMPQZ256rrik, VPCMPEQQZ256rrk, VPCMPGTQZ256rrk) |
255 | FROM_TO(VPCMPQZrmi, VPCMPEQQZrm, VPCMPGTQZrm) |
256 | FROM_TO(VPCMPQZrmib, VPCMPEQQZrmb, VPCMPGTQZrmb) |
257 | FROM_TO(VPCMPQZrmibk, VPCMPEQQZrmbk, VPCMPGTQZrmbk) |
258 | FROM_TO(VPCMPQZrmik, VPCMPEQQZrmk, VPCMPGTQZrmk) |
259 | FROM_TO(VPCMPQZrri, VPCMPEQQZrr, VPCMPGTQZrr) |
260 | FROM_TO(VPCMPQZrrik, VPCMPEQQZrrk, VPCMPGTQZrrk) |
261 | FROM_TO(VPCMPWZ128rmi, VPCMPEQWZ128rm, VPCMPGTWZ128rm) |
262 | FROM_TO(VPCMPWZ128rmik, VPCMPEQWZ128rmk, VPCMPGTWZ128rmk) |
263 | FROM_TO(VPCMPWZ128rri, VPCMPEQWZ128rr, VPCMPGTWZ128rr) |
264 | FROM_TO(VPCMPWZ128rrik, VPCMPEQWZ128rrk, VPCMPGTWZ128rrk) |
265 | FROM_TO(VPCMPWZ256rmi, VPCMPEQWZ256rm, VPCMPGTWZ256rm) |
266 | FROM_TO(VPCMPWZ256rmik, VPCMPEQWZ256rmk, VPCMPGTWZ256rmk) |
267 | FROM_TO(VPCMPWZ256rri, VPCMPEQWZ256rr, VPCMPGTWZ256rr) |
268 | FROM_TO(VPCMPWZ256rrik, VPCMPEQWZ256rrk, VPCMPGTWZ256rrk) |
269 | FROM_TO(VPCMPWZrmi, VPCMPEQWZrm, VPCMPGTWZrm) |
270 | FROM_TO(VPCMPWZrmik, VPCMPEQWZrmk, VPCMPGTWZrmk) |
271 | FROM_TO(VPCMPWZrri, VPCMPEQWZrr, VPCMPGTWZrr) |
272 | FROM_TO(VPCMPWZrrik, VPCMPEQWZrrk, VPCMPGTWZrrk) |
273 | #undef FROM_TO |
274 | } |
275 | MCOperand &LastOp = MI.getOperand(i: MI.getNumOperands() - 1); |
276 | int64_t Imm = LastOp.getImm(); |
277 | unsigned NewOpc; |
278 | if (Imm == 0) |
279 | NewOpc = Opc1; |
280 | else if(Imm == 6) |
281 | NewOpc = Opc2; |
282 | else |
283 | return false; |
284 | MI.setOpcode(NewOpc); |
285 | MI.erase(I: &LastOp); |
286 | return true; |
287 | } |
288 | |
289 | bool X86::optimizeMOVSX(MCInst &MI) { |
290 | unsigned NewOpc; |
291 | #define FROM_TO(FROM, TO, R0, R1) \ |
292 | case X86::FROM: \ |
293 | if (MI.getOperand(0).getReg() != X86::R0 || \ |
294 | MI.getOperand(1).getReg() != X86::R1) \ |
295 | return false; \ |
296 | NewOpc = X86::TO; \ |
297 | break; |
298 | switch (MI.getOpcode()) { |
299 | default: |
300 | return false; |
301 | FROM_TO(MOVSX16rr8, CBW, AX, AL) // movsbw %al, %ax --> cbtw |
302 | FROM_TO(MOVSX32rr16, CWDE, EAX, AX) // movswl %ax, %eax --> cwtl |
303 | FROM_TO(MOVSX64rr32, CDQE, RAX, EAX) // movslq %eax, %rax --> cltq |
304 | #undef FROM_TO |
305 | } |
306 | MI.clear(); |
307 | MI.setOpcode(NewOpc); |
308 | return true; |
309 | } |
310 | |
311 | bool X86::optimizeINCDEC(MCInst &MI, bool In64BitMode) { |
312 | if (In64BitMode) |
313 | return false; |
314 | unsigned NewOpc; |
315 | // If we aren't in 64-bit mode we can use the 1-byte inc/dec instructions. |
316 | #define FROM_TO(FROM, TO) \ |
317 | case X86::FROM: \ |
318 | NewOpc = X86::TO; \ |
319 | break; |
320 | switch (MI.getOpcode()) { |
321 | default: |
322 | return false; |
323 | FROM_TO(DEC16r, DEC16r_alt) |
324 | FROM_TO(DEC32r, DEC32r_alt) |
325 | FROM_TO(INC16r, INC16r_alt) |
326 | FROM_TO(INC32r, INC32r_alt) |
327 | } |
328 | MI.setOpcode(NewOpc); |
329 | return true; |
330 | } |
331 | |
332 | static bool isARegister(unsigned Reg) { |
333 | return Reg == X86::AL || Reg == X86::AX || Reg == X86::EAX || Reg == X86::RAX; |
334 | } |
335 | |
336 | /// Simplify things like MOV32rm to MOV32o32a. |
337 | bool X86::optimizeMOV(MCInst &MI, bool In64BitMode) { |
338 | // Don't make these simplifications in 64-bit mode; other assemblers don't |
339 | // perform them because they make the code larger. |
340 | if (In64BitMode) |
341 | return false; |
342 | unsigned NewOpc; |
343 | // We don't currently select the correct instruction form for instructions |
344 | // which have a short %eax, etc. form. Handle this by custom lowering, for |
345 | // now. |
346 | // |
347 | // Note, we are currently not handling the following instructions: |
348 | // MOV64ao8, MOV64o8a |
349 | // XCHG16ar, XCHG32ar, XCHG64ar |
350 | switch (MI.getOpcode()) { |
351 | default: |
352 | return false; |
353 | FROM_TO(MOV8mr_NOREX, MOV8o32a) |
354 | FROM_TO(MOV8mr, MOV8o32a) |
355 | FROM_TO(MOV8rm_NOREX, MOV8ao32) |
356 | FROM_TO(MOV8rm, MOV8ao32) |
357 | FROM_TO(MOV16mr, MOV16o32a) |
358 | FROM_TO(MOV16rm, MOV16ao32) |
359 | FROM_TO(MOV32mr, MOV32o32a) |
360 | FROM_TO(MOV32rm, MOV32ao32) |
361 | } |
362 | bool IsStore = MI.getOperand(i: 0).isReg() && MI.getOperand(i: 1).isReg(); |
363 | unsigned AddrBase = IsStore; |
364 | unsigned RegOp = IsStore ? 0 : 5; |
365 | unsigned AddrOp = AddrBase + 3; |
366 | // Check whether the destination register can be fixed. |
367 | unsigned Reg = MI.getOperand(i: RegOp).getReg(); |
368 | if (!isARegister(Reg)) |
369 | return false; |
370 | // Check whether this is an absolute address. |
371 | // FIXME: We know TLVP symbol refs aren't, but there should be a better way |
372 | // to do this here. |
373 | bool Absolute = true; |
374 | if (MI.getOperand(i: AddrOp).isExpr()) { |
375 | const MCExpr *MCE = MI.getOperand(i: AddrOp).getExpr(); |
376 | if (const MCSymbolRefExpr *SRE = dyn_cast<MCSymbolRefExpr>(Val: MCE)) |
377 | if (SRE->getKind() == MCSymbolRefExpr::VK_TLVP) |
378 | Absolute = false; |
379 | } |
380 | if (Absolute && (MI.getOperand(i: AddrBase + X86::AddrBaseReg).getReg() != 0 || |
381 | MI.getOperand(i: AddrBase + X86::AddrScaleAmt).getImm() != 1 || |
382 | MI.getOperand(i: AddrBase + X86::AddrIndexReg).getReg() != 0)) |
383 | return false; |
384 | // If so, rewrite the instruction. |
385 | MCOperand Saved = MI.getOperand(i: AddrOp); |
386 | MCOperand Seg = MI.getOperand(i: AddrBase + X86::AddrSegmentReg); |
387 | MI.clear(); |
388 | MI.setOpcode(NewOpc); |
389 | MI.addOperand(Op: Saved); |
390 | MI.addOperand(Op: Seg); |
391 | return true; |
392 | } |
393 | |
394 | /// Simplify FOO $imm, %{al,ax,eax,rax} to FOO $imm, for instruction with |
395 | /// a short fixed-register form. |
396 | static bool optimizeToFixedRegisterForm(MCInst &MI) { |
397 | unsigned NewOpc; |
398 | switch (MI.getOpcode()) { |
399 | default: |
400 | return false; |
401 | FROM_TO(ADC8ri, ADC8i8) |
402 | FROM_TO(ADC16ri, ADC16i16) |
403 | FROM_TO(ADC32ri, ADC32i32) |
404 | FROM_TO(ADC64ri32, ADC64i32) |
405 | FROM_TO(ADD8ri, ADD8i8) |
406 | FROM_TO(ADD16ri, ADD16i16) |
407 | FROM_TO(ADD32ri, ADD32i32) |
408 | FROM_TO(ADD64ri32, ADD64i32) |
409 | FROM_TO(AND8ri, AND8i8) |
410 | FROM_TO(AND16ri, AND16i16) |
411 | FROM_TO(AND32ri, AND32i32) |
412 | FROM_TO(AND64ri32, AND64i32) |
413 | FROM_TO(CMP8ri, CMP8i8) |
414 | FROM_TO(CMP16ri, CMP16i16) |
415 | FROM_TO(CMP32ri, CMP32i32) |
416 | FROM_TO(CMP64ri32, CMP64i32) |
417 | FROM_TO(OR8ri, OR8i8) |
418 | FROM_TO(OR16ri, OR16i16) |
419 | FROM_TO(OR32ri, OR32i32) |
420 | FROM_TO(OR64ri32, OR64i32) |
421 | FROM_TO(SBB8ri, SBB8i8) |
422 | FROM_TO(SBB16ri, SBB16i16) |
423 | FROM_TO(SBB32ri, SBB32i32) |
424 | FROM_TO(SBB64ri32, SBB64i32) |
425 | FROM_TO(SUB8ri, SUB8i8) |
426 | FROM_TO(SUB16ri, SUB16i16) |
427 | FROM_TO(SUB32ri, SUB32i32) |
428 | FROM_TO(SUB64ri32, SUB64i32) |
429 | FROM_TO(TEST8ri, TEST8i8) |
430 | FROM_TO(TEST16ri, TEST16i16) |
431 | FROM_TO(TEST32ri, TEST32i32) |
432 | FROM_TO(TEST64ri32, TEST64i32) |
433 | FROM_TO(XOR8ri, XOR8i8) |
434 | FROM_TO(XOR16ri, XOR16i16) |
435 | FROM_TO(XOR32ri, XOR32i32) |
436 | FROM_TO(XOR64ri32, XOR64i32) |
437 | } |
438 | // Check whether the destination register can be fixed. |
439 | unsigned Reg = MI.getOperand(i: 0).getReg(); |
440 | if (!isARegister(Reg)) |
441 | return false; |
442 | |
443 | // If so, rewrite the instruction. |
444 | MCOperand Saved = MI.getOperand(i: MI.getNumOperands() - 1); |
445 | MI.clear(); |
446 | MI.setOpcode(NewOpc); |
447 | MI.addOperand(Op: Saved); |
448 | return true; |
449 | } |
450 | |
451 | unsigned X86::getOpcodeForShortImmediateForm(unsigned Opcode) { |
452 | #define ENTRY(LONG, SHORT) \ |
453 | case X86::LONG: \ |
454 | return X86::SHORT; |
455 | switch (Opcode) { |
456 | default: |
457 | return Opcode; |
458 | #include "X86EncodingOptimizationForImmediate.def" |
459 | } |
460 | } |
461 | |
462 | unsigned X86::getOpcodeForLongImmediateForm(unsigned Opcode) { |
463 | #define ENTRY(LONG, SHORT) \ |
464 | case X86::SHORT: \ |
465 | return X86::LONG; |
466 | switch (Opcode) { |
467 | default: |
468 | return Opcode; |
469 | #include "X86EncodingOptimizationForImmediate.def" |
470 | } |
471 | } |
472 | |
473 | static bool optimizeToShortImmediateForm(MCInst &MI) { |
474 | unsigned NewOpc; |
475 | #define ENTRY(LONG, SHORT) \ |
476 | case X86::LONG: \ |
477 | NewOpc = X86::SHORT; \ |
478 | break; |
479 | switch (MI.getOpcode()) { |
480 | default: |
481 | return false; |
482 | #include "X86EncodingOptimizationForImmediate.def" |
483 | } |
484 | unsigned SkipOperands = X86::isCCMPCC(Opcode: MI.getOpcode()) ? 2 : 0; |
485 | MCOperand &LastOp = MI.getOperand(i: MI.getNumOperands() - 1 - SkipOperands); |
486 | if (LastOp.isExpr()) { |
487 | const MCSymbolRefExpr *SRE = dyn_cast<MCSymbolRefExpr>(Val: LastOp.getExpr()); |
488 | if (!SRE || SRE->getKind() != MCSymbolRefExpr::VK_X86_ABS8) |
489 | return false; |
490 | } else if (LastOp.isImm()) { |
491 | if (!isInt<8>(x: LastOp.getImm())) |
492 | return false; |
493 | } |
494 | MI.setOpcode(NewOpc); |
495 | return true; |
496 | } |
497 | |
498 | bool X86::optimizeToFixedRegisterOrShortImmediateForm(MCInst &MI) { |
499 | // We may optimize twice here. |
500 | bool ShortImm = optimizeToShortImmediateForm(MI); |
501 | bool FixedReg = optimizeToFixedRegisterForm(MI); |
502 | return ShortImm || FixedReg; |
503 | } |
504 | |