ARM64CollectLOH.cpp [plain text]
#define DEBUG_TYPE "arm64-collect-loh"
#include "ARM64.h"
#include "ARM64InstrInfo.h"
#include "ARM64MachineFunctionInfo.h"
#include "MCTargetDesc/ARM64AddressingModes.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/Statistic.h"
using namespace llvm;
static cl::opt<bool>
PreCollectRegister("arm64-collect-loh-pre-collect-register", cl::Hidden,
cl::desc("Restrict analysis to registers invovled"
" in LOHs"),
cl::init(true));
static cl::opt<bool>
BasicBlockScopeOnly("arm64-collect-loh-bb-only", cl::Hidden,
cl::desc("Restrict analysis at basic block scope"),
cl::init(true));
STATISTIC(NumADRPSimpleCandidate,
"Number of simplifiable ADRP dominate by another");
STATISTIC(NumADRPComplexCandidate2,
"Number of simplifiable ADRP reachable by 2 defs");
STATISTIC(NumADRPComplexCandidate3,
"Number of simplifiable ADRP reachable by 3 defs");
STATISTIC(NumADRPComplexCandidateOther,
"Number of simplifiable ADRP reachable by 4 or more defs");
STATISTIC(NumADDToSTRWithImm,
"Number of simplifiable STR with imm reachable by ADD");
STATISTIC(NumLDRToSTRWithImm,
"Number of simplifiable STR with imm reachable by LDR");
STATISTIC(NumADDToSTR,
"Number of simplifiable STR reachable by ADD");
STATISTIC(NumLDRToSTR,
"Number of simplifiable STR reachable by LDR");
STATISTIC(NumADDToLDRWithImm,
"Number of simplifiable LDR with imm reachable by ADD");
STATISTIC(NumLDRToLDRWithImm,
"Number of simplifiable LDR with imm reachable by LDR");
STATISTIC(NumADDToLDR,
"Number of simplifiable LDR reachable by ADD");
STATISTIC(NumLDRToLDR,
"Number of simplifiable LDR reachable by LDR");
STATISTIC(NumADRPToLDR,
"Number of simplifiable LDR reachable by ADRP");
STATISTIC(NumCplxLvl1,
"Number of complex case of level 1");
STATISTIC(NumTooCplxLvl1,
"Number of too complex case of level 1");
STATISTIC(NumCplxLvl2,
"Number of complex case of level 2");
STATISTIC(NumTooCplxLvl2,
"Number of too complex case of level 2");
STATISTIC(NumADRSimpleCandidate,
"Number of simplifiable ADRP + ADD");
STATISTIC(NumADRComplexCandidate,
"Number of too complex ADRP + ADD");
namespace llvm {
void initializeARM64CollectLOHPass(PassRegistry&);
}
namespace {
struct ARM64CollectLOH : public MachineFunctionPass {
static char ID;
ARM64CollectLOH() : MachineFunctionPass(ID) {
initializeARM64CollectLOHPass(*PassRegistry::getPassRegistry());
}
virtual bool runOnMachineFunction(MachineFunction &Fn);
virtual const char *getPassName() const {
return "ARM64 Collect Linker Optimization Hint (LOH)";
}
void getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
MachineFunctionPass::getAnalysisUsage(AU);
AU.addRequired<MachineDominatorTree>();
}
private:
};
typedef SetVector<const MachineInstr *> SetOfMachineInstr;
typedef MapVector<const MachineBasicBlock *, SetOfMachineInstr *>
BlockToSetOfInstrsPerColor;
typedef MapVector<const MachineBasicBlock *, const MachineInstr **>
BlockToInstrPerColor;
typedef MapVector<const MachineInstr *, SetOfMachineInstr > InstrToInstrs;
typedef MapVector<const MachineBasicBlock *, BitVector > BlockToRegSet;
typedef DenseMap<unsigned, unsigned> MapRegToId;
typedef SmallVector<unsigned, 32> MapIdToReg;
}
char ARM64CollectLOH::ID = 0;
INITIALIZE_PASS_BEGIN(ARM64CollectLOH, "arm64-collect-loh",
"ARM64 Collect Linker Optimization Hint (LOH)", false,
false)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
INITIALIZE_PASS_END(ARM64CollectLOH, "arm64-collect-loh",
"ARM64 Collect Linker Optimization Hint (LOH)", false,
false)
static SetOfMachineInstr&
getSet(BlockToSetOfInstrsPerColor& sets, const MachineBasicBlock *MBB,
unsigned reg, unsigned nbRegs) {
SetOfMachineInstr *result;
BlockToSetOfInstrsPerColor::iterator it = sets.find(MBB);
if (it != sets.end()) {
result = it->second;
} else {
result = sets[MBB] = new SetOfMachineInstr[nbRegs];
}
return result[reg];
}
static SetOfMachineInstr&
getUses(InstrToInstrs * sets, unsigned reg, const MachineInstr *MI) {
return sets[reg][MI];
}
static const SetOfMachineInstr*
getUses(const InstrToInstrs * sets, unsigned reg, const MachineInstr *MI) {
InstrToInstrs::const_iterator Res = sets[reg].find(MI);
if (Res != sets[reg].end())
return &(Res->second);
return NULL;
}
static void
initReachingDef(MachineFunction *MF, InstrToInstrs *ColorOpToReachedUses,
BlockToInstrPerColor &Gen, BlockToRegSet &Kill,
BlockToSetOfInstrsPerColor &ReachableUses,
const MapRegToId &RegToId, const MachineInstr *DummyOp,
bool ADRPMode) {
const TargetMachine &TM = MF->getTarget();
const TargetRegisterInfo *TRI = TM.getRegisterInfo();
unsigned NbReg = RegToId.size();
for (MachineFunction::const_iterator IMBB = MF->begin(), IMBBEnd = MF->end();
IMBB != IMBBEnd; ++IMBB) {
const MachineBasicBlock *MBB = &(*IMBB);
const MachineInstr **& BBGen = Gen[MBB];
BBGen = new const MachineInstr*[NbReg];
memset(BBGen, 0, sizeof(const MachineInstr *) * NbReg);
BitVector& BBKillSet = Kill[MBB];
BBKillSet.resize(NbReg);
for (MachineBasicBlock::const_iterator II = MBB->begin(), IEnd = MBB->end();
II != IEnd; ++II) {
bool IsADRP = II->getOpcode() == ARM64::ADRP;
if (IsADRP || !ADRPMode)
for (MachineInstr::const_mop_iterator IO = II->operands_begin(),
IOEnd = II->operands_end();
IO != IOEnd; ++IO) {
if (!IO->isReg() || (!ADRPMode && !IO->isUse())
|| (ADRPMode && (!IsADRP || !IO->isDef())))
continue;
unsigned CurReg = IO->getReg();
MapRegToId::const_iterator ItCurRegId = RegToId.find(CurReg);
if (ItCurRegId == RegToId.end())
continue;
CurReg = ItCurRegId->second;
if(!BBGen[CurReg] && !BBKillSet.test(CurReg))
getSet(ReachableUses, MBB, CurReg, NbReg).insert(&(*II));
if(BBGen[CurReg])
getUses(ColorOpToReachedUses, CurReg, BBGen[CurReg]).insert(&(*II));
}
for (MachineInstr::const_mop_iterator IO = II->operands_begin(),
IOEnd = II->operands_end();
IO != IOEnd; ++IO) {
if (!IO->isRegMask())
continue;
const uint32_t* PreservedRegs = IO->getRegMask();
for (MapRegToId::const_iterator ItRegId = RegToId.begin(),
EndIt = RegToId.end(); ItRegId != EndIt; ++ItRegId) {
unsigned Reg = ItRegId->second;
if (MachineOperand::clobbersPhysReg(PreservedRegs, ItRegId->first)) {
BBGen[Reg] = ADRPMode ? II : NULL;
BBKillSet.set(Reg);
}
}
}
for (MachineInstr::const_mop_iterator IO = II->operands_begin(),
IOEnd = II->operands_end();
IO != IOEnd; ++IO) {
if (!IO->isReg() || !IO->isDef())
continue;
unsigned CurReg = IO->getReg();
MapRegToId::const_iterator ItCurRegId = RegToId.find(CurReg);
if (ItCurRegId == RegToId.end())
continue;
for (MCRegAliasIterator AI(CurReg, TRI, true); AI.isValid(); ++AI) {
MapRegToId::const_iterator ItRegId = RegToId.find(*AI);
assert (ItRegId != RegToId.end() && "Sub-register of an "
"involved register, not recorded as involved!");
BBKillSet.set(ItRegId->second);
BBGen[ItRegId->second] = &(*II);
}
BBGen[ItCurRegId->second] = &(*II);
}
}
if (!ADRPMode && DummyOp && !MBB->succ_empty())
for (unsigned CurReg = 0; CurReg < NbReg; ++CurReg)
if (BBGen[CurReg])
getUses(ColorOpToReachedUses, CurReg, BBGen[CurReg]).insert(DummyOp);
}
}
static void
reachingDefAlgorithm(MachineFunction *MF, InstrToInstrs *ColorOpToReachedUses,
BlockToSetOfInstrsPerColor &In,
BlockToSetOfInstrsPerColor &Out,
BlockToInstrPerColor &Gen, BlockToRegSet &Kill,
BlockToSetOfInstrsPerColor &ReachableUses,
unsigned NbReg) {
bool HasChanged;
do {
HasChanged = false;
for (MachineFunction::const_iterator IMBB = MF->begin(),
IMBBEnd = MF->end(); IMBB != IMBBEnd; ++IMBB) {
const MachineBasicBlock *MBB = &(*IMBB);
unsigned CurReg;
for (CurReg = 0; CurReg < NbReg; ++CurReg) {
SetOfMachineInstr& BBInSet = getSet(In, MBB, CurReg, NbReg);
SetOfMachineInstr& BBReachableUses = getSet(ReachableUses, MBB, CurReg,
NbReg);
SetOfMachineInstr& BBOutSet = getSet(Out, MBB, CurReg, NbReg);
unsigned Size = BBOutSet.size();
for (MachineBasicBlock::const_pred_iterator PredMBB = MBB->pred_begin(),
EndPredMBB = MBB->pred_end(); PredMBB != EndPredMBB; ++PredMBB) {
SetOfMachineInstr& PredOutSet = getSet(Out, *PredMBB, CurReg, NbReg);
BBInSet.insert(PredOutSet.begin(), PredOutSet.end());
}
for (SetOfMachineInstr::const_iterator InstrIt = BBInSet.begin(),
EndInstrIt = BBInSet.end(); InstrIt != EndInstrIt; ++InstrIt) {
SetOfMachineInstr& OpReachedUses = getUses(ColorOpToReachedUses,
CurReg, *InstrIt);
OpReachedUses.insert(BBReachableUses.begin(), BBReachableUses.end());
}
if(!Kill[MBB].test(CurReg))
BBOutSet.insert(BBInSet.begin(), BBInSet.end());
if (Gen[MBB][CurReg])
BBOutSet.insert(Gen[MBB][CurReg]);
HasChanged |= BBOutSet.size() != Size;
}
}
} while(HasChanged);
}
static void
finitReachingDef(BlockToSetOfInstrsPerColor &In,
BlockToSetOfInstrsPerColor &Out,
BlockToInstrPerColor &Gen,
BlockToSetOfInstrsPerColor &ReachableUses) {
for (BlockToSetOfInstrsPerColor::const_iterator IT = Out.begin(),
End = Out.end(); IT != End; ++IT)
delete[] IT->second;
for (BlockToSetOfInstrsPerColor::const_iterator IT = In.begin(),
End = In.end(); IT != End; ++IT)
delete[] IT->second;
for (BlockToSetOfInstrsPerColor::const_iterator IT = ReachableUses.begin(),
End = ReachableUses.end(); IT != End; ++IT)
delete[] IT->second;
for (BlockToInstrPerColor::const_iterator IT = Gen.begin(),
End = Gen.end(); IT != End; ++IT)
delete[] IT->second;
}
static void
reachingDef(MachineFunction *MF, InstrToInstrs *ColorOpToReachedUses,
const MapRegToId &RegToId, bool ADRPMode = false,
const MachineInstr *DummyOp = NULL) {
BlockToSetOfInstrsPerColor Out, In, ReachableUses;
BlockToInstrPerColor Gen;
BlockToRegSet Kill;
initReachingDef(MF, ColorOpToReachedUses, Gen, Kill, ReachableUses, RegToId,
DummyOp, ADRPMode);
if (!DummyOp)
reachingDefAlgorithm(MF, ColorOpToReachedUses, In, Out, Gen, Kill,
ReachableUses, RegToId.size());
finitReachingDef(In, Out, Gen, ReachableUses);
}
#ifndef NDEBUG
static void
printReachingDef(const InstrToInstrs *ColorOpToReachedUses,
unsigned NbReg, const TargetRegisterInfo *TRI,
const MapIdToReg &IdToReg) {
unsigned CurReg;
for (CurReg = 0; CurReg < NbReg; ++CurReg) {
if (ColorOpToReachedUses[CurReg].empty())
continue;
DEBUG(dbgs() << "*** Reg " << PrintReg(IdToReg[CurReg], TRI) << " ***\n");
InstrToInstrs::const_iterator DefsIt = ColorOpToReachedUses[CurReg].begin();
InstrToInstrs::const_iterator DefsItEnd =
ColorOpToReachedUses[CurReg].end();
for (; DefsIt != DefsItEnd; ++DefsIt) {
DEBUG(dbgs() << "Def:\n");
DEBUG(DefsIt->first->print(dbgs()));
DEBUG(dbgs() << "Reachable uses:\n");
for (SetOfMachineInstr::const_iterator UsesIt = DefsIt->second.begin(),
UsesItEnd = DefsIt->second.end(); UsesIt != UsesItEnd; ++UsesIt) {
DEBUG((*UsesIt)->print(dbgs()));
}
}
}
}
#endif // NDEBUG
static bool
canDefBePartOfLOH(const MachineInstr *Def) {
unsigned Opc = Def->getOpcode();
switch (Opc) {
default: return false;
case ARM64::ADRP:
return true;
case ARM64::ADDXri:
switch (Def->getOperand(2).getType()) {
default: return false;
case MachineOperand::MO_GlobalAddress:
case MachineOperand::MO_JumpTableIndex:
case MachineOperand::MO_ConstantPoolIndex:
case MachineOperand::MO_BlockAddress:
return true;
}
case ARM64::LDRXui:
switch (Def->getOperand(2).getType()) {
default: return false;
case MachineOperand::MO_GlobalAddress:
return true;
}
}
return false;
}
static bool
isCandidateStore(const MachineInstr *Instr) {
switch(Instr->getOpcode()) {
default: return false;
case ARM64::STRBui:
case ARM64::STRHui:
case ARM64::STRWui:
case ARM64::STRXui:
case ARM64::STRSui:
case ARM64::STRDui:
case ARM64::STRQui:
if (Instr->getOperand(0).getReg() != Instr->getOperand(1).getReg())
return true;
}
return false;
}
static void
reachedUsesToDefs(InstrToInstrs &UseToReachingDefs,
const InstrToInstrs *ColorOpToReachedUses,
const MapRegToId &RegToId, bool ADRPMode = false) {
SetOfMachineInstr NotCandidate;
unsigned NbReg = RegToId.size();
MapRegToId::const_iterator EndIt = RegToId.end();
for (unsigned CurReg = 0; CurReg < NbReg; ++CurReg) {
if (ColorOpToReachedUses[CurReg].empty())
continue;
InstrToInstrs::const_iterator DefsIt = ColorOpToReachedUses[CurReg].begin();
InstrToInstrs::const_iterator DefsItEnd =
ColorOpToReachedUses[CurReg].end();
for (; DefsIt != DefsItEnd; ++DefsIt) {
for (SetOfMachineInstr::const_iterator UsesIt = DefsIt->second.begin(),
UsesItEnd = DefsIt->second.end(); UsesIt != UsesItEnd; ++UsesIt) {
const MachineInstr *Def = DefsIt->first;
MapRegToId::const_iterator It;
if ((ADRPMode && Def->getOpcode() != ARM64::ADRP) ||
(!ADRPMode && !canDefBePartOfLOH(Def)) ||
(!ADRPMode && isCandidateStore(*UsesIt) &&
((It = RegToId.find((*UsesIt)->getOperand(1).getReg())) == EndIt ||
It->second != CurReg))) {
NotCandidate.insert(*UsesIt);
continue;
}
if (!ADRPMode || *UsesIt != DefsIt->first) {
UseToReachingDefs[*UsesIt].insert(DefsIt->first);
if (!ADRPMode && UseToReachingDefs[*UsesIt].size() > 1)
NotCandidate.insert(*UsesIt);
}
}
}
}
for (SetOfMachineInstr::const_iterator NotCandidateIt = NotCandidate.begin(),
NotCandidateItEnd = NotCandidate.end();
NotCandidateIt != NotCandidateItEnd; ++NotCandidateIt) {
DEBUG(dbgs() << "Too many reaching defs: " << **NotCandidateIt << "\n");
UseToReachingDefs[*NotCandidateIt].clear();
}
}
static void
computeADRP(const InstrToInstrs &UseToDefs, ARM64FunctionInfo &ARM64FI,
const MachineDominatorTree *MDT) {
DEBUG(dbgs() << "*** Compute LOH for ADRP\n");
for (InstrToInstrs::const_iterator UseIt = UseToDefs.begin(),
EndUseIt = UseToDefs.end(); UseIt != EndUseIt; ++UseIt) {
unsigned Size = UseIt->second.size();
if (Size == 0)
continue;
if (Size == 1) {
const MachineInstr *L2 = *UseIt->second.begin();
const MachineInstr *L1 = UseIt->first;
if (!MDT->dominates(L2, L1)) {
DEBUG(dbgs() << "Dominance check failed:\n" << *L2 << '\n'
<< *L1 << '\n');
continue;
}
DEBUG(dbgs() << "Record AdrpAdrp:\n" << *L2 << '\n' << *L1 << '\n');
SmallVector<const MachineInstr *, 2> Args;
Args.push_back(L2);
Args.push_back(L1);
ARM64FI.addLOHDirective(MCLOH_AdrpAdrp, Args);
++NumADRPSimpleCandidate;
}
#ifdef DEBUG
else if (Size == 2)
++NumADRPComplexCandidate2;
else if (Size == 3)
++NumADRPComplexCandidate3;
else
++NumADRPComplexCandidateOther;
#endif
assert(Size >= 1 && "No reaching defs for that use!");
}
}
static bool
isCandidateLoad(const MachineInstr *Instr) {
switch(Instr->getOpcode()) {
default: return false;
case ARM64::LDRSBWui:
case ARM64::LDRSBXui:
case ARM64::LDRSHWui:
case ARM64::LDRSHXui:
case ARM64::LDRSWui:
case ARM64::LDRBui:
case ARM64::LDRHui:
case ARM64::LDRWui:
case ARM64::LDRXui:
case ARM64::LDRSui:
case ARM64::LDRDui:
case ARM64::LDRQui:
if (Instr->getOperand(2).getTargetFlags() & ARM64II::MO_GOT)
return false;
return true;
}
return false;
}
static bool supportLoadFromLiteral(const MachineInstr *Instr) {
switch(Instr->getOpcode()) {
default: return false;
case ARM64::LDRSWui:
case ARM64::LDRWui:
case ARM64::LDRXui:
case ARM64::LDRSui:
case ARM64::LDRDui:
case ARM64::LDRQui:
return true;
}
return false;
}
static bool
isCandidate(const MachineInstr *Instr, const InstrToInstrs &UseToDefs,
const MachineDominatorTree *MDT) {
if (!isCandidateLoad(Instr) && !isCandidateStore(Instr))
return false;
const MachineInstr *Def = *UseToDefs.find(Instr)->second.begin();
if (Def->getOpcode() != ARM64::ADRP) {
if (!MDT->dominates(Def, Instr))
return false;
if (UseToDefs.find(Def) == UseToDefs.end()
|| UseToDefs.find(Def)->second.empty())
return false;
Instr = Def;
Def = *UseToDefs.find(Def)->second.begin();
}
if (Def->getOpcode() == ARM64::ADRP)
return MDT->dominates(Def, Instr);
return false;
}
static bool
registerADRCandidate(const MachineInstr *Use, const InstrToInstrs &UseToDefs,
const InstrToInstrs *DefsPerColorToUses,
ARM64FunctionInfo &ARM64FI,
SetOfMachineInstr *InvolvedInLOHs,
const MapRegToId &RegToId) {
if (Use->getOpcode() != ARM64::ADDXri &&
(Use->getOpcode() != ARM64::LDRXui ||
!(Use->getOperand(2).getTargetFlags() & ARM64II::MO_GOT)))
return false;
InstrToInstrs::const_iterator It = UseToDefs.find(Use);
if (It == UseToDefs.end() || It->second.empty())
return false;
const MachineInstr *Def = *It->second.begin();
if (Def->getOpcode() != ARM64::ADRP)
return false;
const SetOfMachineInstr *Users =
getUses(DefsPerColorToUses,
RegToId.find(Def->getOperand(0).getReg())->second, Def);
if (Users->size() > 1) {
++NumADRComplexCandidate;
return false;
}
++NumADRSimpleCandidate;
assert((!InvolvedInLOHs || InvolvedInLOHs->insert(Def)) &&
"ADRP already involved in LOH.");
assert((!InvolvedInLOHs || InvolvedInLOHs->insert(Use)) &&
"ADD already involved in LOH.");
DEBUG(dbgs() << "Record AdrpAdd\n" << *Def << '\n' << *Use << '\n');
SmallVector<const MachineInstr *, 2> Args;
Args.push_back(Def);
Args.push_back(Use);
ARM64FI.addLOHDirective(Use->getOpcode() == ARM64::ADDXri ?
MCLOH_AdrpAdd : MCLOH_AdrpLdrGot, Args);
return true;
}
static void
computeOthers(const InstrToInstrs &UseToDefs,
const InstrToInstrs *DefsPerColorToUses,
ARM64FunctionInfo &ARM64FI,
const MapRegToId &RegToId,
const MachineDominatorTree *MDT) {
SetOfMachineInstr *InvolvedInLOHs = NULL;
#ifdef DEBUG
SetOfMachineInstr InvolvedInLOHsStorage;
InvolvedInLOHs = &InvolvedInLOHsStorage;
#endif // DEBUG
DEBUG(dbgs() << "*** Compute LOH for Others\n");
SetOfMachineInstr PotentialCandidates;
SetOfMachineInstr PotentialADROpportunities;
for (InstrToInstrs::const_iterator UseIt = UseToDefs.begin(),
EndUseIt = UseToDefs.end(); UseIt != EndUseIt; ++UseIt) {
if (UseIt->second.empty())
continue;
if (!isCandidate(UseIt->first, UseToDefs, MDT)) {
PotentialADROpportunities.insert(UseIt->first);
continue;
}
PotentialCandidates.insert(UseIt->first);
}
SetOfMachineInstr::const_iterator CandidateIt, EndCandidateIt;
#ifdef DEBUG
SetOfMachineInstr DefsOfPotentialCandidates;
#endif
for (CandidateIt = PotentialCandidates.begin(),
EndCandidateIt = PotentialCandidates.end();
CandidateIt != EndCandidateIt; ++CandidateIt) {
const MachineInstr *Candidate = *CandidateIt;
const MachineInstr *Def = *UseToDefs.find(Candidate)->second.begin();
const MachineInstr *L1 = Def;
const MachineInstr *L2 = NULL;
unsigned ImmediateDefOpc = Def->getOpcode();
if (Def->getOpcode() != ARM64::ADRP) {
const SetOfMachineInstr *Users =
getUses(DefsPerColorToUses,
RegToId.find(Def->getOperand(0).getReg())->second, Def);
if (Users->size() > 1) {
#ifdef DEBUG
SetOfMachineInstr::const_iterator UseIt = Users->begin();
SetOfMachineInstr::const_iterator EndUseIt = Users->end();
for (; UseIt != EndUseIt; ++UseIt) {
if (!PotentialCandidates.count(*UseIt)) {
++NumTooCplxLvl2;
break;
}
}
if (UseIt == EndUseIt)
++NumCplxLvl2;
#endif // DEBUG
PotentialADROpportunities.insert(Def);
continue;
}
L2 = Def;
Def = *UseToDefs.find(Def)->second.begin();
L1 = Def;
}
const SetOfMachineInstr *Users =
getUses(DefsPerColorToUses,
RegToId.find(Def->getOperand(0).getReg())->second, Def);
if (Users->size() > 1) {
#ifdef DEBUG
if (DefsOfPotentialCandidates.empty()) {
DefsOfPotentialCandidates = PotentialCandidates;
for (SetOfMachineInstr::const_iterator It = PotentialCandidates.begin(),
EndIt = PotentialCandidates.end(); It != EndIt; ++It)
if (!UseToDefs.find(Candidate)->second.empty())
DefsOfPotentialCandidates.insert(*UseToDefs.find(Candidate)->
second.begin());
}
SetOfMachineInstr::const_iterator UseIt = Users->begin();
SetOfMachineInstr::const_iterator EndUseIt = Users->end();
for (; UseIt != EndUseIt; ++UseIt) {
if (!DefsOfPotentialCandidates.count(*UseIt)) {
++NumTooCplxLvl1;
break;
}
}
if (UseIt == EndUseIt)
++NumCplxLvl1;
#endif // DEBUG
continue;
}
bool IsL2Add = (ImmediateDefOpc == ARM64::ADDXri);
if (L2 && !IsL2Add &&
L2->getOperand(2).getTargetFlags() != ARM64II::MO_GOT)
continue;
SmallVector<const MachineInstr *, 3> Args;
MCLOHType Kind;
if (isCandidateLoad(Candidate)) {
if (L2 == NULL) {
if(!supportLoadFromLiteral(Candidate))
continue;
DEBUG(dbgs() << "Record AdrpLdr:\n" << *L1 << '\n' <<
*Candidate << '\n');
Kind = MCLOH_AdrpLdr;
Args.push_back(L1);
Args.push_back(Candidate);
assert((!InvolvedInLOHs || InvolvedInLOHs->insert(L1)) &&
"L1 already involved in LOH.");
assert((!InvolvedInLOHs || InvolvedInLOHs->insert(Candidate)) &&
"Candidate already involved in LOH.");
++NumADRPToLDR;
} else {
DEBUG(dbgs() << "Record Adrp" << (IsL2Add ? "Add" : "LdrGot") <<
"Ldr:\n" << *L1 << '\n' << *L2 << '\n' << *Candidate << '\n');
Kind = IsL2Add ? MCLOH_AdrpAddLdr : MCLOH_AdrpLdrGotLdr;
Args.push_back(L1);
Args.push_back(L2);
Args.push_back(Candidate);
PotentialADROpportunities.remove(L2);
assert((!InvolvedInLOHs || InvolvedInLOHs->insert(L1)) &&
"L1 already involved in LOH.");
assert((!InvolvedInLOHs || InvolvedInLOHs->insert(L2)) &&
"L2 already involved in LOH.");
assert((!InvolvedInLOHs || InvolvedInLOHs->insert(Candidate)) &&
"Candidate already involved in LOH.");
#ifdef DEBUG
if (Candidate->getOperand(2).getImm() == 0)
if (ImmediateDefOpc == ARM64::ADDXri)
++NumADDToLDR;
else
++NumLDRToLDR;
else
if (ImmediateDefOpc == ARM64::ADDXri)
++NumADDToLDRWithImm;
else
++NumLDRToLDRWithImm;
#endif // DEBUG
}
} else {
if (ImmediateDefOpc == ARM64::ADRP)
continue;
else {
DEBUG(dbgs() << "Record Adrp" << (IsL2Add ? "Add" : "LdrGot") <<
"Str:\n" << *L1 << '\n' << *L2 << '\n' << *Candidate << '\n');
Kind = IsL2Add ? MCLOH_AdrpAddStr : MCLOH_AdrpLdrGotStr;
Args.push_back(L1);
Args.push_back(L2);
Args.push_back(Candidate);
PotentialADROpportunities.remove(L2);
assert((!InvolvedInLOHs || InvolvedInLOHs->insert(L1)) &&
"L1 already involved in LOH.");
assert((!InvolvedInLOHs || InvolvedInLOHs->insert(L2)) &&
"L2 already involved in LOH.");
assert((!InvolvedInLOHs || InvolvedInLOHs->insert(Candidate)) &&
"Candidate already involved in LOH.");
#ifdef DEBUG
if (Candidate->getOperand(2).getImm() == 0)
if (ImmediateDefOpc == ARM64::ADDXri)
++NumADDToSTR;
else
++NumLDRToSTR;
else
if (ImmediateDefOpc == ARM64::ADDXri)
++NumADDToSTRWithImm;
else
++NumLDRToSTRWithImm;
#endif // DEBUG
}
}
ARM64FI.addLOHDirective(Kind, Args);
}
for (SetOfMachineInstr::const_iterator CandidateIt =
PotentialADROpportunities.begin(),
EndCandidateIt = PotentialADROpportunities.end();
CandidateIt != EndCandidateIt; ++CandidateIt)
registerADRCandidate(*CandidateIt, UseToDefs, DefsPerColorToUses,
ARM64FI, InvolvedInLOHs, RegToId);
}
static void collectInvolvedReg(MachineFunction &MF, MapRegToId &RegToId,
MapIdToReg &IdToReg,
const TargetRegisterInfo *TRI) {
unsigned CurRegId = 0;
if (!PreCollectRegister) {
unsigned NbReg = TRI->getNumRegs();
for (; CurRegId < NbReg; ++CurRegId) {
RegToId[CurRegId] = CurRegId;
DEBUG(IdToReg.push_back(CurRegId));
DEBUG(assert(IdToReg[CurRegId] == CurRegId &&
"Reg index mismatches"));
}
return;
}
DEBUG(dbgs() << "** Collect Involved Register\n");
for (MachineFunction::const_iterator IMBB = MF.begin(), IMBBEnd = MF.end();
IMBB != IMBBEnd; ++IMBB)
for (MachineBasicBlock::const_iterator II = IMBB->begin(), IEnd = IMBB->end();
II != IEnd; ++II) {
if (!canDefBePartOfLOH(II)) continue;
for (MachineInstr::const_mop_iterator IO = II->operands_begin(),
IOEnd = II->operands_end();
IO != IOEnd; ++IO) {
if (!IO->isReg() || !IO->isDef())
continue;
unsigned CurReg = IO->getReg();
for (MCRegAliasIterator AI(CurReg, TRI, true); AI.isValid(); ++AI)
if (RegToId.find(*AI) == RegToId.end()) {
DEBUG(IdToReg.push_back(*AI);
assert(IdToReg[CurRegId] == *AI &&
"Reg index mismatches insertion index."));
RegToId[*AI] = CurRegId++;
DEBUG(dbgs() << "Register: " << PrintReg(*AI, TRI) << '\n');
}
}
}
}
bool ARM64CollectLOH::runOnMachineFunction(MachineFunction &Fn) {
const TargetMachine &TM = Fn.getTarget();
const TargetRegisterInfo *TRI = TM.getRegisterInfo();
const MachineDominatorTree *MDT = &getAnalysis<MachineDominatorTree>();
MapRegToId RegToId;
MapIdToReg IdToReg;
ARM64FunctionInfo *ARM64FI = Fn.getInfo<ARM64FunctionInfo>();
assert(ARM64FI && "No MachineFunctionInfo for this function!");
DEBUG(dbgs() << "Looking for LOH in " << Fn.getName() << '\n');
collectInvolvedReg(Fn, RegToId, IdToReg, TRI);
if (RegToId.empty()) return false;
MachineInstr *DummyOp = NULL;
if (BasicBlockScopeOnly) {
const ARM64InstrInfo *TII =
static_cast<const ARM64InstrInfo*>(TM.getInstrInfo());
DummyOp = Fn.CreateMachineInstr(TII->get(ARM64::COPY), DebugLoc());
}
unsigned NbReg = RegToId.size();
bool Modified = false;
InstrToInstrs *ColorOpToReachedUses = new InstrToInstrs[NbReg];
reachingDef(&Fn, ColorOpToReachedUses, RegToId, true, DummyOp);
DEBUG(dbgs() << "ADRP reaching defs\n");
DEBUG(printReachingDef(ColorOpToReachedUses, NbReg, TRI, IdToReg));
InstrToInstrs ADRPToReachingDefs;
reachedUsesToDefs(ADRPToReachingDefs, ColorOpToReachedUses, RegToId, true);
computeADRP(ADRPToReachingDefs, *ARM64FI, MDT);
delete [] ColorOpToReachedUses;
ColorOpToReachedUses = new InstrToInstrs[NbReg];
reachingDef(&Fn, ColorOpToReachedUses, RegToId, false, DummyOp);
DEBUG(dbgs() << "All reaching defs\n");
DEBUG(printReachingDef(ColorOpToReachedUses, NbReg, TRI, IdToReg));
InstrToInstrs UsesToReachingDefs;
reachedUsesToDefs(UsesToReachingDefs, ColorOpToReachedUses, RegToId, false);
computeOthers(UsesToReachingDefs, ColorOpToReachedUses, *ARM64FI, RegToId, MDT);
delete [] ColorOpToReachedUses;
if (BasicBlockScopeOnly)
Fn.DeleteMachineInstr(DummyOp);
return Modified;
}
FunctionPass *llvm::createARM64CollectLOHPass() {
return new ARM64CollectLOH();
}