33#define DEBUG_TYPE "x86-domain-reassignment"
35STATISTIC(NumClosuresConverted,
"Number of closures converted by the pass");
42enum RegDomain { NoDomain = -1, GPRDomain, MaskDomain, OtherDomain, NumDomains };
46 return X86::VK16RegClass.hasSubClassEq(RC);
51 if (
TRI->isGeneralPurposeRegisterClass(RC))
62 if (X86::GR8RegClass.hasSubClassEq(SrcRC))
63 return &X86::VK8RegClass;
64 if (X86::GR16RegClass.hasSubClassEq(SrcRC))
65 return &X86::VK16RegClass;
66 if (X86::GR32RegClass.hasSubClassEq(SrcRC))
67 return &X86::VK32RegClass;
68 if (X86::GR64RegClass.hasSubClassEq(SrcRC))
69 return &X86::VK64RegClass;
75class InstrConverterBase {
80 InstrConverterBase(
unsigned SrcOpcode) : SrcOpcode(SrcOpcode) {}
82 virtual ~InstrConverterBase() =
default;
87 assert(
MI->getOpcode() == SrcOpcode &&
88 "Wrong instruction passed to converter");
106class InstrIgnore :
public InstrConverterBase {
108 InstrIgnore(
unsigned SrcOpcode) : InstrConverterBase(SrcOpcode) {}
112 assert(isLegal(
MI,
TII) &&
"Cannot convert instruction");
123class InstrReplacer :
public InstrConverterBase {
128 InstrReplacer(
unsigned SrcOpcode,
unsigned DstOpcode)
129 : InstrConverterBase(SrcOpcode), DstOpcode(DstOpcode) {}
133 if (!InstrConverterBase::isLegal(
MI,
TII))
137 for (
const auto &MO :
MI->implicit_operands())
138 if (MO.isReg() && MO.isDef() && !MO.isDead() &&
139 !
TII->get(DstOpcode).hasImplicitDefOfPhysReg(MO.getReg()))
146 assert(isLegal(
MI,
TII) &&
"Cannot convert instruction");
151 for (
auto &
Op :
MI->explicit_operands())
165class InstrReplacerDstCOPY :
public InstrConverterBase {
169 InstrReplacerDstCOPY(
unsigned SrcOpcode,
unsigned DstOpcode)
170 : InstrConverterBase(SrcOpcode), DstOpcode(DstOpcode) {}
174 assert(isLegal(
MI,
TII) &&
"Cannot convert instruction");
179 TII->getRegClass(
TII->get(DstOpcode), 0,
MRI->getTargetRegisterInfo(),
186 .
add(
MI->getOperand(0))
201class InstrCOPYReplacer :
public InstrReplacer {
205 InstrCOPYReplacer(
unsigned SrcOpcode, RegDomain DstDomain,
unsigned DstOpcode)
206 : InstrReplacer(SrcOpcode, DstOpcode), DstDomain(DstDomain) {}
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)))
229 assert(
MI->getOpcode() == TargetOpcode::COPY &&
"Expected a COPY");
231 for (
const auto &MO :
MI->operands()) {
235 if (MO.getReg().isPhysical())
238 RegDomain OpDomain =
getDomain(
MRI->getRegClass(MO.getReg()),
239 MRI->getTargetRegisterInfo());
242 if (OpDomain == DstDomain)
250class InstrReplaceWithCopy :
public InstrConverterBase {
255 InstrReplaceWithCopy(
unsigned SrcOpcode,
unsigned SrcOpIdx)
256 : InstrConverterBase(SrcOpcode), SrcOpIdx(SrcOpIdx) {}
260 assert(isLegal(
MI,
TII) &&
"Cannot convert instruction");
262 TII->get(TargetOpcode::COPY))
263 .
add({
MI->getOperand(0),
MI->getOperand(SrcOpIdx)});
275typedef std::pair<int, unsigned> InstrConverterBaseKeyTy;
278 InstrConverterBaseMap;
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; }
342 dbgs() <<
"Registers: ";
350 dbgs() <<
"\n" <<
"Instructions:";
358 unsigned getID()
const {
388 return "X86 Domain Reassignment Pass";
393 InstrConverterBaseMap Converters;
396 void initConverters();
399 void buildClosure(Closure &,
Register Reg);
406 void reassign(
const Closure &
C, RegDomain
Domain)
const;
412 bool isReassignmentProfitable(
const Closure &
C, RegDomain
Domain)
const;
415 double calculateCost(
const Closure &
C, RegDomain
Domain)
const;
418char X86DomainReassignment::ID = 0;
422void X86DomainReassignment::visitRegister(Closure &
C,
Register Reg,
425 if (!
Reg.isVirtual())
431 if (!
MRI->hasOneDef(Reg))
434 RegDomain RD =
getDomain(
MRI->getRegClass(Reg),
MRI->getTargetRegisterInfo());
445void X86DomainReassignment::encloseInstr(Closure &
C,
MachineInstr *
MI) {
446 auto I = EnclosedInstrs.find(
MI);
447 if (
I != EnclosedInstrs.end()) {
448 if (
I->second !=
C.getID())
455 EnclosedInstrs[
MI] =
C.getID();
456 C.addInstruction(
MI);
461 for (
int i = 0; i != NumDomains; ++i) {
462 if (
C.isLegal((RegDomain)i)) {
463 auto I = Converters.find({i,
MI->getOpcode()});
464 if (
I == Converters.end() || !
I->second->isLegal(
MI,
TII))
465 C.setIllegal((RegDomain)i);
470double X86DomainReassignment::calculateCost(
const Closure &
C,
471 RegDomain DstDomain)
const {
472 assert(
C.isLegal(DstDomain) &&
"Cannot calculate cost for illegal closure");
475 for (
auto *
MI :
C.instructions())
476 Cost += Converters.find({DstDomain,
MI->getOpcode()})
477 ->second->getExtraCost(
MI,
MRI);
481bool X86DomainReassignment::isReassignmentProfitable(
const Closure &
C,
483 return calculateCost(
C,
Domain) < 0.0;
486void X86DomainReassignment::reassign(
const Closure &
C, RegDomain
Domain)
const {
487 assert(
C.isLegal(
Domain) &&
"Cannot convert illegal closure");
492 for (
auto *
MI :
C.instructions())
493 if (Converters.find({Domain, MI->getOpcode()})
494 ->second->convertInstr(
MI,
TII,
MRI))
500 MRI->setRegClass(Reg, getDstRC(
MRI->getRegClass(Reg),
Domain));
501 for (
auto &MO :
MRI->use_operands(Reg)) {
509 for (
auto *
MI : ToErase)
510 MI->eraseFromParent();
517 if (!
MI.mayLoadOrStore())
522 if (MemOpStart == -1)
526 for (
unsigned MemOpIdx = MemOpStart,
528 MemOpIdx < MemOpEnd; ++MemOpIdx) {
530 if (
Op.isReg() &&
Op.getReg() == Reg)
536void X86DomainReassignment::buildClosure(Closure &
C,
Register Reg) {
538 RegDomain
Domain = NoDomain;
539 visitRegister(
C, Reg,
Domain, Worklist);
540 while (!Worklist.
empty()) {
544 if (!
C.insertEdge(CurReg))
559 for (
int OpIdx = 0; OpIdx < OpEnd; ++OpIdx) {
560 if (OpIdx ==
MemOp) {
566 if (!
Op.isReg() || !
Op.isUse())
568 visitRegister(
C,
Op.getReg(),
Domain, Worklist);
572 for (
auto &
UseMI :
MRI->use_nodbg_instructions(CurReg)) {
581 for (
auto &DefOp :
UseMI.defs()) {
590 visitRegister(
C, DefReg,
Domain, Worklist);
596void X86DomainReassignment::initConverters() {
597 Converters[{MaskDomain, TargetOpcode::PHI}] =
598 std::make_unique<InstrIgnore>(TargetOpcode::PHI);
600 Converters[{MaskDomain, TargetOpcode::IMPLICIT_DEF}] =
601 std::make_unique<InstrIgnore>(TargetOpcode::IMPLICIT_DEF);
603 Converters[{MaskDomain, TargetOpcode::INSERT_SUBREG}] =
604 std::make_unique<InstrReplaceWithCopy>(TargetOpcode::INSERT_SUBREG, 2);
606 Converters[{MaskDomain, TargetOpcode::COPY}] =
607 std::make_unique<InstrCOPYReplacer>(TargetOpcode::COPY, MaskDomain,
610 auto createReplacerDstCOPY = [&](
unsigned From,
unsigned To) {
611 Converters[{MaskDomain,
From}] =
612 std::make_unique<InstrReplacerDstCOPY>(
From, To);
615#define GET_EGPR_IF_ENABLED(OPC) STI->hasEGPR() ? OPC##_EVEX : OPC
632 auto createReplacer = [&](
unsigned From,
unsigned To) {
633 Converters[{MaskDomain,
From}] = std::make_unique<InstrReplacer>(
From, To);
639 createReplacer(X86::SHR16ri, X86::KSHIFTRWri);
640 createReplacer(X86::SHL16ri, X86::KSHIFTLWri);
641 createReplacer(X86::NOT16r, X86::KNOTWrr);
642 createReplacer(X86::OR16rr, X86::KORWrr);
643 createReplacer(X86::AND16rr, X86::KANDWrr);
644 createReplacer(X86::XOR16rr, X86::KXORWrr);
646 bool HasNDD = STI->hasNDD();
648 createReplacer(X86::SHR16ri_ND, X86::KSHIFTRWri);
649 createReplacer(X86::SHL16ri_ND, X86::KSHIFTLWri);
650 createReplacer(X86::NOT16r_ND, X86::KNOTWrr);
651 createReplacer(X86::OR16rr_ND, X86::KORWrr);
652 createReplacer(X86::AND16rr_ND, X86::KANDWrr);
653 createReplacer(X86::XOR16rr_ND, X86::KXORWrr);
666 createReplacer(X86::SHR32ri, X86::KSHIFTRDri);
667 createReplacer(X86::SHR64ri, X86::KSHIFTRQri);
669 createReplacer(X86::SHL32ri, X86::KSHIFTLDri);
670 createReplacer(X86::SHL64ri, X86::KSHIFTLQri);
672 createReplacer(X86::ADD32rr, X86::KADDDrr);
673 createReplacer(X86::ADD64rr, X86::KADDQrr);
675 createReplacer(X86::NOT32r, X86::KNOTDrr);
676 createReplacer(X86::NOT64r, X86::KNOTQrr);
678 createReplacer(X86::OR32rr, X86::KORDrr);
679 createReplacer(X86::OR64rr, X86::KORQrr);
681 createReplacer(X86::AND32rr, X86::KANDDrr);
682 createReplacer(X86::AND64rr, X86::KANDQrr);
684 createReplacer(X86::ANDN32rr, X86::KANDNDrr);
685 createReplacer(X86::ANDN64rr, X86::KANDNQrr);
687 createReplacer(X86::XOR32rr, X86::KXORDrr);
688 createReplacer(X86::XOR64rr, X86::KXORQrr);
691 createReplacer(X86::SHR32ri_ND, X86::KSHIFTRDri);
692 createReplacer(X86::SHL32ri_ND, X86::KSHIFTLDri);
693 createReplacer(X86::ADD32rr_ND, X86::KADDDrr);
694 createReplacer(X86::NOT32r_ND, X86::KNOTDrr);
695 createReplacer(X86::OR32rr_ND, X86::KORDrr);
696 createReplacer(X86::AND32rr_ND, X86::KANDDrr);
697 createReplacer(X86::XOR32rr_ND, X86::KXORDrr);
698 createReplacer(X86::SHR64ri_ND, X86::KSHIFTRQri);
699 createReplacer(X86::SHL64ri_ND, X86::KSHIFTLQri);
700 createReplacer(X86::ADD64rr_ND, X86::KADDQrr);
701 createReplacer(X86::NOT64r_ND, X86::KNOTQrr);
702 createReplacer(X86::OR64rr_ND, X86::KORQrr);
703 createReplacer(X86::AND64rr_ND, X86::KANDQrr);
704 createReplacer(X86::XOR64rr_ND, X86::KXORQrr);
714 createReplacer(X86::ADD8rr, X86::KADDBrr);
715 createReplacer(X86::ADD16rr, X86::KADDWrr);
717 createReplacer(X86::AND8rr, X86::KANDBrr);
723 createReplacer(X86::NOT8r, X86::KNOTBrr);
725 createReplacer(X86::OR8rr, X86::KORBrr);
727 createReplacer(X86::SHR8ri, X86::KSHIFTRBri);
728 createReplacer(X86::SHL8ri, X86::KSHIFTLBri);
735 createReplacer(X86::XOR8rr, X86::KXORBrr);
738 createReplacer(X86::ADD8rr_ND, X86::KADDBrr);
739 createReplacer(X86::ADD16rr_ND, X86::KADDWrr);
740 createReplacer(X86::AND8rr_ND, X86::KANDBrr);
741 createReplacer(X86::NOT8r_ND, X86::KNOTBrr);
742 createReplacer(X86::OR8rr_ND, X86::KORBrr);
743 createReplacer(X86::SHR8ri_ND, X86::KSHIFTRBri);
744 createReplacer(X86::SHL8ri_ND, X86::KSHIFTLBri);
745 createReplacer(X86::XOR8rr_ND, X86::KXORBrr);
748#undef GET_EGPR_IF_ENABLED
758 dbgs() <<
"***** Machine Function before Domain Reassignment *****\n");
767 if (!STI->hasAVX512() || !STI->hasBWI())
771 assert(
MRI->isSSA() &&
"Expected MIR to be in SSA form");
773 TII = STI->getInstrInfo();
775 bool Changed =
false;
777 EnclosedEdges.clear();
778 EnclosedEdges.resize(
MRI->getNumVirtRegs());
779 EnclosedInstrs.clear();
781 std::vector<Closure> Closures;
784 unsigned ClosureID = 0;
785 for (
unsigned Idx = 0;
Idx <
MRI->getNumVirtRegs(); ++
Idx) {
789 if (
MRI->reg_nodbg_empty(Reg))
793 if (!
MRI->getTargetRegisterInfo()->isGeneralPurposeRegisterClass(
794 MRI->getRegClass(Reg)))
798 if (EnclosedEdges.test(
Idx))
802 Closure
C(ClosureID++, {MaskDomain});
803 buildClosure(
C, Reg);
806 if (!
C.empty() &&
C.isLegal(MaskDomain))
807 Closures.push_back(std::move(
C));
810 for (Closure &
C : Closures) {
812 if (isReassignmentProfitable(
C, MaskDomain)) {
813 reassign(
C, MaskDomain);
814 ++NumClosuresConverted;
820 dbgs() <<
"***** Machine Function after Domain Reassignment *****\n");
827 "X86 Domain Reassignment Pass",
false,
false)
831 return new X86DomainReassignment();
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
This file implements the BitVector class.
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.
static unsigned virtReg2Index(Register Reg)
Convert a virtual register number to a 0-based index.
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.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ C
The default llvm calling convention, compatible with C.
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.