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.
@ 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.
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.