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 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. 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 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 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 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 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. 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. 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 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 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 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 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