33#define DEBUG_TYPE "x86-domain-reassignment"
35STATISTIC(NumClosuresConverted,
"Number of closures converted by the pass");
36STATISTIC(NumClosuresBuilt,
"Number of closures built by the pass");
43enum RegDomain { NoDomain = -1, GPRDomain, MaskDomain, OtherDomain, NumDomains };
47 return X86::VK16RegClass.hasSubClassEq(RC);
52 if (
TRI->isGeneralPurposeRegisterClass(RC))
63 if (X86::GR8RegClass.hasSubClassEq(SrcRC))
64 return &X86::VK8RegClass;
65 if (X86::GR16RegClass.hasSubClassEq(SrcRC))
66 return &X86::VK16RegClass;
67 if (X86::GR32RegClass.hasSubClassEq(SrcRC))
68 return &X86::VK32RegClass;
69 if (X86::GR64RegClass.hasSubClassEq(SrcRC))
70 return &X86::VK64RegClass;
76class InstrConverterBase {
81 InstrConverterBase(
unsigned SrcOpcode) : SrcOpcode(SrcOpcode) {}
83 virtual ~InstrConverterBase() =
default;
86 virtual bool isLegal(
const MachineInstr *
MI,
87 const TargetInstrInfo *
TII)
const {
88 assert(
MI->getOpcode() == SrcOpcode &&
89 "Wrong instruction passed to converter");
96 virtual bool convertInstr(MachineInstr *
MI,
const TargetInstrInfo *
TII,
97 MachineRegisterInfo *MRI)
const = 0;
100 virtual double getExtraCost(
const MachineInstr *
MI,
101 MachineRegisterInfo *MRI)
const = 0;
107class InstrIgnore :
public InstrConverterBase {
109 InstrIgnore(
unsigned SrcOpcode) : InstrConverterBase(SrcOpcode) {}
111 bool convertInstr(MachineInstr *
MI,
const TargetInstrInfo *
TII,
112 MachineRegisterInfo *MRI)
const override {
113 assert(isLegal(
MI,
TII) &&
"Cannot convert instruction");
117 double getExtraCost(
const MachineInstr *
MI,
118 MachineRegisterInfo *MRI)
const override {
124class InstrReplacer :
public InstrConverterBase {
129 InstrReplacer(
unsigned SrcOpcode,
unsigned DstOpcode)
130 : InstrConverterBase(SrcOpcode), DstOpcode(DstOpcode) {}
132 bool isLegal(
const MachineInstr *
MI,
133 const TargetInstrInfo *
TII)
const override {
134 if (!InstrConverterBase::isLegal(
MI,
TII))
138 for (
const auto &MO :
MI->implicit_operands())
139 if (MO.isReg() && MO.isDef() && !MO.isDead() &&
140 !
TII->get(DstOpcode).hasImplicitDefOfPhysReg(MO.getReg()))
145 bool convertInstr(MachineInstr *
MI,
const TargetInstrInfo *
TII,
146 MachineRegisterInfo *MRI)
const override {
147 assert(isLegal(
MI,
TII) &&
"Cannot convert instruction");
148 MachineInstrBuilder Bld =
152 for (
auto &
Op :
MI->explicit_operands())
157 double getExtraCost(
const MachineInstr *
MI,
158 MachineRegisterInfo *MRI)
const override {
166class InstrReplacerDstCOPY :
public InstrConverterBase {
170 InstrReplacerDstCOPY(
unsigned SrcOpcode,
unsigned DstOpcode)
171 : InstrConverterBase(SrcOpcode), DstOpcode(DstOpcode) {}
173 bool convertInstr(MachineInstr *
MI,
const TargetInstrInfo *
TII,
174 MachineRegisterInfo *MRI)
const override {
175 assert(isLegal(
MI,
TII) &&
"Cannot convert instruction");
176 MachineBasicBlock *
MBB =
MI->getParent();
186 .
add(
MI->getOperand(0))
192 double getExtraCost(
const MachineInstr *
MI,
193 MachineRegisterInfo *MRI)
const override {
201class InstrCOPYReplacer :
public InstrReplacer {
205 InstrCOPYReplacer(
unsigned SrcOpcode, RegDomain DstDomain,
unsigned DstOpcode)
206 : InstrReplacer(SrcOpcode, DstOpcode), DstDomain(DstDomain) {}
208 bool isLegal(
const MachineInstr *
MI,
209 const TargetInstrInfo *
TII)
const override {
210 if (!InstrConverterBase::isLegal(
MI,
TII))
216 if (DstReg.
isPhysical() && (X86::GR8RegClass.contains(DstReg) ||
217 X86::GR16RegClass.contains(DstReg)))
220 if (SrcReg.
isPhysical() && (X86::GR8RegClass.contains(SrcReg) ||
221 X86::GR16RegClass.contains(SrcReg)))
227 double getExtraCost(
const MachineInstr *
MI,
228 MachineRegisterInfo *MRI)
const override {
229 assert(
MI->getOpcode() == TargetOpcode::COPY &&
"Expected a COPY");
231 for (
const auto &MO :
MI->operands()) {
235 if (MO.getReg().isPhysical())
242 if (OpDomain == DstDomain)
250class InstrReplaceWithCopy :
public InstrConverterBase {
255 InstrReplaceWithCopy(
unsigned SrcOpcode,
unsigned SrcOpIdx)
256 : InstrConverterBase(SrcOpcode), SrcOpIdx(SrcOpIdx) {}
258 bool convertInstr(MachineInstr *
MI,
const TargetInstrInfo *
TII,
259 MachineRegisterInfo *MRI)
const override {
260 assert(isLegal(
MI,
TII) &&
"Cannot convert instruction");
262 TII->get(TargetOpcode::COPY))
263 .
add({
MI->getOperand(0),
MI->getOperand(SrcOpIdx)});
267 double getExtraCost(
const MachineInstr *
MI,
268 MachineRegisterInfo *MRI)
const override {
275typedef std::pair<int, unsigned> InstrConverterBaseKeyTy;
278 InstrConverterBaseMap;
294 DenseSet<Register> Edges;
297 SmallVector<MachineInstr *, 8> Instrs;
300 std::bitset<NumDomains> LegalDstDomains;
307 Closure(
unsigned ID, std::initializer_list<RegDomain> LegalDstDomainList) : ID(ID) {
308 for (RegDomain
D : LegalDstDomainList)
309 LegalDstDomains.set(
D);
313 void setAllIllegal() { LegalDstDomains.reset(); }
316 bool hasLegalDstDomain()
const {
return LegalDstDomains.any(); }
319 bool isLegal(RegDomain RD)
const {
return LegalDstDomains[RD]; }
322 void setIllegal(RegDomain RD) { LegalDstDomains[RD] =
false; }
324 bool empty()
const {
return Edges.empty(); }
326 bool insertEdge(
Register Reg) {
return Edges.insert(
Reg).second; }
328 using const_edge_iterator = DenseSet<Register>::const_iterator;
331 void addInstruction(MachineInstr *
I) {
340 dbgs() <<
"Registers: ";
344 dbgs() <<
"\n" <<
"Instructions:";
345 for (MachineInstr *
MI : Instrs) {
352 unsigned getID()
const {
358class X86DomainReassignmentImpl {
360 bool runOnMachineFunction(MachineFunction &MF);
363 const X86Subtarget *STI =
nullptr;
364 MachineRegisterInfo *MRI =
nullptr;
365 const X86InstrInfo *TII =
nullptr;
368 DenseMap<Register, unsigned> EnclosedEdges;
371 DenseMap<MachineInstr *, unsigned> EnclosedInstrs;
374 InstrConverterBaseMap Converters;
377 void initConverters();
385 SmallVectorImpl<Register> &Worklist);
388 void reassign(
const Closure &
C, RegDomain
Domain)
const;
392 bool encloseInstr(Closure &
C, MachineInstr *
MI);
395 bool isReassignmentProfitable(
const Closure &
C, RegDomain
Domain)
const;
398 double calculateCost(
const Closure &
C, RegDomain
Domain)
const;
405 X86DomainReassignmentLegacy() : MachineFunctionPass(ID) {}
407 bool runOnMachineFunction(MachineFunction &MF)
override;
409 void getAnalysisUsage(AnalysisUsage &AU)
const override {
414 StringRef getPassName()
const override {
415 return "X86 Domain Reassignment Pass";
419char X86DomainReassignmentLegacy::ID = 0;
423bool X86DomainReassignmentImpl::visitRegister(
429 auto I = EnclosedEdges.find(
Reg);
430 if (
I != EnclosedEdges.end()) {
431 if (
I->second !=
C.getID()) {
453bool X86DomainReassignmentImpl::encloseInstr(Closure &
C, MachineInstr *
MI) {
456 if (
I->second !=
C.getID()) {
465 C.addInstruction(
MI);
470 for (
int i = 0; i != NumDomains; ++i) {
471 if (
C.isLegal((RegDomain)i)) {
472 auto I = Converters.find({i,
MI->getOpcode()});
473 if (
I == Converters.end() || !
I->second->isLegal(
MI,
TII))
474 C.setIllegal((RegDomain)i);
477 return C.hasLegalDstDomain();
480double X86DomainReassignmentImpl::calculateCost(
const Closure &
C,
481 RegDomain DstDomain)
const {
482 assert(
C.isLegal(DstDomain) &&
"Cannot calculate cost for illegal closure");
485 for (
auto *
MI :
C.instructions())
486 Cost += Converters.find({DstDomain,
MI->getOpcode()})
487 ->second->getExtraCost(
MI, MRI);
491bool X86DomainReassignmentImpl::isReassignmentProfitable(
492 const Closure &
C, RegDomain
Domain)
const {
493 return calculateCost(
C,
Domain) < 0.0;
496void X86DomainReassignmentImpl::reassign(
const Closure &
C,
498 assert(
C.isLegal(
Domain) &&
"Cannot convert illegal closure");
502 SmallVector<MachineInstr *, 8> ToErase;
503 for (
auto *
MI :
C.instructions())
504 if (Converters.find({Domain, MI->getOpcode()})
505 ->second->convertInstr(
MI,
TII, MRI))
520 for (
auto *
MI : ToErase)
521 MI->eraseFromParent();
528 if (!
MI.mayLoadOrStore())
533 if (MemOpStart == -1)
537 for (
unsigned MemOpIdx = MemOpStart,
539 MemOpIdx < MemOpEnd; ++MemOpIdx) {
541 if (
Op.isReg() &&
Op.getReg() ==
Reg)
547void X86DomainReassignmentImpl::buildClosure(Closure &
C,
Register Reg) {
549 RegDomain
Domain = NoDomain;
551 while (!Worklist.
empty()) {
555 if (!
C.insertEdge(CurReg))
557 EnclosedEdges[CurReg] =
C.getID();
560 if (!encloseInstr(
C,
DefMI))
572 if (
OpIdx == MemOp) {
578 if (!
Op.isReg() || !
Op.isUse())
580 if (!visitRegister(
C,
Op.getReg(),
Domain, Worklist))
592 if (!encloseInstr(
C, &
UseMI))
595 for (
auto &DefOp :
UseMI.defs()) {
604 if (!visitRegister(
C, DefReg,
Domain, Worklist))
611void X86DomainReassignmentImpl::initConverters() {
612 Converters[{MaskDomain, TargetOpcode::PHI}] =
613 std::make_unique<InstrIgnore>(TargetOpcode::PHI);
615 Converters[{MaskDomain, TargetOpcode::IMPLICIT_DEF}] =
616 std::make_unique<InstrIgnore>(TargetOpcode::IMPLICIT_DEF);
618 Converters[{MaskDomain, TargetOpcode::INSERT_SUBREG}] =
619 std::make_unique<InstrReplaceWithCopy>(TargetOpcode::INSERT_SUBREG, 2);
621 Converters[{MaskDomain, TargetOpcode::COPY}] =
622 std::make_unique<InstrCOPYReplacer>(TargetOpcode::COPY, MaskDomain,
625 auto createReplacerDstCOPY = [&](
unsigned From,
unsigned To) {
626 Converters[{MaskDomain, From}] =
627 std::make_unique<InstrReplacerDstCOPY>(From, To);
630#define GET_EGPR_IF_ENABLED(OPC) STI->hasEGPR() ? OPC##_EVEX : OPC
647 auto createReplacer = [&](
unsigned From,
unsigned To) {
648 Converters[{MaskDomain, From}] = std::make_unique<InstrReplacer>(From, To);
654 createReplacer(X86::SHR16ri, X86::KSHIFTRWki);
655 createReplacer(X86::SHL16ri, X86::KSHIFTLWki);
656 createReplacer(X86::NOT16r, X86::KNOTWkk);
657 createReplacer(X86::OR16rr, X86::KORWkk);
658 createReplacer(X86::AND16rr, X86::KANDWkk);
659 createReplacer(X86::XOR16rr, X86::KXORWkk);
661 bool HasNDD = STI->hasNDD();
663 createReplacer(X86::SHR16ri_ND, X86::KSHIFTRWki);
664 createReplacer(X86::SHL16ri_ND, X86::KSHIFTLWki);
665 createReplacer(X86::NOT16r_ND, X86::KNOTWkk);
666 createReplacer(X86::OR16rr_ND, X86::KORWkk);
667 createReplacer(X86::AND16rr_ND, X86::KANDWkk);
668 createReplacer(X86::XOR16rr_ND, X86::KXORWkk);
681 createReplacer(X86::SHR32ri, X86::KSHIFTRDki);
682 createReplacer(X86::SHR64ri, X86::KSHIFTRQki);
684 createReplacer(X86::SHL32ri, X86::KSHIFTLDki);
685 createReplacer(X86::SHL64ri, X86::KSHIFTLQki);
687 createReplacer(X86::ADD32rr, X86::KADDDkk);
688 createReplacer(X86::ADD64rr, X86::KADDQkk);
690 createReplacer(X86::NOT32r, X86::KNOTDkk);
691 createReplacer(X86::NOT64r, X86::KNOTQkk);
693 createReplacer(X86::OR32rr, X86::KORDkk);
694 createReplacer(X86::OR64rr, X86::KORQkk);
696 createReplacer(X86::AND32rr, X86::KANDDkk);
697 createReplacer(X86::AND64rr, X86::KANDQkk);
699 createReplacer(X86::ANDN32rr, X86::KANDNDkk);
700 createReplacer(X86::ANDN64rr, X86::KANDNQkk);
702 createReplacer(X86::XOR32rr, X86::KXORDkk);
703 createReplacer(X86::XOR64rr, X86::KXORQkk);
706 createReplacer(X86::SHR32ri_ND, X86::KSHIFTRDki);
707 createReplacer(X86::SHL32ri_ND, X86::KSHIFTLDki);
708 createReplacer(X86::ADD32rr_ND, X86::KADDDkk);
709 createReplacer(X86::NOT32r_ND, X86::KNOTDkk);
710 createReplacer(X86::OR32rr_ND, X86::KORDkk);
711 createReplacer(X86::AND32rr_ND, X86::KANDDkk);
712 createReplacer(X86::XOR32rr_ND, X86::KXORDkk);
713 createReplacer(X86::SHR64ri_ND, X86::KSHIFTRQki);
714 createReplacer(X86::SHL64ri_ND, X86::KSHIFTLQki);
715 createReplacer(X86::ADD64rr_ND, X86::KADDQkk);
716 createReplacer(X86::NOT64r_ND, X86::KNOTQkk);
717 createReplacer(X86::OR64rr_ND, X86::KORQkk);
718 createReplacer(X86::AND64rr_ND, X86::KANDQkk);
719 createReplacer(X86::XOR64rr_ND, X86::KXORQkk);
729 createReplacer(X86::ADD8rr, X86::KADDBkk);
730 createReplacer(X86::ADD16rr, X86::KADDWkk);
732 createReplacer(X86::AND8rr, X86::KANDBkk);
738 createReplacer(X86::NOT8r, X86::KNOTBkk);
740 createReplacer(X86::OR8rr, X86::KORBkk);
742 createReplacer(X86::SHR8ri, X86::KSHIFTRBki);
743 createReplacer(X86::SHL8ri, X86::KSHIFTLBki);
750 createReplacer(X86::XOR8rr, X86::KXORBkk);
753 createReplacer(X86::ADD8rr_ND, X86::KADDBkk);
754 createReplacer(X86::ADD16rr_ND, X86::KADDWkk);
755 createReplacer(X86::AND8rr_ND, X86::KANDBkk);
756 createReplacer(X86::NOT8r_ND, X86::KNOTBkk);
757 createReplacer(X86::OR8rr_ND, X86::KORBkk);
758 createReplacer(X86::SHR8ri_ND, X86::KSHIFTRBki);
759 createReplacer(X86::SHL8ri_ND, X86::KSHIFTLBki);
760 createReplacer(X86::XOR8rr_ND, X86::KXORBkk);
763#undef GET_EGPR_IF_ENABLED
766bool X86DomainReassignmentImpl::runOnMachineFunction(MachineFunction &MF) {
771 dbgs() <<
"***** Machine Function before Domain Reassignment *****\n");
784 assert(MRI->
isSSA() &&
"Expected MIR to be in SSA form");
790 EnclosedEdges.clear();
791 EnclosedInstrs.
clear();
793 std::vector<Closure> Closures;
796 unsigned ClosureID = 0;
810 if (EnclosedEdges.contains(
Reg))
814 Closure
C(ClosureID++, {MaskDomain});
815 buildClosure(
C,
Reg);
819 if (!
C.empty() &&
C.isLegal(MaskDomain))
820 Closures.push_back(std::move(
C));
823 for (Closure &
C : Closures) {
825 if (isReassignmentProfitable(
C, MaskDomain)) {
826 reassign(
C, MaskDomain);
827 ++NumClosuresConverted;
833 dbgs() <<
"***** Machine Function after Domain Reassignment *****\n");
839bool X86DomainReassignmentLegacy::runOnMachineFunction(MachineFunction &MF) {
842 X86DomainReassignmentImpl Impl;
843 return Impl.runOnMachineFunction(MF);
847 "X86 Domain Reassignment Pass",
false,
false)
851 return new X86DomainReassignmentLegacy();
857 X86DomainReassignmentImpl Impl;
858 bool Changed = Impl.runOnMachineFunction(MF);
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
This file defines the DenseMap class.
const HexagonInstrInfo * TII
Register const TargetRegisterInfo * TRI
Promote Memory to Register
MachineInstr unsigned OpIdx
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
#define GET_EGPR_IF_ENABLED(OPC)
static cl::opt< bool > DisableX86DomainReassignment("disable-x86-domain-reassignment", cl::Hidden, cl::desc("X86: Disable Virtual Register Reassignment."), cl::init(false))
static bool usedAsAddr(const MachineInstr &MI, Register Reg, const TargetInstrInfo *TII)
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Represents analyses that only rely on functions' control flow.
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
FunctionPass class - This class is used to implement most global optimizations.
Describe properties that are true of each instruction in the target description file.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
void print(raw_ostream &OS, const SlotIndexes *=nullptr) const
print - Print out the MachineFunction in a format suitable for debugging to the specified stream.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
Representation of each machine instruction.
unsigned getNumOperands() const
Retuns the total number of operands.
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
bool reg_nodbg_empty(Register RegNo) const
reg_nodbg_empty - Return true if the only instructions using or defining Reg are Debug instructions.
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
bool hasOneDef(Register RegNo) const
Return true if there is exactly one operand defining the specified register.
LLVM_ABI void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
const TargetRegisterInfo * getTargetRegisterInfo() const
iterator_range< use_iterator > use_operands(Register Reg) const
unsigned getNumVirtRegs() const
getNumVirtRegs - Return the number of virtual registers created.
virtual void print(raw_ostream &OS, const Module *M) const
print - Print out the internal state of the pass.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Wrapper class representing virtual and physical registers.
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
TargetInstrInfo - Interface to description of machine instruction set.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual bool isGeneralPurposeRegisterClass(const TargetRegisterClass *RC) const
Returns true if RC is a class/subclass of general purpose register.
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
const X86InstrInfo * getInstrInfo() const override
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
int getMemoryOperandNo(uint64_t TSFlags)
unsigned getOperandBias(const MCInstrDesc &Desc)
Compute whether all of the def operands are repeated in the uses and therefore should be skipped.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
FunctionPass * createX86DomainReassignmentLegacyPass()
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
iterator_range(Container &&) -> iterator_range< llvm::detail::IterOfRange< Container > >
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
LLVM_ABI Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.