1*0b57cec5SDimitry Andric //===--- X86DomainReassignment.cpp - Selectively switch register classes---===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This pass attempts to find instruction chains (closures) in one domain, 10*0b57cec5SDimitry Andric // and convert them to equivalent instructions in a different domain, 11*0b57cec5SDimitry Andric // if profitable. 12*0b57cec5SDimitry Andric // 13*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 14*0b57cec5SDimitry Andric 15*0b57cec5SDimitry Andric #include "X86.h" 16*0b57cec5SDimitry Andric #include "X86InstrInfo.h" 17*0b57cec5SDimitry Andric #include "X86Subtarget.h" 18*0b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 19*0b57cec5SDimitry Andric #include "llvm/ADT/DenseMapInfo.h" 20*0b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 21*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 22*0b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 23*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 24*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 25*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 26*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 27*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 28*0b57cec5SDimitry Andric #include "llvm/Support/Printable.h" 29*0b57cec5SDimitry Andric #include <bitset> 30*0b57cec5SDimitry Andric 31*0b57cec5SDimitry Andric using namespace llvm; 32*0b57cec5SDimitry Andric 33*0b57cec5SDimitry Andric #define DEBUG_TYPE "x86-domain-reassignment" 34*0b57cec5SDimitry Andric 35*0b57cec5SDimitry Andric STATISTIC(NumClosuresConverted, "Number of closures converted by the pass"); 36*0b57cec5SDimitry Andric 37*0b57cec5SDimitry Andric static cl::opt<bool> DisableX86DomainReassignment( 38*0b57cec5SDimitry Andric "disable-x86-domain-reassignment", cl::Hidden, 39*0b57cec5SDimitry Andric cl::desc("X86: Disable Virtual Register Reassignment."), cl::init(false)); 40*0b57cec5SDimitry Andric 41*0b57cec5SDimitry Andric namespace { 42*0b57cec5SDimitry Andric enum RegDomain { NoDomain = -1, GPRDomain, MaskDomain, OtherDomain, NumDomains }; 43*0b57cec5SDimitry Andric 44*0b57cec5SDimitry Andric static bool isGPR(const TargetRegisterClass *RC) { 45*0b57cec5SDimitry Andric return X86::GR64RegClass.hasSubClassEq(RC) || 46*0b57cec5SDimitry Andric X86::GR32RegClass.hasSubClassEq(RC) || 47*0b57cec5SDimitry Andric X86::GR16RegClass.hasSubClassEq(RC) || 48*0b57cec5SDimitry Andric X86::GR8RegClass.hasSubClassEq(RC); 49*0b57cec5SDimitry Andric } 50*0b57cec5SDimitry Andric 51*0b57cec5SDimitry Andric static bool isMask(const TargetRegisterClass *RC, 52*0b57cec5SDimitry Andric const TargetRegisterInfo *TRI) { 53*0b57cec5SDimitry Andric return X86::VK16RegClass.hasSubClassEq(RC); 54*0b57cec5SDimitry Andric } 55*0b57cec5SDimitry Andric 56*0b57cec5SDimitry Andric static RegDomain getDomain(const TargetRegisterClass *RC, 57*0b57cec5SDimitry Andric const TargetRegisterInfo *TRI) { 58*0b57cec5SDimitry Andric if (isGPR(RC)) 59*0b57cec5SDimitry Andric return GPRDomain; 60*0b57cec5SDimitry Andric if (isMask(RC, TRI)) 61*0b57cec5SDimitry Andric return MaskDomain; 62*0b57cec5SDimitry Andric return OtherDomain; 63*0b57cec5SDimitry Andric } 64*0b57cec5SDimitry Andric 65*0b57cec5SDimitry Andric /// Return a register class equivalent to \p SrcRC, in \p Domain. 66*0b57cec5SDimitry Andric static const TargetRegisterClass *getDstRC(const TargetRegisterClass *SrcRC, 67*0b57cec5SDimitry Andric RegDomain Domain) { 68*0b57cec5SDimitry Andric assert(Domain == MaskDomain && "add domain"); 69*0b57cec5SDimitry Andric if (X86::GR8RegClass.hasSubClassEq(SrcRC)) 70*0b57cec5SDimitry Andric return &X86::VK8RegClass; 71*0b57cec5SDimitry Andric if (X86::GR16RegClass.hasSubClassEq(SrcRC)) 72*0b57cec5SDimitry Andric return &X86::VK16RegClass; 73*0b57cec5SDimitry Andric if (X86::GR32RegClass.hasSubClassEq(SrcRC)) 74*0b57cec5SDimitry Andric return &X86::VK32RegClass; 75*0b57cec5SDimitry Andric if (X86::GR64RegClass.hasSubClassEq(SrcRC)) 76*0b57cec5SDimitry Andric return &X86::VK64RegClass; 77*0b57cec5SDimitry Andric llvm_unreachable("add register class"); 78*0b57cec5SDimitry Andric return nullptr; 79*0b57cec5SDimitry Andric } 80*0b57cec5SDimitry Andric 81*0b57cec5SDimitry Andric /// Abstract Instruction Converter class. 82*0b57cec5SDimitry Andric class InstrConverterBase { 83*0b57cec5SDimitry Andric protected: 84*0b57cec5SDimitry Andric unsigned SrcOpcode; 85*0b57cec5SDimitry Andric 86*0b57cec5SDimitry Andric public: 87*0b57cec5SDimitry Andric InstrConverterBase(unsigned SrcOpcode) : SrcOpcode(SrcOpcode) {} 88*0b57cec5SDimitry Andric 89*0b57cec5SDimitry Andric virtual ~InstrConverterBase() {} 90*0b57cec5SDimitry Andric 91*0b57cec5SDimitry Andric /// \returns true if \p MI is legal to convert. 92*0b57cec5SDimitry Andric virtual bool isLegal(const MachineInstr *MI, 93*0b57cec5SDimitry Andric const TargetInstrInfo *TII) const { 94*0b57cec5SDimitry Andric assert(MI->getOpcode() == SrcOpcode && 95*0b57cec5SDimitry Andric "Wrong instruction passed to converter"); 96*0b57cec5SDimitry Andric return true; 97*0b57cec5SDimitry Andric } 98*0b57cec5SDimitry Andric 99*0b57cec5SDimitry Andric /// Applies conversion to \p MI. 100*0b57cec5SDimitry Andric /// 101*0b57cec5SDimitry Andric /// \returns true if \p MI is no longer need, and can be deleted. 102*0b57cec5SDimitry Andric virtual bool convertInstr(MachineInstr *MI, const TargetInstrInfo *TII, 103*0b57cec5SDimitry Andric MachineRegisterInfo *MRI) const = 0; 104*0b57cec5SDimitry Andric 105*0b57cec5SDimitry Andric /// \returns the cost increment incurred by converting \p MI. 106*0b57cec5SDimitry Andric virtual double getExtraCost(const MachineInstr *MI, 107*0b57cec5SDimitry Andric MachineRegisterInfo *MRI) const = 0; 108*0b57cec5SDimitry Andric }; 109*0b57cec5SDimitry Andric 110*0b57cec5SDimitry Andric /// An Instruction Converter which ignores the given instruction. 111*0b57cec5SDimitry Andric /// For example, PHI instructions can be safely ignored since only the registers 112*0b57cec5SDimitry Andric /// need to change. 113*0b57cec5SDimitry Andric class InstrIgnore : public InstrConverterBase { 114*0b57cec5SDimitry Andric public: 115*0b57cec5SDimitry Andric InstrIgnore(unsigned SrcOpcode) : InstrConverterBase(SrcOpcode) {} 116*0b57cec5SDimitry Andric 117*0b57cec5SDimitry Andric bool convertInstr(MachineInstr *MI, const TargetInstrInfo *TII, 118*0b57cec5SDimitry Andric MachineRegisterInfo *MRI) const override { 119*0b57cec5SDimitry Andric assert(isLegal(MI, TII) && "Cannot convert instruction"); 120*0b57cec5SDimitry Andric return false; 121*0b57cec5SDimitry Andric } 122*0b57cec5SDimitry Andric 123*0b57cec5SDimitry Andric double getExtraCost(const MachineInstr *MI, 124*0b57cec5SDimitry Andric MachineRegisterInfo *MRI) const override { 125*0b57cec5SDimitry Andric return 0; 126*0b57cec5SDimitry Andric } 127*0b57cec5SDimitry Andric }; 128*0b57cec5SDimitry Andric 129*0b57cec5SDimitry Andric /// An Instruction Converter which replaces an instruction with another. 130*0b57cec5SDimitry Andric class InstrReplacer : public InstrConverterBase { 131*0b57cec5SDimitry Andric public: 132*0b57cec5SDimitry Andric /// Opcode of the destination instruction. 133*0b57cec5SDimitry Andric unsigned DstOpcode; 134*0b57cec5SDimitry Andric 135*0b57cec5SDimitry Andric InstrReplacer(unsigned SrcOpcode, unsigned DstOpcode) 136*0b57cec5SDimitry Andric : InstrConverterBase(SrcOpcode), DstOpcode(DstOpcode) {} 137*0b57cec5SDimitry Andric 138*0b57cec5SDimitry Andric bool isLegal(const MachineInstr *MI, 139*0b57cec5SDimitry Andric const TargetInstrInfo *TII) const override { 140*0b57cec5SDimitry Andric if (!InstrConverterBase::isLegal(MI, TII)) 141*0b57cec5SDimitry Andric return false; 142*0b57cec5SDimitry Andric // It's illegal to replace an instruction that implicitly defines a register 143*0b57cec5SDimitry Andric // with an instruction that doesn't, unless that register dead. 144*0b57cec5SDimitry Andric for (auto &MO : MI->implicit_operands()) 145*0b57cec5SDimitry Andric if (MO.isReg() && MO.isDef() && !MO.isDead() && 146*0b57cec5SDimitry Andric !TII->get(DstOpcode).hasImplicitDefOfPhysReg(MO.getReg())) 147*0b57cec5SDimitry Andric return false; 148*0b57cec5SDimitry Andric return true; 149*0b57cec5SDimitry Andric } 150*0b57cec5SDimitry Andric 151*0b57cec5SDimitry Andric bool convertInstr(MachineInstr *MI, const TargetInstrInfo *TII, 152*0b57cec5SDimitry Andric MachineRegisterInfo *MRI) const override { 153*0b57cec5SDimitry Andric assert(isLegal(MI, TII) && "Cannot convert instruction"); 154*0b57cec5SDimitry Andric MachineInstrBuilder Bld = 155*0b57cec5SDimitry Andric BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII->get(DstOpcode)); 156*0b57cec5SDimitry Andric // Transfer explicit operands from original instruction. Implicit operands 157*0b57cec5SDimitry Andric // are handled by BuildMI. 158*0b57cec5SDimitry Andric for (auto &Op : MI->explicit_operands()) 159*0b57cec5SDimitry Andric Bld.add(Op); 160*0b57cec5SDimitry Andric return true; 161*0b57cec5SDimitry Andric } 162*0b57cec5SDimitry Andric 163*0b57cec5SDimitry Andric double getExtraCost(const MachineInstr *MI, 164*0b57cec5SDimitry Andric MachineRegisterInfo *MRI) const override { 165*0b57cec5SDimitry Andric // Assuming instructions have the same cost. 166*0b57cec5SDimitry Andric return 0; 167*0b57cec5SDimitry Andric } 168*0b57cec5SDimitry Andric }; 169*0b57cec5SDimitry Andric 170*0b57cec5SDimitry Andric /// An Instruction Converter which replaces an instruction with another, and 171*0b57cec5SDimitry Andric /// adds a COPY from the new instruction's destination to the old one's. 172*0b57cec5SDimitry Andric class InstrReplacerDstCOPY : public InstrConverterBase { 173*0b57cec5SDimitry Andric public: 174*0b57cec5SDimitry Andric unsigned DstOpcode; 175*0b57cec5SDimitry Andric 176*0b57cec5SDimitry Andric InstrReplacerDstCOPY(unsigned SrcOpcode, unsigned DstOpcode) 177*0b57cec5SDimitry Andric : InstrConverterBase(SrcOpcode), DstOpcode(DstOpcode) {} 178*0b57cec5SDimitry Andric 179*0b57cec5SDimitry Andric bool convertInstr(MachineInstr *MI, const TargetInstrInfo *TII, 180*0b57cec5SDimitry Andric MachineRegisterInfo *MRI) const override { 181*0b57cec5SDimitry Andric assert(isLegal(MI, TII) && "Cannot convert instruction"); 182*0b57cec5SDimitry Andric MachineBasicBlock *MBB = MI->getParent(); 183*0b57cec5SDimitry Andric auto &DL = MI->getDebugLoc(); 184*0b57cec5SDimitry Andric 185*0b57cec5SDimitry Andric unsigned Reg = MRI->createVirtualRegister( 186*0b57cec5SDimitry Andric TII->getRegClass(TII->get(DstOpcode), 0, MRI->getTargetRegisterInfo(), 187*0b57cec5SDimitry Andric *MBB->getParent())); 188*0b57cec5SDimitry Andric MachineInstrBuilder Bld = BuildMI(*MBB, MI, DL, TII->get(DstOpcode), Reg); 189*0b57cec5SDimitry Andric for (unsigned Idx = 1, End = MI->getNumOperands(); Idx < End; ++Idx) 190*0b57cec5SDimitry Andric Bld.add(MI->getOperand(Idx)); 191*0b57cec5SDimitry Andric 192*0b57cec5SDimitry Andric BuildMI(*MBB, MI, DL, TII->get(TargetOpcode::COPY)) 193*0b57cec5SDimitry Andric .add(MI->getOperand(0)) 194*0b57cec5SDimitry Andric .addReg(Reg); 195*0b57cec5SDimitry Andric 196*0b57cec5SDimitry Andric return true; 197*0b57cec5SDimitry Andric } 198*0b57cec5SDimitry Andric 199*0b57cec5SDimitry Andric double getExtraCost(const MachineInstr *MI, 200*0b57cec5SDimitry Andric MachineRegisterInfo *MRI) const override { 201*0b57cec5SDimitry Andric // Assuming instructions have the same cost, and that COPY is in the same 202*0b57cec5SDimitry Andric // domain so it will be eliminated. 203*0b57cec5SDimitry Andric return 0; 204*0b57cec5SDimitry Andric } 205*0b57cec5SDimitry Andric }; 206*0b57cec5SDimitry Andric 207*0b57cec5SDimitry Andric /// An Instruction Converter for replacing COPY instructions. 208*0b57cec5SDimitry Andric class InstrCOPYReplacer : public InstrReplacer { 209*0b57cec5SDimitry Andric public: 210*0b57cec5SDimitry Andric RegDomain DstDomain; 211*0b57cec5SDimitry Andric 212*0b57cec5SDimitry Andric InstrCOPYReplacer(unsigned SrcOpcode, RegDomain DstDomain, unsigned DstOpcode) 213*0b57cec5SDimitry Andric : InstrReplacer(SrcOpcode, DstOpcode), DstDomain(DstDomain) {} 214*0b57cec5SDimitry Andric 215*0b57cec5SDimitry Andric bool isLegal(const MachineInstr *MI, 216*0b57cec5SDimitry Andric const TargetInstrInfo *TII) const override { 217*0b57cec5SDimitry Andric if (!InstrConverterBase::isLegal(MI, TII)) 218*0b57cec5SDimitry Andric return false; 219*0b57cec5SDimitry Andric 220*0b57cec5SDimitry Andric // Don't allow copies to/flow GR8/GR16 physical registers. 221*0b57cec5SDimitry Andric // FIXME: Is there some better way to support this? 222*0b57cec5SDimitry Andric unsigned DstReg = MI->getOperand(0).getReg(); 223*0b57cec5SDimitry Andric if (TargetRegisterInfo::isPhysicalRegister(DstReg) && 224*0b57cec5SDimitry Andric (X86::GR8RegClass.contains(DstReg) || 225*0b57cec5SDimitry Andric X86::GR16RegClass.contains(DstReg))) 226*0b57cec5SDimitry Andric return false; 227*0b57cec5SDimitry Andric unsigned SrcReg = MI->getOperand(1).getReg(); 228*0b57cec5SDimitry Andric if (TargetRegisterInfo::isPhysicalRegister(SrcReg) && 229*0b57cec5SDimitry Andric (X86::GR8RegClass.contains(SrcReg) || 230*0b57cec5SDimitry Andric X86::GR16RegClass.contains(SrcReg))) 231*0b57cec5SDimitry Andric return false; 232*0b57cec5SDimitry Andric 233*0b57cec5SDimitry Andric return true; 234*0b57cec5SDimitry Andric } 235*0b57cec5SDimitry Andric 236*0b57cec5SDimitry Andric double getExtraCost(const MachineInstr *MI, 237*0b57cec5SDimitry Andric MachineRegisterInfo *MRI) const override { 238*0b57cec5SDimitry Andric assert(MI->getOpcode() == TargetOpcode::COPY && "Expected a COPY"); 239*0b57cec5SDimitry Andric 240*0b57cec5SDimitry Andric for (auto &MO : MI->operands()) { 241*0b57cec5SDimitry Andric // Physical registers will not be converted. Assume that converting the 242*0b57cec5SDimitry Andric // COPY to the destination domain will eventually result in a actual 243*0b57cec5SDimitry Andric // instruction. 244*0b57cec5SDimitry Andric if (TargetRegisterInfo::isPhysicalRegister(MO.getReg())) 245*0b57cec5SDimitry Andric return 1; 246*0b57cec5SDimitry Andric 247*0b57cec5SDimitry Andric RegDomain OpDomain = getDomain(MRI->getRegClass(MO.getReg()), 248*0b57cec5SDimitry Andric MRI->getTargetRegisterInfo()); 249*0b57cec5SDimitry Andric // Converting a cross domain COPY to a same domain COPY should eliminate 250*0b57cec5SDimitry Andric // an insturction 251*0b57cec5SDimitry Andric if (OpDomain == DstDomain) 252*0b57cec5SDimitry Andric return -1; 253*0b57cec5SDimitry Andric } 254*0b57cec5SDimitry Andric return 0; 255*0b57cec5SDimitry Andric } 256*0b57cec5SDimitry Andric }; 257*0b57cec5SDimitry Andric 258*0b57cec5SDimitry Andric /// An Instruction Converter which replaces an instruction with a COPY. 259*0b57cec5SDimitry Andric class InstrReplaceWithCopy : public InstrConverterBase { 260*0b57cec5SDimitry Andric public: 261*0b57cec5SDimitry Andric // Source instruction operand Index, to be used as the COPY source. 262*0b57cec5SDimitry Andric unsigned SrcOpIdx; 263*0b57cec5SDimitry Andric 264*0b57cec5SDimitry Andric InstrReplaceWithCopy(unsigned SrcOpcode, unsigned SrcOpIdx) 265*0b57cec5SDimitry Andric : InstrConverterBase(SrcOpcode), SrcOpIdx(SrcOpIdx) {} 266*0b57cec5SDimitry Andric 267*0b57cec5SDimitry Andric bool convertInstr(MachineInstr *MI, const TargetInstrInfo *TII, 268*0b57cec5SDimitry Andric MachineRegisterInfo *MRI) const override { 269*0b57cec5SDimitry Andric assert(isLegal(MI, TII) && "Cannot convert instruction"); 270*0b57cec5SDimitry Andric BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), 271*0b57cec5SDimitry Andric TII->get(TargetOpcode::COPY)) 272*0b57cec5SDimitry Andric .add({MI->getOperand(0), MI->getOperand(SrcOpIdx)}); 273*0b57cec5SDimitry Andric return true; 274*0b57cec5SDimitry Andric } 275*0b57cec5SDimitry Andric 276*0b57cec5SDimitry Andric double getExtraCost(const MachineInstr *MI, 277*0b57cec5SDimitry Andric MachineRegisterInfo *MRI) const override { 278*0b57cec5SDimitry Andric return 0; 279*0b57cec5SDimitry Andric } 280*0b57cec5SDimitry Andric }; 281*0b57cec5SDimitry Andric 282*0b57cec5SDimitry Andric // Key type to be used by the Instruction Converters map. 283*0b57cec5SDimitry Andric // A converter is identified by <destination domain, source opcode> 284*0b57cec5SDimitry Andric typedef std::pair<int, unsigned> InstrConverterBaseKeyTy; 285*0b57cec5SDimitry Andric 286*0b57cec5SDimitry Andric typedef DenseMap<InstrConverterBaseKeyTy, InstrConverterBase *> 287*0b57cec5SDimitry Andric InstrConverterBaseMap; 288*0b57cec5SDimitry Andric 289*0b57cec5SDimitry Andric /// A closure is a set of virtual register representing all of the edges in 290*0b57cec5SDimitry Andric /// the closure, as well as all of the instructions connected by those edges. 291*0b57cec5SDimitry Andric /// 292*0b57cec5SDimitry Andric /// A closure may encompass virtual registers in the same register bank that 293*0b57cec5SDimitry Andric /// have different widths. For example, it may contain 32-bit GPRs as well as 294*0b57cec5SDimitry Andric /// 64-bit GPRs. 295*0b57cec5SDimitry Andric /// 296*0b57cec5SDimitry Andric /// A closure that computes an address (i.e. defines a virtual register that is 297*0b57cec5SDimitry Andric /// used in a memory operand) excludes the instructions that contain memory 298*0b57cec5SDimitry Andric /// operands using the address. Such an instruction will be included in a 299*0b57cec5SDimitry Andric /// different closure that manipulates the loaded or stored value. 300*0b57cec5SDimitry Andric class Closure { 301*0b57cec5SDimitry Andric private: 302*0b57cec5SDimitry Andric /// Virtual registers in the closure. 303*0b57cec5SDimitry Andric DenseSet<unsigned> Edges; 304*0b57cec5SDimitry Andric 305*0b57cec5SDimitry Andric /// Instructions in the closure. 306*0b57cec5SDimitry Andric SmallVector<MachineInstr *, 8> Instrs; 307*0b57cec5SDimitry Andric 308*0b57cec5SDimitry Andric /// Domains which this closure can legally be reassigned to. 309*0b57cec5SDimitry Andric std::bitset<NumDomains> LegalDstDomains; 310*0b57cec5SDimitry Andric 311*0b57cec5SDimitry Andric /// An ID to uniquely identify this closure, even when it gets 312*0b57cec5SDimitry Andric /// moved around 313*0b57cec5SDimitry Andric unsigned ID; 314*0b57cec5SDimitry Andric 315*0b57cec5SDimitry Andric public: 316*0b57cec5SDimitry Andric Closure(unsigned ID, std::initializer_list<RegDomain> LegalDstDomainList) : ID(ID) { 317*0b57cec5SDimitry Andric for (RegDomain D : LegalDstDomainList) 318*0b57cec5SDimitry Andric LegalDstDomains.set(D); 319*0b57cec5SDimitry Andric } 320*0b57cec5SDimitry Andric 321*0b57cec5SDimitry Andric /// Mark this closure as illegal for reassignment to all domains. 322*0b57cec5SDimitry Andric void setAllIllegal() { LegalDstDomains.reset(); } 323*0b57cec5SDimitry Andric 324*0b57cec5SDimitry Andric /// \returns true if this closure has domains which are legal to reassign to. 325*0b57cec5SDimitry Andric bool hasLegalDstDomain() const { return LegalDstDomains.any(); } 326*0b57cec5SDimitry Andric 327*0b57cec5SDimitry Andric /// \returns true if is legal to reassign this closure to domain \p RD. 328*0b57cec5SDimitry Andric bool isLegal(RegDomain RD) const { return LegalDstDomains[RD]; } 329*0b57cec5SDimitry Andric 330*0b57cec5SDimitry Andric /// Mark this closure as illegal for reassignment to domain \p RD. 331*0b57cec5SDimitry Andric void setIllegal(RegDomain RD) { LegalDstDomains[RD] = false; } 332*0b57cec5SDimitry Andric 333*0b57cec5SDimitry Andric bool empty() const { return Edges.empty(); } 334*0b57cec5SDimitry Andric 335*0b57cec5SDimitry Andric bool insertEdge(unsigned Reg) { 336*0b57cec5SDimitry Andric return Edges.insert(Reg).second; 337*0b57cec5SDimitry Andric } 338*0b57cec5SDimitry Andric 339*0b57cec5SDimitry Andric using const_edge_iterator = DenseSet<unsigned>::const_iterator; 340*0b57cec5SDimitry Andric iterator_range<const_edge_iterator> edges() const { 341*0b57cec5SDimitry Andric return iterator_range<const_edge_iterator>(Edges.begin(), Edges.end()); 342*0b57cec5SDimitry Andric } 343*0b57cec5SDimitry Andric 344*0b57cec5SDimitry Andric void addInstruction(MachineInstr *I) { 345*0b57cec5SDimitry Andric Instrs.push_back(I); 346*0b57cec5SDimitry Andric } 347*0b57cec5SDimitry Andric 348*0b57cec5SDimitry Andric ArrayRef<MachineInstr *> instructions() const { 349*0b57cec5SDimitry Andric return Instrs; 350*0b57cec5SDimitry Andric } 351*0b57cec5SDimitry Andric 352*0b57cec5SDimitry Andric LLVM_DUMP_METHOD void dump(const MachineRegisterInfo *MRI) const { 353*0b57cec5SDimitry Andric dbgs() << "Registers: "; 354*0b57cec5SDimitry Andric bool First = true; 355*0b57cec5SDimitry Andric for (unsigned Reg : Edges) { 356*0b57cec5SDimitry Andric if (!First) 357*0b57cec5SDimitry Andric dbgs() << ", "; 358*0b57cec5SDimitry Andric First = false; 359*0b57cec5SDimitry Andric dbgs() << printReg(Reg, MRI->getTargetRegisterInfo(), 0, MRI); 360*0b57cec5SDimitry Andric } 361*0b57cec5SDimitry Andric dbgs() << "\n" << "Instructions:"; 362*0b57cec5SDimitry Andric for (MachineInstr *MI : Instrs) { 363*0b57cec5SDimitry Andric dbgs() << "\n "; 364*0b57cec5SDimitry Andric MI->print(dbgs()); 365*0b57cec5SDimitry Andric } 366*0b57cec5SDimitry Andric dbgs() << "\n"; 367*0b57cec5SDimitry Andric } 368*0b57cec5SDimitry Andric 369*0b57cec5SDimitry Andric unsigned getID() const { 370*0b57cec5SDimitry Andric return ID; 371*0b57cec5SDimitry Andric } 372*0b57cec5SDimitry Andric 373*0b57cec5SDimitry Andric }; 374*0b57cec5SDimitry Andric 375*0b57cec5SDimitry Andric class X86DomainReassignment : public MachineFunctionPass { 376*0b57cec5SDimitry Andric const X86Subtarget *STI; 377*0b57cec5SDimitry Andric MachineRegisterInfo *MRI; 378*0b57cec5SDimitry Andric const X86InstrInfo *TII; 379*0b57cec5SDimitry Andric 380*0b57cec5SDimitry Andric /// All edges that are included in some closure 381*0b57cec5SDimitry Andric DenseSet<unsigned> EnclosedEdges; 382*0b57cec5SDimitry Andric 383*0b57cec5SDimitry Andric /// All instructions that are included in some closure. 384*0b57cec5SDimitry Andric DenseMap<MachineInstr *, unsigned> EnclosedInstrs; 385*0b57cec5SDimitry Andric 386*0b57cec5SDimitry Andric public: 387*0b57cec5SDimitry Andric static char ID; 388*0b57cec5SDimitry Andric 389*0b57cec5SDimitry Andric X86DomainReassignment() : MachineFunctionPass(ID) { } 390*0b57cec5SDimitry Andric 391*0b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 392*0b57cec5SDimitry Andric 393*0b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 394*0b57cec5SDimitry Andric AU.setPreservesCFG(); 395*0b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 396*0b57cec5SDimitry Andric } 397*0b57cec5SDimitry Andric 398*0b57cec5SDimitry Andric StringRef getPassName() const override { 399*0b57cec5SDimitry Andric return "X86 Domain Reassignment Pass"; 400*0b57cec5SDimitry Andric } 401*0b57cec5SDimitry Andric 402*0b57cec5SDimitry Andric private: 403*0b57cec5SDimitry Andric /// A map of available Instruction Converters. 404*0b57cec5SDimitry Andric InstrConverterBaseMap Converters; 405*0b57cec5SDimitry Andric 406*0b57cec5SDimitry Andric /// Initialize Converters map. 407*0b57cec5SDimitry Andric void initConverters(); 408*0b57cec5SDimitry Andric 409*0b57cec5SDimitry Andric /// Starting from \Reg, expand the closure as much as possible. 410*0b57cec5SDimitry Andric void buildClosure(Closure &, unsigned Reg); 411*0b57cec5SDimitry Andric 412*0b57cec5SDimitry Andric /// Enqueue \p Reg to be considered for addition to the closure. 413*0b57cec5SDimitry Andric void visitRegister(Closure &, unsigned Reg, RegDomain &Domain, 414*0b57cec5SDimitry Andric SmallVectorImpl<unsigned> &Worklist); 415*0b57cec5SDimitry Andric 416*0b57cec5SDimitry Andric /// Reassign the closure to \p Domain. 417*0b57cec5SDimitry Andric void reassign(const Closure &C, RegDomain Domain) const; 418*0b57cec5SDimitry Andric 419*0b57cec5SDimitry Andric /// Add \p MI to the closure. 420*0b57cec5SDimitry Andric void encloseInstr(Closure &C, MachineInstr *MI); 421*0b57cec5SDimitry Andric 422*0b57cec5SDimitry Andric /// /returns true if it is profitable to reassign the closure to \p Domain. 423*0b57cec5SDimitry Andric bool isReassignmentProfitable(const Closure &C, RegDomain Domain) const; 424*0b57cec5SDimitry Andric 425*0b57cec5SDimitry Andric /// Calculate the total cost of reassigning the closure to \p Domain. 426*0b57cec5SDimitry Andric double calculateCost(const Closure &C, RegDomain Domain) const; 427*0b57cec5SDimitry Andric }; 428*0b57cec5SDimitry Andric 429*0b57cec5SDimitry Andric char X86DomainReassignment::ID = 0; 430*0b57cec5SDimitry Andric 431*0b57cec5SDimitry Andric } // End anonymous namespace. 432*0b57cec5SDimitry Andric 433*0b57cec5SDimitry Andric void X86DomainReassignment::visitRegister(Closure &C, unsigned Reg, 434*0b57cec5SDimitry Andric RegDomain &Domain, 435*0b57cec5SDimitry Andric SmallVectorImpl<unsigned> &Worklist) { 436*0b57cec5SDimitry Andric if (EnclosedEdges.count(Reg)) 437*0b57cec5SDimitry Andric return; 438*0b57cec5SDimitry Andric 439*0b57cec5SDimitry Andric if (!TargetRegisterInfo::isVirtualRegister(Reg)) 440*0b57cec5SDimitry Andric return; 441*0b57cec5SDimitry Andric 442*0b57cec5SDimitry Andric if (!MRI->hasOneDef(Reg)) 443*0b57cec5SDimitry Andric return; 444*0b57cec5SDimitry Andric 445*0b57cec5SDimitry Andric RegDomain RD = getDomain(MRI->getRegClass(Reg), MRI->getTargetRegisterInfo()); 446*0b57cec5SDimitry Andric // First edge in closure sets the domain. 447*0b57cec5SDimitry Andric if (Domain == NoDomain) 448*0b57cec5SDimitry Andric Domain = RD; 449*0b57cec5SDimitry Andric 450*0b57cec5SDimitry Andric if (Domain != RD) 451*0b57cec5SDimitry Andric return; 452*0b57cec5SDimitry Andric 453*0b57cec5SDimitry Andric Worklist.push_back(Reg); 454*0b57cec5SDimitry Andric } 455*0b57cec5SDimitry Andric 456*0b57cec5SDimitry Andric void X86DomainReassignment::encloseInstr(Closure &C, MachineInstr *MI) { 457*0b57cec5SDimitry Andric auto I = EnclosedInstrs.find(MI); 458*0b57cec5SDimitry Andric if (I != EnclosedInstrs.end()) { 459*0b57cec5SDimitry Andric if (I->second != C.getID()) 460*0b57cec5SDimitry Andric // Instruction already belongs to another closure, avoid conflicts between 461*0b57cec5SDimitry Andric // closure and mark this closure as illegal. 462*0b57cec5SDimitry Andric C.setAllIllegal(); 463*0b57cec5SDimitry Andric return; 464*0b57cec5SDimitry Andric } 465*0b57cec5SDimitry Andric 466*0b57cec5SDimitry Andric EnclosedInstrs[MI] = C.getID(); 467*0b57cec5SDimitry Andric C.addInstruction(MI); 468*0b57cec5SDimitry Andric 469*0b57cec5SDimitry Andric // Mark closure as illegal for reassignment to domains, if there is no 470*0b57cec5SDimitry Andric // converter for the instruction or if the converter cannot convert the 471*0b57cec5SDimitry Andric // instruction. 472*0b57cec5SDimitry Andric for (int i = 0; i != NumDomains; ++i) { 473*0b57cec5SDimitry Andric if (C.isLegal((RegDomain)i)) { 474*0b57cec5SDimitry Andric InstrConverterBase *IC = Converters.lookup({i, MI->getOpcode()}); 475*0b57cec5SDimitry Andric if (!IC || !IC->isLegal(MI, TII)) 476*0b57cec5SDimitry Andric C.setIllegal((RegDomain)i); 477*0b57cec5SDimitry Andric } 478*0b57cec5SDimitry Andric } 479*0b57cec5SDimitry Andric } 480*0b57cec5SDimitry Andric 481*0b57cec5SDimitry Andric double X86DomainReassignment::calculateCost(const Closure &C, 482*0b57cec5SDimitry Andric RegDomain DstDomain) const { 483*0b57cec5SDimitry Andric assert(C.isLegal(DstDomain) && "Cannot calculate cost for illegal closure"); 484*0b57cec5SDimitry Andric 485*0b57cec5SDimitry Andric double Cost = 0.0; 486*0b57cec5SDimitry Andric for (auto *MI : C.instructions()) 487*0b57cec5SDimitry Andric Cost += 488*0b57cec5SDimitry Andric Converters.lookup({DstDomain, MI->getOpcode()})->getExtraCost(MI, MRI); 489*0b57cec5SDimitry Andric return Cost; 490*0b57cec5SDimitry Andric } 491*0b57cec5SDimitry Andric 492*0b57cec5SDimitry Andric bool X86DomainReassignment::isReassignmentProfitable(const Closure &C, 493*0b57cec5SDimitry Andric RegDomain Domain) const { 494*0b57cec5SDimitry Andric return calculateCost(C, Domain) < 0.0; 495*0b57cec5SDimitry Andric } 496*0b57cec5SDimitry Andric 497*0b57cec5SDimitry Andric void X86DomainReassignment::reassign(const Closure &C, RegDomain Domain) const { 498*0b57cec5SDimitry Andric assert(C.isLegal(Domain) && "Cannot convert illegal closure"); 499*0b57cec5SDimitry Andric 500*0b57cec5SDimitry Andric // Iterate all instructions in the closure, convert each one using the 501*0b57cec5SDimitry Andric // appropriate converter. 502*0b57cec5SDimitry Andric SmallVector<MachineInstr *, 8> ToErase; 503*0b57cec5SDimitry Andric for (auto *MI : C.instructions()) 504*0b57cec5SDimitry Andric if (Converters.lookup({Domain, MI->getOpcode()}) 505*0b57cec5SDimitry Andric ->convertInstr(MI, TII, MRI)) 506*0b57cec5SDimitry Andric ToErase.push_back(MI); 507*0b57cec5SDimitry Andric 508*0b57cec5SDimitry Andric // Iterate all registers in the closure, replace them with registers in the 509*0b57cec5SDimitry Andric // destination domain. 510*0b57cec5SDimitry Andric for (unsigned Reg : C.edges()) { 511*0b57cec5SDimitry Andric MRI->setRegClass(Reg, getDstRC(MRI->getRegClass(Reg), Domain)); 512*0b57cec5SDimitry Andric for (auto &MO : MRI->use_operands(Reg)) { 513*0b57cec5SDimitry Andric if (MO.isReg()) 514*0b57cec5SDimitry Andric // Remove all subregister references as they are not valid in the 515*0b57cec5SDimitry Andric // destination domain. 516*0b57cec5SDimitry Andric MO.setSubReg(0); 517*0b57cec5SDimitry Andric } 518*0b57cec5SDimitry Andric } 519*0b57cec5SDimitry Andric 520*0b57cec5SDimitry Andric for (auto MI : ToErase) 521*0b57cec5SDimitry Andric MI->eraseFromParent(); 522*0b57cec5SDimitry Andric } 523*0b57cec5SDimitry Andric 524*0b57cec5SDimitry Andric /// \returns true when \p Reg is used as part of an address calculation in \p 525*0b57cec5SDimitry Andric /// MI. 526*0b57cec5SDimitry Andric static bool usedAsAddr(const MachineInstr &MI, unsigned Reg, 527*0b57cec5SDimitry Andric const TargetInstrInfo *TII) { 528*0b57cec5SDimitry Andric if (!MI.mayLoadOrStore()) 529*0b57cec5SDimitry Andric return false; 530*0b57cec5SDimitry Andric 531*0b57cec5SDimitry Andric const MCInstrDesc &Desc = TII->get(MI.getOpcode()); 532*0b57cec5SDimitry Andric int MemOpStart = X86II::getMemoryOperandNo(Desc.TSFlags); 533*0b57cec5SDimitry Andric if (MemOpStart == -1) 534*0b57cec5SDimitry Andric return false; 535*0b57cec5SDimitry Andric 536*0b57cec5SDimitry Andric MemOpStart += X86II::getOperandBias(Desc); 537*0b57cec5SDimitry Andric for (unsigned MemOpIdx = MemOpStart, 538*0b57cec5SDimitry Andric MemOpEnd = MemOpStart + X86::AddrNumOperands; 539*0b57cec5SDimitry Andric MemOpIdx < MemOpEnd; ++MemOpIdx) { 540*0b57cec5SDimitry Andric auto &Op = MI.getOperand(MemOpIdx); 541*0b57cec5SDimitry Andric if (Op.isReg() && Op.getReg() == Reg) 542*0b57cec5SDimitry Andric return true; 543*0b57cec5SDimitry Andric } 544*0b57cec5SDimitry Andric return false; 545*0b57cec5SDimitry Andric } 546*0b57cec5SDimitry Andric 547*0b57cec5SDimitry Andric void X86DomainReassignment::buildClosure(Closure &C, unsigned Reg) { 548*0b57cec5SDimitry Andric SmallVector<unsigned, 4> Worklist; 549*0b57cec5SDimitry Andric RegDomain Domain = NoDomain; 550*0b57cec5SDimitry Andric visitRegister(C, Reg, Domain, Worklist); 551*0b57cec5SDimitry Andric while (!Worklist.empty()) { 552*0b57cec5SDimitry Andric unsigned CurReg = Worklist.pop_back_val(); 553*0b57cec5SDimitry Andric 554*0b57cec5SDimitry Andric // Register already in this closure. 555*0b57cec5SDimitry Andric if (!C.insertEdge(CurReg)) 556*0b57cec5SDimitry Andric continue; 557*0b57cec5SDimitry Andric EnclosedEdges.insert(Reg); 558*0b57cec5SDimitry Andric 559*0b57cec5SDimitry Andric MachineInstr *DefMI = MRI->getVRegDef(CurReg); 560*0b57cec5SDimitry Andric encloseInstr(C, DefMI); 561*0b57cec5SDimitry Andric 562*0b57cec5SDimitry Andric // Add register used by the defining MI to the worklist. 563*0b57cec5SDimitry Andric // Do not add registers which are used in address calculation, they will be 564*0b57cec5SDimitry Andric // added to a different closure. 565*0b57cec5SDimitry Andric int OpEnd = DefMI->getNumOperands(); 566*0b57cec5SDimitry Andric const MCInstrDesc &Desc = DefMI->getDesc(); 567*0b57cec5SDimitry Andric int MemOp = X86II::getMemoryOperandNo(Desc.TSFlags); 568*0b57cec5SDimitry Andric if (MemOp != -1) 569*0b57cec5SDimitry Andric MemOp += X86II::getOperandBias(Desc); 570*0b57cec5SDimitry Andric for (int OpIdx = 0; OpIdx < OpEnd; ++OpIdx) { 571*0b57cec5SDimitry Andric if (OpIdx == MemOp) { 572*0b57cec5SDimitry Andric // skip address calculation. 573*0b57cec5SDimitry Andric OpIdx += (X86::AddrNumOperands - 1); 574*0b57cec5SDimitry Andric continue; 575*0b57cec5SDimitry Andric } 576*0b57cec5SDimitry Andric auto &Op = DefMI->getOperand(OpIdx); 577*0b57cec5SDimitry Andric if (!Op.isReg() || !Op.isUse()) 578*0b57cec5SDimitry Andric continue; 579*0b57cec5SDimitry Andric visitRegister(C, Op.getReg(), Domain, Worklist); 580*0b57cec5SDimitry Andric } 581*0b57cec5SDimitry Andric 582*0b57cec5SDimitry Andric // Expand closure through register uses. 583*0b57cec5SDimitry Andric for (auto &UseMI : MRI->use_nodbg_instructions(CurReg)) { 584*0b57cec5SDimitry Andric // We would like to avoid converting closures which calculare addresses, 585*0b57cec5SDimitry Andric // as this should remain in GPRs. 586*0b57cec5SDimitry Andric if (usedAsAddr(UseMI, CurReg, TII)) { 587*0b57cec5SDimitry Andric C.setAllIllegal(); 588*0b57cec5SDimitry Andric continue; 589*0b57cec5SDimitry Andric } 590*0b57cec5SDimitry Andric encloseInstr(C, &UseMI); 591*0b57cec5SDimitry Andric 592*0b57cec5SDimitry Andric for (auto &DefOp : UseMI.defs()) { 593*0b57cec5SDimitry Andric if (!DefOp.isReg()) 594*0b57cec5SDimitry Andric continue; 595*0b57cec5SDimitry Andric 596*0b57cec5SDimitry Andric unsigned DefReg = DefOp.getReg(); 597*0b57cec5SDimitry Andric if (!TargetRegisterInfo::isVirtualRegister(DefReg)) { 598*0b57cec5SDimitry Andric C.setAllIllegal(); 599*0b57cec5SDimitry Andric continue; 600*0b57cec5SDimitry Andric } 601*0b57cec5SDimitry Andric visitRegister(C, DefReg, Domain, Worklist); 602*0b57cec5SDimitry Andric } 603*0b57cec5SDimitry Andric } 604*0b57cec5SDimitry Andric } 605*0b57cec5SDimitry Andric } 606*0b57cec5SDimitry Andric 607*0b57cec5SDimitry Andric void X86DomainReassignment::initConverters() { 608*0b57cec5SDimitry Andric Converters[{MaskDomain, TargetOpcode::PHI}] = 609*0b57cec5SDimitry Andric new InstrIgnore(TargetOpcode::PHI); 610*0b57cec5SDimitry Andric 611*0b57cec5SDimitry Andric Converters[{MaskDomain, TargetOpcode::IMPLICIT_DEF}] = 612*0b57cec5SDimitry Andric new InstrIgnore(TargetOpcode::IMPLICIT_DEF); 613*0b57cec5SDimitry Andric 614*0b57cec5SDimitry Andric Converters[{MaskDomain, TargetOpcode::INSERT_SUBREG}] = 615*0b57cec5SDimitry Andric new InstrReplaceWithCopy(TargetOpcode::INSERT_SUBREG, 2); 616*0b57cec5SDimitry Andric 617*0b57cec5SDimitry Andric Converters[{MaskDomain, TargetOpcode::COPY}] = 618*0b57cec5SDimitry Andric new InstrCOPYReplacer(TargetOpcode::COPY, MaskDomain, TargetOpcode::COPY); 619*0b57cec5SDimitry Andric 620*0b57cec5SDimitry Andric auto createReplacerDstCOPY = [&](unsigned From, unsigned To) { 621*0b57cec5SDimitry Andric Converters[{MaskDomain, From}] = new InstrReplacerDstCOPY(From, To); 622*0b57cec5SDimitry Andric }; 623*0b57cec5SDimitry Andric 624*0b57cec5SDimitry Andric createReplacerDstCOPY(X86::MOVZX32rm16, X86::KMOVWkm); 625*0b57cec5SDimitry Andric createReplacerDstCOPY(X86::MOVZX64rm16, X86::KMOVWkm); 626*0b57cec5SDimitry Andric 627*0b57cec5SDimitry Andric createReplacerDstCOPY(X86::MOVZX32rr16, X86::KMOVWkk); 628*0b57cec5SDimitry Andric createReplacerDstCOPY(X86::MOVZX64rr16, X86::KMOVWkk); 629*0b57cec5SDimitry Andric 630*0b57cec5SDimitry Andric if (STI->hasDQI()) { 631*0b57cec5SDimitry Andric createReplacerDstCOPY(X86::MOVZX16rm8, X86::KMOVBkm); 632*0b57cec5SDimitry Andric createReplacerDstCOPY(X86::MOVZX32rm8, X86::KMOVBkm); 633*0b57cec5SDimitry Andric createReplacerDstCOPY(X86::MOVZX64rm8, X86::KMOVBkm); 634*0b57cec5SDimitry Andric 635*0b57cec5SDimitry Andric createReplacerDstCOPY(X86::MOVZX16rr8, X86::KMOVBkk); 636*0b57cec5SDimitry Andric createReplacerDstCOPY(X86::MOVZX32rr8, X86::KMOVBkk); 637*0b57cec5SDimitry Andric createReplacerDstCOPY(X86::MOVZX64rr8, X86::KMOVBkk); 638*0b57cec5SDimitry Andric } 639*0b57cec5SDimitry Andric 640*0b57cec5SDimitry Andric auto createReplacer = [&](unsigned From, unsigned To) { 641*0b57cec5SDimitry Andric Converters[{MaskDomain, From}] = new InstrReplacer(From, To); 642*0b57cec5SDimitry Andric }; 643*0b57cec5SDimitry Andric 644*0b57cec5SDimitry Andric createReplacer(X86::MOV16rm, X86::KMOVWkm); 645*0b57cec5SDimitry Andric createReplacer(X86::MOV16mr, X86::KMOVWmk); 646*0b57cec5SDimitry Andric createReplacer(X86::MOV16rr, X86::KMOVWkk); 647*0b57cec5SDimitry Andric createReplacer(X86::SHR16ri, X86::KSHIFTRWri); 648*0b57cec5SDimitry Andric createReplacer(X86::SHL16ri, X86::KSHIFTLWri); 649*0b57cec5SDimitry Andric createReplacer(X86::NOT16r, X86::KNOTWrr); 650*0b57cec5SDimitry Andric createReplacer(X86::OR16rr, X86::KORWrr); 651*0b57cec5SDimitry Andric createReplacer(X86::AND16rr, X86::KANDWrr); 652*0b57cec5SDimitry Andric createReplacer(X86::XOR16rr, X86::KXORWrr); 653*0b57cec5SDimitry Andric 654*0b57cec5SDimitry Andric if (STI->hasBWI()) { 655*0b57cec5SDimitry Andric createReplacer(X86::MOV32rm, X86::KMOVDkm); 656*0b57cec5SDimitry Andric createReplacer(X86::MOV64rm, X86::KMOVQkm); 657*0b57cec5SDimitry Andric 658*0b57cec5SDimitry Andric createReplacer(X86::MOV32mr, X86::KMOVDmk); 659*0b57cec5SDimitry Andric createReplacer(X86::MOV64mr, X86::KMOVQmk); 660*0b57cec5SDimitry Andric 661*0b57cec5SDimitry Andric createReplacer(X86::MOV32rr, X86::KMOVDkk); 662*0b57cec5SDimitry Andric createReplacer(X86::MOV64rr, X86::KMOVQkk); 663*0b57cec5SDimitry Andric 664*0b57cec5SDimitry Andric createReplacer(X86::SHR32ri, X86::KSHIFTRDri); 665*0b57cec5SDimitry Andric createReplacer(X86::SHR64ri, X86::KSHIFTRQri); 666*0b57cec5SDimitry Andric 667*0b57cec5SDimitry Andric createReplacer(X86::SHL32ri, X86::KSHIFTLDri); 668*0b57cec5SDimitry Andric createReplacer(X86::SHL64ri, X86::KSHIFTLQri); 669*0b57cec5SDimitry Andric 670*0b57cec5SDimitry Andric createReplacer(X86::ADD32rr, X86::KADDDrr); 671*0b57cec5SDimitry Andric createReplacer(X86::ADD64rr, X86::KADDQrr); 672*0b57cec5SDimitry Andric 673*0b57cec5SDimitry Andric createReplacer(X86::NOT32r, X86::KNOTDrr); 674*0b57cec5SDimitry Andric createReplacer(X86::NOT64r, X86::KNOTQrr); 675*0b57cec5SDimitry Andric 676*0b57cec5SDimitry Andric createReplacer(X86::OR32rr, X86::KORDrr); 677*0b57cec5SDimitry Andric createReplacer(X86::OR64rr, X86::KORQrr); 678*0b57cec5SDimitry Andric 679*0b57cec5SDimitry Andric createReplacer(X86::AND32rr, X86::KANDDrr); 680*0b57cec5SDimitry Andric createReplacer(X86::AND64rr, X86::KANDQrr); 681*0b57cec5SDimitry Andric 682*0b57cec5SDimitry Andric createReplacer(X86::ANDN32rr, X86::KANDNDrr); 683*0b57cec5SDimitry Andric createReplacer(X86::ANDN64rr, X86::KANDNQrr); 684*0b57cec5SDimitry Andric 685*0b57cec5SDimitry Andric createReplacer(X86::XOR32rr, X86::KXORDrr); 686*0b57cec5SDimitry Andric createReplacer(X86::XOR64rr, X86::KXORQrr); 687*0b57cec5SDimitry Andric 688*0b57cec5SDimitry Andric // TODO: KTEST is not a replacement for TEST due to flag differences. Need 689*0b57cec5SDimitry Andric // to prove only Z flag is used. 690*0b57cec5SDimitry Andric //createReplacer(X86::TEST32rr, X86::KTESTDrr); 691*0b57cec5SDimitry Andric //createReplacer(X86::TEST64rr, X86::KTESTQrr); 692*0b57cec5SDimitry Andric } 693*0b57cec5SDimitry Andric 694*0b57cec5SDimitry Andric if (STI->hasDQI()) { 695*0b57cec5SDimitry Andric createReplacer(X86::ADD8rr, X86::KADDBrr); 696*0b57cec5SDimitry Andric createReplacer(X86::ADD16rr, X86::KADDWrr); 697*0b57cec5SDimitry Andric 698*0b57cec5SDimitry Andric createReplacer(X86::AND8rr, X86::KANDBrr); 699*0b57cec5SDimitry Andric 700*0b57cec5SDimitry Andric createReplacer(X86::MOV8rm, X86::KMOVBkm); 701*0b57cec5SDimitry Andric createReplacer(X86::MOV8mr, X86::KMOVBmk); 702*0b57cec5SDimitry Andric createReplacer(X86::MOV8rr, X86::KMOVBkk); 703*0b57cec5SDimitry Andric 704*0b57cec5SDimitry Andric createReplacer(X86::NOT8r, X86::KNOTBrr); 705*0b57cec5SDimitry Andric 706*0b57cec5SDimitry Andric createReplacer(X86::OR8rr, X86::KORBrr); 707*0b57cec5SDimitry Andric 708*0b57cec5SDimitry Andric createReplacer(X86::SHR8ri, X86::KSHIFTRBri); 709*0b57cec5SDimitry Andric createReplacer(X86::SHL8ri, X86::KSHIFTLBri); 710*0b57cec5SDimitry Andric 711*0b57cec5SDimitry Andric // TODO: KTEST is not a replacement for TEST due to flag differences. Need 712*0b57cec5SDimitry Andric // to prove only Z flag is used. 713*0b57cec5SDimitry Andric //createReplacer(X86::TEST8rr, X86::KTESTBrr); 714*0b57cec5SDimitry Andric //createReplacer(X86::TEST16rr, X86::KTESTWrr); 715*0b57cec5SDimitry Andric 716*0b57cec5SDimitry Andric createReplacer(X86::XOR8rr, X86::KXORBrr); 717*0b57cec5SDimitry Andric } 718*0b57cec5SDimitry Andric } 719*0b57cec5SDimitry Andric 720*0b57cec5SDimitry Andric bool X86DomainReassignment::runOnMachineFunction(MachineFunction &MF) { 721*0b57cec5SDimitry Andric if (skipFunction(MF.getFunction())) 722*0b57cec5SDimitry Andric return false; 723*0b57cec5SDimitry Andric if (DisableX86DomainReassignment) 724*0b57cec5SDimitry Andric return false; 725*0b57cec5SDimitry Andric 726*0b57cec5SDimitry Andric LLVM_DEBUG( 727*0b57cec5SDimitry Andric dbgs() << "***** Machine Function before Domain Reassignment *****\n"); 728*0b57cec5SDimitry Andric LLVM_DEBUG(MF.print(dbgs())); 729*0b57cec5SDimitry Andric 730*0b57cec5SDimitry Andric STI = &MF.getSubtarget<X86Subtarget>(); 731*0b57cec5SDimitry Andric // GPR->K is the only transformation currently supported, bail out early if no 732*0b57cec5SDimitry Andric // AVX512. 733*0b57cec5SDimitry Andric // TODO: We're also bailing of AVX512BW isn't supported since we use VK32 and 734*0b57cec5SDimitry Andric // VK64 for GR32/GR64, but those aren't legal classes on KNL. If the register 735*0b57cec5SDimitry Andric // coalescer doesn't clean it up and we generate a spill we will crash. 736*0b57cec5SDimitry Andric if (!STI->hasAVX512() || !STI->hasBWI()) 737*0b57cec5SDimitry Andric return false; 738*0b57cec5SDimitry Andric 739*0b57cec5SDimitry Andric MRI = &MF.getRegInfo(); 740*0b57cec5SDimitry Andric assert(MRI->isSSA() && "Expected MIR to be in SSA form"); 741*0b57cec5SDimitry Andric 742*0b57cec5SDimitry Andric TII = STI->getInstrInfo(); 743*0b57cec5SDimitry Andric initConverters(); 744*0b57cec5SDimitry Andric bool Changed = false; 745*0b57cec5SDimitry Andric 746*0b57cec5SDimitry Andric EnclosedEdges.clear(); 747*0b57cec5SDimitry Andric EnclosedInstrs.clear(); 748*0b57cec5SDimitry Andric 749*0b57cec5SDimitry Andric std::vector<Closure> Closures; 750*0b57cec5SDimitry Andric 751*0b57cec5SDimitry Andric // Go over all virtual registers and calculate a closure. 752*0b57cec5SDimitry Andric unsigned ClosureID = 0; 753*0b57cec5SDimitry Andric for (unsigned Idx = 0; Idx < MRI->getNumVirtRegs(); ++Idx) { 754*0b57cec5SDimitry Andric unsigned Reg = TargetRegisterInfo::index2VirtReg(Idx); 755*0b57cec5SDimitry Andric 756*0b57cec5SDimitry Andric // GPR only current source domain supported. 757*0b57cec5SDimitry Andric if (!isGPR(MRI->getRegClass(Reg))) 758*0b57cec5SDimitry Andric continue; 759*0b57cec5SDimitry Andric 760*0b57cec5SDimitry Andric // Register already in closure. 761*0b57cec5SDimitry Andric if (EnclosedEdges.count(Reg)) 762*0b57cec5SDimitry Andric continue; 763*0b57cec5SDimitry Andric 764*0b57cec5SDimitry Andric // Calculate closure starting with Reg. 765*0b57cec5SDimitry Andric Closure C(ClosureID++, {MaskDomain}); 766*0b57cec5SDimitry Andric buildClosure(C, Reg); 767*0b57cec5SDimitry Andric 768*0b57cec5SDimitry Andric // Collect all closures that can potentially be converted. 769*0b57cec5SDimitry Andric if (!C.empty() && C.isLegal(MaskDomain)) 770*0b57cec5SDimitry Andric Closures.push_back(std::move(C)); 771*0b57cec5SDimitry Andric } 772*0b57cec5SDimitry Andric 773*0b57cec5SDimitry Andric for (Closure &C : Closures) { 774*0b57cec5SDimitry Andric LLVM_DEBUG(C.dump(MRI)); 775*0b57cec5SDimitry Andric if (isReassignmentProfitable(C, MaskDomain)) { 776*0b57cec5SDimitry Andric reassign(C, MaskDomain); 777*0b57cec5SDimitry Andric ++NumClosuresConverted; 778*0b57cec5SDimitry Andric Changed = true; 779*0b57cec5SDimitry Andric } 780*0b57cec5SDimitry Andric } 781*0b57cec5SDimitry Andric 782*0b57cec5SDimitry Andric DeleteContainerSeconds(Converters); 783*0b57cec5SDimitry Andric 784*0b57cec5SDimitry Andric LLVM_DEBUG( 785*0b57cec5SDimitry Andric dbgs() << "***** Machine Function after Domain Reassignment *****\n"); 786*0b57cec5SDimitry Andric LLVM_DEBUG(MF.print(dbgs())); 787*0b57cec5SDimitry Andric 788*0b57cec5SDimitry Andric return Changed; 789*0b57cec5SDimitry Andric } 790*0b57cec5SDimitry Andric 791*0b57cec5SDimitry Andric INITIALIZE_PASS(X86DomainReassignment, "x86-domain-reassignment", 792*0b57cec5SDimitry Andric "X86 Domain Reassignment Pass", false, false) 793*0b57cec5SDimitry Andric 794*0b57cec5SDimitry Andric /// Returns an instance of the Domain Reassignment pass. 795*0b57cec5SDimitry Andric FunctionPass *llvm::createX86DomainReassignmentPass() { 796*0b57cec5SDimitry Andric return new X86DomainReassignment(); 797*0b57cec5SDimitry Andric } 798