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 {
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) {}
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(
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())
532 if (MemOpStart == -1)
535 for (
unsigned MemOpIdx = MemOpStart,
537 MemOpIdx < MemOpEnd; ++MemOpIdx) {
539 if (
Op.isReg() &&
Op.getReg() ==
Reg)
545void X86DomainReassignmentImpl::buildClosure(Closure &
C,
Register Reg) {
547 RegDomain
Domain = NoDomain;
549 while (!Worklist.
empty()) {
553 if (!
C.insertEdge(CurReg))
555 EnclosedEdges[CurReg] =
C.getID();
558 if (!encloseInstr(
C,
DefMI))
566 for (
int OpIdx = 0; OpIdx < OpEnd; ++OpIdx) {
567 if (OpIdx == MemOp) {
573 if (!
Op.isReg() || !
Op.isUse())
575 if (!visitRegister(
C,
Op.getReg(),
Domain, Worklist))
587 if (!encloseInstr(
C, &
UseMI))
590 for (
auto &DefOp :
UseMI.defs()) {
599 if (!visitRegister(
C, DefReg,
Domain, Worklist))
606void X86DomainReassignmentImpl::initConverters() {
607 Converters[{MaskDomain, TargetOpcode::PHI}] =
608 std::make_unique<InstrIgnore>(TargetOpcode::PHI);
610 Converters[{MaskDomain, TargetOpcode::IMPLICIT_DEF}] =
611 std::make_unique<InstrIgnore>(TargetOpcode::IMPLICIT_DEF);
613 Converters[{MaskDomain, TargetOpcode::INSERT_SUBREG}] =
614 std::make_unique<InstrReplaceWithCopy>(TargetOpcode::INSERT_SUBREG, 2);
616 Converters[{MaskDomain, TargetOpcode::COPY}] =
617 std::make_unique<InstrCOPYReplacer>(TargetOpcode::COPY, MaskDomain,
620 auto createReplacerDstCOPY = [&](
unsigned From,
unsigned To) {
621 Converters[{MaskDomain, From}] =
622 std::make_unique<InstrReplacerDstCOPY>(From, To);
625#define GET_EGPR_IF_ENABLED(OPC) STI->hasEGPR() ? OPC##_EVEX : OPC
642 auto createReplacer = [&](
unsigned From,
unsigned To) {
643 Converters[{MaskDomain, From}] = std::make_unique<InstrReplacer>(From, To);
649 createReplacer(X86::SHR16ri, X86::KSHIFTRWki);
650 createReplacer(X86::SHL16ri, X86::KSHIFTLWki);
651 createReplacer(X86::NOT16r, X86::KNOTWkk);
652 createReplacer(X86::OR16rr, X86::KORWkk);
653 createReplacer(X86::AND16rr, X86::KANDWkk);
654 createReplacer(X86::XOR16rr, X86::KXORWkk);
656 bool HasNDD = STI->hasNDD();
658 createReplacer(X86::SHR16ri_ND, X86::KSHIFTRWki);
659 createReplacer(X86::SHL16ri_ND, X86::KSHIFTLWki);
660 createReplacer(X86::NOT16r_ND, X86::KNOTWkk);
661 createReplacer(X86::OR16rr_ND, X86::KORWkk);
662 createReplacer(X86::AND16rr_ND, X86::KANDWkk);
663 createReplacer(X86::XOR16rr_ND, X86::KXORWkk);
676 createReplacer(X86::SHR32ri, X86::KSHIFTRDki);
677 createReplacer(X86::SHR64ri, X86::KSHIFTRQki);
679 createReplacer(X86::SHL32ri, X86::KSHIFTLDki);
680 createReplacer(X86::SHL64ri, X86::KSHIFTLQki);
682 createReplacer(X86::ADD32rr, X86::KADDDkk);
683 createReplacer(X86::ADD64rr, X86::KADDQkk);
685 createReplacer(X86::NOT32r, X86::KNOTDkk);
686 createReplacer(X86::NOT64r, X86::KNOTQkk);
688 createReplacer(X86::OR32rr, X86::KORDkk);
689 createReplacer(X86::OR64rr, X86::KORQkk);
691 createReplacer(X86::AND32rr, X86::KANDDkk);
692 createReplacer(X86::AND64rr, X86::KANDQkk);
694 createReplacer(X86::ANDN32rr, X86::KANDNDkk);
695 createReplacer(X86::ANDN64rr, X86::KANDNQkk);
697 createReplacer(X86::XOR32rr, X86::KXORDkk);
698 createReplacer(X86::XOR64rr, X86::KXORQkk);
701 createReplacer(X86::SHR32ri_ND, X86::KSHIFTRDki);
702 createReplacer(X86::SHL32ri_ND, X86::KSHIFTLDki);
703 createReplacer(X86::ADD32rr_ND, X86::KADDDkk);
704 createReplacer(X86::NOT32r_ND, X86::KNOTDkk);
705 createReplacer(X86::OR32rr_ND, X86::KORDkk);
706 createReplacer(X86::AND32rr_ND, X86::KANDDkk);
707 createReplacer(X86::XOR32rr_ND, X86::KXORDkk);
708 createReplacer(X86::SHR64ri_ND, X86::KSHIFTRQki);
709 createReplacer(X86::SHL64ri_ND, X86::KSHIFTLQki);
710 createReplacer(X86::ADD64rr_ND, X86::KADDQkk);
711 createReplacer(X86::NOT64r_ND, X86::KNOTQkk);
712 createReplacer(X86::OR64rr_ND, X86::KORQkk);
713 createReplacer(X86::AND64rr_ND, X86::KANDQkk);
714 createReplacer(X86::XOR64rr_ND, X86::KXORQkk);
724 createReplacer(X86::ADD8rr, X86::KADDBkk);
725 createReplacer(X86::ADD16rr, X86::KADDWkk);
727 createReplacer(X86::AND8rr, X86::KANDBkk);
733 createReplacer(X86::NOT8r, X86::KNOTBkk);
735 createReplacer(X86::OR8rr, X86::KORBkk);
737 createReplacer(X86::SHR8ri, X86::KSHIFTRBki);
738 createReplacer(X86::SHL8ri, X86::KSHIFTLBki);
745 createReplacer(X86::XOR8rr, X86::KXORBkk);
748 createReplacer(X86::ADD8rr_ND, X86::KADDBkk);
749 createReplacer(X86::ADD16rr_ND, X86::KADDWkk);
750 createReplacer(X86::AND8rr_ND, X86::KANDBkk);
751 createReplacer(X86::NOT8r_ND, X86::KNOTBkk);
752 createReplacer(X86::OR8rr_ND, X86::KORBkk);
753 createReplacer(X86::SHR8ri_ND, X86::KSHIFTRBki);
754 createReplacer(X86::SHL8ri_ND, X86::KSHIFTLBki);
755 createReplacer(X86::XOR8rr_ND, X86::KXORBkk);
758#undef GET_EGPR_IF_ENABLED
761bool X86DomainReassignmentImpl::runOnMachineFunction(
MachineFunction &MF) {
766 dbgs() <<
"***** Machine Function before Domain Reassignment *****\n");
779 assert(MRI->
isSSA() &&
"Expected MIR to be in SSA form");
785 EnclosedEdges.
clear();
786 EnclosedInstrs.
clear();
788 std::vector<Closure> Closures;
791 unsigned ClosureID = 0;
809 Closure
C(ClosureID++, {MaskDomain});
810 buildClosure(
C,
Reg);
814 if (!
C.empty() &&
C.isLegal(MaskDomain))
815 Closures.push_back(std::move(
C));
818 for (Closure &
C : Closures) {
820 if (isReassignmentProfitable(
C, MaskDomain)) {
821 reassign(
C, MaskDomain);
822 ++NumClosuresConverted;
828 dbgs() <<
"***** Machine Function after Domain Reassignment *****\n");
834bool X86DomainReassignmentLegacy::runOnMachineFunction(
MachineFunction &MF) {
837 X86DomainReassignmentImpl Impl;
838 return Impl.runOnMachineFunction(MF);
842 "X86 Domain Reassignment Pass",
false,
false)
846 return new X86DomainReassignmentLegacy();
852 X86DomainReassignmentImpl Impl;
853 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< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
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
#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.
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
FunctionPass class - This class is used to implement most global optimizations.
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.
int getMemoryOperandIdx(const MCInstrDesc &Desc)
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.
MCRegisterClass TargetRegisterClass