10b57cec5SDimitry Andric //===--- X86DomainReassignment.cpp - Selectively switch register classes---===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This pass attempts to find instruction chains (closures) in one domain, 100b57cec5SDimitry Andric // and convert them to equivalent instructions in a different domain, 110b57cec5SDimitry Andric // if profitable. 120b57cec5SDimitry Andric // 130b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #include "X86.h" 160b57cec5SDimitry Andric #include "X86InstrInfo.h" 170b57cec5SDimitry Andric #include "X86Subtarget.h" 180b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 190b57cec5SDimitry Andric #include "llvm/ADT/DenseMapInfo.h" 200b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 210b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 220b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 230b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 240b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 250b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 260b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 270b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 280b57cec5SDimitry Andric #include "llvm/Support/Printable.h" 290b57cec5SDimitry Andric #include <bitset> 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric using namespace llvm; 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric #define DEBUG_TYPE "x86-domain-reassignment" 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric STATISTIC(NumClosuresConverted, "Number of closures converted by the pass"); 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric static cl::opt<bool> DisableX86DomainReassignment( 380b57cec5SDimitry Andric "disable-x86-domain-reassignment", cl::Hidden, 390b57cec5SDimitry Andric cl::desc("X86: Disable Virtual Register Reassignment."), cl::init(false)); 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric namespace { 420b57cec5SDimitry Andric enum RegDomain { NoDomain = -1, GPRDomain, MaskDomain, OtherDomain, NumDomains }; 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric static bool isGPR(const TargetRegisterClass *RC) { 450b57cec5SDimitry Andric return X86::GR64RegClass.hasSubClassEq(RC) || 460b57cec5SDimitry Andric X86::GR32RegClass.hasSubClassEq(RC) || 470b57cec5SDimitry Andric X86::GR16RegClass.hasSubClassEq(RC) || 480b57cec5SDimitry Andric X86::GR8RegClass.hasSubClassEq(RC); 490b57cec5SDimitry Andric } 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric static bool isMask(const TargetRegisterClass *RC, 520b57cec5SDimitry Andric const TargetRegisterInfo *TRI) { 530b57cec5SDimitry Andric return X86::VK16RegClass.hasSubClassEq(RC); 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric static RegDomain getDomain(const TargetRegisterClass *RC, 570b57cec5SDimitry Andric const TargetRegisterInfo *TRI) { 580b57cec5SDimitry Andric if (isGPR(RC)) 590b57cec5SDimitry Andric return GPRDomain; 600b57cec5SDimitry Andric if (isMask(RC, TRI)) 610b57cec5SDimitry Andric return MaskDomain; 620b57cec5SDimitry Andric return OtherDomain; 630b57cec5SDimitry Andric } 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric /// Return a register class equivalent to \p SrcRC, in \p Domain. 660b57cec5SDimitry Andric static const TargetRegisterClass *getDstRC(const TargetRegisterClass *SrcRC, 670b57cec5SDimitry Andric RegDomain Domain) { 680b57cec5SDimitry Andric assert(Domain == MaskDomain && "add domain"); 690b57cec5SDimitry Andric if (X86::GR8RegClass.hasSubClassEq(SrcRC)) 700b57cec5SDimitry Andric return &X86::VK8RegClass; 710b57cec5SDimitry Andric if (X86::GR16RegClass.hasSubClassEq(SrcRC)) 720b57cec5SDimitry Andric return &X86::VK16RegClass; 730b57cec5SDimitry Andric if (X86::GR32RegClass.hasSubClassEq(SrcRC)) 740b57cec5SDimitry Andric return &X86::VK32RegClass; 750b57cec5SDimitry Andric if (X86::GR64RegClass.hasSubClassEq(SrcRC)) 760b57cec5SDimitry Andric return &X86::VK64RegClass; 770b57cec5SDimitry Andric llvm_unreachable("add register class"); 780b57cec5SDimitry Andric return nullptr; 790b57cec5SDimitry Andric } 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric /// Abstract Instruction Converter class. 820b57cec5SDimitry Andric class InstrConverterBase { 830b57cec5SDimitry Andric protected: 840b57cec5SDimitry Andric unsigned SrcOpcode; 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric public: 870b57cec5SDimitry Andric InstrConverterBase(unsigned SrcOpcode) : SrcOpcode(SrcOpcode) {} 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric virtual ~InstrConverterBase() {} 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric /// \returns true if \p MI is legal to convert. 920b57cec5SDimitry Andric virtual bool isLegal(const MachineInstr *MI, 930b57cec5SDimitry Andric const TargetInstrInfo *TII) const { 940b57cec5SDimitry Andric assert(MI->getOpcode() == SrcOpcode && 950b57cec5SDimitry Andric "Wrong instruction passed to converter"); 960b57cec5SDimitry Andric return true; 970b57cec5SDimitry Andric } 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric /// Applies conversion to \p MI. 1000b57cec5SDimitry Andric /// 1010b57cec5SDimitry Andric /// \returns true if \p MI is no longer need, and can be deleted. 1020b57cec5SDimitry Andric virtual bool convertInstr(MachineInstr *MI, const TargetInstrInfo *TII, 1030b57cec5SDimitry Andric MachineRegisterInfo *MRI) const = 0; 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric /// \returns the cost increment incurred by converting \p MI. 1060b57cec5SDimitry Andric virtual double getExtraCost(const MachineInstr *MI, 1070b57cec5SDimitry Andric MachineRegisterInfo *MRI) const = 0; 1080b57cec5SDimitry Andric }; 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric /// An Instruction Converter which ignores the given instruction. 1110b57cec5SDimitry Andric /// For example, PHI instructions can be safely ignored since only the registers 1120b57cec5SDimitry Andric /// need to change. 1130b57cec5SDimitry Andric class InstrIgnore : public InstrConverterBase { 1140b57cec5SDimitry Andric public: 1150b57cec5SDimitry Andric InstrIgnore(unsigned SrcOpcode) : InstrConverterBase(SrcOpcode) {} 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric bool convertInstr(MachineInstr *MI, const TargetInstrInfo *TII, 1180b57cec5SDimitry Andric MachineRegisterInfo *MRI) const override { 1190b57cec5SDimitry Andric assert(isLegal(MI, TII) && "Cannot convert instruction"); 1200b57cec5SDimitry Andric return false; 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric double getExtraCost(const MachineInstr *MI, 1240b57cec5SDimitry Andric MachineRegisterInfo *MRI) const override { 1250b57cec5SDimitry Andric return 0; 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric }; 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric /// An Instruction Converter which replaces an instruction with another. 1300b57cec5SDimitry Andric class InstrReplacer : public InstrConverterBase { 1310b57cec5SDimitry Andric public: 1320b57cec5SDimitry Andric /// Opcode of the destination instruction. 1330b57cec5SDimitry Andric unsigned DstOpcode; 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric InstrReplacer(unsigned SrcOpcode, unsigned DstOpcode) 1360b57cec5SDimitry Andric : InstrConverterBase(SrcOpcode), DstOpcode(DstOpcode) {} 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric bool isLegal(const MachineInstr *MI, 1390b57cec5SDimitry Andric const TargetInstrInfo *TII) const override { 1400b57cec5SDimitry Andric if (!InstrConverterBase::isLegal(MI, TII)) 1410b57cec5SDimitry Andric return false; 1420b57cec5SDimitry Andric // It's illegal to replace an instruction that implicitly defines a register 1430b57cec5SDimitry Andric // with an instruction that doesn't, unless that register dead. 1440b57cec5SDimitry Andric for (auto &MO : MI->implicit_operands()) 1450b57cec5SDimitry Andric if (MO.isReg() && MO.isDef() && !MO.isDead() && 1460b57cec5SDimitry Andric !TII->get(DstOpcode).hasImplicitDefOfPhysReg(MO.getReg())) 1470b57cec5SDimitry Andric return false; 1480b57cec5SDimitry Andric return true; 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric bool convertInstr(MachineInstr *MI, const TargetInstrInfo *TII, 1520b57cec5SDimitry Andric MachineRegisterInfo *MRI) const override { 1530b57cec5SDimitry Andric assert(isLegal(MI, TII) && "Cannot convert instruction"); 1540b57cec5SDimitry Andric MachineInstrBuilder Bld = 1550b57cec5SDimitry Andric BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), TII->get(DstOpcode)); 1560b57cec5SDimitry Andric // Transfer explicit operands from original instruction. Implicit operands 1570b57cec5SDimitry Andric // are handled by BuildMI. 1580b57cec5SDimitry Andric for (auto &Op : MI->explicit_operands()) 1590b57cec5SDimitry Andric Bld.add(Op); 1600b57cec5SDimitry Andric return true; 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric double getExtraCost(const MachineInstr *MI, 1640b57cec5SDimitry Andric MachineRegisterInfo *MRI) const override { 1650b57cec5SDimitry Andric // Assuming instructions have the same cost. 1660b57cec5SDimitry Andric return 0; 1670b57cec5SDimitry Andric } 1680b57cec5SDimitry Andric }; 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric /// An Instruction Converter which replaces an instruction with another, and 1710b57cec5SDimitry Andric /// adds a COPY from the new instruction's destination to the old one's. 1720b57cec5SDimitry Andric class InstrReplacerDstCOPY : public InstrConverterBase { 1730b57cec5SDimitry Andric public: 1740b57cec5SDimitry Andric unsigned DstOpcode; 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric InstrReplacerDstCOPY(unsigned SrcOpcode, unsigned DstOpcode) 1770b57cec5SDimitry Andric : InstrConverterBase(SrcOpcode), DstOpcode(DstOpcode) {} 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric bool convertInstr(MachineInstr *MI, const TargetInstrInfo *TII, 1800b57cec5SDimitry Andric MachineRegisterInfo *MRI) const override { 1810b57cec5SDimitry Andric assert(isLegal(MI, TII) && "Cannot convert instruction"); 1820b57cec5SDimitry Andric MachineBasicBlock *MBB = MI->getParent(); 1830b57cec5SDimitry Andric auto &DL = MI->getDebugLoc(); 1840b57cec5SDimitry Andric 185*8bcb0991SDimitry Andric Register Reg = MRI->createVirtualRegister( 1860b57cec5SDimitry Andric TII->getRegClass(TII->get(DstOpcode), 0, MRI->getTargetRegisterInfo(), 1870b57cec5SDimitry Andric *MBB->getParent())); 1880b57cec5SDimitry Andric MachineInstrBuilder Bld = BuildMI(*MBB, MI, DL, TII->get(DstOpcode), Reg); 1890b57cec5SDimitry Andric for (unsigned Idx = 1, End = MI->getNumOperands(); Idx < End; ++Idx) 1900b57cec5SDimitry Andric Bld.add(MI->getOperand(Idx)); 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric BuildMI(*MBB, MI, DL, TII->get(TargetOpcode::COPY)) 1930b57cec5SDimitry Andric .add(MI->getOperand(0)) 1940b57cec5SDimitry Andric .addReg(Reg); 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric return true; 1970b57cec5SDimitry Andric } 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric double getExtraCost(const MachineInstr *MI, 2000b57cec5SDimitry Andric MachineRegisterInfo *MRI) const override { 2010b57cec5SDimitry Andric // Assuming instructions have the same cost, and that COPY is in the same 2020b57cec5SDimitry Andric // domain so it will be eliminated. 2030b57cec5SDimitry Andric return 0; 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric }; 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric /// An Instruction Converter for replacing COPY instructions. 2080b57cec5SDimitry Andric class InstrCOPYReplacer : public InstrReplacer { 2090b57cec5SDimitry Andric public: 2100b57cec5SDimitry Andric RegDomain DstDomain; 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric InstrCOPYReplacer(unsigned SrcOpcode, RegDomain DstDomain, unsigned DstOpcode) 2130b57cec5SDimitry Andric : InstrReplacer(SrcOpcode, DstOpcode), DstDomain(DstDomain) {} 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric bool isLegal(const MachineInstr *MI, 2160b57cec5SDimitry Andric const TargetInstrInfo *TII) const override { 2170b57cec5SDimitry Andric if (!InstrConverterBase::isLegal(MI, TII)) 2180b57cec5SDimitry Andric return false; 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric // Don't allow copies to/flow GR8/GR16 physical registers. 2210b57cec5SDimitry Andric // FIXME: Is there some better way to support this? 222*8bcb0991SDimitry Andric Register DstReg = MI->getOperand(0).getReg(); 223*8bcb0991SDimitry Andric if (Register::isPhysicalRegister(DstReg) && 2240b57cec5SDimitry Andric (X86::GR8RegClass.contains(DstReg) || 2250b57cec5SDimitry Andric X86::GR16RegClass.contains(DstReg))) 2260b57cec5SDimitry Andric return false; 227*8bcb0991SDimitry Andric Register SrcReg = MI->getOperand(1).getReg(); 228*8bcb0991SDimitry Andric if (Register::isPhysicalRegister(SrcReg) && 2290b57cec5SDimitry Andric (X86::GR8RegClass.contains(SrcReg) || 2300b57cec5SDimitry Andric X86::GR16RegClass.contains(SrcReg))) 2310b57cec5SDimitry Andric return false; 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric return true; 2340b57cec5SDimitry Andric } 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric double getExtraCost(const MachineInstr *MI, 2370b57cec5SDimitry Andric MachineRegisterInfo *MRI) const override { 2380b57cec5SDimitry Andric assert(MI->getOpcode() == TargetOpcode::COPY && "Expected a COPY"); 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric for (auto &MO : MI->operands()) { 2410b57cec5SDimitry Andric // Physical registers will not be converted. Assume that converting the 2420b57cec5SDimitry Andric // COPY to the destination domain will eventually result in a actual 2430b57cec5SDimitry Andric // instruction. 244*8bcb0991SDimitry Andric if (Register::isPhysicalRegister(MO.getReg())) 2450b57cec5SDimitry Andric return 1; 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric RegDomain OpDomain = getDomain(MRI->getRegClass(MO.getReg()), 2480b57cec5SDimitry Andric MRI->getTargetRegisterInfo()); 2490b57cec5SDimitry Andric // Converting a cross domain COPY to a same domain COPY should eliminate 2500b57cec5SDimitry Andric // an insturction 2510b57cec5SDimitry Andric if (OpDomain == DstDomain) 2520b57cec5SDimitry Andric return -1; 2530b57cec5SDimitry Andric } 2540b57cec5SDimitry Andric return 0; 2550b57cec5SDimitry Andric } 2560b57cec5SDimitry Andric }; 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric /// An Instruction Converter which replaces an instruction with a COPY. 2590b57cec5SDimitry Andric class InstrReplaceWithCopy : public InstrConverterBase { 2600b57cec5SDimitry Andric public: 2610b57cec5SDimitry Andric // Source instruction operand Index, to be used as the COPY source. 2620b57cec5SDimitry Andric unsigned SrcOpIdx; 2630b57cec5SDimitry Andric 2640b57cec5SDimitry Andric InstrReplaceWithCopy(unsigned SrcOpcode, unsigned SrcOpIdx) 2650b57cec5SDimitry Andric : InstrConverterBase(SrcOpcode), SrcOpIdx(SrcOpIdx) {} 2660b57cec5SDimitry Andric 2670b57cec5SDimitry Andric bool convertInstr(MachineInstr *MI, const TargetInstrInfo *TII, 2680b57cec5SDimitry Andric MachineRegisterInfo *MRI) const override { 2690b57cec5SDimitry Andric assert(isLegal(MI, TII) && "Cannot convert instruction"); 2700b57cec5SDimitry Andric BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), 2710b57cec5SDimitry Andric TII->get(TargetOpcode::COPY)) 2720b57cec5SDimitry Andric .add({MI->getOperand(0), MI->getOperand(SrcOpIdx)}); 2730b57cec5SDimitry Andric return true; 2740b57cec5SDimitry Andric } 2750b57cec5SDimitry Andric 2760b57cec5SDimitry Andric double getExtraCost(const MachineInstr *MI, 2770b57cec5SDimitry Andric MachineRegisterInfo *MRI) const override { 2780b57cec5SDimitry Andric return 0; 2790b57cec5SDimitry Andric } 2800b57cec5SDimitry Andric }; 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric // Key type to be used by the Instruction Converters map. 2830b57cec5SDimitry Andric // A converter is identified by <destination domain, source opcode> 2840b57cec5SDimitry Andric typedef std::pair<int, unsigned> InstrConverterBaseKeyTy; 2850b57cec5SDimitry Andric 2860b57cec5SDimitry Andric typedef DenseMap<InstrConverterBaseKeyTy, InstrConverterBase *> 2870b57cec5SDimitry Andric InstrConverterBaseMap; 2880b57cec5SDimitry Andric 2890b57cec5SDimitry Andric /// A closure is a set of virtual register representing all of the edges in 2900b57cec5SDimitry Andric /// the closure, as well as all of the instructions connected by those edges. 2910b57cec5SDimitry Andric /// 2920b57cec5SDimitry Andric /// A closure may encompass virtual registers in the same register bank that 2930b57cec5SDimitry Andric /// have different widths. For example, it may contain 32-bit GPRs as well as 2940b57cec5SDimitry Andric /// 64-bit GPRs. 2950b57cec5SDimitry Andric /// 2960b57cec5SDimitry Andric /// A closure that computes an address (i.e. defines a virtual register that is 2970b57cec5SDimitry Andric /// used in a memory operand) excludes the instructions that contain memory 2980b57cec5SDimitry Andric /// operands using the address. Such an instruction will be included in a 2990b57cec5SDimitry Andric /// different closure that manipulates the loaded or stored value. 3000b57cec5SDimitry Andric class Closure { 3010b57cec5SDimitry Andric private: 3020b57cec5SDimitry Andric /// Virtual registers in the closure. 3030b57cec5SDimitry Andric DenseSet<unsigned> Edges; 3040b57cec5SDimitry Andric 3050b57cec5SDimitry Andric /// Instructions in the closure. 3060b57cec5SDimitry Andric SmallVector<MachineInstr *, 8> Instrs; 3070b57cec5SDimitry Andric 3080b57cec5SDimitry Andric /// Domains which this closure can legally be reassigned to. 3090b57cec5SDimitry Andric std::bitset<NumDomains> LegalDstDomains; 3100b57cec5SDimitry Andric 3110b57cec5SDimitry Andric /// An ID to uniquely identify this closure, even when it gets 3120b57cec5SDimitry Andric /// moved around 3130b57cec5SDimitry Andric unsigned ID; 3140b57cec5SDimitry Andric 3150b57cec5SDimitry Andric public: 3160b57cec5SDimitry Andric Closure(unsigned ID, std::initializer_list<RegDomain> LegalDstDomainList) : ID(ID) { 3170b57cec5SDimitry Andric for (RegDomain D : LegalDstDomainList) 3180b57cec5SDimitry Andric LegalDstDomains.set(D); 3190b57cec5SDimitry Andric } 3200b57cec5SDimitry Andric 3210b57cec5SDimitry Andric /// Mark this closure as illegal for reassignment to all domains. 3220b57cec5SDimitry Andric void setAllIllegal() { LegalDstDomains.reset(); } 3230b57cec5SDimitry Andric 3240b57cec5SDimitry Andric /// \returns true if this closure has domains which are legal to reassign to. 3250b57cec5SDimitry Andric bool hasLegalDstDomain() const { return LegalDstDomains.any(); } 3260b57cec5SDimitry Andric 3270b57cec5SDimitry Andric /// \returns true if is legal to reassign this closure to domain \p RD. 3280b57cec5SDimitry Andric bool isLegal(RegDomain RD) const { return LegalDstDomains[RD]; } 3290b57cec5SDimitry Andric 3300b57cec5SDimitry Andric /// Mark this closure as illegal for reassignment to domain \p RD. 3310b57cec5SDimitry Andric void setIllegal(RegDomain RD) { LegalDstDomains[RD] = false; } 3320b57cec5SDimitry Andric 3330b57cec5SDimitry Andric bool empty() const { return Edges.empty(); } 3340b57cec5SDimitry Andric 3350b57cec5SDimitry Andric bool insertEdge(unsigned Reg) { 3360b57cec5SDimitry Andric return Edges.insert(Reg).second; 3370b57cec5SDimitry Andric } 3380b57cec5SDimitry Andric 3390b57cec5SDimitry Andric using const_edge_iterator = DenseSet<unsigned>::const_iterator; 3400b57cec5SDimitry Andric iterator_range<const_edge_iterator> edges() const { 3410b57cec5SDimitry Andric return iterator_range<const_edge_iterator>(Edges.begin(), Edges.end()); 3420b57cec5SDimitry Andric } 3430b57cec5SDimitry Andric 3440b57cec5SDimitry Andric void addInstruction(MachineInstr *I) { 3450b57cec5SDimitry Andric Instrs.push_back(I); 3460b57cec5SDimitry Andric } 3470b57cec5SDimitry Andric 3480b57cec5SDimitry Andric ArrayRef<MachineInstr *> instructions() const { 3490b57cec5SDimitry Andric return Instrs; 3500b57cec5SDimitry Andric } 3510b57cec5SDimitry Andric 3520b57cec5SDimitry Andric LLVM_DUMP_METHOD void dump(const MachineRegisterInfo *MRI) const { 3530b57cec5SDimitry Andric dbgs() << "Registers: "; 3540b57cec5SDimitry Andric bool First = true; 3550b57cec5SDimitry Andric for (unsigned Reg : Edges) { 3560b57cec5SDimitry Andric if (!First) 3570b57cec5SDimitry Andric dbgs() << ", "; 3580b57cec5SDimitry Andric First = false; 3590b57cec5SDimitry Andric dbgs() << printReg(Reg, MRI->getTargetRegisterInfo(), 0, MRI); 3600b57cec5SDimitry Andric } 3610b57cec5SDimitry Andric dbgs() << "\n" << "Instructions:"; 3620b57cec5SDimitry Andric for (MachineInstr *MI : Instrs) { 3630b57cec5SDimitry Andric dbgs() << "\n "; 3640b57cec5SDimitry Andric MI->print(dbgs()); 3650b57cec5SDimitry Andric } 3660b57cec5SDimitry Andric dbgs() << "\n"; 3670b57cec5SDimitry Andric } 3680b57cec5SDimitry Andric 3690b57cec5SDimitry Andric unsigned getID() const { 3700b57cec5SDimitry Andric return ID; 3710b57cec5SDimitry Andric } 3720b57cec5SDimitry Andric 3730b57cec5SDimitry Andric }; 3740b57cec5SDimitry Andric 3750b57cec5SDimitry Andric class X86DomainReassignment : public MachineFunctionPass { 3760b57cec5SDimitry Andric const X86Subtarget *STI; 3770b57cec5SDimitry Andric MachineRegisterInfo *MRI; 3780b57cec5SDimitry Andric const X86InstrInfo *TII; 3790b57cec5SDimitry Andric 3800b57cec5SDimitry Andric /// All edges that are included in some closure 3810b57cec5SDimitry Andric DenseSet<unsigned> EnclosedEdges; 3820b57cec5SDimitry Andric 3830b57cec5SDimitry Andric /// All instructions that are included in some closure. 3840b57cec5SDimitry Andric DenseMap<MachineInstr *, unsigned> EnclosedInstrs; 3850b57cec5SDimitry Andric 3860b57cec5SDimitry Andric public: 3870b57cec5SDimitry Andric static char ID; 3880b57cec5SDimitry Andric 3890b57cec5SDimitry Andric X86DomainReassignment() : MachineFunctionPass(ID) { } 3900b57cec5SDimitry Andric 3910b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 3920b57cec5SDimitry Andric 3930b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 3940b57cec5SDimitry Andric AU.setPreservesCFG(); 3950b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 3960b57cec5SDimitry Andric } 3970b57cec5SDimitry Andric 3980b57cec5SDimitry Andric StringRef getPassName() const override { 3990b57cec5SDimitry Andric return "X86 Domain Reassignment Pass"; 4000b57cec5SDimitry Andric } 4010b57cec5SDimitry Andric 4020b57cec5SDimitry Andric private: 4030b57cec5SDimitry Andric /// A map of available Instruction Converters. 4040b57cec5SDimitry Andric InstrConverterBaseMap Converters; 4050b57cec5SDimitry Andric 4060b57cec5SDimitry Andric /// Initialize Converters map. 4070b57cec5SDimitry Andric void initConverters(); 4080b57cec5SDimitry Andric 4090b57cec5SDimitry Andric /// Starting from \Reg, expand the closure as much as possible. 4100b57cec5SDimitry Andric void buildClosure(Closure &, unsigned Reg); 4110b57cec5SDimitry Andric 4120b57cec5SDimitry Andric /// Enqueue \p Reg to be considered for addition to the closure. 4130b57cec5SDimitry Andric void visitRegister(Closure &, unsigned Reg, RegDomain &Domain, 4140b57cec5SDimitry Andric SmallVectorImpl<unsigned> &Worklist); 4150b57cec5SDimitry Andric 4160b57cec5SDimitry Andric /// Reassign the closure to \p Domain. 4170b57cec5SDimitry Andric void reassign(const Closure &C, RegDomain Domain) const; 4180b57cec5SDimitry Andric 4190b57cec5SDimitry Andric /// Add \p MI to the closure. 4200b57cec5SDimitry Andric void encloseInstr(Closure &C, MachineInstr *MI); 4210b57cec5SDimitry Andric 4220b57cec5SDimitry Andric /// /returns true if it is profitable to reassign the closure to \p Domain. 4230b57cec5SDimitry Andric bool isReassignmentProfitable(const Closure &C, RegDomain Domain) const; 4240b57cec5SDimitry Andric 4250b57cec5SDimitry Andric /// Calculate the total cost of reassigning the closure to \p Domain. 4260b57cec5SDimitry Andric double calculateCost(const Closure &C, RegDomain Domain) const; 4270b57cec5SDimitry Andric }; 4280b57cec5SDimitry Andric 4290b57cec5SDimitry Andric char X86DomainReassignment::ID = 0; 4300b57cec5SDimitry Andric 4310b57cec5SDimitry Andric } // End anonymous namespace. 4320b57cec5SDimitry Andric 4330b57cec5SDimitry Andric void X86DomainReassignment::visitRegister(Closure &C, unsigned Reg, 4340b57cec5SDimitry Andric RegDomain &Domain, 4350b57cec5SDimitry Andric SmallVectorImpl<unsigned> &Worklist) { 4360b57cec5SDimitry Andric if (EnclosedEdges.count(Reg)) 4370b57cec5SDimitry Andric return; 4380b57cec5SDimitry Andric 439*8bcb0991SDimitry Andric if (!Register::isVirtualRegister(Reg)) 4400b57cec5SDimitry Andric return; 4410b57cec5SDimitry Andric 4420b57cec5SDimitry Andric if (!MRI->hasOneDef(Reg)) 4430b57cec5SDimitry Andric return; 4440b57cec5SDimitry Andric 4450b57cec5SDimitry Andric RegDomain RD = getDomain(MRI->getRegClass(Reg), MRI->getTargetRegisterInfo()); 4460b57cec5SDimitry Andric // First edge in closure sets the domain. 4470b57cec5SDimitry Andric if (Domain == NoDomain) 4480b57cec5SDimitry Andric Domain = RD; 4490b57cec5SDimitry Andric 4500b57cec5SDimitry Andric if (Domain != RD) 4510b57cec5SDimitry Andric return; 4520b57cec5SDimitry Andric 4530b57cec5SDimitry Andric Worklist.push_back(Reg); 4540b57cec5SDimitry Andric } 4550b57cec5SDimitry Andric 4560b57cec5SDimitry Andric void X86DomainReassignment::encloseInstr(Closure &C, MachineInstr *MI) { 4570b57cec5SDimitry Andric auto I = EnclosedInstrs.find(MI); 4580b57cec5SDimitry Andric if (I != EnclosedInstrs.end()) { 4590b57cec5SDimitry Andric if (I->second != C.getID()) 4600b57cec5SDimitry Andric // Instruction already belongs to another closure, avoid conflicts between 4610b57cec5SDimitry Andric // closure and mark this closure as illegal. 4620b57cec5SDimitry Andric C.setAllIllegal(); 4630b57cec5SDimitry Andric return; 4640b57cec5SDimitry Andric } 4650b57cec5SDimitry Andric 4660b57cec5SDimitry Andric EnclosedInstrs[MI] = C.getID(); 4670b57cec5SDimitry Andric C.addInstruction(MI); 4680b57cec5SDimitry Andric 4690b57cec5SDimitry Andric // Mark closure as illegal for reassignment to domains, if there is no 4700b57cec5SDimitry Andric // converter for the instruction or if the converter cannot convert the 4710b57cec5SDimitry Andric // instruction. 4720b57cec5SDimitry Andric for (int i = 0; i != NumDomains; ++i) { 4730b57cec5SDimitry Andric if (C.isLegal((RegDomain)i)) { 4740b57cec5SDimitry Andric InstrConverterBase *IC = Converters.lookup({i, MI->getOpcode()}); 4750b57cec5SDimitry Andric if (!IC || !IC->isLegal(MI, TII)) 4760b57cec5SDimitry Andric C.setIllegal((RegDomain)i); 4770b57cec5SDimitry Andric } 4780b57cec5SDimitry Andric } 4790b57cec5SDimitry Andric } 4800b57cec5SDimitry Andric 4810b57cec5SDimitry Andric double X86DomainReassignment::calculateCost(const Closure &C, 4820b57cec5SDimitry Andric RegDomain DstDomain) const { 4830b57cec5SDimitry Andric assert(C.isLegal(DstDomain) && "Cannot calculate cost for illegal closure"); 4840b57cec5SDimitry Andric 4850b57cec5SDimitry Andric double Cost = 0.0; 4860b57cec5SDimitry Andric for (auto *MI : C.instructions()) 4870b57cec5SDimitry Andric Cost += 4880b57cec5SDimitry Andric Converters.lookup({DstDomain, MI->getOpcode()})->getExtraCost(MI, MRI); 4890b57cec5SDimitry Andric return Cost; 4900b57cec5SDimitry Andric } 4910b57cec5SDimitry Andric 4920b57cec5SDimitry Andric bool X86DomainReassignment::isReassignmentProfitable(const Closure &C, 4930b57cec5SDimitry Andric RegDomain Domain) const { 4940b57cec5SDimitry Andric return calculateCost(C, Domain) < 0.0; 4950b57cec5SDimitry Andric } 4960b57cec5SDimitry Andric 4970b57cec5SDimitry Andric void X86DomainReassignment::reassign(const Closure &C, RegDomain Domain) const { 4980b57cec5SDimitry Andric assert(C.isLegal(Domain) && "Cannot convert illegal closure"); 4990b57cec5SDimitry Andric 5000b57cec5SDimitry Andric // Iterate all instructions in the closure, convert each one using the 5010b57cec5SDimitry Andric // appropriate converter. 5020b57cec5SDimitry Andric SmallVector<MachineInstr *, 8> ToErase; 5030b57cec5SDimitry Andric for (auto *MI : C.instructions()) 5040b57cec5SDimitry Andric if (Converters.lookup({Domain, MI->getOpcode()}) 5050b57cec5SDimitry Andric ->convertInstr(MI, TII, MRI)) 5060b57cec5SDimitry Andric ToErase.push_back(MI); 5070b57cec5SDimitry Andric 5080b57cec5SDimitry Andric // Iterate all registers in the closure, replace them with registers in the 5090b57cec5SDimitry Andric // destination domain. 5100b57cec5SDimitry Andric for (unsigned Reg : C.edges()) { 5110b57cec5SDimitry Andric MRI->setRegClass(Reg, getDstRC(MRI->getRegClass(Reg), Domain)); 5120b57cec5SDimitry Andric for (auto &MO : MRI->use_operands(Reg)) { 5130b57cec5SDimitry Andric if (MO.isReg()) 5140b57cec5SDimitry Andric // Remove all subregister references as they are not valid in the 5150b57cec5SDimitry Andric // destination domain. 5160b57cec5SDimitry Andric MO.setSubReg(0); 5170b57cec5SDimitry Andric } 5180b57cec5SDimitry Andric } 5190b57cec5SDimitry Andric 5200b57cec5SDimitry Andric for (auto MI : ToErase) 5210b57cec5SDimitry Andric MI->eraseFromParent(); 5220b57cec5SDimitry Andric } 5230b57cec5SDimitry Andric 5240b57cec5SDimitry Andric /// \returns true when \p Reg is used as part of an address calculation in \p 5250b57cec5SDimitry Andric /// MI. 5260b57cec5SDimitry Andric static bool usedAsAddr(const MachineInstr &MI, unsigned Reg, 5270b57cec5SDimitry Andric const TargetInstrInfo *TII) { 5280b57cec5SDimitry Andric if (!MI.mayLoadOrStore()) 5290b57cec5SDimitry Andric return false; 5300b57cec5SDimitry Andric 5310b57cec5SDimitry Andric const MCInstrDesc &Desc = TII->get(MI.getOpcode()); 5320b57cec5SDimitry Andric int MemOpStart = X86II::getMemoryOperandNo(Desc.TSFlags); 5330b57cec5SDimitry Andric if (MemOpStart == -1) 5340b57cec5SDimitry Andric return false; 5350b57cec5SDimitry Andric 5360b57cec5SDimitry Andric MemOpStart += X86II::getOperandBias(Desc); 5370b57cec5SDimitry Andric for (unsigned MemOpIdx = MemOpStart, 5380b57cec5SDimitry Andric MemOpEnd = MemOpStart + X86::AddrNumOperands; 5390b57cec5SDimitry Andric MemOpIdx < MemOpEnd; ++MemOpIdx) { 5400b57cec5SDimitry Andric auto &Op = MI.getOperand(MemOpIdx); 5410b57cec5SDimitry Andric if (Op.isReg() && Op.getReg() == Reg) 5420b57cec5SDimitry Andric return true; 5430b57cec5SDimitry Andric } 5440b57cec5SDimitry Andric return false; 5450b57cec5SDimitry Andric } 5460b57cec5SDimitry Andric 5470b57cec5SDimitry Andric void X86DomainReassignment::buildClosure(Closure &C, unsigned Reg) { 5480b57cec5SDimitry Andric SmallVector<unsigned, 4> Worklist; 5490b57cec5SDimitry Andric RegDomain Domain = NoDomain; 5500b57cec5SDimitry Andric visitRegister(C, Reg, Domain, Worklist); 5510b57cec5SDimitry Andric while (!Worklist.empty()) { 5520b57cec5SDimitry Andric unsigned CurReg = Worklist.pop_back_val(); 5530b57cec5SDimitry Andric 5540b57cec5SDimitry Andric // Register already in this closure. 5550b57cec5SDimitry Andric if (!C.insertEdge(CurReg)) 5560b57cec5SDimitry Andric continue; 5570b57cec5SDimitry Andric EnclosedEdges.insert(Reg); 5580b57cec5SDimitry Andric 5590b57cec5SDimitry Andric MachineInstr *DefMI = MRI->getVRegDef(CurReg); 5600b57cec5SDimitry Andric encloseInstr(C, DefMI); 5610b57cec5SDimitry Andric 5620b57cec5SDimitry Andric // Add register used by the defining MI to the worklist. 5630b57cec5SDimitry Andric // Do not add registers which are used in address calculation, they will be 5640b57cec5SDimitry Andric // added to a different closure. 5650b57cec5SDimitry Andric int OpEnd = DefMI->getNumOperands(); 5660b57cec5SDimitry Andric const MCInstrDesc &Desc = DefMI->getDesc(); 5670b57cec5SDimitry Andric int MemOp = X86II::getMemoryOperandNo(Desc.TSFlags); 5680b57cec5SDimitry Andric if (MemOp != -1) 5690b57cec5SDimitry Andric MemOp += X86II::getOperandBias(Desc); 5700b57cec5SDimitry Andric for (int OpIdx = 0; OpIdx < OpEnd; ++OpIdx) { 5710b57cec5SDimitry Andric if (OpIdx == MemOp) { 5720b57cec5SDimitry Andric // skip address calculation. 5730b57cec5SDimitry Andric OpIdx += (X86::AddrNumOperands - 1); 5740b57cec5SDimitry Andric continue; 5750b57cec5SDimitry Andric } 5760b57cec5SDimitry Andric auto &Op = DefMI->getOperand(OpIdx); 5770b57cec5SDimitry Andric if (!Op.isReg() || !Op.isUse()) 5780b57cec5SDimitry Andric continue; 5790b57cec5SDimitry Andric visitRegister(C, Op.getReg(), Domain, Worklist); 5800b57cec5SDimitry Andric } 5810b57cec5SDimitry Andric 5820b57cec5SDimitry Andric // Expand closure through register uses. 5830b57cec5SDimitry Andric for (auto &UseMI : MRI->use_nodbg_instructions(CurReg)) { 5840b57cec5SDimitry Andric // We would like to avoid converting closures which calculare addresses, 5850b57cec5SDimitry Andric // as this should remain in GPRs. 5860b57cec5SDimitry Andric if (usedAsAddr(UseMI, CurReg, TII)) { 5870b57cec5SDimitry Andric C.setAllIllegal(); 5880b57cec5SDimitry Andric continue; 5890b57cec5SDimitry Andric } 5900b57cec5SDimitry Andric encloseInstr(C, &UseMI); 5910b57cec5SDimitry Andric 5920b57cec5SDimitry Andric for (auto &DefOp : UseMI.defs()) { 5930b57cec5SDimitry Andric if (!DefOp.isReg()) 5940b57cec5SDimitry Andric continue; 5950b57cec5SDimitry Andric 596*8bcb0991SDimitry Andric Register DefReg = DefOp.getReg(); 597*8bcb0991SDimitry Andric if (!Register::isVirtualRegister(DefReg)) { 5980b57cec5SDimitry Andric C.setAllIllegal(); 5990b57cec5SDimitry Andric continue; 6000b57cec5SDimitry Andric } 6010b57cec5SDimitry Andric visitRegister(C, DefReg, Domain, Worklist); 6020b57cec5SDimitry Andric } 6030b57cec5SDimitry Andric } 6040b57cec5SDimitry Andric } 6050b57cec5SDimitry Andric } 6060b57cec5SDimitry Andric 6070b57cec5SDimitry Andric void X86DomainReassignment::initConverters() { 6080b57cec5SDimitry Andric Converters[{MaskDomain, TargetOpcode::PHI}] = 6090b57cec5SDimitry Andric new InstrIgnore(TargetOpcode::PHI); 6100b57cec5SDimitry Andric 6110b57cec5SDimitry Andric Converters[{MaskDomain, TargetOpcode::IMPLICIT_DEF}] = 6120b57cec5SDimitry Andric new InstrIgnore(TargetOpcode::IMPLICIT_DEF); 6130b57cec5SDimitry Andric 6140b57cec5SDimitry Andric Converters[{MaskDomain, TargetOpcode::INSERT_SUBREG}] = 6150b57cec5SDimitry Andric new InstrReplaceWithCopy(TargetOpcode::INSERT_SUBREG, 2); 6160b57cec5SDimitry Andric 6170b57cec5SDimitry Andric Converters[{MaskDomain, TargetOpcode::COPY}] = 6180b57cec5SDimitry Andric new InstrCOPYReplacer(TargetOpcode::COPY, MaskDomain, TargetOpcode::COPY); 6190b57cec5SDimitry Andric 6200b57cec5SDimitry Andric auto createReplacerDstCOPY = [&](unsigned From, unsigned To) { 6210b57cec5SDimitry Andric Converters[{MaskDomain, From}] = new InstrReplacerDstCOPY(From, To); 6220b57cec5SDimitry Andric }; 6230b57cec5SDimitry Andric 6240b57cec5SDimitry Andric createReplacerDstCOPY(X86::MOVZX32rm16, X86::KMOVWkm); 6250b57cec5SDimitry Andric createReplacerDstCOPY(X86::MOVZX64rm16, X86::KMOVWkm); 6260b57cec5SDimitry Andric 6270b57cec5SDimitry Andric createReplacerDstCOPY(X86::MOVZX32rr16, X86::KMOVWkk); 6280b57cec5SDimitry Andric createReplacerDstCOPY(X86::MOVZX64rr16, X86::KMOVWkk); 6290b57cec5SDimitry Andric 6300b57cec5SDimitry Andric if (STI->hasDQI()) { 6310b57cec5SDimitry Andric createReplacerDstCOPY(X86::MOVZX16rm8, X86::KMOVBkm); 6320b57cec5SDimitry Andric createReplacerDstCOPY(X86::MOVZX32rm8, X86::KMOVBkm); 6330b57cec5SDimitry Andric createReplacerDstCOPY(X86::MOVZX64rm8, X86::KMOVBkm); 6340b57cec5SDimitry Andric 6350b57cec5SDimitry Andric createReplacerDstCOPY(X86::MOVZX16rr8, X86::KMOVBkk); 6360b57cec5SDimitry Andric createReplacerDstCOPY(X86::MOVZX32rr8, X86::KMOVBkk); 6370b57cec5SDimitry Andric createReplacerDstCOPY(X86::MOVZX64rr8, X86::KMOVBkk); 6380b57cec5SDimitry Andric } 6390b57cec5SDimitry Andric 6400b57cec5SDimitry Andric auto createReplacer = [&](unsigned From, unsigned To) { 6410b57cec5SDimitry Andric Converters[{MaskDomain, From}] = new InstrReplacer(From, To); 6420b57cec5SDimitry Andric }; 6430b57cec5SDimitry Andric 6440b57cec5SDimitry Andric createReplacer(X86::MOV16rm, X86::KMOVWkm); 6450b57cec5SDimitry Andric createReplacer(X86::MOV16mr, X86::KMOVWmk); 6460b57cec5SDimitry Andric createReplacer(X86::MOV16rr, X86::KMOVWkk); 6470b57cec5SDimitry Andric createReplacer(X86::SHR16ri, X86::KSHIFTRWri); 6480b57cec5SDimitry Andric createReplacer(X86::SHL16ri, X86::KSHIFTLWri); 6490b57cec5SDimitry Andric createReplacer(X86::NOT16r, X86::KNOTWrr); 6500b57cec5SDimitry Andric createReplacer(X86::OR16rr, X86::KORWrr); 6510b57cec5SDimitry Andric createReplacer(X86::AND16rr, X86::KANDWrr); 6520b57cec5SDimitry Andric createReplacer(X86::XOR16rr, X86::KXORWrr); 6530b57cec5SDimitry Andric 6540b57cec5SDimitry Andric if (STI->hasBWI()) { 6550b57cec5SDimitry Andric createReplacer(X86::MOV32rm, X86::KMOVDkm); 6560b57cec5SDimitry Andric createReplacer(X86::MOV64rm, X86::KMOVQkm); 6570b57cec5SDimitry Andric 6580b57cec5SDimitry Andric createReplacer(X86::MOV32mr, X86::KMOVDmk); 6590b57cec5SDimitry Andric createReplacer(X86::MOV64mr, X86::KMOVQmk); 6600b57cec5SDimitry Andric 6610b57cec5SDimitry Andric createReplacer(X86::MOV32rr, X86::KMOVDkk); 6620b57cec5SDimitry Andric createReplacer(X86::MOV64rr, X86::KMOVQkk); 6630b57cec5SDimitry Andric 6640b57cec5SDimitry Andric createReplacer(X86::SHR32ri, X86::KSHIFTRDri); 6650b57cec5SDimitry Andric createReplacer(X86::SHR64ri, X86::KSHIFTRQri); 6660b57cec5SDimitry Andric 6670b57cec5SDimitry Andric createReplacer(X86::SHL32ri, X86::KSHIFTLDri); 6680b57cec5SDimitry Andric createReplacer(X86::SHL64ri, X86::KSHIFTLQri); 6690b57cec5SDimitry Andric 6700b57cec5SDimitry Andric createReplacer(X86::ADD32rr, X86::KADDDrr); 6710b57cec5SDimitry Andric createReplacer(X86::ADD64rr, X86::KADDQrr); 6720b57cec5SDimitry Andric 6730b57cec5SDimitry Andric createReplacer(X86::NOT32r, X86::KNOTDrr); 6740b57cec5SDimitry Andric createReplacer(X86::NOT64r, X86::KNOTQrr); 6750b57cec5SDimitry Andric 6760b57cec5SDimitry Andric createReplacer(X86::OR32rr, X86::KORDrr); 6770b57cec5SDimitry Andric createReplacer(X86::OR64rr, X86::KORQrr); 6780b57cec5SDimitry Andric 6790b57cec5SDimitry Andric createReplacer(X86::AND32rr, X86::KANDDrr); 6800b57cec5SDimitry Andric createReplacer(X86::AND64rr, X86::KANDQrr); 6810b57cec5SDimitry Andric 6820b57cec5SDimitry Andric createReplacer(X86::ANDN32rr, X86::KANDNDrr); 6830b57cec5SDimitry Andric createReplacer(X86::ANDN64rr, X86::KANDNQrr); 6840b57cec5SDimitry Andric 6850b57cec5SDimitry Andric createReplacer(X86::XOR32rr, X86::KXORDrr); 6860b57cec5SDimitry Andric createReplacer(X86::XOR64rr, X86::KXORQrr); 6870b57cec5SDimitry Andric 6880b57cec5SDimitry Andric // TODO: KTEST is not a replacement for TEST due to flag differences. Need 6890b57cec5SDimitry Andric // to prove only Z flag is used. 6900b57cec5SDimitry Andric //createReplacer(X86::TEST32rr, X86::KTESTDrr); 6910b57cec5SDimitry Andric //createReplacer(X86::TEST64rr, X86::KTESTQrr); 6920b57cec5SDimitry Andric } 6930b57cec5SDimitry Andric 6940b57cec5SDimitry Andric if (STI->hasDQI()) { 6950b57cec5SDimitry Andric createReplacer(X86::ADD8rr, X86::KADDBrr); 6960b57cec5SDimitry Andric createReplacer(X86::ADD16rr, X86::KADDWrr); 6970b57cec5SDimitry Andric 6980b57cec5SDimitry Andric createReplacer(X86::AND8rr, X86::KANDBrr); 6990b57cec5SDimitry Andric 7000b57cec5SDimitry Andric createReplacer(X86::MOV8rm, X86::KMOVBkm); 7010b57cec5SDimitry Andric createReplacer(X86::MOV8mr, X86::KMOVBmk); 7020b57cec5SDimitry Andric createReplacer(X86::MOV8rr, X86::KMOVBkk); 7030b57cec5SDimitry Andric 7040b57cec5SDimitry Andric createReplacer(X86::NOT8r, X86::KNOTBrr); 7050b57cec5SDimitry Andric 7060b57cec5SDimitry Andric createReplacer(X86::OR8rr, X86::KORBrr); 7070b57cec5SDimitry Andric 7080b57cec5SDimitry Andric createReplacer(X86::SHR8ri, X86::KSHIFTRBri); 7090b57cec5SDimitry Andric createReplacer(X86::SHL8ri, X86::KSHIFTLBri); 7100b57cec5SDimitry Andric 7110b57cec5SDimitry Andric // TODO: KTEST is not a replacement for TEST due to flag differences. Need 7120b57cec5SDimitry Andric // to prove only Z flag is used. 7130b57cec5SDimitry Andric //createReplacer(X86::TEST8rr, X86::KTESTBrr); 7140b57cec5SDimitry Andric //createReplacer(X86::TEST16rr, X86::KTESTWrr); 7150b57cec5SDimitry Andric 7160b57cec5SDimitry Andric createReplacer(X86::XOR8rr, X86::KXORBrr); 7170b57cec5SDimitry Andric } 7180b57cec5SDimitry Andric } 7190b57cec5SDimitry Andric 7200b57cec5SDimitry Andric bool X86DomainReassignment::runOnMachineFunction(MachineFunction &MF) { 7210b57cec5SDimitry Andric if (skipFunction(MF.getFunction())) 7220b57cec5SDimitry Andric return false; 7230b57cec5SDimitry Andric if (DisableX86DomainReassignment) 7240b57cec5SDimitry Andric return false; 7250b57cec5SDimitry Andric 7260b57cec5SDimitry Andric LLVM_DEBUG( 7270b57cec5SDimitry Andric dbgs() << "***** Machine Function before Domain Reassignment *****\n"); 7280b57cec5SDimitry Andric LLVM_DEBUG(MF.print(dbgs())); 7290b57cec5SDimitry Andric 7300b57cec5SDimitry Andric STI = &MF.getSubtarget<X86Subtarget>(); 7310b57cec5SDimitry Andric // GPR->K is the only transformation currently supported, bail out early if no 7320b57cec5SDimitry Andric // AVX512. 7330b57cec5SDimitry Andric // TODO: We're also bailing of AVX512BW isn't supported since we use VK32 and 7340b57cec5SDimitry Andric // VK64 for GR32/GR64, but those aren't legal classes on KNL. If the register 7350b57cec5SDimitry Andric // coalescer doesn't clean it up and we generate a spill we will crash. 7360b57cec5SDimitry Andric if (!STI->hasAVX512() || !STI->hasBWI()) 7370b57cec5SDimitry Andric return false; 7380b57cec5SDimitry Andric 7390b57cec5SDimitry Andric MRI = &MF.getRegInfo(); 7400b57cec5SDimitry Andric assert(MRI->isSSA() && "Expected MIR to be in SSA form"); 7410b57cec5SDimitry Andric 7420b57cec5SDimitry Andric TII = STI->getInstrInfo(); 7430b57cec5SDimitry Andric initConverters(); 7440b57cec5SDimitry Andric bool Changed = false; 7450b57cec5SDimitry Andric 7460b57cec5SDimitry Andric EnclosedEdges.clear(); 7470b57cec5SDimitry Andric EnclosedInstrs.clear(); 7480b57cec5SDimitry Andric 7490b57cec5SDimitry Andric std::vector<Closure> Closures; 7500b57cec5SDimitry Andric 7510b57cec5SDimitry Andric // Go over all virtual registers and calculate a closure. 7520b57cec5SDimitry Andric unsigned ClosureID = 0; 7530b57cec5SDimitry Andric for (unsigned Idx = 0; Idx < MRI->getNumVirtRegs(); ++Idx) { 754*8bcb0991SDimitry Andric unsigned Reg = Register::index2VirtReg(Idx); 7550b57cec5SDimitry Andric 7560b57cec5SDimitry Andric // GPR only current source domain supported. 7570b57cec5SDimitry Andric if (!isGPR(MRI->getRegClass(Reg))) 7580b57cec5SDimitry Andric continue; 7590b57cec5SDimitry Andric 7600b57cec5SDimitry Andric // Register already in closure. 7610b57cec5SDimitry Andric if (EnclosedEdges.count(Reg)) 7620b57cec5SDimitry Andric continue; 7630b57cec5SDimitry Andric 7640b57cec5SDimitry Andric // Calculate closure starting with Reg. 7650b57cec5SDimitry Andric Closure C(ClosureID++, {MaskDomain}); 7660b57cec5SDimitry Andric buildClosure(C, Reg); 7670b57cec5SDimitry Andric 7680b57cec5SDimitry Andric // Collect all closures that can potentially be converted. 7690b57cec5SDimitry Andric if (!C.empty() && C.isLegal(MaskDomain)) 7700b57cec5SDimitry Andric Closures.push_back(std::move(C)); 7710b57cec5SDimitry Andric } 7720b57cec5SDimitry Andric 7730b57cec5SDimitry Andric for (Closure &C : Closures) { 7740b57cec5SDimitry Andric LLVM_DEBUG(C.dump(MRI)); 7750b57cec5SDimitry Andric if (isReassignmentProfitable(C, MaskDomain)) { 7760b57cec5SDimitry Andric reassign(C, MaskDomain); 7770b57cec5SDimitry Andric ++NumClosuresConverted; 7780b57cec5SDimitry Andric Changed = true; 7790b57cec5SDimitry Andric } 7800b57cec5SDimitry Andric } 7810b57cec5SDimitry Andric 7820b57cec5SDimitry Andric DeleteContainerSeconds(Converters); 7830b57cec5SDimitry Andric 7840b57cec5SDimitry Andric LLVM_DEBUG( 7850b57cec5SDimitry Andric dbgs() << "***** Machine Function after Domain Reassignment *****\n"); 7860b57cec5SDimitry Andric LLVM_DEBUG(MF.print(dbgs())); 7870b57cec5SDimitry Andric 7880b57cec5SDimitry Andric return Changed; 7890b57cec5SDimitry Andric } 7900b57cec5SDimitry Andric 7910b57cec5SDimitry Andric INITIALIZE_PASS(X86DomainReassignment, "x86-domain-reassignment", 7920b57cec5SDimitry Andric "X86 Domain Reassignment Pass", false, false) 7930b57cec5SDimitry Andric 7940b57cec5SDimitry Andric /// Returns an instance of the Domain Reassignment pass. 7950b57cec5SDimitry Andric FunctionPass *llvm::createX86DomainReassignmentPass() { 7960b57cec5SDimitry Andric return new X86DomainReassignment(); 7970b57cec5SDimitry Andric } 798