xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/X86/X86DomainReassignment.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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