xref: /freebsd/contrib/llvm-project/llvm/lib/Target/X86/MCTargetDesc/X86EncodingOptimization.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
106c3fb27SDimitry Andric //===-- X86EncodingOptimization.cpp - X86 Encoding optimization -*- C++ -*-===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric //
906c3fb27SDimitry Andric // This file contains the implementation of the X86 encoding optimization
1006c3fb27SDimitry Andric //
1106c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
1206c3fb27SDimitry Andric 
1306c3fb27SDimitry Andric #include "X86EncodingOptimization.h"
1406c3fb27SDimitry Andric #include "X86BaseInfo.h"
1506c3fb27SDimitry Andric #include "llvm/MC/MCExpr.h"
1606c3fb27SDimitry Andric #include "llvm/MC/MCInst.h"
1706c3fb27SDimitry Andric #include "llvm/MC/MCInstrDesc.h"
1806c3fb27SDimitry Andric #include "llvm/Support/Casting.h"
1906c3fb27SDimitry Andric 
2006c3fb27SDimitry Andric using namespace llvm;
2106c3fb27SDimitry Andric 
optimizeInstFromVEX3ToVEX2(MCInst & MI,const MCInstrDesc & Desc)2206c3fb27SDimitry Andric bool X86::optimizeInstFromVEX3ToVEX2(MCInst &MI, const MCInstrDesc &Desc) {
2306c3fb27SDimitry Andric   unsigned OpIdx1, OpIdx2;
2406c3fb27SDimitry Andric   unsigned Opcode = MI.getOpcode();
2506c3fb27SDimitry Andric   unsigned NewOpc = 0;
2606c3fb27SDimitry Andric #define FROM_TO(FROM, TO, IDX1, IDX2)                                          \
2706c3fb27SDimitry Andric   case X86::FROM:                                                              \
2806c3fb27SDimitry Andric     NewOpc = X86::TO;                                                          \
2906c3fb27SDimitry Andric     OpIdx1 = IDX1;                                                             \
3006c3fb27SDimitry Andric     OpIdx2 = IDX2;                                                             \
3106c3fb27SDimitry Andric     break;
3206c3fb27SDimitry Andric #define TO_REV(FROM) FROM_TO(FROM, FROM##_REV, 0, 1)
3306c3fb27SDimitry Andric   switch (Opcode) {
3406c3fb27SDimitry Andric   default: {
3506c3fb27SDimitry Andric     // If the instruction is a commutable arithmetic instruction we might be
3606c3fb27SDimitry Andric     // able to commute the operands to get a 2 byte VEX prefix.
3706c3fb27SDimitry Andric     uint64_t TSFlags = Desc.TSFlags;
3806c3fb27SDimitry Andric     if (!Desc.isCommutable() || (TSFlags & X86II::EncodingMask) != X86II::VEX ||
3906c3fb27SDimitry Andric         (TSFlags & X86II::OpMapMask) != X86II::TB ||
4006c3fb27SDimitry Andric         (TSFlags & X86II::FormMask) != X86II::MRMSrcReg ||
4106c3fb27SDimitry Andric         (TSFlags & X86II::REX_W) || !(TSFlags & X86II::VEX_4V) ||
4206c3fb27SDimitry Andric         MI.getNumOperands() != 3)
4306c3fb27SDimitry Andric       return false;
4406c3fb27SDimitry Andric     // These two are not truly commutable.
4506c3fb27SDimitry Andric     if (Opcode == X86::VMOVHLPSrr || Opcode == X86::VUNPCKHPDrr)
4606c3fb27SDimitry Andric       return false;
4706c3fb27SDimitry Andric     OpIdx1 = 1;
4806c3fb27SDimitry Andric     OpIdx2 = 2;
4906c3fb27SDimitry Andric     break;
5006c3fb27SDimitry Andric   }
5106c3fb27SDimitry Andric   case X86::VCMPPDrri:
5206c3fb27SDimitry Andric   case X86::VCMPPDYrri:
5306c3fb27SDimitry Andric   case X86::VCMPPSrri:
5406c3fb27SDimitry Andric   case X86::VCMPPSYrri:
55*0fca6ea1SDimitry Andric   case X86::VCMPSDrri:
56*0fca6ea1SDimitry Andric   case X86::VCMPSSrri: {
5706c3fb27SDimitry Andric     switch (MI.getOperand(3).getImm() & 0x7) {
5806c3fb27SDimitry Andric     default:
5906c3fb27SDimitry Andric       return false;
6006c3fb27SDimitry Andric     case 0x00: // EQUAL
6106c3fb27SDimitry Andric     case 0x03: // UNORDERED
6206c3fb27SDimitry Andric     case 0x04: // NOT EQUAL
6306c3fb27SDimitry Andric     case 0x07: // ORDERED
6406c3fb27SDimitry Andric       OpIdx1 = 1;
6506c3fb27SDimitry Andric       OpIdx2 = 2;
6606c3fb27SDimitry Andric       break;
6706c3fb27SDimitry Andric     }
6806c3fb27SDimitry Andric     break;
6906c3fb27SDimitry Andric   }
7006c3fb27SDimitry Andric     // Commute operands to get a smaller encoding by using VEX.R instead of
7106c3fb27SDimitry Andric     // VEX.B if one of the registers is extended, but other isn't.
7206c3fb27SDimitry Andric     FROM_TO(VMOVZPQILo2PQIrr, VMOVPQI2QIrr, 0, 1)
7306c3fb27SDimitry Andric     TO_REV(VMOVAPDrr)
7406c3fb27SDimitry Andric     TO_REV(VMOVAPDYrr)
7506c3fb27SDimitry Andric     TO_REV(VMOVAPSrr)
7606c3fb27SDimitry Andric     TO_REV(VMOVAPSYrr)
7706c3fb27SDimitry Andric     TO_REV(VMOVDQArr)
7806c3fb27SDimitry Andric     TO_REV(VMOVDQAYrr)
7906c3fb27SDimitry Andric     TO_REV(VMOVDQUrr)
8006c3fb27SDimitry Andric     TO_REV(VMOVDQUYrr)
8106c3fb27SDimitry Andric     TO_REV(VMOVUPDrr)
8206c3fb27SDimitry Andric     TO_REV(VMOVUPDYrr)
8306c3fb27SDimitry Andric     TO_REV(VMOVUPSrr)
8406c3fb27SDimitry Andric     TO_REV(VMOVUPSYrr)
8506c3fb27SDimitry Andric #undef TO_REV
8606c3fb27SDimitry Andric #define TO_REV(FROM) FROM_TO(FROM, FROM##_REV, 0, 2)
8706c3fb27SDimitry Andric     TO_REV(VMOVSDrr)
8806c3fb27SDimitry Andric     TO_REV(VMOVSSrr)
8906c3fb27SDimitry Andric #undef TO_REV
9006c3fb27SDimitry Andric #undef FROM_TO
9106c3fb27SDimitry Andric   }
9206c3fb27SDimitry Andric   if (X86II::isX86_64ExtendedReg(MI.getOperand(OpIdx1).getReg()) ||
9306c3fb27SDimitry Andric       !X86II::isX86_64ExtendedReg(MI.getOperand(OpIdx2).getReg()))
9406c3fb27SDimitry Andric     return false;
9506c3fb27SDimitry Andric   if (NewOpc)
9606c3fb27SDimitry Andric     MI.setOpcode(NewOpc);
9706c3fb27SDimitry Andric   else
9806c3fb27SDimitry Andric     std::swap(MI.getOperand(OpIdx1), MI.getOperand(OpIdx2));
9906c3fb27SDimitry Andric   return true;
10006c3fb27SDimitry Andric }
10106c3fb27SDimitry Andric 
10206c3fb27SDimitry Andric // NOTE: We may write this as an InstAlias if it's only used by AsmParser. See
10306c3fb27SDimitry Andric // validateTargetOperandClass.
optimizeShiftRotateWithImmediateOne(MCInst & MI)10406c3fb27SDimitry Andric bool X86::optimizeShiftRotateWithImmediateOne(MCInst &MI) {
10506c3fb27SDimitry Andric   unsigned NewOpc;
10606c3fb27SDimitry Andric #define TO_IMM1(FROM)                                                          \
10706c3fb27SDimitry Andric   case X86::FROM##i:                                                           \
10806c3fb27SDimitry Andric     NewOpc = X86::FROM##1;                                                     \
109*0fca6ea1SDimitry Andric     break;                                                                     \
110*0fca6ea1SDimitry Andric   case X86::FROM##i_EVEX:                                                      \
111*0fca6ea1SDimitry Andric     NewOpc = X86::FROM##1_EVEX;                                                \
112*0fca6ea1SDimitry Andric     break;                                                                     \
113*0fca6ea1SDimitry Andric   case X86::FROM##i_ND:                                                        \
114*0fca6ea1SDimitry Andric     NewOpc = X86::FROM##1_ND;                                                  \
11506c3fb27SDimitry Andric     break;
11606c3fb27SDimitry Andric   switch (MI.getOpcode()) {
11706c3fb27SDimitry Andric   default:
11806c3fb27SDimitry Andric     return false;
11906c3fb27SDimitry Andric     TO_IMM1(RCR8r)
12006c3fb27SDimitry Andric     TO_IMM1(RCR16r)
12106c3fb27SDimitry Andric     TO_IMM1(RCR32r)
12206c3fb27SDimitry Andric     TO_IMM1(RCR64r)
12306c3fb27SDimitry Andric     TO_IMM1(RCL8r)
12406c3fb27SDimitry Andric     TO_IMM1(RCL16r)
12506c3fb27SDimitry Andric     TO_IMM1(RCL32r)
12606c3fb27SDimitry Andric     TO_IMM1(RCL64r)
127*0fca6ea1SDimitry Andric     TO_IMM1(RCR8m)
128*0fca6ea1SDimitry Andric     TO_IMM1(RCR16m)
129*0fca6ea1SDimitry Andric     TO_IMM1(RCR32m)
130*0fca6ea1SDimitry Andric     TO_IMM1(RCR64m)
131*0fca6ea1SDimitry Andric     TO_IMM1(RCL8m)
132*0fca6ea1SDimitry Andric     TO_IMM1(RCL16m)
133*0fca6ea1SDimitry Andric     TO_IMM1(RCL32m)
134*0fca6ea1SDimitry Andric     TO_IMM1(RCL64m)
135*0fca6ea1SDimitry Andric #undef TO_IMM1
136*0fca6ea1SDimitry Andric #define TO_IMM1(FROM)                                                          \
137*0fca6ea1SDimitry Andric   case X86::FROM##i:                                                           \
138*0fca6ea1SDimitry Andric     NewOpc = X86::FROM##1;                                                     \
139*0fca6ea1SDimitry Andric     break;                                                                     \
140*0fca6ea1SDimitry Andric   case X86::FROM##i_EVEX:                                                      \
141*0fca6ea1SDimitry Andric     NewOpc = X86::FROM##1_EVEX;                                                \
142*0fca6ea1SDimitry Andric     break;                                                                     \
143*0fca6ea1SDimitry Andric   case X86::FROM##i_NF:                                                        \
144*0fca6ea1SDimitry Andric     NewOpc = X86::FROM##1_NF;                                                  \
145*0fca6ea1SDimitry Andric     break;                                                                     \
146*0fca6ea1SDimitry Andric   case X86::FROM##i_ND:                                                        \
147*0fca6ea1SDimitry Andric     NewOpc = X86::FROM##1_ND;                                                  \
148*0fca6ea1SDimitry Andric     break;                                                                     \
149*0fca6ea1SDimitry Andric   case X86::FROM##i_NF_ND:                                                     \
150*0fca6ea1SDimitry Andric     NewOpc = X86::FROM##1_NF_ND;                                               \
151*0fca6ea1SDimitry Andric     break;
15206c3fb27SDimitry Andric     TO_IMM1(ROR8r)
15306c3fb27SDimitry Andric     TO_IMM1(ROR16r)
15406c3fb27SDimitry Andric     TO_IMM1(ROR32r)
15506c3fb27SDimitry Andric     TO_IMM1(ROR64r)
15606c3fb27SDimitry Andric     TO_IMM1(ROL8r)
15706c3fb27SDimitry Andric     TO_IMM1(ROL16r)
15806c3fb27SDimitry Andric     TO_IMM1(ROL32r)
15906c3fb27SDimitry Andric     TO_IMM1(ROL64r)
16006c3fb27SDimitry Andric     TO_IMM1(SAR8r)
16106c3fb27SDimitry Andric     TO_IMM1(SAR16r)
16206c3fb27SDimitry Andric     TO_IMM1(SAR32r)
16306c3fb27SDimitry Andric     TO_IMM1(SAR64r)
16406c3fb27SDimitry Andric     TO_IMM1(SHR8r)
16506c3fb27SDimitry Andric     TO_IMM1(SHR16r)
16606c3fb27SDimitry Andric     TO_IMM1(SHR32r)
16706c3fb27SDimitry Andric     TO_IMM1(SHR64r)
16806c3fb27SDimitry Andric     TO_IMM1(SHL8r)
16906c3fb27SDimitry Andric     TO_IMM1(SHL16r)
17006c3fb27SDimitry Andric     TO_IMM1(SHL32r)
17106c3fb27SDimitry Andric     TO_IMM1(SHL64r)
17206c3fb27SDimitry Andric     TO_IMM1(ROR8m)
17306c3fb27SDimitry Andric     TO_IMM1(ROR16m)
17406c3fb27SDimitry Andric     TO_IMM1(ROR32m)
17506c3fb27SDimitry Andric     TO_IMM1(ROR64m)
17606c3fb27SDimitry Andric     TO_IMM1(ROL8m)
17706c3fb27SDimitry Andric     TO_IMM1(ROL16m)
17806c3fb27SDimitry Andric     TO_IMM1(ROL32m)
17906c3fb27SDimitry Andric     TO_IMM1(ROL64m)
18006c3fb27SDimitry Andric     TO_IMM1(SAR8m)
18106c3fb27SDimitry Andric     TO_IMM1(SAR16m)
18206c3fb27SDimitry Andric     TO_IMM1(SAR32m)
18306c3fb27SDimitry Andric     TO_IMM1(SAR64m)
18406c3fb27SDimitry Andric     TO_IMM1(SHR8m)
18506c3fb27SDimitry Andric     TO_IMM1(SHR16m)
18606c3fb27SDimitry Andric     TO_IMM1(SHR32m)
18706c3fb27SDimitry Andric     TO_IMM1(SHR64m)
18806c3fb27SDimitry Andric     TO_IMM1(SHL8m)
18906c3fb27SDimitry Andric     TO_IMM1(SHL16m)
19006c3fb27SDimitry Andric     TO_IMM1(SHL32m)
19106c3fb27SDimitry Andric     TO_IMM1(SHL64m)
19206c3fb27SDimitry Andric #undef TO_IMM1
19306c3fb27SDimitry Andric   }
19406c3fb27SDimitry Andric   MCOperand &LastOp = MI.getOperand(MI.getNumOperands() - 1);
19506c3fb27SDimitry Andric   if (!LastOp.isImm() || LastOp.getImm() != 1)
19606c3fb27SDimitry Andric     return false;
19706c3fb27SDimitry Andric   MI.setOpcode(NewOpc);
19806c3fb27SDimitry Andric   MI.erase(&LastOp);
19906c3fb27SDimitry Andric   return true;
20006c3fb27SDimitry Andric }
20106c3fb27SDimitry Andric 
optimizeVPCMPWithImmediateOneOrSix(MCInst & MI)20206c3fb27SDimitry Andric bool X86::optimizeVPCMPWithImmediateOneOrSix(MCInst &MI) {
20306c3fb27SDimitry Andric   unsigned Opc1;
20406c3fb27SDimitry Andric   unsigned Opc2;
20506c3fb27SDimitry Andric #define FROM_TO(FROM, TO1, TO2)                                                \
20606c3fb27SDimitry Andric   case X86::FROM:                                                              \
20706c3fb27SDimitry Andric     Opc1 = X86::TO1;                                                           \
20806c3fb27SDimitry Andric     Opc2 = X86::TO2;                                                           \
20906c3fb27SDimitry Andric     break;
21006c3fb27SDimitry Andric   switch (MI.getOpcode()) {
21106c3fb27SDimitry Andric   default:
21206c3fb27SDimitry Andric     return false;
21306c3fb27SDimitry Andric     FROM_TO(VPCMPBZ128rmi, VPCMPEQBZ128rm, VPCMPGTBZ128rm)
21406c3fb27SDimitry Andric     FROM_TO(VPCMPBZ128rmik, VPCMPEQBZ128rmk, VPCMPGTBZ128rmk)
21506c3fb27SDimitry Andric     FROM_TO(VPCMPBZ128rri, VPCMPEQBZ128rr, VPCMPGTBZ128rr)
21606c3fb27SDimitry Andric     FROM_TO(VPCMPBZ128rrik, VPCMPEQBZ128rrk, VPCMPGTBZ128rrk)
21706c3fb27SDimitry Andric     FROM_TO(VPCMPBZ256rmi, VPCMPEQBZ256rm, VPCMPGTBZ256rm)
21806c3fb27SDimitry Andric     FROM_TO(VPCMPBZ256rmik, VPCMPEQBZ256rmk, VPCMPGTBZ256rmk)
21906c3fb27SDimitry Andric     FROM_TO(VPCMPBZ256rri, VPCMPEQBZ256rr, VPCMPGTBZ256rr)
22006c3fb27SDimitry Andric     FROM_TO(VPCMPBZ256rrik, VPCMPEQBZ256rrk, VPCMPGTBZ256rrk)
22106c3fb27SDimitry Andric     FROM_TO(VPCMPBZrmi, VPCMPEQBZrm, VPCMPGTBZrm)
22206c3fb27SDimitry Andric     FROM_TO(VPCMPBZrmik, VPCMPEQBZrmk, VPCMPGTBZrmk)
22306c3fb27SDimitry Andric     FROM_TO(VPCMPBZrri, VPCMPEQBZrr, VPCMPGTBZrr)
22406c3fb27SDimitry Andric     FROM_TO(VPCMPBZrrik, VPCMPEQBZrrk, VPCMPGTBZrrk)
22506c3fb27SDimitry Andric     FROM_TO(VPCMPDZ128rmi, VPCMPEQDZ128rm, VPCMPGTDZ128rm)
22606c3fb27SDimitry Andric     FROM_TO(VPCMPDZ128rmib, VPCMPEQDZ128rmb, VPCMPGTDZ128rmb)
22706c3fb27SDimitry Andric     FROM_TO(VPCMPDZ128rmibk, VPCMPEQDZ128rmbk, VPCMPGTDZ128rmbk)
22806c3fb27SDimitry Andric     FROM_TO(VPCMPDZ128rmik, VPCMPEQDZ128rmk, VPCMPGTDZ128rmk)
22906c3fb27SDimitry Andric     FROM_TO(VPCMPDZ128rri, VPCMPEQDZ128rr, VPCMPGTDZ128rr)
23006c3fb27SDimitry Andric     FROM_TO(VPCMPDZ128rrik, VPCMPEQDZ128rrk, VPCMPGTDZ128rrk)
23106c3fb27SDimitry Andric     FROM_TO(VPCMPDZ256rmi, VPCMPEQDZ256rm, VPCMPGTDZ256rm)
23206c3fb27SDimitry Andric     FROM_TO(VPCMPDZ256rmib, VPCMPEQDZ256rmb, VPCMPGTDZ256rmb)
23306c3fb27SDimitry Andric     FROM_TO(VPCMPDZ256rmibk, VPCMPEQDZ256rmbk, VPCMPGTDZ256rmbk)
23406c3fb27SDimitry Andric     FROM_TO(VPCMPDZ256rmik, VPCMPEQDZ256rmk, VPCMPGTDZ256rmk)
23506c3fb27SDimitry Andric     FROM_TO(VPCMPDZ256rri, VPCMPEQDZ256rr, VPCMPGTDZ256rr)
23606c3fb27SDimitry Andric     FROM_TO(VPCMPDZ256rrik, VPCMPEQDZ256rrk, VPCMPGTDZ256rrk)
23706c3fb27SDimitry Andric     FROM_TO(VPCMPDZrmi, VPCMPEQDZrm, VPCMPGTDZrm)
23806c3fb27SDimitry Andric     FROM_TO(VPCMPDZrmib, VPCMPEQDZrmb, VPCMPGTDZrmb)
23906c3fb27SDimitry Andric     FROM_TO(VPCMPDZrmibk, VPCMPEQDZrmbk, VPCMPGTDZrmbk)
24006c3fb27SDimitry Andric     FROM_TO(VPCMPDZrmik, VPCMPEQDZrmk, VPCMPGTDZrmk)
24106c3fb27SDimitry Andric     FROM_TO(VPCMPDZrri, VPCMPEQDZrr, VPCMPGTDZrr)
24206c3fb27SDimitry Andric     FROM_TO(VPCMPDZrrik, VPCMPEQDZrrk, VPCMPGTDZrrk)
24306c3fb27SDimitry Andric     FROM_TO(VPCMPQZ128rmi, VPCMPEQQZ128rm, VPCMPGTQZ128rm)
24406c3fb27SDimitry Andric     FROM_TO(VPCMPQZ128rmib, VPCMPEQQZ128rmb, VPCMPGTQZ128rmb)
24506c3fb27SDimitry Andric     FROM_TO(VPCMPQZ128rmibk, VPCMPEQQZ128rmbk, VPCMPGTQZ128rmbk)
24606c3fb27SDimitry Andric     FROM_TO(VPCMPQZ128rmik, VPCMPEQQZ128rmk, VPCMPGTQZ128rmk)
24706c3fb27SDimitry Andric     FROM_TO(VPCMPQZ128rri, VPCMPEQQZ128rr, VPCMPGTQZ128rr)
24806c3fb27SDimitry Andric     FROM_TO(VPCMPQZ128rrik, VPCMPEQQZ128rrk, VPCMPGTQZ128rrk)
24906c3fb27SDimitry Andric     FROM_TO(VPCMPQZ256rmi, VPCMPEQQZ256rm, VPCMPGTQZ256rm)
25006c3fb27SDimitry Andric     FROM_TO(VPCMPQZ256rmib, VPCMPEQQZ256rmb, VPCMPGTQZ256rmb)
25106c3fb27SDimitry Andric     FROM_TO(VPCMPQZ256rmibk, VPCMPEQQZ256rmbk, VPCMPGTQZ256rmbk)
25206c3fb27SDimitry Andric     FROM_TO(VPCMPQZ256rmik, VPCMPEQQZ256rmk, VPCMPGTQZ256rmk)
25306c3fb27SDimitry Andric     FROM_TO(VPCMPQZ256rri, VPCMPEQQZ256rr, VPCMPGTQZ256rr)
25406c3fb27SDimitry Andric     FROM_TO(VPCMPQZ256rrik, VPCMPEQQZ256rrk, VPCMPGTQZ256rrk)
25506c3fb27SDimitry Andric     FROM_TO(VPCMPQZrmi, VPCMPEQQZrm, VPCMPGTQZrm)
25606c3fb27SDimitry Andric     FROM_TO(VPCMPQZrmib, VPCMPEQQZrmb, VPCMPGTQZrmb)
25706c3fb27SDimitry Andric     FROM_TO(VPCMPQZrmibk, VPCMPEQQZrmbk, VPCMPGTQZrmbk)
25806c3fb27SDimitry Andric     FROM_TO(VPCMPQZrmik, VPCMPEQQZrmk, VPCMPGTQZrmk)
25906c3fb27SDimitry Andric     FROM_TO(VPCMPQZrri, VPCMPEQQZrr, VPCMPGTQZrr)
26006c3fb27SDimitry Andric     FROM_TO(VPCMPQZrrik, VPCMPEQQZrrk, VPCMPGTQZrrk)
26106c3fb27SDimitry Andric     FROM_TO(VPCMPWZ128rmi, VPCMPEQWZ128rm, VPCMPGTWZ128rm)
26206c3fb27SDimitry Andric     FROM_TO(VPCMPWZ128rmik, VPCMPEQWZ128rmk, VPCMPGTWZ128rmk)
26306c3fb27SDimitry Andric     FROM_TO(VPCMPWZ128rri, VPCMPEQWZ128rr, VPCMPGTWZ128rr)
26406c3fb27SDimitry Andric     FROM_TO(VPCMPWZ128rrik, VPCMPEQWZ128rrk, VPCMPGTWZ128rrk)
26506c3fb27SDimitry Andric     FROM_TO(VPCMPWZ256rmi, VPCMPEQWZ256rm, VPCMPGTWZ256rm)
26606c3fb27SDimitry Andric     FROM_TO(VPCMPWZ256rmik, VPCMPEQWZ256rmk, VPCMPGTWZ256rmk)
26706c3fb27SDimitry Andric     FROM_TO(VPCMPWZ256rri, VPCMPEQWZ256rr, VPCMPGTWZ256rr)
26806c3fb27SDimitry Andric     FROM_TO(VPCMPWZ256rrik, VPCMPEQWZ256rrk, VPCMPGTWZ256rrk)
26906c3fb27SDimitry Andric     FROM_TO(VPCMPWZrmi, VPCMPEQWZrm, VPCMPGTWZrm)
27006c3fb27SDimitry Andric     FROM_TO(VPCMPWZrmik, VPCMPEQWZrmk, VPCMPGTWZrmk)
27106c3fb27SDimitry Andric     FROM_TO(VPCMPWZrri, VPCMPEQWZrr, VPCMPGTWZrr)
27206c3fb27SDimitry Andric     FROM_TO(VPCMPWZrrik, VPCMPEQWZrrk, VPCMPGTWZrrk)
27306c3fb27SDimitry Andric #undef FROM_TO
27406c3fb27SDimitry Andric   }
27506c3fb27SDimitry Andric   MCOperand &LastOp = MI.getOperand(MI.getNumOperands() - 1);
27606c3fb27SDimitry Andric   int64_t Imm = LastOp.getImm();
27706c3fb27SDimitry Andric   unsigned NewOpc;
27806c3fb27SDimitry Andric   if (Imm == 0)
27906c3fb27SDimitry Andric     NewOpc = Opc1;
28006c3fb27SDimitry Andric   else if(Imm == 6)
28106c3fb27SDimitry Andric     NewOpc = Opc2;
28206c3fb27SDimitry Andric   else
28306c3fb27SDimitry Andric     return false;
28406c3fb27SDimitry Andric   MI.setOpcode(NewOpc);
28506c3fb27SDimitry Andric   MI.erase(&LastOp);
28606c3fb27SDimitry Andric   return true;
28706c3fb27SDimitry Andric }
28806c3fb27SDimitry Andric 
optimizeMOVSX(MCInst & MI)28906c3fb27SDimitry Andric bool X86::optimizeMOVSX(MCInst &MI) {
29006c3fb27SDimitry Andric   unsigned NewOpc;
29106c3fb27SDimitry Andric #define FROM_TO(FROM, TO, R0, R1)                                              \
29206c3fb27SDimitry Andric   case X86::FROM:                                                              \
29306c3fb27SDimitry Andric     if (MI.getOperand(0).getReg() != X86::R0 ||                                \
29406c3fb27SDimitry Andric         MI.getOperand(1).getReg() != X86::R1)                                  \
29506c3fb27SDimitry Andric       return false;                                                            \
29606c3fb27SDimitry Andric     NewOpc = X86::TO;                                                          \
29706c3fb27SDimitry Andric     break;
29806c3fb27SDimitry Andric   switch (MI.getOpcode()) {
29906c3fb27SDimitry Andric   default:
30006c3fb27SDimitry Andric     return false;
30106c3fb27SDimitry Andric     FROM_TO(MOVSX16rr8, CBW, AX, AL)     // movsbw %al, %ax   --> cbtw
30206c3fb27SDimitry Andric     FROM_TO(MOVSX32rr16, CWDE, EAX, AX)  // movswl %ax, %eax  --> cwtl
30306c3fb27SDimitry Andric     FROM_TO(MOVSX64rr32, CDQE, RAX, EAX) // movslq %eax, %rax --> cltq
30406c3fb27SDimitry Andric #undef FROM_TO
30506c3fb27SDimitry Andric   }
30606c3fb27SDimitry Andric   MI.clear();
30706c3fb27SDimitry Andric   MI.setOpcode(NewOpc);
30806c3fb27SDimitry Andric   return true;
30906c3fb27SDimitry Andric }
31006c3fb27SDimitry Andric 
optimizeINCDEC(MCInst & MI,bool In64BitMode)31106c3fb27SDimitry Andric bool X86::optimizeINCDEC(MCInst &MI, bool In64BitMode) {
31206c3fb27SDimitry Andric   if (In64BitMode)
31306c3fb27SDimitry Andric     return false;
31406c3fb27SDimitry Andric   unsigned NewOpc;
31506c3fb27SDimitry Andric   // If we aren't in 64-bit mode we can use the 1-byte inc/dec instructions.
31606c3fb27SDimitry Andric #define FROM_TO(FROM, TO)                                                      \
31706c3fb27SDimitry Andric   case X86::FROM:                                                              \
31806c3fb27SDimitry Andric     NewOpc = X86::TO;                                                          \
31906c3fb27SDimitry Andric     break;
32006c3fb27SDimitry Andric   switch (MI.getOpcode()) {
32106c3fb27SDimitry Andric   default:
32206c3fb27SDimitry Andric     return false;
32306c3fb27SDimitry Andric     FROM_TO(DEC16r, DEC16r_alt)
32406c3fb27SDimitry Andric     FROM_TO(DEC32r, DEC32r_alt)
32506c3fb27SDimitry Andric     FROM_TO(INC16r, INC16r_alt)
32606c3fb27SDimitry Andric     FROM_TO(INC32r, INC32r_alt)
32706c3fb27SDimitry Andric   }
32806c3fb27SDimitry Andric   MI.setOpcode(NewOpc);
32906c3fb27SDimitry Andric   return true;
33006c3fb27SDimitry Andric }
33106c3fb27SDimitry Andric 
isARegister(unsigned Reg)33206c3fb27SDimitry Andric static bool isARegister(unsigned Reg) {
33306c3fb27SDimitry Andric   return Reg == X86::AL || Reg == X86::AX || Reg == X86::EAX || Reg == X86::RAX;
33406c3fb27SDimitry Andric }
33506c3fb27SDimitry Andric 
33606c3fb27SDimitry Andric /// Simplify things like MOV32rm to MOV32o32a.
optimizeMOV(MCInst & MI,bool In64BitMode)33706c3fb27SDimitry Andric bool X86::optimizeMOV(MCInst &MI, bool In64BitMode) {
33806c3fb27SDimitry Andric   // Don't make these simplifications in 64-bit mode; other assemblers don't
33906c3fb27SDimitry Andric   // perform them because they make the code larger.
34006c3fb27SDimitry Andric   if (In64BitMode)
34106c3fb27SDimitry Andric     return false;
34206c3fb27SDimitry Andric   unsigned NewOpc;
34306c3fb27SDimitry Andric   // We don't currently select the correct instruction form for instructions
34406c3fb27SDimitry Andric   // which have a short %eax, etc. form. Handle this by custom lowering, for
34506c3fb27SDimitry Andric   // now.
34606c3fb27SDimitry Andric   //
34706c3fb27SDimitry Andric   // Note, we are currently not handling the following instructions:
34806c3fb27SDimitry Andric   // MOV64ao8, MOV64o8a
34906c3fb27SDimitry Andric   // XCHG16ar, XCHG32ar, XCHG64ar
35006c3fb27SDimitry Andric   switch (MI.getOpcode()) {
35106c3fb27SDimitry Andric   default:
35206c3fb27SDimitry Andric     return false;
35306c3fb27SDimitry Andric     FROM_TO(MOV8mr_NOREX, MOV8o32a)
35406c3fb27SDimitry Andric     FROM_TO(MOV8mr, MOV8o32a)
35506c3fb27SDimitry Andric     FROM_TO(MOV8rm_NOREX, MOV8ao32)
35606c3fb27SDimitry Andric     FROM_TO(MOV8rm, MOV8ao32)
35706c3fb27SDimitry Andric     FROM_TO(MOV16mr, MOV16o32a)
35806c3fb27SDimitry Andric     FROM_TO(MOV16rm, MOV16ao32)
35906c3fb27SDimitry Andric     FROM_TO(MOV32mr, MOV32o32a)
36006c3fb27SDimitry Andric     FROM_TO(MOV32rm, MOV32ao32)
36106c3fb27SDimitry Andric   }
36206c3fb27SDimitry Andric   bool IsStore = MI.getOperand(0).isReg() && MI.getOperand(1).isReg();
36306c3fb27SDimitry Andric   unsigned AddrBase = IsStore;
36406c3fb27SDimitry Andric   unsigned RegOp = IsStore ? 0 : 5;
36506c3fb27SDimitry Andric   unsigned AddrOp = AddrBase + 3;
36606c3fb27SDimitry Andric   // Check whether the destination register can be fixed.
36706c3fb27SDimitry Andric   unsigned Reg = MI.getOperand(RegOp).getReg();
36806c3fb27SDimitry Andric   if (!isARegister(Reg))
36906c3fb27SDimitry Andric     return false;
37006c3fb27SDimitry Andric   // Check whether this is an absolute address.
37106c3fb27SDimitry Andric   // FIXME: We know TLVP symbol refs aren't, but there should be a better way
37206c3fb27SDimitry Andric   // to do this here.
37306c3fb27SDimitry Andric   bool Absolute = true;
37406c3fb27SDimitry Andric   if (MI.getOperand(AddrOp).isExpr()) {
37506c3fb27SDimitry Andric     const MCExpr *MCE = MI.getOperand(AddrOp).getExpr();
37606c3fb27SDimitry Andric     if (const MCSymbolRefExpr *SRE = dyn_cast<MCSymbolRefExpr>(MCE))
37706c3fb27SDimitry Andric       if (SRE->getKind() == MCSymbolRefExpr::VK_TLVP)
37806c3fb27SDimitry Andric         Absolute = false;
37906c3fb27SDimitry Andric   }
38006c3fb27SDimitry Andric   if (Absolute && (MI.getOperand(AddrBase + X86::AddrBaseReg).getReg() != 0 ||
38106c3fb27SDimitry Andric                    MI.getOperand(AddrBase + X86::AddrScaleAmt).getImm() != 1 ||
38206c3fb27SDimitry Andric                    MI.getOperand(AddrBase + X86::AddrIndexReg).getReg() != 0))
38306c3fb27SDimitry Andric     return false;
38406c3fb27SDimitry Andric   // If so, rewrite the instruction.
38506c3fb27SDimitry Andric   MCOperand Saved = MI.getOperand(AddrOp);
38606c3fb27SDimitry Andric   MCOperand Seg = MI.getOperand(AddrBase + X86::AddrSegmentReg);
38706c3fb27SDimitry Andric   MI.clear();
38806c3fb27SDimitry Andric   MI.setOpcode(NewOpc);
38906c3fb27SDimitry Andric   MI.addOperand(Saved);
39006c3fb27SDimitry Andric   MI.addOperand(Seg);
39106c3fb27SDimitry Andric   return true;
39206c3fb27SDimitry Andric }
39306c3fb27SDimitry Andric 
39406c3fb27SDimitry Andric /// Simplify FOO $imm, %{al,ax,eax,rax} to FOO $imm, for instruction with
39506c3fb27SDimitry Andric /// a short fixed-register form.
optimizeToFixedRegisterForm(MCInst & MI)39606c3fb27SDimitry Andric static bool optimizeToFixedRegisterForm(MCInst &MI) {
39706c3fb27SDimitry Andric   unsigned NewOpc;
39806c3fb27SDimitry Andric   switch (MI.getOpcode()) {
39906c3fb27SDimitry Andric   default:
40006c3fb27SDimitry Andric     return false;
40106c3fb27SDimitry Andric     FROM_TO(ADC8ri, ADC8i8)
40206c3fb27SDimitry Andric     FROM_TO(ADC16ri, ADC16i16)
40306c3fb27SDimitry Andric     FROM_TO(ADC32ri, ADC32i32)
40406c3fb27SDimitry Andric     FROM_TO(ADC64ri32, ADC64i32)
40506c3fb27SDimitry Andric     FROM_TO(ADD8ri, ADD8i8)
40606c3fb27SDimitry Andric     FROM_TO(ADD16ri, ADD16i16)
40706c3fb27SDimitry Andric     FROM_TO(ADD32ri, ADD32i32)
40806c3fb27SDimitry Andric     FROM_TO(ADD64ri32, ADD64i32)
40906c3fb27SDimitry Andric     FROM_TO(AND8ri, AND8i8)
41006c3fb27SDimitry Andric     FROM_TO(AND16ri, AND16i16)
41106c3fb27SDimitry Andric     FROM_TO(AND32ri, AND32i32)
41206c3fb27SDimitry Andric     FROM_TO(AND64ri32, AND64i32)
41306c3fb27SDimitry Andric     FROM_TO(CMP8ri, CMP8i8)
41406c3fb27SDimitry Andric     FROM_TO(CMP16ri, CMP16i16)
41506c3fb27SDimitry Andric     FROM_TO(CMP32ri, CMP32i32)
41606c3fb27SDimitry Andric     FROM_TO(CMP64ri32, CMP64i32)
41706c3fb27SDimitry Andric     FROM_TO(OR8ri, OR8i8)
41806c3fb27SDimitry Andric     FROM_TO(OR16ri, OR16i16)
41906c3fb27SDimitry Andric     FROM_TO(OR32ri, OR32i32)
42006c3fb27SDimitry Andric     FROM_TO(OR64ri32, OR64i32)
42106c3fb27SDimitry Andric     FROM_TO(SBB8ri, SBB8i8)
42206c3fb27SDimitry Andric     FROM_TO(SBB16ri, SBB16i16)
42306c3fb27SDimitry Andric     FROM_TO(SBB32ri, SBB32i32)
42406c3fb27SDimitry Andric     FROM_TO(SBB64ri32, SBB64i32)
42506c3fb27SDimitry Andric     FROM_TO(SUB8ri, SUB8i8)
42606c3fb27SDimitry Andric     FROM_TO(SUB16ri, SUB16i16)
42706c3fb27SDimitry Andric     FROM_TO(SUB32ri, SUB32i32)
42806c3fb27SDimitry Andric     FROM_TO(SUB64ri32, SUB64i32)
42906c3fb27SDimitry Andric     FROM_TO(TEST8ri, TEST8i8)
43006c3fb27SDimitry Andric     FROM_TO(TEST16ri, TEST16i16)
43106c3fb27SDimitry Andric     FROM_TO(TEST32ri, TEST32i32)
43206c3fb27SDimitry Andric     FROM_TO(TEST64ri32, TEST64i32)
43306c3fb27SDimitry Andric     FROM_TO(XOR8ri, XOR8i8)
43406c3fb27SDimitry Andric     FROM_TO(XOR16ri, XOR16i16)
43506c3fb27SDimitry Andric     FROM_TO(XOR32ri, XOR32i32)
43606c3fb27SDimitry Andric     FROM_TO(XOR64ri32, XOR64i32)
43706c3fb27SDimitry Andric   }
43806c3fb27SDimitry Andric   // Check whether the destination register can be fixed.
43906c3fb27SDimitry Andric   unsigned Reg = MI.getOperand(0).getReg();
44006c3fb27SDimitry Andric   if (!isARegister(Reg))
44106c3fb27SDimitry Andric     return false;
44206c3fb27SDimitry Andric 
44306c3fb27SDimitry Andric   // If so, rewrite the instruction.
44406c3fb27SDimitry Andric   MCOperand Saved = MI.getOperand(MI.getNumOperands() - 1);
44506c3fb27SDimitry Andric   MI.clear();
44606c3fb27SDimitry Andric   MI.setOpcode(NewOpc);
44706c3fb27SDimitry Andric   MI.addOperand(Saved);
44806c3fb27SDimitry Andric   return true;
44906c3fb27SDimitry Andric }
45006c3fb27SDimitry Andric 
getOpcodeForShortImmediateForm(unsigned Opcode)45106c3fb27SDimitry Andric unsigned X86::getOpcodeForShortImmediateForm(unsigned Opcode) {
45206c3fb27SDimitry Andric #define ENTRY(LONG, SHORT)                                                     \
45306c3fb27SDimitry Andric   case X86::LONG:                                                              \
45406c3fb27SDimitry Andric     return X86::SHORT;
45506c3fb27SDimitry Andric   switch (Opcode) {
45606c3fb27SDimitry Andric   default:
45706c3fb27SDimitry Andric     return Opcode;
45806c3fb27SDimitry Andric #include "X86EncodingOptimizationForImmediate.def"
45906c3fb27SDimitry Andric   }
46006c3fb27SDimitry Andric }
46106c3fb27SDimitry Andric 
getOpcodeForLongImmediateForm(unsigned Opcode)46206c3fb27SDimitry Andric unsigned X86::getOpcodeForLongImmediateForm(unsigned Opcode) {
46306c3fb27SDimitry Andric #define ENTRY(LONG, SHORT)                                                     \
46406c3fb27SDimitry Andric   case X86::SHORT:                                                             \
46506c3fb27SDimitry Andric     return X86::LONG;
46606c3fb27SDimitry Andric   switch (Opcode) {
46706c3fb27SDimitry Andric   default:
46806c3fb27SDimitry Andric     return Opcode;
46906c3fb27SDimitry Andric #include "X86EncodingOptimizationForImmediate.def"
47006c3fb27SDimitry Andric   }
47106c3fb27SDimitry Andric }
47206c3fb27SDimitry Andric 
optimizeToShortImmediateForm(MCInst & MI)47306c3fb27SDimitry Andric static bool optimizeToShortImmediateForm(MCInst &MI) {
47406c3fb27SDimitry Andric   unsigned NewOpc;
47506c3fb27SDimitry Andric #define ENTRY(LONG, SHORT)                                                     \
47606c3fb27SDimitry Andric   case X86::LONG:                                                              \
47706c3fb27SDimitry Andric     NewOpc = X86::SHORT;                                                       \
47806c3fb27SDimitry Andric     break;
47906c3fb27SDimitry Andric   switch (MI.getOpcode()) {
48006c3fb27SDimitry Andric   default:
48106c3fb27SDimitry Andric     return false;
48206c3fb27SDimitry Andric #include "X86EncodingOptimizationForImmediate.def"
48306c3fb27SDimitry Andric   }
484*0fca6ea1SDimitry Andric   unsigned SkipOperands = X86::isCCMPCC(MI.getOpcode()) ? 2 : 0;
485*0fca6ea1SDimitry Andric   MCOperand &LastOp = MI.getOperand(MI.getNumOperands() - 1 - SkipOperands);
48606c3fb27SDimitry Andric   if (LastOp.isExpr()) {
48706c3fb27SDimitry Andric     const MCSymbolRefExpr *SRE = dyn_cast<MCSymbolRefExpr>(LastOp.getExpr());
48806c3fb27SDimitry Andric     if (!SRE || SRE->getKind() != MCSymbolRefExpr::VK_X86_ABS8)
48906c3fb27SDimitry Andric       return false;
49006c3fb27SDimitry Andric   } else if (LastOp.isImm()) {
49106c3fb27SDimitry Andric     if (!isInt<8>(LastOp.getImm()))
49206c3fb27SDimitry Andric       return false;
49306c3fb27SDimitry Andric   }
49406c3fb27SDimitry Andric   MI.setOpcode(NewOpc);
49506c3fb27SDimitry Andric   return true;
49606c3fb27SDimitry Andric }
49706c3fb27SDimitry Andric 
optimizeToFixedRegisterOrShortImmediateForm(MCInst & MI)49806c3fb27SDimitry Andric bool X86::optimizeToFixedRegisterOrShortImmediateForm(MCInst &MI) {
49906c3fb27SDimitry Andric   // We may optimize twice here.
50006c3fb27SDimitry Andric   bool ShortImm = optimizeToShortImmediateForm(MI);
50106c3fb27SDimitry Andric   bool FixedReg = optimizeToFixedRegisterForm(MI);
50206c3fb27SDimitry Andric   return ShortImm || FixedReg;
50306c3fb27SDimitry Andric }
504