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