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
isGPR(const TargetRegisterClass * RC)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
isMask(const TargetRegisterClass * RC,const TargetRegisterInfo * TRI)510b57cec5SDimitry Andric static bool isMask(const TargetRegisterClass *RC,
520b57cec5SDimitry Andric const TargetRegisterInfo *TRI) {
530b57cec5SDimitry Andric return X86::VK16RegClass.hasSubClassEq(RC);
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric
getDomain(const TargetRegisterClass * RC,const TargetRegisterInfo * TRI)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.
getDstRC(const TargetRegisterClass * SrcRC,RegDomain 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:
InstrConverterBase(unsigned SrcOpcode)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.
isLegal(const MachineInstr * MI,const TargetInstrInfo * TII) const920b57cec5SDimitry 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:
InstrIgnore(unsigned SrcOpcode)1150b57cec5SDimitry Andric InstrIgnore(unsigned SrcOpcode) : InstrConverterBase(SrcOpcode) {}
1160b57cec5SDimitry Andric
convertInstr(MachineInstr * MI,const TargetInstrInfo * TII,MachineRegisterInfo * MRI) const1170b57cec5SDimitry 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
getExtraCost(const MachineInstr * MI,MachineRegisterInfo * MRI) const1230b57cec5SDimitry 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
InstrReplacer(unsigned SrcOpcode,unsigned DstOpcode)1350b57cec5SDimitry Andric InstrReplacer(unsigned SrcOpcode, unsigned DstOpcode)
1360b57cec5SDimitry Andric : InstrConverterBase(SrcOpcode), DstOpcode(DstOpcode) {}
1370b57cec5SDimitry Andric
isLegal(const MachineInstr * MI,const TargetInstrInfo * TII) const1380b57cec5SDimitry 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
convertInstr(MachineInstr * MI,const TargetInstrInfo * TII,MachineRegisterInfo * MRI) const1510b57cec5SDimitry 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
getExtraCost(const MachineInstr * MI,MachineRegisterInfo * MRI) const1630b57cec5SDimitry 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
InstrReplacerDstCOPY(unsigned SrcOpcode,unsigned DstOpcode)1760b57cec5SDimitry Andric InstrReplacerDstCOPY(unsigned SrcOpcode, unsigned DstOpcode)
1770b57cec5SDimitry Andric : InstrConverterBase(SrcOpcode), DstOpcode(DstOpcode) {}
1780b57cec5SDimitry Andric
convertInstr(MachineInstr * MI,const TargetInstrInfo * TII,MachineRegisterInfo * MRI) const1790b57cec5SDimitry 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
getExtraCost(const MachineInstr * MI,MachineRegisterInfo * MRI) const1990b57cec5SDimitry 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
InstrCOPYReplacer(unsigned SrcOpcode,RegDomain DstDomain,unsigned DstOpcode)2120b57cec5SDimitry Andric InstrCOPYReplacer(unsigned SrcOpcode, RegDomain DstDomain, unsigned DstOpcode)
2130b57cec5SDimitry Andric : InstrReplacer(SrcOpcode, DstOpcode), DstDomain(DstDomain) {}
2140b57cec5SDimitry Andric
isLegal(const MachineInstr * MI,const TargetInstrInfo * TII) const2150b57cec5SDimitry 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
getExtraCost(const MachineInstr * MI,MachineRegisterInfo * MRI) const2340b57cec5SDimitry 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
InstrReplaceWithCopy(unsigned SrcOpcode,unsigned SrcOpIdx)2620b57cec5SDimitry Andric InstrReplaceWithCopy(unsigned SrcOpcode, unsigned SrcOpIdx)
2630b57cec5SDimitry Andric : InstrConverterBase(SrcOpcode), SrcOpIdx(SrcOpIdx) {}
2640b57cec5SDimitry Andric
convertInstr(MachineInstr * MI,const TargetInstrInfo * TII,MachineRegisterInfo * MRI) const2650b57cec5SDimitry 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
getExtraCost(const MachineInstr * MI,MachineRegisterInfo * MRI) const2740b57cec5SDimitry 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:
Closure(unsigned ID,std::initializer_list<RegDomain> LegalDstDomainList)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.
setAllIllegal()3200b57cec5SDimitry Andric void setAllIllegal() { LegalDstDomains.reset(); }
3210b57cec5SDimitry Andric
3220b57cec5SDimitry Andric /// \returns true if this closure has domains which are legal to reassign to.
hasLegalDstDomain() const3230b57cec5SDimitry Andric bool hasLegalDstDomain() const { return LegalDstDomains.any(); }
3240b57cec5SDimitry Andric
3250b57cec5SDimitry Andric /// \returns true if is legal to reassign this closure to domain \p RD.
isLegal(RegDomain RD) const3260b57cec5SDimitry Andric bool isLegal(RegDomain RD) const { return LegalDstDomains[RD]; }
3270b57cec5SDimitry Andric
3280b57cec5SDimitry Andric /// Mark this closure as illegal for reassignment to domain \p RD.
setIllegal(RegDomain RD)3290b57cec5SDimitry Andric void setIllegal(RegDomain RD) { LegalDstDomains[RD] = false; }
3300b57cec5SDimitry Andric
empty() const3310b57cec5SDimitry Andric bool empty() const { return Edges.empty(); }
3320b57cec5SDimitry Andric
insertEdge(Register Reg)333e8d8bef9SDimitry Andric bool insertEdge(Register Reg) { return Edges.insert(Reg).second; }
3340b57cec5SDimitry Andric
335e8d8bef9SDimitry Andric using const_edge_iterator = DenseSet<Register>::const_iterator;
edges() const3360b57cec5SDimitry Andric iterator_range<const_edge_iterator> edges() const {
3370b57cec5SDimitry Andric return iterator_range<const_edge_iterator>(Edges.begin(), Edges.end());
3380b57cec5SDimitry Andric }
3390b57cec5SDimitry Andric
addInstruction(MachineInstr * I)3400b57cec5SDimitry Andric void addInstruction(MachineInstr *I) {
3410b57cec5SDimitry Andric Instrs.push_back(I);
3420b57cec5SDimitry Andric }
3430b57cec5SDimitry Andric
instructions() const3440b57cec5SDimitry Andric ArrayRef<MachineInstr *> instructions() const {
3450b57cec5SDimitry Andric return Instrs;
3460b57cec5SDimitry Andric }
3470b57cec5SDimitry Andric
dump(const MachineRegisterInfo * MRI) const3480b57cec5SDimitry 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
getID() const3650b57cec5SDimitry 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
X86DomainReassignment()3850b57cec5SDimitry Andric X86DomainReassignment() : MachineFunctionPass(ID) { }
3860b57cec5SDimitry Andric
3870b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override;
3880b57cec5SDimitry Andric
getAnalysisUsage(AnalysisUsage & AU) const3890b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
3900b57cec5SDimitry Andric AU.setPreservesCFG();
3910b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU);
3920b57cec5SDimitry Andric }
3930b57cec5SDimitry Andric
getPassName() const3940b57cec5SDimitry 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
visitRegister(Closure & C,Register Reg,RegDomain & Domain,SmallVectorImpl<unsigned> & Worklist)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
encloseInstr(Closure & C,MachineInstr * MI)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
calculateCost(const Closure & C,RegDomain DstDomain) const4770b57cec5SDimitry 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
isReassignmentProfitable(const Closure & C,RegDomain Domain) const4880b57cec5SDimitry Andric bool X86DomainReassignment::isReassignmentProfitable(const Closure &C,
4890b57cec5SDimitry Andric RegDomain Domain) const {
4900b57cec5SDimitry Andric return calculateCost(C, Domain) < 0.0;
4910b57cec5SDimitry Andric }
4920b57cec5SDimitry Andric
reassign(const Closure & C,RegDomain Domain) const4930b57cec5SDimitry 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.
usedAsAddr(const MachineInstr & MI,Register Reg,const TargetInstrInfo * TII)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
buildClosure(Closure & C,Register Reg)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
initConverters()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
runOnMachineFunction(MachineFunction & MF)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.
createX86DomainReassignmentPass()8360b57cec5SDimitry Andric FunctionPass *llvm::createX86DomainReassignmentPass() {
8370b57cec5SDimitry Andric return new X86DomainReassignment();
8380b57cec5SDimitry Andric }
839