32#define DEBUG_TYPE "x86-domain-reassignment"
34STATISTIC(NumClosuresConverted,
"Number of closures converted by the pass");
41enum RegDomain { NoDomain = -1, GPRDomain, MaskDomain, OtherDomain, NumDomains };
45 return X86::VK16RegClass.hasSubClassEq(RC);
50 if (
TRI->isGeneralPurposeRegisterClass(RC))
61 if (X86::GR8RegClass.hasSubClassEq(SrcRC))
62 return &X86::VK8RegClass;
63 if (X86::GR16RegClass.hasSubClassEq(SrcRC))
64 return &X86::VK16RegClass;
65 if (X86::GR32RegClass.hasSubClassEq(SrcRC))
66 return &X86::VK32RegClass;
67 if (X86::GR64RegClass.hasSubClassEq(SrcRC))
68 return &X86::VK64RegClass;
74class InstrConverterBase {
79 InstrConverterBase(
unsigned SrcOpcode) : SrcOpcode(SrcOpcode) {}
81 virtual ~InstrConverterBase() =
default;
86 assert(
MI->getOpcode() == SrcOpcode &&
87 "Wrong instruction passed to converter");
105class InstrIgnore :
public InstrConverterBase {
107 InstrIgnore(
unsigned SrcOpcode) : InstrConverterBase(SrcOpcode) {}
111 assert(isLegal(
MI,
TII) &&
"Cannot convert instruction");
122class InstrReplacer :
public InstrConverterBase {
127 InstrReplacer(
unsigned SrcOpcode,
unsigned DstOpcode)
128 : InstrConverterBase(SrcOpcode), DstOpcode(DstOpcode) {}
132 if (!InstrConverterBase::isLegal(
MI,
TII))
136 for (
const auto &MO :
MI->implicit_operands())
137 if (MO.isReg() && MO.isDef() && !MO.isDead() &&
138 !
TII->get(DstOpcode).hasImplicitDefOfPhysReg(MO.getReg()))
145 assert(isLegal(
MI,
TII) &&
"Cannot convert instruction");
150 for (
auto &
Op :
MI->explicit_operands())
164class InstrReplacerDstCOPY :
public InstrConverterBase {
168 InstrReplacerDstCOPY(
unsigned SrcOpcode,
unsigned DstOpcode)
169 : InstrConverterBase(SrcOpcode), DstOpcode(DstOpcode) {}
173 assert(isLegal(
MI,
TII) &&
"Cannot convert instruction");
178 TII->getRegClass(
TII->get(DstOpcode), 0,
MRI->getTargetRegisterInfo(),
185 .
add(
MI->getOperand(0))
200class InstrCOPYReplacer :
public InstrReplacer {
204 InstrCOPYReplacer(
unsigned SrcOpcode, RegDomain DstDomain,
unsigned DstOpcode)
205 : InstrReplacer(SrcOpcode, DstOpcode), DstDomain(DstDomain) {}
209 if (!InstrConverterBase::isLegal(
MI,
TII))
215 if (DstReg.
isPhysical() && (X86::GR8RegClass.contains(DstReg) ||
216 X86::GR16RegClass.contains(DstReg)))
219 if (SrcReg.
isPhysical() && (X86::GR8RegClass.contains(SrcReg) ||
220 X86::GR16RegClass.contains(SrcReg)))
228 assert(
MI->getOpcode() == TargetOpcode::COPY &&
"Expected a COPY");
230 for (
const auto &MO :
MI->operands()) {
234 if (MO.getReg().isPhysical())
237 RegDomain OpDomain =
getDomain(
MRI->getRegClass(MO.getReg()),
238 MRI->getTargetRegisterInfo());
241 if (OpDomain == DstDomain)
249class InstrReplaceWithCopy :
public InstrConverterBase {
254 InstrReplaceWithCopy(
unsigned SrcOpcode,
unsigned SrcOpIdx)
255 : InstrConverterBase(SrcOpcode), SrcOpIdx(SrcOpIdx) {}
259 assert(isLegal(
MI,
TII) &&
"Cannot convert instruction");
261 TII->get(TargetOpcode::COPY))
262 .
add({
MI->getOperand(0),
MI->getOperand(SrcOpIdx)});
274typedef std::pair<int, unsigned> InstrConverterBaseKeyTy;
277 InstrConverterBaseMap;
299 std::bitset<NumDomains> LegalDstDomains;
306 Closure(
unsigned ID, std::initializer_list<RegDomain> LegalDstDomainList) :
ID(
ID) {
307 for (RegDomain
D : LegalDstDomainList)
308 LegalDstDomains.set(
D);
312 void setAllIllegal() { LegalDstDomains.reset(); }
315 bool hasLegalDstDomain()
const {
return LegalDstDomains.any(); }
318 bool isLegal(RegDomain RD)
const {
return LegalDstDomains[RD]; }
321 void setIllegal(RegDomain RD) { LegalDstDomains[RD] =
false; }
323 bool empty()
const {
return Edges.
empty(); }
325 bool insertEdge(
Register Reg) {
return Edges.
insert(Reg).second; }
341 dbgs() <<
"Registers: ";
349 dbgs() <<
"\n" <<
"Instructions:";
357 unsigned getID()
const {
387 return "X86 Domain Reassignment Pass";
392 InstrConverterBaseMap Converters;
395 void initConverters();
398 void buildClosure(Closure &,
Register Reg);
406 void reassign(
const Closure &
C, RegDomain
Domain)
const;
413 bool isReassignmentProfitable(
const Closure &
C, RegDomain
Domain)
const;
416 double calculateCost(
const Closure &
C, RegDomain
Domain)
const;
419char X86DomainReassignment::ID = 0;
423bool X86DomainReassignment::visitRegister(Closure &
C,
Register Reg,
426 if (!
Reg.isVirtual())
429 auto I = EnclosedEdges.find(Reg);
430 if (
I != EnclosedEdges.end()) {
431 if (
I->second !=
C.getID()) {
438 if (!
MRI->hasOneDef(Reg))
441 RegDomain RD =
getDomain(
MRI->getRegClass(Reg),
MRI->getTargetRegisterInfo());
453bool X86DomainReassignment::encloseInstr(Closure &
C,
MachineInstr *
MI) {
454 auto I = EnclosedInstrs.find(
MI);
455 if (
I != EnclosedInstrs.end()) {
456 if (
I->second !=
C.getID()) {
465 EnclosedInstrs[
MI] =
C.getID();
466 C.addInstruction(
MI);
471 for (
int i = 0; i != NumDomains; ++i) {
472 if (
C.isLegal((RegDomain)i)) {
473 auto I = Converters.find({i,
MI->getOpcode()});
474 if (
I == Converters.end() || !
I->second->isLegal(
MI,
TII))
475 C.setIllegal((RegDomain)i);
478 return C.hasLegalDstDomain();
481double X86DomainReassignment::calculateCost(
const Closure &
C,
482 RegDomain DstDomain)
const {
483 assert(
C.isLegal(DstDomain) &&
"Cannot calculate cost for illegal closure");
486 for (
auto *
MI :
C.instructions())
487 Cost += Converters.find({DstDomain,
MI->getOpcode()})
488 ->second->getExtraCost(
MI,
MRI);
492bool X86DomainReassignment::isReassignmentProfitable(
const Closure &
C,
494 return calculateCost(
C,
Domain) < 0.0;
497void X86DomainReassignment::reassign(
const Closure &
C, RegDomain
Domain)
const {
498 assert(
C.isLegal(
Domain) &&
"Cannot convert illegal closure");
503 for (
auto *
MI :
C.instructions())
504 if (Converters.find({Domain, MI->getOpcode()})
505 ->second->convertInstr(
MI,
TII,
MRI))
511 MRI->setRegClass(Reg, getDstRC(
MRI->getRegClass(Reg),
Domain));
512 for (
auto &MO :
MRI->use_operands(Reg)) {
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 X86DomainReassignment::buildClosure(Closure &
C,
Register Reg) {
549 RegDomain
Domain = NoDomain;
550 visitRegister(
C, Reg,
Domain, Worklist);
551 while (!Worklist.
empty()) {
555 if (!
C.insertEdge(CurReg))
557 EnclosedEdges[
Reg] =
C.getID();
560 if (!encloseInstr(
C,
DefMI))
571 for (
int OpIdx = 0; OpIdx < OpEnd; ++OpIdx) {
572 if (OpIdx ==
MemOp) {
578 if (!
Op.isReg() || !
Op.isUse())
580 if (!visitRegister(
C,
Op.getReg(),
Domain, Worklist))
585 for (
auto &
UseMI :
MRI->use_nodbg_instructions(CurReg)) {
592 if (!encloseInstr(
C, &
UseMI))
595 for (
auto &DefOp :
UseMI.defs()) {
604 if (!visitRegister(
C, DefReg,
Domain, Worklist))
611void X86DomainReassignment::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
773 dbgs() <<
"***** Machine Function before Domain Reassignment *****\n");
782 if (!STI->hasAVX512() || !STI->hasBWI())
786 assert(
MRI->isSSA() &&
"Expected MIR to be in SSA form");
788 TII = STI->getInstrInfo();
790 bool Changed =
false;
792 EnclosedEdges.clear();
793 EnclosedInstrs.clear();
795 std::vector<Closure> Closures;
798 unsigned ClosureID = 0;
799 for (
unsigned Idx = 0;
Idx <
MRI->getNumVirtRegs(); ++
Idx) {
803 if (
MRI->reg_nodbg_empty(Reg))
807 if (!
MRI->getTargetRegisterInfo()->isGeneralPurposeRegisterClass(
808 MRI->getRegClass(Reg)))
812 if (EnclosedEdges.contains(Reg))
816 Closure
C(ClosureID++, {MaskDomain});
817 buildClosure(
C, Reg);
820 if (!
C.empty() &&
C.isLegal(MaskDomain))
821 Closures.push_back(std::move(
C));
824 for (Closure &
C : Closures) {
826 if (isReassignmentProfitable(
C, MaskDomain)) {
827 reassign(
C, MaskDomain);
828 ++NumClosuresConverted;
834 dbgs() <<
"***** Machine Function after Domain Reassignment *****\n");
841 "X86 Domain Reassignment Pass",
false,
false)
845 return new X86DomainReassignment();
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
BlockVerifier::State From
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.
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
This file defines the DenseMap class.
const HexagonInstrInfo * TII
unsigned const TargetRegisterInfo * TRI
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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)
Represent the analysis usage information of a pass.
void setPreservesCFG()
This function should be called by the pass, iff they do not:
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
This class represents an Operation in the Expression.
Implements a dense probed hash-table based set.
FunctionPass class - This class is used to implement most global optimizations.
Describe properties that are true of each instruction in the target description file.
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.
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
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 & add(const MachineOperand &MO) const
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
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.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
virtual void print(raw_ostream &OS, const Module *M) const
print - Print out the internal state of the pass.
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Wrapper class representing virtual and physical registers.
static Register index2VirtReg(unsigned Index)
Convert a 0-based index to a virtual register number.
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)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
TargetInstrInfo - Interface to description of machine instruction set.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
std::pair< iterator, bool > insert(const ValueT &V)
A range adaptor for a pair of iterators.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Reg
All possible values of the reg field in the ModR/M byte.
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)
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
FunctionPass * createX86DomainReassignmentPass()
Return a Machine IR pass that reassigns instruction chains from one domain to another,...
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
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.
Description of the encoding of one expression Op.