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");
39enum RegDomain { NoDomain = -1, GPRDomain, MaskDomain, OtherDomain, NumDomains };
43 return X86::VK16RegClass.hasSubClassEq(RC);
48 if (
TRI->isGeneralPurposeRegisterClass(RC))
59 if (X86::GR8RegClass.hasSubClassEq(SrcRC))
60 return &X86::VK8RegClass;
61 if (X86::GR16RegClass.hasSubClassEq(SrcRC))
62 return &X86::VK16RegClass;
63 if (X86::GR32RegClass.hasSubClassEq(SrcRC))
64 return &X86::VK32RegClass;
65 if (X86::GR64RegClass.hasSubClassEq(SrcRC))
66 return &X86::VK64RegClass;
72class InstrConverterBase {
77 InstrConverterBase(
unsigned SrcOpcode) : SrcOpcode(SrcOpcode) {}
79 virtual ~InstrConverterBase() =
default;
82 virtual bool isLegal(
const MachineInstr *
MI,
83 const TargetInstrInfo *
TII)
const {
84 assert(
MI->getOpcode() == SrcOpcode &&
85 "Wrong instruction passed to converter");
92 virtual bool convertInstr(MachineInstr *
MI,
const TargetInstrInfo *
TII,
93 MachineRegisterInfo *MRI)
const = 0;
96 virtual double getExtraCost(
const MachineInstr *
MI,
97 MachineRegisterInfo *MRI)
const = 0;
103class InstrIgnore :
public InstrConverterBase {
105 InstrIgnore(
unsigned SrcOpcode) : InstrConverterBase(SrcOpcode) {}
107 bool convertInstr(MachineInstr *
MI,
const TargetInstrInfo *
TII,
108 MachineRegisterInfo *MRI)
const override {
109 assert(isLegal(
MI,
TII) &&
"Cannot convert instruction");
113 double getExtraCost(
const MachineInstr *
MI,
114 MachineRegisterInfo *MRI)
const override {
120class InstrReplacer :
public InstrConverterBase {
125 InstrReplacer(
unsigned SrcOpcode,
unsigned DstOpcode)
126 : InstrConverterBase(SrcOpcode), DstOpcode(DstOpcode) {}
128 bool isLegal(
const MachineInstr *
MI,
129 const TargetInstrInfo *
TII)
const override {
130 if (!InstrConverterBase::isLegal(
MI,
TII))
134 for (
const auto &MO :
MI->implicit_operands())
135 if (MO.isReg() && MO.isDef() && !MO.isDead() &&
136 !
TII->get(DstOpcode).hasImplicitDefOfPhysReg(MO.getReg()))
141 bool convertInstr(MachineInstr *
MI,
const TargetInstrInfo *
TII,
142 MachineRegisterInfo *MRI)
const override {
143 assert(isLegal(
MI,
TII) &&
"Cannot convert instruction");
144 MachineInstrBuilder Bld =
148 for (
auto &
Op :
MI->explicit_operands())
153 double getExtraCost(
const MachineInstr *
MI,
154 MachineRegisterInfo *MRI)
const override {
162class InstrReplacerDstCOPY :
public InstrConverterBase {
166 InstrReplacerDstCOPY(
unsigned SrcOpcode,
unsigned DstOpcode)
167 : InstrConverterBase(SrcOpcode), DstOpcode(DstOpcode) {}
169 bool convertInstr(MachineInstr *
MI,
const TargetInstrInfo *
TII,
170 MachineRegisterInfo *MRI)
const override {
171 assert(isLegal(
MI,
TII) &&
"Cannot convert instruction");
182 .
add(
MI->getOperand(0))
188 double getExtraCost(
const MachineInstr *
MI,
189 MachineRegisterInfo *MRI)
const override {
197class InstrCOPYReplacer :
public InstrReplacer {
201 InstrCOPYReplacer(
unsigned SrcOpcode, RegDomain DstDomain,
unsigned DstOpcode)
202 : InstrReplacer(SrcOpcode, DstOpcode), DstDomain(DstDomain) {}
204 bool isLegal(
const MachineInstr *
MI,
205 const TargetInstrInfo *
TII)
const override {
206 if (!InstrConverterBase::isLegal(
MI,
TII))
212 if (DstReg.
isPhysical() && (X86::GR8RegClass.contains(DstReg) ||
213 X86::GR16RegClass.contains(DstReg)))
216 if (SrcReg.
isPhysical() && (X86::GR8RegClass.contains(SrcReg) ||
217 X86::GR16RegClass.contains(SrcReg)))
223 double getExtraCost(
const MachineInstr *
MI,
224 MachineRegisterInfo *MRI)
const override {
225 assert(
MI->getOpcode() == TargetOpcode::COPY &&
"Expected a COPY");
227 for (
const auto &MO :
MI->operands()) {
231 if (MO.getReg().isPhysical())
238 if (OpDomain == DstDomain)
246class InstrReplaceWithCopy :
public InstrConverterBase {
251 InstrReplaceWithCopy(
unsigned SrcOpcode,
unsigned SrcOpIdx)
252 : InstrConverterBase(SrcOpcode), SrcOpIdx(SrcOpIdx) {}
254 bool convertInstr(MachineInstr *
MI,
const TargetInstrInfo *
TII,
255 MachineRegisterInfo *MRI)
const override {
256 assert(isLegal(
MI,
TII) &&
"Cannot convert instruction");
258 TII->get(TargetOpcode::COPY))
259 .
add({
MI->getOperand(0),
MI->getOperand(SrcOpIdx)});
263 double getExtraCost(
const MachineInstr *
MI,
264 MachineRegisterInfo *MRI)
const override {
271typedef std::pair<int, unsigned> InstrConverterBaseKeyTy;
274 InstrConverterBaseMap;
290 DenseSet<Register> Edges;
293 SmallVector<MachineInstr *, 8> Instrs;
296 std::bitset<NumDomains> LegalDstDomains;
303 Closure(
unsigned ID, std::initializer_list<RegDomain> LegalDstDomainList) : ID(ID) {
304 for (RegDomain
D : LegalDstDomainList)
305 LegalDstDomains.set(
D);
309 void setAllIllegal() { LegalDstDomains.reset(); }
312 bool hasLegalDstDomain()
const {
return LegalDstDomains.any(); }
315 bool isLegal(RegDomain RD)
const {
return LegalDstDomains[RD]; }
318 void setIllegal(RegDomain RD) { LegalDstDomains[RD] =
false; }
320 bool empty()
const {
return Edges.empty(); }
322 bool insertEdge(
Register Reg) {
return Edges.insert(
Reg).second; }
324 using const_edge_iterator = DenseSet<Register>::const_iterator;
327 void addInstruction(MachineInstr *
I) {
336 dbgs() <<
"Registers: ";
340 dbgs() <<
"\n" <<
"Instructions:";
341 for (MachineInstr *
MI : Instrs) {
348 unsigned getID()
const {
354class X86DomainReassignmentImpl {
359 const X86Subtarget *STI =
nullptr;
360 MachineRegisterInfo *MRI =
nullptr;
361 const X86InstrInfo *TII =
nullptr;
364 DenseMap<Register, unsigned> EnclosedEdges;
367 DenseMap<MachineInstr *, unsigned> EnclosedInstrs;
370 InstrConverterBaseMap Converters;
373 void initConverters();
381 SmallVectorImpl<Register> &Worklist);
384 void reassign(
const Closure &
C, RegDomain
Domain)
const;
388 bool encloseInstr(Closure &
C, MachineInstr *
MI);
391 bool isReassignmentProfitable(
const Closure &
C, RegDomain
Domain)
const;
394 double calculateCost(
const Closure &
C, RegDomain
Domain)
const;
401 X86DomainReassignmentLegacy() : MachineFunctionPass(ID) {}
405 void getAnalysisUsage(AnalysisUsage &AU)
const override {
410 StringRef getPassName()
const override {
411 return "X86 Domain Reassignment Pass";
415char X86DomainReassignmentLegacy::ID = 0;
419bool X86DomainReassignmentImpl::visitRegister(
426 if (
I != EnclosedEdges.
end()) {
427 if (
I->second !=
C.getID()) {
449bool X86DomainReassignmentImpl::encloseInstr(Closure &
C, MachineInstr *
MI) {
452 if (
I->second !=
C.getID()) {
461 C.addInstruction(
MI);
466 for (
int i = 0; i != NumDomains; ++i) {
467 if (
C.isLegal((RegDomain)i)) {
468 auto I = Converters.find({i,
MI->getOpcode()});
469 if (
I == Converters.end() || !
I->second->isLegal(
MI,
TII))
470 C.setIllegal((RegDomain)i);
473 return C.hasLegalDstDomain();
476double X86DomainReassignmentImpl::calculateCost(
const Closure &
C,
477 RegDomain DstDomain)
const {
478 assert(
C.isLegal(DstDomain) &&
"Cannot calculate cost for illegal closure");
481 for (
auto *
MI :
C.instructions())
482 Cost += Converters.find({DstDomain,
MI->getOpcode()})
483 ->second->getExtraCost(
MI, MRI);
487bool X86DomainReassignmentImpl::isReassignmentProfitable(
488 const Closure &
C, RegDomain
Domain)
const {
489 return calculateCost(
C,
Domain) < 0.0;
492void X86DomainReassignmentImpl::reassign(
const Closure &
C,
494 assert(
C.isLegal(
Domain) &&
"Cannot convert illegal closure");
498 SmallVector<MachineInstr *, 8> ToErase;
499 for (
auto *
MI :
C.instructions())
500 if (Converters.find({Domain, MI->getOpcode()})
501 ->second->convertInstr(
MI,
TII, MRI))
516 for (
auto *
MI : ToErase)
517 MI->eraseFromParent();
524 if (!
MI.mayLoadOrStore())
528 if (MemOpStart == -1)
531 for (
unsigned MemOpIdx = MemOpStart,
533 MemOpIdx < MemOpEnd; ++MemOpIdx) {
535 if (
Op.isReg() &&
Op.getReg() ==
Reg)
541void X86DomainReassignmentImpl::buildClosure(Closure &
C,
Register Reg) {
543 RegDomain
Domain = NoDomain;
545 while (!Worklist.
empty()) {
549 if (!
C.insertEdge(CurReg))
551 EnclosedEdges[CurReg] =
C.getID();
554 if (!encloseInstr(
C,
DefMI))
562 for (
int OpIdx = 0; OpIdx < OpEnd; ++OpIdx) {
563 if (OpIdx == MemOp) {
569 if (!
Op.isReg() || !
Op.isUse())
571 if (!visitRegister(
C,
Op.getReg(),
Domain, Worklist))
583 if (!encloseInstr(
C, &
UseMI))
586 for (
auto &DefOp :
UseMI.defs()) {
595 if (!visitRegister(
C, DefReg,
Domain, Worklist))
602void X86DomainReassignmentImpl::initConverters() {
603 Converters[{MaskDomain, TargetOpcode::PHI}] =
604 std::make_unique<InstrIgnore>(TargetOpcode::PHI);
606 Converters[{MaskDomain, TargetOpcode::IMPLICIT_DEF}] =
607 std::make_unique<InstrIgnore>(TargetOpcode::IMPLICIT_DEF);
609 Converters[{MaskDomain, TargetOpcode::INSERT_SUBREG}] =
610 std::make_unique<InstrReplaceWithCopy>(TargetOpcode::INSERT_SUBREG, 2);
612 Converters[{MaskDomain, TargetOpcode::COPY}] =
613 std::make_unique<InstrCOPYReplacer>(TargetOpcode::COPY, MaskDomain,
616 auto createReplacerDstCOPY = [&](
unsigned From,
unsigned To) {
617 Converters[{MaskDomain, From}] =
618 std::make_unique<InstrReplacerDstCOPY>(From, To);
621#define GET_EGPR_IF_ENABLED(OPC) STI->hasEGPR() ? OPC##_EVEX : OPC
638 auto createReplacer = [&](
unsigned From,
unsigned To) {
639 Converters[{MaskDomain, From}] = std::make_unique<InstrReplacer>(From, To);
645 createReplacer(X86::SHR16ri, X86::KSHIFTRWki);
646 createReplacer(X86::SHL16ri, X86::KSHIFTLWki);
647 createReplacer(X86::NOT16r, X86::KNOTWkk);
648 createReplacer(X86::OR16rr, X86::KORWkk);
649 createReplacer(X86::AND16rr, X86::KANDWkk);
650 createReplacer(X86::XOR16rr, X86::KXORWkk);
652 bool HasNDD = STI->hasNDD();
654 createReplacer(X86::SHR16ri_ND, X86::KSHIFTRWki);
655 createReplacer(X86::SHL16ri_ND, X86::KSHIFTLWki);
656 createReplacer(X86::NOT16r_ND, X86::KNOTWkk);
657 createReplacer(X86::OR16rr_ND, X86::KORWkk);
658 createReplacer(X86::AND16rr_ND, X86::KANDWkk);
659 createReplacer(X86::XOR16rr_ND, X86::KXORWkk);
672 createReplacer(X86::SHR32ri, X86::KSHIFTRDki);
673 createReplacer(X86::SHR64ri, X86::KSHIFTRQki);
675 createReplacer(X86::SHL32ri, X86::KSHIFTLDki);
676 createReplacer(X86::SHL64ri, X86::KSHIFTLQki);
678 createReplacer(X86::ADD32rr, X86::KADDDkk);
679 createReplacer(X86::ADD64rr, X86::KADDQkk);
681 createReplacer(X86::NOT32r, X86::KNOTDkk);
682 createReplacer(X86::NOT64r, X86::KNOTQkk);
684 createReplacer(X86::OR32rr, X86::KORDkk);
685 createReplacer(X86::OR64rr, X86::KORQkk);
687 createReplacer(X86::AND32rr, X86::KANDDkk);
688 createReplacer(X86::AND64rr, X86::KANDQkk);
690 createReplacer(X86::ANDN32rr, X86::KANDNDkk);
691 createReplacer(X86::ANDN64rr, X86::KANDNQkk);
693 createReplacer(X86::XOR32rr, X86::KXORDkk);
694 createReplacer(X86::XOR64rr, X86::KXORQkk);
697 createReplacer(X86::SHR32ri_ND, X86::KSHIFTRDki);
698 createReplacer(X86::SHL32ri_ND, X86::KSHIFTLDki);
699 createReplacer(X86::ADD32rr_ND, X86::KADDDkk);
700 createReplacer(X86::NOT32r_ND, X86::KNOTDkk);
701 createReplacer(X86::OR32rr_ND, X86::KORDkk);
702 createReplacer(X86::AND32rr_ND, X86::KANDDkk);
703 createReplacer(X86::XOR32rr_ND, X86::KXORDkk);
704 createReplacer(X86::SHR64ri_ND, X86::KSHIFTRQki);
705 createReplacer(X86::SHL64ri_ND, X86::KSHIFTLQki);
706 createReplacer(X86::ADD64rr_ND, X86::KADDQkk);
707 createReplacer(X86::NOT64r_ND, X86::KNOTQkk);
708 createReplacer(X86::OR64rr_ND, X86::KORQkk);
709 createReplacer(X86::AND64rr_ND, X86::KANDQkk);
710 createReplacer(X86::XOR64rr_ND, X86::KXORQkk);
720 createReplacer(X86::ADD8rr, X86::KADDBkk);
721 createReplacer(X86::ADD16rr, X86::KADDWkk);
723 createReplacer(X86::AND8rr, X86::KANDBkk);
729 createReplacer(X86::NOT8r, X86::KNOTBkk);
731 createReplacer(X86::OR8rr, X86::KORBkk);
733 createReplacer(X86::SHR8ri, X86::KSHIFTRBki);
734 createReplacer(X86::SHL8ri, X86::KSHIFTLBki);
741 createReplacer(X86::XOR8rr, X86::KXORBkk);
744 createReplacer(X86::ADD8rr_ND, X86::KADDBkk);
745 createReplacer(X86::ADD16rr_ND, X86::KADDWkk);
746 createReplacer(X86::AND8rr_ND, X86::KANDBkk);
747 createReplacer(X86::NOT8r_ND, X86::KNOTBkk);
748 createReplacer(X86::OR8rr_ND, X86::KORBkk);
749 createReplacer(X86::SHR8ri_ND, X86::KSHIFTRBki);
750 createReplacer(X86::SHL8ri_ND, X86::KSHIFTLBki);
751 createReplacer(X86::XOR8rr_ND, X86::KXORBkk);
754#undef GET_EGPR_IF_ENABLED
757bool X86DomainReassignmentImpl::runOnMachineFunction(
MachineFunction &MF) {
759 if (STI->
getCLOpts().disable_x86_domain_reassignment)
763 dbgs() <<
"***** Machine Function before Domain Reassignment *****\n");
775 assert(MRI->
isSSA() &&
"Expected MIR to be in SSA form");
781 EnclosedEdges.
clear();
782 EnclosedInstrs.
clear();
784 std::vector<Closure> Closures;
787 unsigned ClosureID = 0;
805 Closure
C(ClosureID++, {MaskDomain});
806 buildClosure(
C,
Reg);
810 if (!
C.empty() &&
C.isLegal(MaskDomain))
811 Closures.push_back(std::move(
C));
814 for (Closure &
C : Closures) {
816 if (isReassignmentProfitable(
C, MaskDomain)) {
817 reassign(
C, MaskDomain);
818 ++NumClosuresConverted;
824 dbgs() <<
"***** Machine Function after Domain Reassignment *****\n");
830bool X86DomainReassignmentLegacy::runOnMachineFunction(
MachineFunction &MF) {
833 X86DomainReassignmentImpl Impl;
834 return Impl.runOnMachineFunction(MF);
838 "X86 Domain Reassignment Pass",
false,
false)
842 return new X86DomainReassignmentLegacy();
848 X86DomainReassignmentImpl Impl;
849 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 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.
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
FunctionPass class - This class is used to implement most global optimizations.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
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 LLVM_READONLY 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.
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
const X86Options & getCLOpts() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
int getMemoryOperandIdx(const MCInstrDesc &Desc)
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