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