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