47#define DEBUG_TYPE "aarch64-a57-fp-load-balancing"
53 cl::desc(
"Always modify dest registers regardless of color"),
60 cl::desc(
"Ignore balance information, always return "
61 "(1: Even, 2: Odd)."),
69 switch (
MI->getOpcode()) {
70 case AArch64::FMULSrr:
71 case AArch64::FNMULSrr:
72 case AArch64::FMULDrr:
73 case AArch64::FNMULDrr:
82 switch (
MI->getOpcode()) {
83 case AArch64::FMSUBSrrr:
84 case AArch64::FMADDSrrr:
85 case AArch64::FNMSUBSrrr:
86 case AArch64::FNMADDSrrr:
87 case AArch64::FMSUBDrrr:
88 case AArch64::FMADDDrrr:
89 case AArch64::FNMSUBDrrr:
90 case AArch64::FNMADDDrrr:
102enum class Color { Even, Odd };
104static const char *ColorNames[2] = {
"Even",
"Odd" };
109class AArch64A57FPLoadBalancingImpl {
111 explicit AArch64A57FPLoadBalancingImpl(RegisterClassInfo *RCI) : RCI(RCI) {}
113 bool run(MachineFunction &MF);
116 MachineRegisterInfo *MRI;
117 const TargetRegisterInfo *TRI;
118 RegisterClassInfo *RCI =
nullptr;
121 bool colorChainSet(std::vector<Chain *> GV, MachineBasicBlock &
MBB,
123 bool colorChain(Chain *
G, Color
C, MachineBasicBlock &
MBB);
124 int scavengeRegister(Chain *
G, Color
C, MachineBasicBlock &
MBB);
125 void scanInstruction(MachineInstr *
MI,
unsigned Idx,
126 std::map<unsigned, Chain *> &Active,
127 std::vector<std::unique_ptr<Chain>> &AllChains);
128 void maybeKillChain(MachineOperand &MO,
unsigned Idx,
129 std::map<unsigned, Chain *> &RegChains);
131 Chain *getAndEraseNext(Color PreferredColor, std::vector<Chain *> &L);
137 explicit AArch64A57FPLoadBalancingLegacy() : MachineFunctionPass(ID) {}
139 bool runOnMachineFunction(MachineFunction &MF)
override;
141 MachineFunctionProperties getRequiredProperties()
const override {
142 return MachineFunctionProperties().setNoVRegs();
145 StringRef getPassName()
const override {
146 return "A57 FP Anti-dependency breaker";
149 void getAnalysisUsage(AnalysisUsage &AU)
const override {
151 AU.
addRequired<MachineRegisterClassInfoWrapperPass>();
158char AArch64A57FPLoadBalancingLegacy::ID = 0;
161 "AArch64 A57 FP Load-Balancing",
false,
false)
224 "Chain: broken invariant. A Chain can only be killed after its last "
245 "Chain: broken invariant. A Chain can only be killed after its last "
275 unsigned OtherEnd =
Other.KillInst ?
317 if (!MF.
getSubtarget<AArch64Subtarget>().balanceFPOps())
326 for (
auto &
MBB : MF) {
333bool AArch64A57FPLoadBalancingLegacy::runOnMachineFunction(
334 MachineFunction &MF) {
337 RegisterClassInfo *RCI =
338 &getAnalysis<MachineRegisterClassInfoWrapperPass>().getRCI();
339 return AArch64A57FPLoadBalancingImpl(RCI).run(MF);
346 if (AArch64A57FPLoadBalancingImpl(RCI).
run(MF)) {
357 <<
" - scanning instructions...\n");
364 std::map<unsigned, Chain*> ActiveChains;
365 std::vector<std::unique_ptr<Chain>> AllChains;
368 scanInstruction(&
MI, Idx++, ActiveChains, AllChains);
371 <<
" chains created.\n");
381 for (
auto &
I : AllChains)
384 for (
auto &
I : AllChains)
385 for (
auto &J : AllChains)
386 if (
I != J &&
I->rangeOverlapsWith(*J))
387 EC.unionSets(
I.get(), J.get());
388 LLVM_DEBUG(
dbgs() <<
"Created " << EC.getNumClasses() <<
" disjoint sets.\n");
394 std::vector<std::vector<Chain*> > V;
395 for (
const auto &E : EC) {
398 std::vector<Chain *> Cs(EC.member_begin(*E), EC.member_end());
399 if (Cs.empty())
continue;
400 V.push_back(std::move(Cs));
406 [](
const std::vector<Chain *> &
A,
const std::vector<Chain *> &
B) {
407 return A.front()->startsBefore(
B.front());
424 Changed |= colorChainSet(std::move(
I),
MBB, Parity);
429Chain *AArch64A57FPLoadBalancingImpl::getAndEraseNext(Color PreferredColor,
430 std::vector<Chain *> &L) {
442 const unsigned SizeFuzz = 1;
443 unsigned MinSize =
L.front()->size() - SizeFuzz;
444 for (
auto I =
L.begin(),
E =
L.end();
I !=
E; ++
I) {
445 if ((*I)->size() <= MinSize) {
452 if ((*I)->getPreferredColor() == PreferredColor) {
460 Chain *Ch =
L.front();
465bool AArch64A57FPLoadBalancingImpl::colorChainSet(std::vector<Chain *> GV,
466 MachineBasicBlock &
MBB,
469 LLVM_DEBUG(
dbgs() <<
"colorChainSet(): #sets=" << GV.size() <<
"\n");
480 llvm::sort(GV, [](
const Chain *G1,
const Chain *G2) {
481 if (G1->size() != G2->size())
482 return G1->size() > G2->size();
483 if (G1->requiresFixup() != G2->requiresFixup())
484 return G1->requiresFixup() > G2->requiresFixup();
486 assert((G1 == G2 || (G1->startsBefore(G2) ^ G2->startsBefore(G1))) &&
487 "Starts before not total order!");
488 return G1->startsBefore(G2);
491 Color PreferredColor = Parity < 0 ? Color::Even : Color::Odd;
492 while (Chain *
G = getAndEraseNext(PreferredColor, GV)) {
494 Color
C = PreferredColor;
497 C =
G->getPreferredColor();
500 <<
", Color=" << ColorNames[(
int)
C] <<
"\n");
505 if (
G->requiresFixup() &&
C !=
G->getPreferredColor()) {
506 C =
G->getPreferredColor();
508 <<
" - not worthwhile changing; "
510 << ColorNames[(
int)
C] <<
"\n");
515 Parity += (
C == Color::Even) ?
G->size() : -
G->size();
516 PreferredColor = Parity < 0 ? Color::Even : Color::Odd;
522int AArch64A57FPLoadBalancingImpl::scavengeRegister(Chain *
G, Color
C,
523 MachineBasicBlock &
MBB) {
526 LiveRegUnits Units(*
TRI);
527 Units.addLiveOuts(
MBB);
530 while (
I != ChainEnd) {
532 if (!
I->isDebugInstr())
533 Units.stepBackward(*
I);
538 assert(ChainBegin != ChainEnd &&
"Chain should contain instructions");
541 Units.accumulate(*
I);
542 }
while (
I != ChainBegin);
545 unsigned RegClassID = ChainBegin->getDesc().operands()[0].RegClass;
546 auto Ord = RCI->
getOrder(
TRI->getRegClass(RegClassID));
547 for (
auto Reg : Ord) {
548 if (!Units.available(
Reg))
550 if (
C == getColor(
Reg))
557bool AArch64A57FPLoadBalancingImpl::colorChain(Chain *
G, Color
C,
558 MachineBasicBlock &
MBB) {
561 << ColorNames[(
int)
C] <<
")\n");
565 int Reg = scavengeRegister(
G,
C,
MBB);
572 std::map<unsigned, unsigned> Substs;
573 for (MachineInstr &
I : *
G) {
574 if (!
G->contains(
I) && (&
I !=
G->getKill() ||
G->isKillImmutable()))
579 std::vector<unsigned> ToErase;
580 for (
auto &U :
I.operands()) {
581 if (
U.isReg() &&
U.isUse() && Substs.find(
U.getReg()) != Substs.end()) {
583 U.setReg(Substs[OrigReg]);
587 ToErase.push_back(OrigReg);
588 }
else if (
U.isRegMask()) {
589 for (
auto J : Substs) {
590 if (
U.clobbersPhysReg(J.first))
591 ToErase.push_back(J.first);
596 for (
auto J : ToErase)
600 if (&
I !=
G->getKill()) {
601 MachineOperand &MO =
I.getOperand(0);
604 if (
G->requiresFixup() && &
I ==
G->getLast())
615 assert(Substs.size() == 0 &&
"No substitutions should be left active!");
627void AArch64A57FPLoadBalancingImpl::scanInstruction(
628 MachineInstr *
MI,
unsigned Idx, std::map<unsigned, Chain *> &ActiveChains,
629 std::vector<std::unique_ptr<Chain>> &AllChains) {
634 for (
auto &
I :
MI->uses())
635 maybeKillChain(
I, Idx, ActiveChains);
636 for (
auto &
I :
MI->defs())
637 maybeKillChain(
I, Idx, ActiveChains);
641 Register DestReg =
MI->getOperand(0).getReg();
646 auto G = std::make_unique<Chain>(
MI, Idx, getColor(DestReg));
647 ActiveChains[DestReg] =
G.get();
648 AllChains.push_back(std::move(
G));
654 Register DestReg =
MI->getOperand(0).getReg();
655 Register AccumReg =
MI->getOperand(3).getReg();
657 maybeKillChain(
MI->getOperand(1), Idx, ActiveChains);
658 maybeKillChain(
MI->getOperand(2), Idx, ActiveChains);
659 if (DestReg != AccumReg)
660 maybeKillChain(
MI->getOperand(0), Idx, ActiveChains);
662 if (ActiveChains.find(AccumReg) != ActiveChains.end()) {
671 if (
MI->getOperand(3).isKill()) {
673 LLVM_DEBUG(
dbgs() <<
"Instruction was successfully added to chain.\n");
674 ActiveChains[AccumReg]->add(
MI, Idx, getColor(DestReg));
676 if (DestReg != AccumReg) {
677 ActiveChains[DestReg] = ActiveChains[AccumReg];
678 ActiveChains.erase(AccumReg);
684 dbgs() <<
"Cannot add to chain because accumulator operand wasn't "
685 <<
"marked <kill>!\n");
686 maybeKillChain(
MI->getOperand(3), Idx, ActiveChains);
691 auto G = std::make_unique<Chain>(
MI, Idx, getColor(DestReg));
692 ActiveChains[DestReg] =
G.get();
693 AllChains.push_back(std::move(
G));
699 for (
auto &
I :
MI->uses())
700 maybeKillChain(
I, Idx, ActiveChains);
701 for (
auto &
I :
MI->defs())
702 maybeKillChain(
I, Idx, ActiveChains);
707void AArch64A57FPLoadBalancingImpl::maybeKillChain(
708 MachineOperand &MO,
unsigned Idx,
709 std::map<unsigned, Chain *> &ActiveChains) {
717 if (MO.
isKill() && ActiveChains.find(MO.
getReg()) != ActiveChains.end()) {
722 ActiveChains.erase(MO.
getReg());
726 for (
auto I = ActiveChains.begin(),
E = ActiveChains.end();
731 I->second->setKill(
MI, Idx,
true);
732 ActiveChains.erase(
I++);
740Color AArch64A57FPLoadBalancingImpl::getColor(
unsigned Reg) {
741 if ((
TRI->getEncodingValue(
Reg) % 2) == 0)
749 return new AArch64A57FPLoadBalancingLegacy();
static bool isMul(MachineInstr *MI)
static cl::opt< unsigned > OverrideBalance("aarch64-a57-fp-load-balancing-override", cl::desc("Ignore balance information, always return " "(1: Even, 2: Odd)."), cl::init(0), cl::Hidden)
static cl::opt< bool > TransformAll("aarch64-a57-fp-load-balancing-force-all", cl::desc("Always modify dest registers regardless of color"), cl::init(false), cl::Hidden)
static bool isMla(MachineInstr *MI)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Generic implementation of equivalence classes through the use Tarjan's efficient union-find algorithm...
static bool runOnBasicBlock(MachineBasicBlock *MBB, unsigned BasicBlockNum, VRegRenamer &Renamer)
Register const TargetRegisterInfo * TRI
Promote Memory to Register
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
This file declares the machine register scavenger class.
MachineInstr * StartInst
The important (marker) instructions.
MachineBasicBlock::iterator begin() const
bool isKillImmutable() const
Can the Kill instruction (assuming one exists) be modified?
void add(MachineInstr *MI, unsigned Idx, Color C)
Add a new instruction into the chain.
bool contains(MachineInstr &MI)
Return true if MI is a member of the chain.
Color LastColor
The "color" of LastInst.
bool requiresFixup() const
Return true if the group will require a fixup MOV at the end.
MachineInstr * getLast() const
Return the last instruction in the chain.
bool KillIsImmutable
True if KillInst cannot be modified.
bool rangeOverlapsWith(const Chain &Other) const
Return true if this chain (StartInst..KillInst) overlaps with Other.
MachineInstr * getStart() const
Return the first instruction in the chain.
unsigned size() const
Return the number of instructions in the chain.
MachineBasicBlock::iterator end() const
Return an instruction that can be used as an iterator for the end of the chain.
void setKill(MachineInstr *MI, unsigned Idx, bool Immutable)
Inform the chain that its last active register (the dest register of LastInst) is killed by MI with n...
MachineInstr * getKill() const
Return the "kill" instruction (as set with setKill()) or NULL.
unsigned StartInstIdx
The index, from the start of the basic block, that each marker appears.
Color getPreferredColor()
Return the preferred color of this chain.
std::string str() const
Return a simple string representation of the chain.
std::set< MachineInstr * > Insts
All instructions in the chain.
Chain(MachineInstr *MI, unsigned Idx, Color C)
bool startsBefore(const Chain *Other) const
Return true if this chain starts before Other.
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
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.
This represents a collection of equivalence classes and supports three efficient operations: insert a...
FunctionPass class - This class is used to implement most global optimizations.
MachineInstrBundleIterator< MachineInstr > iterator
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.
Representation of each machine instruction.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
bool isRegMask() const
isRegMask - Tests if this is a MO_RegisterMask operand.
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
Register getReg() const
getReg - Returns the register number.
static bool clobbersPhysReg(const uint32_t *RegMask, MCRegister PhysReg)
clobbersPhysReg - Returns true if this RegMask clobbers PhysReg.
const TargetRegisterInfo * getTargetRegisterInfo() const
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.
ArrayRef< MCPhysReg > getOrder(const TargetRegisterClass *RC) const
getOrder - Returns the preferred allocation order for RC.
A raw_ostream that writes to an std::string.
std::string & str()
Returns the string's reference.
@ C
The default llvm calling convention, compatible with C.
initializer< Ty > init(const Ty &Val)
DXILDebugInfoMap run(Module &M)
This is an optimization pass for GlobalISel generic memory operations.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
FunctionPass * createAArch64A57FPLoadBalancingLegacyPass()
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
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.