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>();
157char AArch64A57FPLoadBalancingLegacy::ID = 0;
160 "AArch64 A57 FP Load-Balancing",
false,
false)
223 "Chain: broken invariant. A Chain can only be killed after its last "
244 "Chain: broken invariant. A Chain can only be killed after its last "
274 unsigned OtherEnd =
Other.KillInst ?
316 if (!MF.
getSubtarget<AArch64Subtarget>().balanceFPOps())
325 for (
auto &
MBB : MF) {
332bool AArch64A57FPLoadBalancingLegacy::runOnMachineFunction(
333 MachineFunction &MF) {
336 RegisterClassInfo *RCI =
337 &getAnalysis<MachineRegisterClassInfoWrapperPass>().getRCI();
338 return AArch64A57FPLoadBalancingImpl(RCI).run(MF);
345 if (AArch64A57FPLoadBalancingImpl(RCI).
run(MF)) {
356 <<
" - scanning instructions...\n");
363 std::map<unsigned, Chain*> ActiveChains;
364 std::vector<std::unique_ptr<Chain>> AllChains;
367 scanInstruction(&
MI, Idx++, ActiveChains, AllChains);
370 <<
" chains created.\n");
380 for (
auto &
I : AllChains)
383 for (
auto &
I : AllChains)
384 for (
auto &J : AllChains)
385 if (
I != J &&
I->rangeOverlapsWith(*J))
386 EC.unionSets(
I.get(), J.get());
387 LLVM_DEBUG(
dbgs() <<
"Created " << EC.getNumClasses() <<
" disjoint sets.\n");
393 std::vector<std::vector<Chain*> > V;
394 for (
const auto &E : EC) {
397 std::vector<Chain *> Cs(EC.member_begin(*E), EC.member_end());
398 if (Cs.empty())
continue;
399 V.push_back(std::move(Cs));
405 [](
const std::vector<Chain *> &
A,
const std::vector<Chain *> &
B) {
406 return A.front()->startsBefore(
B.front());
423 Changed |= colorChainSet(std::move(
I),
MBB, Parity);
428Chain *AArch64A57FPLoadBalancingImpl::getAndEraseNext(Color PreferredColor,
429 std::vector<Chain *> &L) {
441 const unsigned SizeFuzz = 1;
442 unsigned MinSize =
L.front()->size() - SizeFuzz;
443 for (
auto I =
L.begin(),
E =
L.end();
I !=
E; ++
I) {
444 if ((*I)->size() <= MinSize) {
451 if ((*I)->getPreferredColor() == PreferredColor) {
459 Chain *Ch =
L.front();
464bool AArch64A57FPLoadBalancingImpl::colorChainSet(std::vector<Chain *> GV,
465 MachineBasicBlock &
MBB,
468 LLVM_DEBUG(
dbgs() <<
"colorChainSet(): #sets=" << GV.size() <<
"\n");
479 llvm::sort(GV, [](
const Chain *G1,
const Chain *G2) {
480 if (G1->size() != G2->size())
481 return G1->size() > G2->size();
482 if (G1->requiresFixup() != G2->requiresFixup())
483 return G1->requiresFixup() > G2->requiresFixup();
485 assert((G1 == G2 || (G1->startsBefore(G2) ^ G2->startsBefore(G1))) &&
486 "Starts before not total order!");
487 return G1->startsBefore(G2);
490 Color PreferredColor = Parity < 0 ? Color::Even : Color::Odd;
491 while (Chain *
G = getAndEraseNext(PreferredColor, GV)) {
493 Color
C = PreferredColor;
496 C =
G->getPreferredColor();
499 <<
", Color=" << ColorNames[(
int)
C] <<
"\n");
504 if (
G->requiresFixup() &&
C !=
G->getPreferredColor()) {
505 C =
G->getPreferredColor();
507 <<
" - not worthwhile changing; "
509 << ColorNames[(
int)
C] <<
"\n");
514 Parity += (
C == Color::Even) ?
G->size() : -
G->size();
515 PreferredColor = Parity < 0 ? Color::Even : Color::Odd;
521int AArch64A57FPLoadBalancingImpl::scavengeRegister(Chain *
G, Color
C,
522 MachineBasicBlock &
MBB) {
525 LiveRegUnits Units(*
TRI);
526 Units.addLiveOuts(
MBB);
529 while (
I != ChainEnd) {
531 if (!
I->isDebugInstr())
532 Units.stepBackward(*
I);
537 assert(ChainBegin != ChainEnd &&
"Chain should contain instructions");
540 Units.accumulate(*
I);
541 }
while (
I != ChainBegin);
544 unsigned RegClassID = ChainBegin->getDesc().operands()[0].RegClass;
545 auto Ord = RCI->
getOrder(
TRI->getRegClass(RegClassID));
546 for (
auto Reg : Ord) {
547 if (!Units.available(
Reg))
549 if (
C == getColor(
Reg))
556bool AArch64A57FPLoadBalancingImpl::colorChain(Chain *
G, Color
C,
557 MachineBasicBlock &
MBB) {
560 << ColorNames[(
int)
C] <<
")\n");
564 int Reg = scavengeRegister(
G,
C,
MBB);
571 std::map<unsigned, unsigned> Substs;
572 for (MachineInstr &
I : *
G) {
573 if (!
G->contains(
I) && (&
I !=
G->getKill() ||
G->isKillImmutable()))
578 std::vector<unsigned> ToErase;
579 for (
auto &U :
I.operands()) {
580 if (
U.isReg() &&
U.isUse() && Substs.find(
U.getReg()) != Substs.end()) {
582 U.setReg(Substs[OrigReg]);
586 ToErase.push_back(OrigReg);
587 }
else if (
U.isRegMask()) {
588 for (
auto J : Substs) {
589 if (
U.clobbersPhysReg(J.first))
590 ToErase.push_back(J.first);
595 for (
auto J : ToErase)
599 if (&
I !=
G->getKill()) {
600 MachineOperand &MO =
I.getOperand(0);
603 if (
G->requiresFixup() && &
I ==
G->getLast())
614 assert(Substs.size() == 0 &&
"No substitutions should be left active!");
626void AArch64A57FPLoadBalancingImpl::scanInstruction(
627 MachineInstr *
MI,
unsigned Idx, std::map<unsigned, Chain *> &ActiveChains,
628 std::vector<std::unique_ptr<Chain>> &AllChains) {
633 for (
auto &
I :
MI->uses())
634 maybeKillChain(
I, Idx, ActiveChains);
635 for (
auto &
I :
MI->defs())
636 maybeKillChain(
I, Idx, ActiveChains);
640 Register DestReg =
MI->getOperand(0).getReg();
645 auto G = std::make_unique<Chain>(
MI, Idx, getColor(DestReg));
646 ActiveChains[DestReg] =
G.get();
647 AllChains.push_back(std::move(
G));
653 Register DestReg =
MI->getOperand(0).getReg();
654 Register AccumReg =
MI->getOperand(3).getReg();
656 maybeKillChain(
MI->getOperand(1), Idx, ActiveChains);
657 maybeKillChain(
MI->getOperand(2), Idx, ActiveChains);
658 if (DestReg != AccumReg)
659 maybeKillChain(
MI->getOperand(0), Idx, ActiveChains);
661 if (ActiveChains.find(AccumReg) != ActiveChains.end()) {
670 if (
MI->getOperand(3).isKill()) {
672 LLVM_DEBUG(
dbgs() <<
"Instruction was successfully added to chain.\n");
673 ActiveChains[AccumReg]->add(
MI, Idx, getColor(DestReg));
675 if (DestReg != AccumReg) {
676 ActiveChains[DestReg] = ActiveChains[AccumReg];
677 ActiveChains.erase(AccumReg);
683 dbgs() <<
"Cannot add to chain because accumulator operand wasn't "
684 <<
"marked <kill>!\n");
685 maybeKillChain(
MI->getOperand(3), Idx, ActiveChains);
690 auto G = std::make_unique<Chain>(
MI, Idx, getColor(DestReg));
691 ActiveChains[DestReg] =
G.get();
692 AllChains.push_back(std::move(
G));
698 for (
auto &
I :
MI->uses())
699 maybeKillChain(
I, Idx, ActiveChains);
700 for (
auto &
I :
MI->defs())
701 maybeKillChain(
I, Idx, ActiveChains);
706void AArch64A57FPLoadBalancingImpl::maybeKillChain(
707 MachineOperand &MO,
unsigned Idx,
708 std::map<unsigned, Chain *> &ActiveChains) {
716 if (MO.
isKill() && ActiveChains.find(MO.
getReg()) != ActiveChains.end()) {
721 ActiveChains.erase(MO.
getReg());
725 for (
auto I = ActiveChains.begin(),
E = ActiveChains.end();
730 I->second->setKill(
MI, Idx,
true);
731 ActiveChains.erase(
I++);
739Color AArch64A57FPLoadBalancingImpl::getColor(
unsigned Reg) {
740 if ((
TRI->getEncodingValue(
Reg) % 2) == 0)
748 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< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
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()
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.
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.