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