46#define DEBUG_TYPE "aarch64-a57-fp-load-balancing"
52 cl::desc(
"Always modify dest registers regardless of color"),
59 cl::desc(
"Ignore balance information, always return "
60 "(1: Even, 2: Odd)."),
68 switch (
MI->getOpcode()) {
69 case AArch64::FMULSrr:
70 case AArch64::FNMULSrr:
71 case AArch64::FMULDrr:
72 case AArch64::FNMULDrr:
81 switch (
MI->getOpcode()) {
82 case AArch64::FMSUBSrrr:
83 case AArch64::FMADDSrrr:
84 case AArch64::FNMSUBSrrr:
85 case AArch64::FNMADDSrrr:
86 case AArch64::FMSUBDrrr:
87 case AArch64::FMADDDrrr:
88 case AArch64::FNMSUBDrrr:
89 case AArch64::FNMADDDrrr:
101enum class Color { Even, Odd };
103static const char *ColorNames[2] = {
"Even",
"Odd" };
123 MachineFunctionProperties::Property::NoVRegs);
127 return "A57 FP Anti-dependency breaker";
142 std::map<unsigned, Chain*> &Active,
143 std::vector<std::unique_ptr<Chain>> &AllChains);
145 std::map<unsigned, Chain*> &RegChains);
147 Chain *getAndEraseNext(Color PreferredColor, std::vector<Chain*> &L);
151char AArch64A57FPLoadBalancing::ID = 0;
154 "AArch64 A57 FP Load-Balancing",
false,
false)
203 : StartInst(
MI), LastInst(
MI), KillInst(nullptr),
204 StartInstIdx(
Idx), LastInstIdx(
Idx), KillInstIdx(0),
215 assert((KillInstIdx == 0 || LastInstIdx < KillInstIdx) &&
216 "Chain: broken invariant. A Chain can only be killed after its last "
235 KillIsImmutable = Immutable;
236 assert((KillInstIdx == 0 || LastInstIdx < KillInstIdx) &&
237 "Chain: broken invariant. A Chain can only be killed after its last "
266 unsigned End = KillInst ? KillInstIdx : LastInstIdx;
267 unsigned OtherEnd =
Other.KillInst ?
270 return StartInstIdx <= OtherEnd &&
Other.StartInstIdx <=
End;
275 return StartInstIdx <
Other->StartInstIdx;
280 return (getKill() && isKillImmutable()) || !getKill();
309 if (skipFunction(
F.getFunction()))
315 bool Changed =
false;
318 MRI = &
F.getRegInfo();
319 TRI =
F.getRegInfo().getTargetRegisterInfo();
322 for (
auto &
MBB :
F) {
330 bool Changed =
false;
332 <<
" - scanning instructions...\n");
339 std::map<unsigned, Chain*> ActiveChains;
340 std::vector<std::unique_ptr<Chain>> AllChains;
343 scanInstruction(&
MI,
Idx++, ActiveChains, AllChains);
346 <<
" chains created.\n");
356 for (
auto &
I : AllChains)
359 for (
auto &
I : AllChains)
360 for (
auto &J : AllChains)
361 if (
I != J &&
I->rangeOverlapsWith(*J))
362 EC.unionSets(
I.get(), J.get());
363 LLVM_DEBUG(
dbgs() <<
"Created " <<
EC.getNumClasses() <<
" disjoint sets.\n");
369 std::vector<std::vector<Chain*> >
V;
370 for (
auto I =
EC.begin(), E =
EC.end();
I != E; ++
I) {
371 std::vector<Chain*> Cs(
EC.member_begin(
I),
EC.member_end());
372 if (Cs.empty())
continue;
373 V.push_back(std::move(Cs));
379 [](
const std::vector<Chain *> &
A,
const std::vector<Chain *> &
B) {
380 return A.front()->startsBefore(
B.front());
397 Changed |= colorChainSet(std::move(
I),
MBB, Parity);
402Chain *AArch64A57FPLoadBalancing::getAndEraseNext(Color PreferredColor,
403 std::vector<Chain*> &L) {
415 const unsigned SizeFuzz = 1;
416 unsigned MinSize =
L.front()->size() - SizeFuzz;
417 for (
auto I =
L.begin(), E =
L.end();
I != E; ++
I) {
418 if ((*I)->size() <= MinSize) {
425 if ((*I)->getPreferredColor() == PreferredColor) {
433 Chain *Ch =
L.front();
438bool AArch64A57FPLoadBalancing::colorChainSet(std::vector<Chain*> GV,
441 bool Changed =
false;
442 LLVM_DEBUG(
dbgs() <<
"colorChainSet(): #sets=" << GV.size() <<
"\n");
453 llvm::sort(GV, [](
const Chain *G1,
const Chain *G2) {
454 if (G1->size() != G2->size())
455 return G1->size() > G2->size();
456 if (G1->requiresFixup() != G2->requiresFixup())
457 return G1->requiresFixup() > G2->requiresFixup();
459 assert((G1 == G2 || (G1->startsBefore(G2) ^ G2->startsBefore(G1))) &&
460 "Starts before not total order!");
461 return G1->startsBefore(G2);
464 Color PreferredColor = Parity < 0 ? Color::Even : Color::Odd;
465 while (Chain *
G = getAndEraseNext(PreferredColor, GV)) {
467 Color
C = PreferredColor;
470 C =
G->getPreferredColor();
473 <<
", Color=" << ColorNames[(
int)
C] <<
"\n");
478 if (
G->requiresFixup() &&
C !=
G->getPreferredColor()) {
479 C =
G->getPreferredColor();
481 <<
" - not worthwhile changing; "
483 << ColorNames[(
int)
C] <<
"\n");
486 Changed |= colorChain(
G,
C,
MBB);
488 Parity += (
C == Color::Even) ?
G->size() : -
G->size();
489 PreferredColor = Parity < 0 ? Color::Even : Color::Odd;
495int AArch64A57FPLoadBalancing::scavengeRegister(Chain *
G, Color
C,
500 Units.addLiveOuts(
MBB);
503 while (
I != ChainEnd) {
505 Units.stepBackward(*
I);
510 assert(ChainBegin != ChainEnd &&
"Chain should contain instructions");
513 Units.accumulate(*
I);
514 }
while (
I != ChainBegin);
517 unsigned RegClassID = ChainBegin->getDesc().operands()[0].RegClass;
518 auto Ord = RCI.
getOrder(
TRI->getRegClass(RegClassID));
519 for (
auto Reg : Ord) {
520 if (!Units.available(Reg))
522 if (
C == getColor(Reg))
529bool AArch64A57FPLoadBalancing::colorChain(Chain *
G, Color
C,
531 bool Changed =
false;
533 << ColorNames[(
int)
C] <<
")\n");
537 int Reg = scavengeRegister(
G,
C,
MBB);
544 std::map<unsigned, unsigned> Substs;
546 if (!
G->contains(
I) && (&
I !=
G->getKill() ||
G->isKillImmutable()))
551 std::vector<unsigned> ToErase;
552 for (
auto &U :
I.operands()) {
553 if (
U.isReg() &&
U.isUse() && Substs.find(
U.getReg()) != Substs.end()) {
555 U.setReg(Substs[OrigReg]);
559 ToErase.push_back(OrigReg);
560 }
else if (
U.isRegMask()) {
561 for (
auto J : Substs) {
562 if (
U.clobbersPhysReg(J.first))
563 ToErase.push_back(J.first);
568 for (
auto J : ToErase)
572 if (&
I !=
G->getKill()) {
576 if (
G->requiresFixup() && &
I ==
G->getLast())
587 assert(Substs.size() == 0 &&
"No substitutions should be left active!");
599void AArch64A57FPLoadBalancing::scanInstruction(
601 std::vector<std::unique_ptr<Chain>> &AllChains) {
606 for (
auto &
I :
MI->uses())
607 maybeKillChain(
I,
Idx, ActiveChains);
608 for (
auto &
I :
MI->defs())
609 maybeKillChain(
I,
Idx, ActiveChains);
613 Register DestReg =
MI->getOperand(0).getReg();
618 auto G = std::make_unique<Chain>(
MI,
Idx, getColor(DestReg));
619 ActiveChains[DestReg] =
G.get();
620 AllChains.push_back(std::move(
G));
626 Register DestReg =
MI->getOperand(0).getReg();
627 Register AccumReg =
MI->getOperand(3).getReg();
629 maybeKillChain(
MI->getOperand(1),
Idx, ActiveChains);
630 maybeKillChain(
MI->getOperand(2),
Idx, ActiveChains);
631 if (DestReg != AccumReg)
632 maybeKillChain(
MI->getOperand(0),
Idx, ActiveChains);
634 if (ActiveChains.find(AccumReg) != ActiveChains.end()) {
643 if (
MI->getOperand(3).isKill()) {
645 LLVM_DEBUG(
dbgs() <<
"Instruction was successfully added to chain.\n");
646 ActiveChains[AccumReg]->add(
MI,
Idx, getColor(DestReg));
648 if (DestReg != AccumReg) {
649 ActiveChains[DestReg] = ActiveChains[AccumReg];
650 ActiveChains.erase(AccumReg);
656 dbgs() <<
"Cannot add to chain because accumulator operand wasn't "
657 <<
"marked <kill>!\n");
658 maybeKillChain(
MI->getOperand(3),
Idx, ActiveChains);
663 auto G = std::make_unique<Chain>(
MI,
Idx, getColor(DestReg));
664 ActiveChains[DestReg] =
G.get();
665 AllChains.push_back(std::move(
G));
671 for (
auto &
I :
MI->uses())
672 maybeKillChain(
I,
Idx, ActiveChains);
673 for (
auto &
I :
MI->defs())
674 maybeKillChain(
I,
Idx, ActiveChains);
679void AArch64A57FPLoadBalancing::
681 std::map<unsigned, Chain*> &ActiveChains) {
689 if (MO.
isKill() && ActiveChains.find(MO.
getReg()) != ActiveChains.end()) {
694 ActiveChains.erase(MO.
getReg());
698 for (
auto I = ActiveChains.begin(), E = ActiveChains.end();
703 I->second->setKill(
MI,
Idx,
true);
704 ActiveChains.erase(
I++);
712Color AArch64A57FPLoadBalancing::getColor(
unsigned Reg) {
713 if ((
TRI->getEncodingValue(Reg) % 2) == 0)
721 return new AArch64A57FPLoadBalancing();
AArch64 A57 FP Load Balancing
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)
unsigned const MachineRegisterInfo * MRI
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
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
std::optional< std::vector< StOtherPiece > > Other
Generic implementation of equivalence classes through the use Tarjan's efficient union-find algorithm...
static bool runOnBasicBlock(MachineBasicBlock *MBB, unsigned BasicBlockNum, VRegRenamer &Renamer)
unsigned const TargetRegisterInfo * TRI
#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.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
A Chain is a sequence of instructions that are linked together by an accumulation operand.
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.
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.
Represent the analysis usage information of a pass.
void setPreservesCFG()
This function should be called by the pass, iff they do not:
EquivalenceClasses - This represents a collection of equivalence classes and supports three efficient...
FunctionPass class - This class is used to implement most global optimizations.
A set of register units used to track register liveness.
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.
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
virtual MachineFunctionProperties getRequiredProperties() const
Properties which a MachineFunction may have at a given point in time.
MachineFunctionProperties & set(Property P)
Representation of each machine instruction.
void print(raw_ostream &OS, bool IsStandalone=true, bool SkipOpers=false, bool SkipDebugLoc=false, bool AddNewLine=true, const TargetInstrInfo *TII=nullptr) const
Print this MI to OS.
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
bool isRegMask() const
isRegMask - Tests if this is a MO_RegisterMask operand.
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.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
void runOnMachineFunction(const MachineFunction &MF)
runOnFunction - Prepare to answer questions about MF.
ArrayRef< MCPhysReg > getOrder(const TargetRegisterClass *RC) const
getOrder - Returns the preferred allocation order for RC.
Wrapper class representing virtual and physical registers.
StringRef - Represent a constant reference to a string, i.e.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
A raw_ostream that writes to an std::string.
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.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
void initializeAArch64A57FPLoadBalancingPass(PassRegistry &)
FunctionPass * createAArch64A57FPLoadBalancing()
void sort(IteratorTy Start, IteratorTy End)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
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.