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" 1881ad6265SDimitry Andric #include "llvm/ADT/BitVector.h" 190b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.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 8981ad6265SDimitry Andric virtual ~InstrConverterBase() = default; 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. 144e8d8bef9SDimitry Andric for (const 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(); 183e8d8bef9SDimitry Andric const DebugLoc &DL = MI->getDebugLoc(); 1840b57cec5SDimitry Andric 1858bcb0991SDimitry 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); 1894824e7fdSDimitry Andric for (const MachineOperand &MO : llvm::drop_begin(MI->operands())) 1904824e7fdSDimitry Andric Bld.add(MO); 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? 2228bcb0991SDimitry Andric Register DstReg = MI->getOperand(0).getReg(); 223e8d8bef9SDimitry Andric if (DstReg.isPhysical() && (X86::GR8RegClass.contains(DstReg) || 2240b57cec5SDimitry Andric X86::GR16RegClass.contains(DstReg))) 2250b57cec5SDimitry Andric return false; 2268bcb0991SDimitry Andric Register SrcReg = MI->getOperand(1).getReg(); 227e8d8bef9SDimitry Andric if (SrcReg.isPhysical() && (X86::GR8RegClass.contains(SrcReg) || 2280b57cec5SDimitry Andric X86::GR16RegClass.contains(SrcReg))) 2290b57cec5SDimitry Andric return false; 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric return true; 2320b57cec5SDimitry Andric } 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric double getExtraCost(const MachineInstr *MI, 2350b57cec5SDimitry Andric MachineRegisterInfo *MRI) const override { 2360b57cec5SDimitry Andric assert(MI->getOpcode() == TargetOpcode::COPY && "Expected a COPY"); 2370b57cec5SDimitry Andric 238e8d8bef9SDimitry Andric for (const auto &MO : MI->operands()) { 2390b57cec5SDimitry Andric // Physical registers will not be converted. Assume that converting the 2400b57cec5SDimitry Andric // COPY to the destination domain will eventually result in a actual 2410b57cec5SDimitry Andric // instruction. 242bdd1243dSDimitry Andric if (MO.getReg().isPhysical()) 2430b57cec5SDimitry Andric return 1; 2440b57cec5SDimitry Andric 2450b57cec5SDimitry Andric RegDomain OpDomain = getDomain(MRI->getRegClass(MO.getReg()), 2460b57cec5SDimitry Andric MRI->getTargetRegisterInfo()); 2470b57cec5SDimitry Andric // Converting a cross domain COPY to a same domain COPY should eliminate 2480b57cec5SDimitry Andric // an insturction 2490b57cec5SDimitry Andric if (OpDomain == DstDomain) 2500b57cec5SDimitry Andric return -1; 2510b57cec5SDimitry Andric } 2520b57cec5SDimitry Andric return 0; 2530b57cec5SDimitry Andric } 2540b57cec5SDimitry Andric }; 2550b57cec5SDimitry Andric 2560b57cec5SDimitry Andric /// An Instruction Converter which replaces an instruction with a COPY. 2570b57cec5SDimitry Andric class InstrReplaceWithCopy : public InstrConverterBase { 2580b57cec5SDimitry Andric public: 2590b57cec5SDimitry Andric // Source instruction operand Index, to be used as the COPY source. 2600b57cec5SDimitry Andric unsigned SrcOpIdx; 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric InstrReplaceWithCopy(unsigned SrcOpcode, unsigned SrcOpIdx) 2630b57cec5SDimitry Andric : InstrConverterBase(SrcOpcode), SrcOpIdx(SrcOpIdx) {} 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric bool convertInstr(MachineInstr *MI, const TargetInstrInfo *TII, 2660b57cec5SDimitry Andric MachineRegisterInfo *MRI) const override { 2670b57cec5SDimitry Andric assert(isLegal(MI, TII) && "Cannot convert instruction"); 2680b57cec5SDimitry Andric BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), 2690b57cec5SDimitry Andric TII->get(TargetOpcode::COPY)) 2700b57cec5SDimitry Andric .add({MI->getOperand(0), MI->getOperand(SrcOpIdx)}); 2710b57cec5SDimitry Andric return true; 2720b57cec5SDimitry Andric } 2730b57cec5SDimitry Andric 2740b57cec5SDimitry Andric double getExtraCost(const MachineInstr *MI, 2750b57cec5SDimitry Andric MachineRegisterInfo *MRI) const override { 2760b57cec5SDimitry Andric return 0; 2770b57cec5SDimitry Andric } 2780b57cec5SDimitry Andric }; 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric // Key type to be used by the Instruction Converters map. 2810b57cec5SDimitry Andric // A converter is identified by <destination domain, source opcode> 2820b57cec5SDimitry Andric typedef std::pair<int, unsigned> InstrConverterBaseKeyTy; 2830b57cec5SDimitry Andric 2845ffd83dbSDimitry Andric typedef DenseMap<InstrConverterBaseKeyTy, std::unique_ptr<InstrConverterBase>> 2850b57cec5SDimitry Andric InstrConverterBaseMap; 2860b57cec5SDimitry Andric 2870b57cec5SDimitry Andric /// A closure is a set of virtual register representing all of the edges in 2880b57cec5SDimitry Andric /// the closure, as well as all of the instructions connected by those edges. 2890b57cec5SDimitry Andric /// 2900b57cec5SDimitry Andric /// A closure may encompass virtual registers in the same register bank that 2910b57cec5SDimitry Andric /// have different widths. For example, it may contain 32-bit GPRs as well as 2920b57cec5SDimitry Andric /// 64-bit GPRs. 2930b57cec5SDimitry Andric /// 2940b57cec5SDimitry Andric /// A closure that computes an address (i.e. defines a virtual register that is 2950b57cec5SDimitry Andric /// used in a memory operand) excludes the instructions that contain memory 2960b57cec5SDimitry Andric /// operands using the address. Such an instruction will be included in a 2970b57cec5SDimitry Andric /// different closure that manipulates the loaded or stored value. 2980b57cec5SDimitry Andric class Closure { 2990b57cec5SDimitry Andric private: 3000b57cec5SDimitry Andric /// Virtual registers in the closure. 301e8d8bef9SDimitry Andric DenseSet<Register> Edges; 3020b57cec5SDimitry Andric 3030b57cec5SDimitry Andric /// Instructions in the closure. 3040b57cec5SDimitry Andric SmallVector<MachineInstr *, 8> Instrs; 3050b57cec5SDimitry Andric 3060b57cec5SDimitry Andric /// Domains which this closure can legally be reassigned to. 3070b57cec5SDimitry Andric std::bitset<NumDomains> LegalDstDomains; 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric /// An ID to uniquely identify this closure, even when it gets 3100b57cec5SDimitry Andric /// moved around 3110b57cec5SDimitry Andric unsigned ID; 3120b57cec5SDimitry Andric 3130b57cec5SDimitry Andric public: 3140b57cec5SDimitry Andric Closure(unsigned ID, std::initializer_list<RegDomain> LegalDstDomainList) : ID(ID) { 3150b57cec5SDimitry Andric for (RegDomain D : LegalDstDomainList) 3160b57cec5SDimitry Andric LegalDstDomains.set(D); 3170b57cec5SDimitry Andric } 3180b57cec5SDimitry Andric 3190b57cec5SDimitry Andric /// Mark this closure as illegal for reassignment to all domains. 3200b57cec5SDimitry Andric void setAllIllegal() { LegalDstDomains.reset(); } 3210b57cec5SDimitry Andric 3220b57cec5SDimitry Andric /// \returns true if this closure has domains which are legal to reassign to. 3230b57cec5SDimitry Andric bool hasLegalDstDomain() const { return LegalDstDomains.any(); } 3240b57cec5SDimitry Andric 3250b57cec5SDimitry Andric /// \returns true if is legal to reassign this closure to domain \p RD. 3260b57cec5SDimitry Andric bool isLegal(RegDomain RD) const { return LegalDstDomains[RD]; } 3270b57cec5SDimitry Andric 3280b57cec5SDimitry Andric /// Mark this closure as illegal for reassignment to domain \p RD. 3290b57cec5SDimitry Andric void setIllegal(RegDomain RD) { LegalDstDomains[RD] = false; } 3300b57cec5SDimitry Andric 3310b57cec5SDimitry Andric bool empty() const { return Edges.empty(); } 3320b57cec5SDimitry Andric 333e8d8bef9SDimitry Andric bool insertEdge(Register Reg) { return Edges.insert(Reg).second; } 3340b57cec5SDimitry Andric 335e8d8bef9SDimitry Andric using const_edge_iterator = DenseSet<Register>::const_iterator; 3360b57cec5SDimitry Andric iterator_range<const_edge_iterator> edges() const { 3370b57cec5SDimitry Andric return iterator_range<const_edge_iterator>(Edges.begin(), Edges.end()); 3380b57cec5SDimitry Andric } 3390b57cec5SDimitry Andric 3400b57cec5SDimitry Andric void addInstruction(MachineInstr *I) { 3410b57cec5SDimitry Andric Instrs.push_back(I); 3420b57cec5SDimitry Andric } 3430b57cec5SDimitry Andric 3440b57cec5SDimitry Andric ArrayRef<MachineInstr *> instructions() const { 3450b57cec5SDimitry Andric return Instrs; 3460b57cec5SDimitry Andric } 3470b57cec5SDimitry Andric 3480b57cec5SDimitry Andric LLVM_DUMP_METHOD void dump(const MachineRegisterInfo *MRI) const { 3490b57cec5SDimitry Andric dbgs() << "Registers: "; 3500b57cec5SDimitry Andric bool First = true; 351e8d8bef9SDimitry Andric for (Register Reg : Edges) { 3520b57cec5SDimitry Andric if (!First) 3530b57cec5SDimitry Andric dbgs() << ", "; 3540b57cec5SDimitry Andric First = false; 3550b57cec5SDimitry Andric dbgs() << printReg(Reg, MRI->getTargetRegisterInfo(), 0, MRI); 3560b57cec5SDimitry Andric } 3570b57cec5SDimitry Andric dbgs() << "\n" << "Instructions:"; 3580b57cec5SDimitry Andric for (MachineInstr *MI : Instrs) { 3590b57cec5SDimitry Andric dbgs() << "\n "; 3600b57cec5SDimitry Andric MI->print(dbgs()); 3610b57cec5SDimitry Andric } 3620b57cec5SDimitry Andric dbgs() << "\n"; 3630b57cec5SDimitry Andric } 3640b57cec5SDimitry Andric 3650b57cec5SDimitry Andric unsigned getID() const { 3660b57cec5SDimitry Andric return ID; 3670b57cec5SDimitry Andric } 3680b57cec5SDimitry Andric 3690b57cec5SDimitry Andric }; 3700b57cec5SDimitry Andric 3710b57cec5SDimitry Andric class X86DomainReassignment : public MachineFunctionPass { 372480093f4SDimitry Andric const X86Subtarget *STI = nullptr; 373480093f4SDimitry Andric MachineRegisterInfo *MRI = nullptr; 374480093f4SDimitry Andric const X86InstrInfo *TII = nullptr; 3750b57cec5SDimitry Andric 3760b57cec5SDimitry Andric /// All edges that are included in some closure 37781ad6265SDimitry Andric BitVector EnclosedEdges{8, false}; 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric /// All instructions that are included in some closure. 3800b57cec5SDimitry Andric DenseMap<MachineInstr *, unsigned> EnclosedInstrs; 3810b57cec5SDimitry Andric 3820b57cec5SDimitry Andric public: 3830b57cec5SDimitry Andric static char ID; 3840b57cec5SDimitry Andric 3850b57cec5SDimitry Andric X86DomainReassignment() : MachineFunctionPass(ID) { } 3860b57cec5SDimitry Andric 3870b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 3880b57cec5SDimitry Andric 3890b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 3900b57cec5SDimitry Andric AU.setPreservesCFG(); 3910b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 3920b57cec5SDimitry Andric } 3930b57cec5SDimitry Andric 3940b57cec5SDimitry Andric StringRef getPassName() const override { 3950b57cec5SDimitry Andric return "X86 Domain Reassignment Pass"; 3960b57cec5SDimitry Andric } 3970b57cec5SDimitry Andric 3980b57cec5SDimitry Andric private: 3990b57cec5SDimitry Andric /// A map of available Instruction Converters. 4000b57cec5SDimitry Andric InstrConverterBaseMap Converters; 4010b57cec5SDimitry Andric 4020b57cec5SDimitry Andric /// Initialize Converters map. 4030b57cec5SDimitry Andric void initConverters(); 4040b57cec5SDimitry Andric 4050b57cec5SDimitry Andric /// Starting from \Reg, expand the closure as much as possible. 406e8d8bef9SDimitry Andric void buildClosure(Closure &, Register Reg); 4070b57cec5SDimitry Andric 4080b57cec5SDimitry Andric /// Enqueue \p Reg to be considered for addition to the closure. 409e8d8bef9SDimitry Andric void visitRegister(Closure &, Register Reg, RegDomain &Domain, 4100b57cec5SDimitry Andric SmallVectorImpl<unsigned> &Worklist); 4110b57cec5SDimitry Andric 4120b57cec5SDimitry Andric /// Reassign the closure to \p Domain. 4130b57cec5SDimitry Andric void reassign(const Closure &C, RegDomain Domain) const; 4140b57cec5SDimitry Andric 4150b57cec5SDimitry Andric /// Add \p MI to the closure. 4160b57cec5SDimitry Andric void encloseInstr(Closure &C, MachineInstr *MI); 4170b57cec5SDimitry Andric 4180b57cec5SDimitry Andric /// /returns true if it is profitable to reassign the closure to \p Domain. 4190b57cec5SDimitry Andric bool isReassignmentProfitable(const Closure &C, RegDomain Domain) const; 4200b57cec5SDimitry Andric 4210b57cec5SDimitry Andric /// Calculate the total cost of reassigning the closure to \p Domain. 4220b57cec5SDimitry Andric double calculateCost(const Closure &C, RegDomain Domain) const; 4230b57cec5SDimitry Andric }; 4240b57cec5SDimitry Andric 4250b57cec5SDimitry Andric char X86DomainReassignment::ID = 0; 4260b57cec5SDimitry Andric 4270b57cec5SDimitry Andric } // End anonymous namespace. 4280b57cec5SDimitry Andric 429e8d8bef9SDimitry Andric void X86DomainReassignment::visitRegister(Closure &C, Register Reg, 4300b57cec5SDimitry Andric RegDomain &Domain, 4310b57cec5SDimitry Andric SmallVectorImpl<unsigned> &Worklist) { 43281ad6265SDimitry Andric if (!Reg.isVirtual()) 4330b57cec5SDimitry Andric return; 4340b57cec5SDimitry Andric 43581ad6265SDimitry Andric if (EnclosedEdges.test(Register::virtReg2Index(Reg))) 4360b57cec5SDimitry Andric return; 4370b57cec5SDimitry Andric 4380b57cec5SDimitry Andric if (!MRI->hasOneDef(Reg)) 4390b57cec5SDimitry Andric return; 4400b57cec5SDimitry Andric 4410b57cec5SDimitry Andric RegDomain RD = getDomain(MRI->getRegClass(Reg), MRI->getTargetRegisterInfo()); 4420b57cec5SDimitry Andric // First edge in closure sets the domain. 4430b57cec5SDimitry Andric if (Domain == NoDomain) 4440b57cec5SDimitry Andric Domain = RD; 4450b57cec5SDimitry Andric 4460b57cec5SDimitry Andric if (Domain != RD) 4470b57cec5SDimitry Andric return; 4480b57cec5SDimitry Andric 4490b57cec5SDimitry Andric Worklist.push_back(Reg); 4500b57cec5SDimitry Andric } 4510b57cec5SDimitry Andric 4520b57cec5SDimitry Andric void X86DomainReassignment::encloseInstr(Closure &C, MachineInstr *MI) { 4530b57cec5SDimitry Andric auto I = EnclosedInstrs.find(MI); 4540b57cec5SDimitry Andric if (I != EnclosedInstrs.end()) { 4550b57cec5SDimitry Andric if (I->second != C.getID()) 4560b57cec5SDimitry Andric // Instruction already belongs to another closure, avoid conflicts between 4570b57cec5SDimitry Andric // closure and mark this closure as illegal. 4580b57cec5SDimitry Andric C.setAllIllegal(); 4590b57cec5SDimitry Andric return; 4600b57cec5SDimitry Andric } 4610b57cec5SDimitry Andric 4620b57cec5SDimitry Andric EnclosedInstrs[MI] = C.getID(); 4630b57cec5SDimitry Andric C.addInstruction(MI); 4640b57cec5SDimitry Andric 4650b57cec5SDimitry Andric // Mark closure as illegal for reassignment to domains, if there is no 4660b57cec5SDimitry Andric // converter for the instruction or if the converter cannot convert the 4670b57cec5SDimitry Andric // instruction. 4680b57cec5SDimitry Andric for (int i = 0; i != NumDomains; ++i) { 4690b57cec5SDimitry Andric if (C.isLegal((RegDomain)i)) { 4705ffd83dbSDimitry Andric auto I = Converters.find({i, MI->getOpcode()}); 4715ffd83dbSDimitry Andric if (I == Converters.end() || !I->second->isLegal(MI, TII)) 4720b57cec5SDimitry Andric C.setIllegal((RegDomain)i); 4730b57cec5SDimitry Andric } 4740b57cec5SDimitry Andric } 4750b57cec5SDimitry Andric } 4760b57cec5SDimitry Andric 4770b57cec5SDimitry Andric double X86DomainReassignment::calculateCost(const Closure &C, 4780b57cec5SDimitry Andric RegDomain DstDomain) const { 4790b57cec5SDimitry Andric assert(C.isLegal(DstDomain) && "Cannot calculate cost for illegal closure"); 4800b57cec5SDimitry Andric 4810b57cec5SDimitry Andric double Cost = 0.0; 4820b57cec5SDimitry Andric for (auto *MI : C.instructions()) 4835ffd83dbSDimitry Andric Cost += Converters.find({DstDomain, MI->getOpcode()}) 4845ffd83dbSDimitry Andric ->second->getExtraCost(MI, MRI); 4850b57cec5SDimitry Andric return Cost; 4860b57cec5SDimitry Andric } 4870b57cec5SDimitry Andric 4880b57cec5SDimitry Andric bool X86DomainReassignment::isReassignmentProfitable(const Closure &C, 4890b57cec5SDimitry Andric RegDomain Domain) const { 4900b57cec5SDimitry Andric return calculateCost(C, Domain) < 0.0; 4910b57cec5SDimitry Andric } 4920b57cec5SDimitry Andric 4930b57cec5SDimitry Andric void X86DomainReassignment::reassign(const Closure &C, RegDomain Domain) const { 4940b57cec5SDimitry Andric assert(C.isLegal(Domain) && "Cannot convert illegal closure"); 4950b57cec5SDimitry Andric 4960b57cec5SDimitry Andric // Iterate all instructions in the closure, convert each one using the 4970b57cec5SDimitry Andric // appropriate converter. 4980b57cec5SDimitry Andric SmallVector<MachineInstr *, 8> ToErase; 4990b57cec5SDimitry Andric for (auto *MI : C.instructions()) 5005ffd83dbSDimitry Andric if (Converters.find({Domain, MI->getOpcode()}) 5015ffd83dbSDimitry Andric ->second->convertInstr(MI, TII, MRI)) 5020b57cec5SDimitry Andric ToErase.push_back(MI); 5030b57cec5SDimitry Andric 5040b57cec5SDimitry Andric // Iterate all registers in the closure, replace them with registers in the 5050b57cec5SDimitry Andric // destination domain. 506e8d8bef9SDimitry Andric for (Register Reg : C.edges()) { 5070b57cec5SDimitry Andric MRI->setRegClass(Reg, getDstRC(MRI->getRegClass(Reg), Domain)); 5080b57cec5SDimitry Andric for (auto &MO : MRI->use_operands(Reg)) { 5090b57cec5SDimitry Andric if (MO.isReg()) 5100b57cec5SDimitry Andric // Remove all subregister references as they are not valid in the 5110b57cec5SDimitry Andric // destination domain. 5120b57cec5SDimitry Andric MO.setSubReg(0); 5130b57cec5SDimitry Andric } 5140b57cec5SDimitry Andric } 5150b57cec5SDimitry Andric 516e8d8bef9SDimitry Andric for (auto *MI : ToErase) 5170b57cec5SDimitry Andric MI->eraseFromParent(); 5180b57cec5SDimitry Andric } 5190b57cec5SDimitry Andric 5200b57cec5SDimitry Andric /// \returns true when \p Reg is used as part of an address calculation in \p 5210b57cec5SDimitry Andric /// MI. 522e8d8bef9SDimitry Andric static bool usedAsAddr(const MachineInstr &MI, Register Reg, 5230b57cec5SDimitry Andric const TargetInstrInfo *TII) { 5240b57cec5SDimitry Andric if (!MI.mayLoadOrStore()) 5250b57cec5SDimitry Andric return false; 5260b57cec5SDimitry Andric 5270b57cec5SDimitry Andric const MCInstrDesc &Desc = TII->get(MI.getOpcode()); 5280b57cec5SDimitry Andric int MemOpStart = X86II::getMemoryOperandNo(Desc.TSFlags); 5290b57cec5SDimitry Andric if (MemOpStart == -1) 5300b57cec5SDimitry Andric return false; 5310b57cec5SDimitry Andric 5320b57cec5SDimitry Andric MemOpStart += X86II::getOperandBias(Desc); 5330b57cec5SDimitry Andric for (unsigned MemOpIdx = MemOpStart, 5340b57cec5SDimitry Andric MemOpEnd = MemOpStart + X86::AddrNumOperands; 5350b57cec5SDimitry Andric MemOpIdx < MemOpEnd; ++MemOpIdx) { 536e8d8bef9SDimitry Andric const MachineOperand &Op = MI.getOperand(MemOpIdx); 5370b57cec5SDimitry Andric if (Op.isReg() && Op.getReg() == Reg) 5380b57cec5SDimitry Andric return true; 5390b57cec5SDimitry Andric } 5400b57cec5SDimitry Andric return false; 5410b57cec5SDimitry Andric } 5420b57cec5SDimitry Andric 543e8d8bef9SDimitry Andric void X86DomainReassignment::buildClosure(Closure &C, Register Reg) { 5440b57cec5SDimitry Andric SmallVector<unsigned, 4> Worklist; 5450b57cec5SDimitry Andric RegDomain Domain = NoDomain; 5460b57cec5SDimitry Andric visitRegister(C, Reg, Domain, Worklist); 5470b57cec5SDimitry Andric while (!Worklist.empty()) { 5480b57cec5SDimitry Andric unsigned CurReg = Worklist.pop_back_val(); 5490b57cec5SDimitry Andric 5500b57cec5SDimitry Andric // Register already in this closure. 5510b57cec5SDimitry Andric if (!C.insertEdge(CurReg)) 5520b57cec5SDimitry Andric continue; 55381ad6265SDimitry Andric EnclosedEdges.set(Register::virtReg2Index(Reg)); 5540b57cec5SDimitry Andric 5550b57cec5SDimitry Andric MachineInstr *DefMI = MRI->getVRegDef(CurReg); 5560b57cec5SDimitry Andric encloseInstr(C, DefMI); 5570b57cec5SDimitry Andric 5580b57cec5SDimitry Andric // Add register used by the defining MI to the worklist. 5590b57cec5SDimitry Andric // Do not add registers which are used in address calculation, they will be 5600b57cec5SDimitry Andric // added to a different closure. 5610b57cec5SDimitry Andric int OpEnd = DefMI->getNumOperands(); 5620b57cec5SDimitry Andric const MCInstrDesc &Desc = DefMI->getDesc(); 5630b57cec5SDimitry Andric int MemOp = X86II::getMemoryOperandNo(Desc.TSFlags); 5640b57cec5SDimitry Andric if (MemOp != -1) 5650b57cec5SDimitry Andric MemOp += X86II::getOperandBias(Desc); 5660b57cec5SDimitry Andric for (int OpIdx = 0; OpIdx < OpEnd; ++OpIdx) { 5670b57cec5SDimitry Andric if (OpIdx == MemOp) { 5680b57cec5SDimitry Andric // skip address calculation. 5690b57cec5SDimitry Andric OpIdx += (X86::AddrNumOperands - 1); 5700b57cec5SDimitry Andric continue; 5710b57cec5SDimitry Andric } 5720b57cec5SDimitry Andric auto &Op = DefMI->getOperand(OpIdx); 5730b57cec5SDimitry Andric if (!Op.isReg() || !Op.isUse()) 5740b57cec5SDimitry Andric continue; 5750b57cec5SDimitry Andric visitRegister(C, Op.getReg(), Domain, Worklist); 5760b57cec5SDimitry Andric } 5770b57cec5SDimitry Andric 5780b57cec5SDimitry Andric // Expand closure through register uses. 5790b57cec5SDimitry Andric for (auto &UseMI : MRI->use_nodbg_instructions(CurReg)) { 5800b57cec5SDimitry Andric // We would like to avoid converting closures which calculare addresses, 5810b57cec5SDimitry Andric // as this should remain in GPRs. 5820b57cec5SDimitry Andric if (usedAsAddr(UseMI, CurReg, TII)) { 5830b57cec5SDimitry Andric C.setAllIllegal(); 5840b57cec5SDimitry Andric continue; 5850b57cec5SDimitry Andric } 5860b57cec5SDimitry Andric encloseInstr(C, &UseMI); 5870b57cec5SDimitry Andric 5880b57cec5SDimitry Andric for (auto &DefOp : UseMI.defs()) { 5890b57cec5SDimitry Andric if (!DefOp.isReg()) 5900b57cec5SDimitry Andric continue; 5910b57cec5SDimitry Andric 5928bcb0991SDimitry Andric Register DefReg = DefOp.getReg(); 593e8d8bef9SDimitry Andric if (!DefReg.isVirtual()) { 5940b57cec5SDimitry Andric C.setAllIllegal(); 5950b57cec5SDimitry Andric continue; 5960b57cec5SDimitry Andric } 5970b57cec5SDimitry Andric visitRegister(C, DefReg, Domain, Worklist); 5980b57cec5SDimitry Andric } 5990b57cec5SDimitry Andric } 6000b57cec5SDimitry Andric } 6010b57cec5SDimitry Andric } 6020b57cec5SDimitry Andric 6030b57cec5SDimitry Andric void X86DomainReassignment::initConverters() { 6040b57cec5SDimitry Andric Converters[{MaskDomain, TargetOpcode::PHI}] = 6055ffd83dbSDimitry Andric std::make_unique<InstrIgnore>(TargetOpcode::PHI); 6060b57cec5SDimitry Andric 6070b57cec5SDimitry Andric Converters[{MaskDomain, TargetOpcode::IMPLICIT_DEF}] = 6085ffd83dbSDimitry Andric std::make_unique<InstrIgnore>(TargetOpcode::IMPLICIT_DEF); 6090b57cec5SDimitry Andric 6100b57cec5SDimitry Andric Converters[{MaskDomain, TargetOpcode::INSERT_SUBREG}] = 6115ffd83dbSDimitry Andric std::make_unique<InstrReplaceWithCopy>(TargetOpcode::INSERT_SUBREG, 2); 6120b57cec5SDimitry Andric 6130b57cec5SDimitry Andric Converters[{MaskDomain, TargetOpcode::COPY}] = 6145ffd83dbSDimitry Andric std::make_unique<InstrCOPYReplacer>(TargetOpcode::COPY, MaskDomain, 6155ffd83dbSDimitry Andric TargetOpcode::COPY); 6160b57cec5SDimitry Andric 6170b57cec5SDimitry Andric auto createReplacerDstCOPY = [&](unsigned From, unsigned To) { 6185ffd83dbSDimitry Andric Converters[{MaskDomain, From}] = 6195ffd83dbSDimitry Andric std::make_unique<InstrReplacerDstCOPY>(From, To); 6200b57cec5SDimitry Andric }; 6210b57cec5SDimitry Andric 6221db9f3b2SDimitry Andric #define GET_EGPR_IF_ENABLED(OPC) STI->hasEGPR() ? OPC##_EVEX : OPC 6231db9f3b2SDimitry Andric createReplacerDstCOPY(X86::MOVZX32rm16, GET_EGPR_IF_ENABLED(X86::KMOVWkm)); 6241db9f3b2SDimitry Andric createReplacerDstCOPY(X86::MOVZX64rm16, GET_EGPR_IF_ENABLED(X86::KMOVWkm)); 6250b57cec5SDimitry Andric 6261db9f3b2SDimitry Andric createReplacerDstCOPY(X86::MOVZX32rr16, GET_EGPR_IF_ENABLED(X86::KMOVWkk)); 6271db9f3b2SDimitry Andric createReplacerDstCOPY(X86::MOVZX64rr16, GET_EGPR_IF_ENABLED(X86::KMOVWkk)); 6280b57cec5SDimitry Andric 6290b57cec5SDimitry Andric if (STI->hasDQI()) { 6301db9f3b2SDimitry Andric createReplacerDstCOPY(X86::MOVZX16rm8, GET_EGPR_IF_ENABLED(X86::KMOVBkm)); 6311db9f3b2SDimitry Andric createReplacerDstCOPY(X86::MOVZX32rm8, GET_EGPR_IF_ENABLED(X86::KMOVBkm)); 6321db9f3b2SDimitry Andric createReplacerDstCOPY(X86::MOVZX64rm8, GET_EGPR_IF_ENABLED(X86::KMOVBkm)); 6330b57cec5SDimitry Andric 6341db9f3b2SDimitry Andric createReplacerDstCOPY(X86::MOVZX16rr8, GET_EGPR_IF_ENABLED(X86::KMOVBkk)); 6351db9f3b2SDimitry Andric createReplacerDstCOPY(X86::MOVZX32rr8, GET_EGPR_IF_ENABLED(X86::KMOVBkk)); 6361db9f3b2SDimitry Andric createReplacerDstCOPY(X86::MOVZX64rr8, GET_EGPR_IF_ENABLED(X86::KMOVBkk)); 6370b57cec5SDimitry Andric } 6380b57cec5SDimitry Andric 6390b57cec5SDimitry Andric auto createReplacer = [&](unsigned From, unsigned To) { 6405ffd83dbSDimitry Andric Converters[{MaskDomain, From}] = std::make_unique<InstrReplacer>(From, To); 6410b57cec5SDimitry Andric }; 6420b57cec5SDimitry Andric 6431db9f3b2SDimitry Andric createReplacer(X86::MOV16rm, GET_EGPR_IF_ENABLED(X86::KMOVWkm)); 6441db9f3b2SDimitry Andric createReplacer(X86::MOV16mr, GET_EGPR_IF_ENABLED(X86::KMOVWmk)); 6451db9f3b2SDimitry Andric createReplacer(X86::MOV16rr, GET_EGPR_IF_ENABLED(X86::KMOVWkk)); 6460b57cec5SDimitry Andric createReplacer(X86::SHR16ri, X86::KSHIFTRWri); 6470b57cec5SDimitry Andric createReplacer(X86::SHL16ri, X86::KSHIFTLWri); 6480b57cec5SDimitry Andric createReplacer(X86::NOT16r, X86::KNOTWrr); 6490b57cec5SDimitry Andric createReplacer(X86::OR16rr, X86::KORWrr); 6500b57cec5SDimitry Andric createReplacer(X86::AND16rr, X86::KANDWrr); 6510b57cec5SDimitry Andric createReplacer(X86::XOR16rr, X86::KXORWrr); 6520b57cec5SDimitry Andric 653*0fca6ea1SDimitry Andric bool HasNDD = STI->hasNDD(); 654*0fca6ea1SDimitry Andric if (HasNDD) { 655*0fca6ea1SDimitry Andric createReplacer(X86::SHR16ri_ND, X86::KSHIFTRWri); 656*0fca6ea1SDimitry Andric createReplacer(X86::SHL16ri_ND, X86::KSHIFTLWri); 657*0fca6ea1SDimitry Andric createReplacer(X86::NOT16r_ND, X86::KNOTWrr); 658*0fca6ea1SDimitry Andric createReplacer(X86::OR16rr_ND, X86::KORWrr); 659*0fca6ea1SDimitry Andric createReplacer(X86::AND16rr_ND, X86::KANDWrr); 660*0fca6ea1SDimitry Andric createReplacer(X86::XOR16rr_ND, X86::KXORWrr); 661*0fca6ea1SDimitry Andric } 662*0fca6ea1SDimitry Andric 6630b57cec5SDimitry Andric if (STI->hasBWI()) { 6641db9f3b2SDimitry Andric createReplacer(X86::MOV32rm, GET_EGPR_IF_ENABLED(X86::KMOVDkm)); 6651db9f3b2SDimitry Andric createReplacer(X86::MOV64rm, GET_EGPR_IF_ENABLED(X86::KMOVQkm)); 6660b57cec5SDimitry Andric 6671db9f3b2SDimitry Andric createReplacer(X86::MOV32mr, GET_EGPR_IF_ENABLED(X86::KMOVDmk)); 6681db9f3b2SDimitry Andric createReplacer(X86::MOV64mr, GET_EGPR_IF_ENABLED(X86::KMOVQmk)); 6690b57cec5SDimitry Andric 6701db9f3b2SDimitry Andric createReplacer(X86::MOV32rr, GET_EGPR_IF_ENABLED(X86::KMOVDkk)); 6711db9f3b2SDimitry Andric createReplacer(X86::MOV64rr, GET_EGPR_IF_ENABLED(X86::KMOVQkk)); 6720b57cec5SDimitry Andric 6730b57cec5SDimitry Andric createReplacer(X86::SHR32ri, X86::KSHIFTRDri); 6740b57cec5SDimitry Andric createReplacer(X86::SHR64ri, X86::KSHIFTRQri); 6750b57cec5SDimitry Andric 6760b57cec5SDimitry Andric createReplacer(X86::SHL32ri, X86::KSHIFTLDri); 6770b57cec5SDimitry Andric createReplacer(X86::SHL64ri, X86::KSHIFTLQri); 6780b57cec5SDimitry Andric 6790b57cec5SDimitry Andric createReplacer(X86::ADD32rr, X86::KADDDrr); 6800b57cec5SDimitry Andric createReplacer(X86::ADD64rr, X86::KADDQrr); 6810b57cec5SDimitry Andric 6820b57cec5SDimitry Andric createReplacer(X86::NOT32r, X86::KNOTDrr); 6830b57cec5SDimitry Andric createReplacer(X86::NOT64r, X86::KNOTQrr); 6840b57cec5SDimitry Andric 6850b57cec5SDimitry Andric createReplacer(X86::OR32rr, X86::KORDrr); 6860b57cec5SDimitry Andric createReplacer(X86::OR64rr, X86::KORQrr); 6870b57cec5SDimitry Andric 6880b57cec5SDimitry Andric createReplacer(X86::AND32rr, X86::KANDDrr); 6890b57cec5SDimitry Andric createReplacer(X86::AND64rr, X86::KANDQrr); 6900b57cec5SDimitry Andric 6910b57cec5SDimitry Andric createReplacer(X86::ANDN32rr, X86::KANDNDrr); 6920b57cec5SDimitry Andric createReplacer(X86::ANDN64rr, X86::KANDNQrr); 6930b57cec5SDimitry Andric 6940b57cec5SDimitry Andric createReplacer(X86::XOR32rr, X86::KXORDrr); 6950b57cec5SDimitry Andric createReplacer(X86::XOR64rr, X86::KXORQrr); 6960b57cec5SDimitry Andric 697*0fca6ea1SDimitry Andric if (HasNDD) { 698*0fca6ea1SDimitry Andric createReplacer(X86::SHR32ri_ND, X86::KSHIFTRDri); 699*0fca6ea1SDimitry Andric createReplacer(X86::SHL32ri_ND, X86::KSHIFTLDri); 700*0fca6ea1SDimitry Andric createReplacer(X86::ADD32rr_ND, X86::KADDDrr); 701*0fca6ea1SDimitry Andric createReplacer(X86::NOT32r_ND, X86::KNOTDrr); 702*0fca6ea1SDimitry Andric createReplacer(X86::OR32rr_ND, X86::KORDrr); 703*0fca6ea1SDimitry Andric createReplacer(X86::AND32rr_ND, X86::KANDDrr); 704*0fca6ea1SDimitry Andric createReplacer(X86::XOR32rr_ND, X86::KXORDrr); 705*0fca6ea1SDimitry Andric createReplacer(X86::SHR64ri_ND, X86::KSHIFTRQri); 706*0fca6ea1SDimitry Andric createReplacer(X86::SHL64ri_ND, X86::KSHIFTLQri); 707*0fca6ea1SDimitry Andric createReplacer(X86::ADD64rr_ND, X86::KADDQrr); 708*0fca6ea1SDimitry Andric createReplacer(X86::NOT64r_ND, X86::KNOTQrr); 709*0fca6ea1SDimitry Andric createReplacer(X86::OR64rr_ND, X86::KORQrr); 710*0fca6ea1SDimitry Andric createReplacer(X86::AND64rr_ND, X86::KANDQrr); 711*0fca6ea1SDimitry Andric createReplacer(X86::XOR64rr_ND, X86::KXORQrr); 712*0fca6ea1SDimitry Andric } 713*0fca6ea1SDimitry Andric 7140b57cec5SDimitry Andric // TODO: KTEST is not a replacement for TEST due to flag differences. Need 7150b57cec5SDimitry Andric // to prove only Z flag is used. 7160b57cec5SDimitry Andric // createReplacer(X86::TEST32rr, X86::KTESTDrr); 7170b57cec5SDimitry Andric // createReplacer(X86::TEST64rr, X86::KTESTQrr); 7180b57cec5SDimitry Andric } 7190b57cec5SDimitry Andric 7200b57cec5SDimitry Andric if (STI->hasDQI()) { 7210b57cec5SDimitry Andric createReplacer(X86::ADD8rr, X86::KADDBrr); 7220b57cec5SDimitry Andric createReplacer(X86::ADD16rr, X86::KADDWrr); 7230b57cec5SDimitry Andric 7240b57cec5SDimitry Andric createReplacer(X86::AND8rr, X86::KANDBrr); 7250b57cec5SDimitry Andric 7261db9f3b2SDimitry Andric createReplacer(X86::MOV8rm, GET_EGPR_IF_ENABLED(X86::KMOVBkm)); 7271db9f3b2SDimitry Andric createReplacer(X86::MOV8mr, GET_EGPR_IF_ENABLED(X86::KMOVBmk)); 7281db9f3b2SDimitry Andric createReplacer(X86::MOV8rr, GET_EGPR_IF_ENABLED(X86::KMOVBkk)); 7290b57cec5SDimitry Andric 7300b57cec5SDimitry Andric createReplacer(X86::NOT8r, X86::KNOTBrr); 7310b57cec5SDimitry Andric 7320b57cec5SDimitry Andric createReplacer(X86::OR8rr, X86::KORBrr); 7330b57cec5SDimitry Andric 7340b57cec5SDimitry Andric createReplacer(X86::SHR8ri, X86::KSHIFTRBri); 7350b57cec5SDimitry Andric createReplacer(X86::SHL8ri, X86::KSHIFTLBri); 7360b57cec5SDimitry Andric 7370b57cec5SDimitry Andric // TODO: KTEST is not a replacement for TEST due to flag differences. Need 7380b57cec5SDimitry Andric // to prove only Z flag is used. 7390b57cec5SDimitry Andric // createReplacer(X86::TEST8rr, X86::KTESTBrr); 7400b57cec5SDimitry Andric // createReplacer(X86::TEST16rr, X86::KTESTWrr); 7410b57cec5SDimitry Andric 7420b57cec5SDimitry Andric createReplacer(X86::XOR8rr, X86::KXORBrr); 743*0fca6ea1SDimitry Andric 744*0fca6ea1SDimitry Andric if (HasNDD) { 745*0fca6ea1SDimitry Andric createReplacer(X86::ADD8rr_ND, X86::KADDBrr); 746*0fca6ea1SDimitry Andric createReplacer(X86::ADD16rr_ND, X86::KADDWrr); 747*0fca6ea1SDimitry Andric createReplacer(X86::AND8rr_ND, X86::KANDBrr); 748*0fca6ea1SDimitry Andric createReplacer(X86::NOT8r_ND, X86::KNOTBrr); 749*0fca6ea1SDimitry Andric createReplacer(X86::OR8rr_ND, X86::KORBrr); 750*0fca6ea1SDimitry Andric createReplacer(X86::SHR8ri_ND, X86::KSHIFTRBri); 751*0fca6ea1SDimitry Andric createReplacer(X86::SHL8ri_ND, X86::KSHIFTLBri); 752*0fca6ea1SDimitry Andric createReplacer(X86::XOR8rr_ND, X86::KXORBrr); 753*0fca6ea1SDimitry Andric } 7540b57cec5SDimitry Andric } 7551db9f3b2SDimitry Andric #undef GET_EGPR_IF_ENABLED 7560b57cec5SDimitry Andric } 7570b57cec5SDimitry Andric 7580b57cec5SDimitry Andric bool X86DomainReassignment::runOnMachineFunction(MachineFunction &MF) { 7590b57cec5SDimitry Andric if (skipFunction(MF.getFunction())) 7600b57cec5SDimitry Andric return false; 7610b57cec5SDimitry Andric if (DisableX86DomainReassignment) 7620b57cec5SDimitry Andric return false; 7630b57cec5SDimitry Andric 7640b57cec5SDimitry Andric LLVM_DEBUG( 7650b57cec5SDimitry Andric dbgs() << "***** Machine Function before Domain Reassignment *****\n"); 7660b57cec5SDimitry Andric LLVM_DEBUG(MF.print(dbgs())); 7670b57cec5SDimitry Andric 7680b57cec5SDimitry Andric STI = &MF.getSubtarget<X86Subtarget>(); 7690b57cec5SDimitry Andric // GPR->K is the only transformation currently supported, bail out early if no 7700b57cec5SDimitry Andric // AVX512. 7710b57cec5SDimitry Andric // TODO: We're also bailing of AVX512BW isn't supported since we use VK32 and 7720b57cec5SDimitry Andric // VK64 for GR32/GR64, but those aren't legal classes on KNL. If the register 7730b57cec5SDimitry Andric // coalescer doesn't clean it up and we generate a spill we will crash. 7740b57cec5SDimitry Andric if (!STI->hasAVX512() || !STI->hasBWI()) 7750b57cec5SDimitry Andric return false; 7760b57cec5SDimitry Andric 7770b57cec5SDimitry Andric MRI = &MF.getRegInfo(); 7780b57cec5SDimitry Andric assert(MRI->isSSA() && "Expected MIR to be in SSA form"); 7790b57cec5SDimitry Andric 7800b57cec5SDimitry Andric TII = STI->getInstrInfo(); 7810b57cec5SDimitry Andric initConverters(); 7820b57cec5SDimitry Andric bool Changed = false; 7830b57cec5SDimitry Andric 7840b57cec5SDimitry Andric EnclosedEdges.clear(); 78581ad6265SDimitry Andric EnclosedEdges.resize(MRI->getNumVirtRegs()); 7860b57cec5SDimitry Andric EnclosedInstrs.clear(); 7870b57cec5SDimitry Andric 7880b57cec5SDimitry Andric std::vector<Closure> Closures; 7890b57cec5SDimitry Andric 7900b57cec5SDimitry Andric // Go over all virtual registers and calculate a closure. 7910b57cec5SDimitry Andric unsigned ClosureID = 0; 7920b57cec5SDimitry Andric for (unsigned Idx = 0; Idx < MRI->getNumVirtRegs(); ++Idx) { 793e8d8bef9SDimitry Andric Register Reg = Register::index2VirtReg(Idx); 7940b57cec5SDimitry Andric 795*0fca6ea1SDimitry Andric // Skip unused VRegs. 796*0fca6ea1SDimitry Andric if (MRI->reg_nodbg_empty(Reg)) 797*0fca6ea1SDimitry Andric continue; 798*0fca6ea1SDimitry Andric 7990b57cec5SDimitry Andric // GPR only current source domain supported. 8000b57cec5SDimitry Andric if (!isGPR(MRI->getRegClass(Reg))) 8010b57cec5SDimitry Andric continue; 8020b57cec5SDimitry Andric 8030b57cec5SDimitry Andric // Register already in closure. 80481ad6265SDimitry Andric if (EnclosedEdges.test(Idx)) 8050b57cec5SDimitry Andric continue; 8060b57cec5SDimitry Andric 8070b57cec5SDimitry Andric // Calculate closure starting with Reg. 8080b57cec5SDimitry Andric Closure C(ClosureID++, {MaskDomain}); 8090b57cec5SDimitry Andric buildClosure(C, Reg); 8100b57cec5SDimitry Andric 8110b57cec5SDimitry Andric // Collect all closures that can potentially be converted. 8120b57cec5SDimitry Andric if (!C.empty() && C.isLegal(MaskDomain)) 8130b57cec5SDimitry Andric Closures.push_back(std::move(C)); 8140b57cec5SDimitry Andric } 8150b57cec5SDimitry Andric 8160b57cec5SDimitry Andric for (Closure &C : Closures) { 8170b57cec5SDimitry Andric LLVM_DEBUG(C.dump(MRI)); 8180b57cec5SDimitry Andric if (isReassignmentProfitable(C, MaskDomain)) { 8190b57cec5SDimitry Andric reassign(C, MaskDomain); 8200b57cec5SDimitry Andric ++NumClosuresConverted; 8210b57cec5SDimitry Andric Changed = true; 8220b57cec5SDimitry Andric } 8230b57cec5SDimitry Andric } 8240b57cec5SDimitry Andric 8250b57cec5SDimitry Andric LLVM_DEBUG( 8260b57cec5SDimitry Andric dbgs() << "***** Machine Function after Domain Reassignment *****\n"); 8270b57cec5SDimitry Andric LLVM_DEBUG(MF.print(dbgs())); 8280b57cec5SDimitry Andric 8290b57cec5SDimitry Andric return Changed; 8300b57cec5SDimitry Andric } 8310b57cec5SDimitry Andric 8320b57cec5SDimitry Andric INITIALIZE_PASS(X86DomainReassignment, "x86-domain-reassignment", 8330b57cec5SDimitry Andric "X86 Domain Reassignment Pass", false, false) 8340b57cec5SDimitry Andric 8350b57cec5SDimitry Andric /// Returns an instance of the Domain Reassignment pass. 8360b57cec5SDimitry Andric FunctionPass *llvm::createX86DomainReassignmentPass() { 8370b57cec5SDimitry Andric return new X86DomainReassignment(); 8380b57cec5SDimitry Andric } 839