blob: 452ef6a5facbfdfb2b7d5231e5c6aa90c2b7add7 [file] [edit]
//===----- HexagonGlobalScheduler.cpp - Global Scheduler ------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Basic infrastructure for the global scheduling + Hexagon pull-up pass.
// Currently run at the very end of code generation for Hexagon, cleans
// up lost scheduling opportunities. Currently breaks liveness, so no passes
// that rely on liveness info should run afterwards. Will be fixed in future
// versions.
//
//===----------------------------------------------------------------------===//
#include "Hexagon.h"
#include "HexagonGlobalRegion.h"
#include "HexagonMachineFunctionInfo.h"
#include "HexagonRegisterInfo.h"
#include "HexagonSubtarget.h"
#include "HexagonTargetMachine.h"
#include "HexagonVLIWPacketizer.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/CodeGen/DFAPacketizer.h"
#include "llvm/CodeGen/LatencyPriorityQueue.h"
#include "llvm/CodeGen/LiveIntervals.h"
#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/PseudoSourceValue.h"
#include "llvm/CodeGen/SchedulerRegistry.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSchedule.h"
#include "llvm/IR/Operator.h"
#include "llvm/InitializePasses.h"
#include "llvm/MC/MCInstrItineraries.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include <list>
#include <map>
#define DEBUG_TYPE "global_sched"
using namespace llvm;
STATISTIC(HexagonNumPullUps, "Number of instructions pull-ups");
STATISTIC(HexagonNumDualJumps, "Number of dual jumps formed");
static cl::opt<bool> DisablePullUp("disable-pull-up", cl::Hidden,
cl::desc("Disable Hexagon pull-up pass"));
static cl::opt<bool> EnableSpeculativePullUp(
"enable-speculative-pull-up", cl::Hidden,
cl::desc("Enable speculation during Hexagon pull-up pass"));
static cl::opt<bool> EnableLocalPullUp(
"enable-local-pull-up", cl::Hidden, cl::init(true),
cl::desc("Enable same BB pull during Hexagon pull-up pass"));
static cl::opt<bool> AllowSpeculateLoads(
"speculate-loads-on-pull-up", cl::Hidden, cl::init(true),
cl::desc("Allow speculative loads during Hexagon pull-up pass"));
static cl::opt<bool> AllowCmpBranchLoads(
"cmp-branch-loads-pull-up", cl::Hidden, cl::init(true),
cl::desc("Allow compare-branch loads during Hexagon pull-up pass"));
static cl::opt<bool> AllowUnlikelyPath("unlikely-path-pull-up", cl::Hidden,
cl::init(true),
cl::desc("Allow unlikely path pull up"));
static cl::opt<bool>
PerformDualJumps("dual-jump-in-pull-up", cl::Hidden, cl::init(true),
cl::desc("Perform dual jump formation during pull up"));
static cl::opt<bool> AllowDependentPullUp(
"enable-dependent-pull-up", cl::Hidden, cl::init(true),
cl::desc("Perform dual jump formation during pull up"));
static cl::opt<bool>
AllowBBPeelPullUp("enable-bb-peel-pull-up", cl::Hidden, cl::init(true),
cl::desc("Peel a reg copy out of a BBloop"));
static cl::opt<bool> PreventCompoundSeparation(
"prevent-compound-separation", cl::Hidden,
cl::desc("Do not destroy existing compounds during pull up"));
static cl::opt<bool> PreventDuplexSeparation(
"prevent-duplex-separation", cl::Hidden, cl::init(true),
cl::desc("Do not destroy existing duplexes during pull up"));
static cl::opt<unsigned> MainCandidateQueueSize("pull-up-main-queue-size",
cl::Hidden, cl::init(8));
static cl::opt<unsigned> SecondaryCandidateQueueSize("pull-up-sec-queue-size",
cl::Hidden, cl::init(2));
static cl::opt<bool> PostPullUpOpt(
"post-pull-up-opt", cl::Hidden, cl::Optional, cl::init(true),
cl::desc("Enable opt. exposed by pull-up e.g., remove redundant jumps"));
static cl::opt<bool> SpeculateNonPredInsn(
"speculate-non-pred-insn", cl::Hidden, cl::Optional, cl::init(true),
cl::desc("Speculate non-predicable instructions in parent BB"));
static cl::opt<bool>
DisableCheckBundles("disable-hexagon-check-bundles", cl::Hidden,
cl::init(true),
cl::desc("Disable Hexagon check bundles pass"));
static cl::opt<bool>
WarnOnBundleSize("warn-on-bundle-size", cl::Hidden,
cl::desc("Hexagon check bundles and warn on size"));
static cl::opt<bool>
ForceNoopHazards("force-noop-hazards", cl::Hidden, cl::init(false),
cl::desc("Force noop hazards in scheduler"));
static cl::opt<bool> OneFloatPerPacket(
"single-float-packet", cl::Hidden,
cl::desc("Allow only one single floating point instruction in a packet"));
static cl::opt<bool> OneComplexPerPacket(
"single-complex-packet", cl::Hidden,
cl::desc("Allow only one complex instruction in a packet"));
namespace llvm {
FunctionPass *createHexagonGlobalScheduler();
void initializeHexagonGlobalSchedulerPass(PassRegistry &);
} // namespace llvm
namespace {
class HexagonGlobalSchedulerImpl;
class HexagonGlobalScheduler : public MachineFunctionPass {
public:
static char ID;
HexagonGlobalScheduler() : MachineFunctionPass(ID) {
initializeHexagonGlobalSchedulerPass(*PassRegistry::getPassRegistry());
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequiredID(MachineDominatorsID);
AU.addRequired<MachineLoopInfoWrapperPass>();
AU.addRequired<AAResultsWrapperPass>();
AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
AU.addRequired<MachineBlockFrequencyInfoWrapperPass>();
AU.addRequired<MachineDominatorTreeWrapperPass>();
MachineFunctionPass::getAnalysisUsage(AU);
}
StringRef getPassName() const override { return "Hexagon Global Scheduler"; }
bool runOnMachineFunction(MachineFunction &Fn) override;
};
char HexagonGlobalScheduler::ID = 0;
// Describes a single pull-up candidate.
class PullUpCandidate {
MachineBasicBlock::instr_iterator CandidateLocation;
MachineBasicBlock::iterator HomeBundle;
bool DependentOp;
signed BenefitCost;
std::vector<MachineInstr *> Backtrack;
public:
PullUpCandidate(MachineBasicBlock::instr_iterator MII) {
CandidateLocation = MII;
BenefitCost = 0;
}
PullUpCandidate(MachineBasicBlock::instr_iterator MII,
MachineBasicBlock::iterator HomeBundle,
std::vector<MachineInstr *> &backtrack, bool DependentOp,
signed Cost)
: CandidateLocation(MII), HomeBundle(HomeBundle),
DependentOp(DependentOp), BenefitCost(Cost) {
// Copy of the backtrack.
Backtrack = backtrack;
}
void populate(MachineBasicBlock::instr_iterator &MII,
MachineBasicBlock::iterator &WorkPoint,
std::vector<MachineInstr *> &backtrack, bool &dependentOp) {
MII = CandidateLocation;
WorkPoint = HomeBundle;
backtrack = Backtrack;
dependentOp = DependentOp;
}
signed getCost() { return BenefitCost; }
MachineInstr *getCandidate() { return &*CandidateLocation; }
void dump() {
dbgs() << "Cost(" << BenefitCost;
dbgs() << ") Dependent(" << DependentOp;
dbgs() << ") backtrack size(" << Backtrack.size() << ")\t";
CandidateLocation->dump();
}
};
/// PullUpCandidateSorter - A Sort utility for pull-up candidates.
struct PullUpCandidateSorter {
PullUpCandidateSorter() {}
bool operator()(PullUpCandidate *LHS, PullUpCandidate *RHS) {
return LHS->getCost() > RHS->getCost();
}
};
// Describes a single pull-up opportunity: location to which
// pull-up is possible with additional information about it.
// Also contains a list of pull-up candidates for this location.
class PullUpState {
friend class HexagonGlobalSchedulerImpl;
// Available opportunity for pull-up.
// FAIAP a bundle with an empty slot.
MachineBasicBlock::iterator HomeLocation;
// Home bundle copy. This is here for speed of iteration.
SmallVector<MachineInstr *, HEXAGON_PACKET_SIZE> HomeBundle;
// Multiple candidates for the Home location.
SmallVector<PullUpCandidate *, 8> PullUpCandidates;
const HexagonInstrInfo *QII;
public:
PullUpState(const HexagonInstrInfo *QII) : HomeLocation(NULL), QII(QII) {}
~PullUpState() { reset(); }
void addPullUpCandidate(MachineBasicBlock::instr_iterator MII,
MachineBasicBlock::iterator HomeBundle,
std::vector<MachineInstr *> &backtrack,
bool DependentOp, signed Cost) {
LLVM_DEBUG(dbgs() << "\t[addPullUpCandidate]: "; (*MII).dump());
PullUpCandidate *PUI =
new PullUpCandidate(MII, HomeBundle, backtrack, DependentOp, Cost);
PullUpCandidates.push_back(PUI);
}
void dump() {
unsigned element = 0;
for (unsigned i = 0; i < HomeBundle.size(); i++) {
dbgs() << "[" << element++;
dbgs() << "] Home Duplex("
<< QII->getDuplexCandidateGroup(*HomeBundle[i]);
dbgs() << ") Compound (" << QII->getCompoundCandidateGroup(*HomeBundle[i])
<< ") ";
HomeBundle[i]->dump();
}
dbgs() << "\n";
element = 0;
for (SmallVector<PullUpCandidate *, 4>::iterator
I = PullUpCandidates.begin(),
E = PullUpCandidates.end();
I != E; ++I) {
dbgs() << "[" << element++ << "] Cand: Compound(";
dbgs() << QII->getCompoundCandidateGroup(*(*I)->getCandidate()) << ") ";
(*I)->dump();
}
}
void reset() {
HomeLocation = NULL;
for (SmallVector<PullUpCandidate *, 4>::iterator
I = PullUpCandidates.begin(),
E = PullUpCandidates.end();
I != E; ++I)
delete *I;
PullUpCandidates.clear();
HomeBundle.clear();
}
void addHomeLocation(MachineBasicBlock::iterator WorkPoint) {
reset();
HomeLocation = WorkPoint;
}
unsigned haveCandidates() { return PullUpCandidates.size(); }
};
class HexagonGlobalSchedulerImpl : public HexagonPacketizerList {
// List of PullUp regions for this function.
std::vector<BasicBlockRegion *> PullUpRegions;
// Map of approximate distance for each BB from the
// function base.
DenseMap<MachineBasicBlock *, unsigned> BlockToInstOffset;
// Keep track of multiple pull-up candidates.
PullUpState CurrentState;
// Empty basic blocks as a result of pull-up.
std::vector<MachineBasicBlock *> EmptyBBs;
// Save all the Speculated MachineInstr that were moved
// FROM MachineBasicBlock because we don't want to have
// more than one speculated instructions pulled into one packet.
// TODO: This can be removed once we have a use-def dependency chain
// for all the instructions in a function.
std::map<MachineInstr *, MachineBasicBlock *> SpeculatedIns;
// All the regs and their aliases used by an instruction.
std::map<MachineInstr *, std::vector<unsigned>> MIUseSet;
// All the regs and their aliases defined by an instruction.
std::map<MachineInstr *, std::vector<unsigned>> MIDefSet;
AliasAnalysis *AA;
const MachineBranchProbabilityInfo *MBPI;
const MachineBlockFrequencyInfo *MBFI;
const MachineRegisterInfo *MRI;
const MachineFrameInfo &MFI;
const HexagonRegisterInfo *QRI;
const HexagonInstrInfo *QII;
MachineLoopInfo &MLI;
MachineDominatorTree &MDT;
MachineInstrBuilder Ext;
MachineInstrBuilder Nop;
const unsigned PacketSize;
TargetSchedModel TSchedModel;
public:
// Ctor.
HexagonGlobalSchedulerImpl(MachineFunction &MF, MachineLoopInfo &MLI,
MachineDominatorTree &MDT, AliasAnalysis *AA,
const MachineBranchProbabilityInfo *MBPI,
const MachineBlockFrequencyInfo *MBFI,
const MachineRegisterInfo *MRI,
const MachineFrameInfo &MFI,
const HexagonRegisterInfo *QRI);
HexagonGlobalSchedulerImpl(const HexagonGlobalSchedulerImpl &) = delete;
HexagonGlobalSchedulerImpl &
operator=(const HexagonGlobalSchedulerImpl &) = delete;
~HexagonGlobalSchedulerImpl() {
// Free regions.
for (std::vector<BasicBlockRegion *>::iterator I = PullUpRegions.begin(),
E = PullUpRegions.end();
I != E; ++I)
delete *I;
MF.deleteMachineInstr(Ext);
MF.deleteMachineInstr(Nop);
}
// initPacketizerState - initialize some internal flags.
void initPacketizerState() override;
// ignorePseudoInstruction - Ignore bundling of pseudo instructions.
bool ignoreInstruction(MachineInstr *MI);
// isSoloInstruction - return true if instruction MI can not be packetized
// with any other instruction, which means that MI itself is a packet.
bool isSoloInstruction(const MachineInstr &MI) override;
// Add MI to packetizer state. Returns false if it cannot fit in the packet.
bool incrementalAddToPacket(MachineInstr &MI);
// formPullUpRegions - Top level call to form regions.
bool formPullUpRegions(MachineFunction &Fn);
// performPullUp - Top level call for pull-up.
bool performPullUp();
// performPullUpCFG - Top level call for pull-up CFG.
bool performPullUpCFG(MachineFunction &Fn);
// performExposedOptimizations -
// Look for optimization opportunities after pullup.
bool performExposedOptimizations(MachineFunction &Fn);
// optimizeBranching -
// 1. A conditional-jump transfers control to a BB with
// jump as the only instruction.
// if(p0) jump t1
// // ...
// t1: jump t2
// 2. When a BB with a single conditional jump, jumps to succ-of-succ and
// falls-through BB with only jump instruction.
// { if(p0) jump t1 }
// { jump t2 }
// t1: { ... }
MachineBasicBlock *optimizeBranches(MachineBasicBlock *MBB,
MachineBasicBlock *TBB,
MachineInstr *FirstTerm,
MachineBasicBlock *FBB);
// removeRedundantBranches -
// 1. Remove jump to the layout successor.
// 2. Remove multiple (dual) jump to the same target.
bool removeRedundantBranches(MachineBasicBlock *MBB, MachineBasicBlock *TBB,
MachineInstr *FirstTerm, MachineBasicBlock *FBB,
MachineInstr *SecondTerm);
// optimizeDualJumps - optimize dual jumps in a packet
// For now: Replace dual jump by single jump in case of a fall through.
bool optimizeDualJumps(MachineBasicBlock *MBB, MachineBasicBlock *TBB,
MachineInstr *FirstTerm, MachineBasicBlock *FBB,
MachineInstr *SecondTerm);
void GenUseDefChain(MachineFunction &Fn);
// Return region pointer or null if none found.
BasicBlockRegion *getRegionForMBB(std::vector<BasicBlockRegion *> &Regions,
MachineBasicBlock *MBB);
// Saves all the used-regs and their aliases in Uses.
// Saves all the defined-regs and their aliases in Defs.
void MIUseDefSet(MachineInstr *MI, std::vector<unsigned> &Defs,
std::vector<unsigned> &Uses);
// This is a very useful debug utility.
unsigned countCompounds(MachineFunction &Fn);
// Check bundle counts
void checkBundleCounts(MachineFunction &Fn);
private:
// Get next BB to be included into the region.
MachineBasicBlock *getNextPURBB(MachineBasicBlock *MBB, bool SecondBest);
void setUsedRegs(BitVector &Set, unsigned Reg);
bool AliasingRegs(unsigned RegA, unsigned RegB);
// Test is true if the two MIs cannot be safely reordered.
bool ReorderDependencyTest(MachineInstr *MIa, MachineInstr *MIb);
bool canAddMIToThisPacket(
MachineInstr *MI,
SmallVector<MachineInstr *, HEXAGON_PACKET_SIZE> &Bundle);
bool CanPromoteToDotNew(MachineInstr *MI, unsigned Reg);
bool pullUpPeelBBLoop(MachineBasicBlock *PredBB, MachineBasicBlock *LoopBB);
MachineInstr *findBundleAndBranch(MachineBasicBlock *BB,
MachineBasicBlock::iterator &Bundle);
// Does this bundle have any slots left?
bool ResourcesAvailableInBundle(BasicBlockRegion *CurrentRegion,
MachineBasicBlock::iterator &TargetPacket);
// Perform the actual move.
MachineInstr *MoveAndUpdateLiveness(
BasicBlockRegion *CurrentRegion, MachineBasicBlock *HomeBB,
MachineInstr *InstrToMove, bool NeedToNewify, unsigned DepReg,
bool MovingDependentOp, MachineBasicBlock *OriginBB,
MachineInstr *OriginalInstruction, SmallVector<MachineOperand, 4> &Cond,
MachineBasicBlock::iterator &SourceLocation,
MachineBasicBlock::iterator &TargetPacket,
MachineBasicBlock::iterator &NextMI,
std::vector<MachineInstr *> &backtrack);
// Updates incremental kill patterns along the backtrack.
void updateKillAlongThePath(MachineBasicBlock *HomeBB,
MachineBasicBlock *OriginBB,
MachineBasicBlock::instr_iterator &Head,
MachineBasicBlock::instr_iterator &Tail,
MachineBasicBlock::iterator &SourcePacket,
MachineBasicBlock::iterator &TargetPacket,
std::vector<MachineInstr *> &backtrack);
// Gather list of pull-up candidates.
bool findPullUpCandidates(MachineBasicBlock::iterator &WorkPoint,
MachineBasicBlock::iterator &FromHere,
std::vector<MachineInstr *> &backtrack,
unsigned MaxCandidates);
// See if the instruction could be pulled up.
bool tryMultipleInstructions(
MachineBasicBlock::iterator &RetVal, /* output parameter */
std::vector<BasicBlockRegion *>::iterator &CurrentRegion,
MachineBasicBlock::iterator &NextMI,
MachineBasicBlock::iterator &ToThisBBEnd,
MachineBasicBlock::iterator &FromThisBBEnd, bool PathInRegion = true);
// Try to move MI into existing bundle.
bool MoveMItoBundle(BasicBlockRegion *CurrentRegion,
MachineBasicBlock::instr_iterator &InstrToMove,
MachineBasicBlock::iterator &NextMI,
MachineBasicBlock::iterator &TargetPacket,
MachineBasicBlock::iterator &SourceLocation,
std::vector<MachineInstr *> &backtrack,
bool MovingDependentOp, bool PathInRegion);
// Insert temporary MI copy into MBB.
MachineBasicBlock::instr_iterator
insertTempCopy(MachineBasicBlock *MBB,
MachineBasicBlock::iterator &TargetPacket, MachineInstr *MI,
bool DeleteOldCopy);
MachineBasicBlock::instr_iterator
findInsertPositionInBundle(MachineBasicBlock::iterator &Bundle,
MachineInstr *MI, bool &LastInBundle);
bool NeedToNewify(MachineBasicBlock::instr_iterator NewMI, unsigned *DepReg,
MachineInstr *TargetPacket);
bool CanNewifiedBeUsedInBundle(MachineBasicBlock::instr_iterator NewMI,
unsigned DepReg, MachineInstr *TargetPacket);
void addInstructionToExistingBundle(MachineBasicBlock *HomeBB,
MachineBasicBlock::instr_iterator &Head,
MachineBasicBlock::instr_iterator &Tail,
MachineBasicBlock::instr_iterator &NewMI,
MachineBasicBlock::iterator &TargetPacket,
MachineBasicBlock::iterator &NextMI,
std::vector<MachineInstr *> &backtrack);
void removeInstructionFromExistingBundle(
MachineBasicBlock *HomeBB, MachineBasicBlock::instr_iterator &Head,
MachineBasicBlock::instr_iterator &Tail,
MachineBasicBlock::iterator &SourceLocation,
MachineBasicBlock::iterator &NextMI, bool MovingDependentOp,
std::vector<MachineInstr *> &backtrack);
// Check for conditional register operaton.
bool MIsCondAssign(MachineInstr *BMI, MachineInstr *MI,
SmallVector<unsigned, 4> &Defs);
// Test all the conditions required for instruction to be
// speculative. These are just required conditions, cost
// or benefit should be computed elsewhere.
bool canMIBeSpeculated(MachineInstr *MI, MachineBasicBlock *ToBB,
MachineBasicBlock *FromBB,
std::vector<MachineInstr *> &backtrack);
// See if this branch target belongs to the current region.
bool isBranchWithinRegion(BasicBlockRegion *CurrentRegion, MachineInstr *MI);
// A collection of low level utilities.
bool MIsAreDependent(MachineInstr *MIa, MachineInstr *MIb);
bool MIsHaveTrueDependency(MachineInstr *MIa, MachineInstr *MIb);
bool canReorderMIs(MachineInstr *MIa, MachineInstr *MIb);
bool canCauseStall(MachineInstr *MI, MachineInstr *MJ);
bool canThisMIBeMoved(MachineInstr *MI,
MachineBasicBlock::iterator &WorkPoint,
bool &MovingDependentOp, int &Cost);
bool MIisDualJumpCandidate(MachineInstr *MI,
MachineBasicBlock::iterator &WorkPoint);
bool DemoteToDotOld(MachineInstr *MI);
bool isNewifiable(MachineBasicBlock::instr_iterator MII, unsigned DepReg,
MachineInstr *TargetPacket);
bool IsNewifyStore(MachineInstr *MI);
bool isJumpOutOfRange(MachineInstr *MI);
bool IsDualJumpFirstCandidate(MachineInstr *MI);
bool IsDualJumpFirstCandidate(MachineBasicBlock *MBB);
bool IsDualJumpFirstCandidate(MachineBasicBlock::iterator &TargetPacket);
bool IsNotDualJumpFirstCandidate(MachineInstr *MI);
bool isJumpOutOfRange(MachineInstr *UnCond, MachineInstr *Cond);
bool IsDualJumpSecondCandidate(MachineInstr *MI);
bool tryAllocateResourcesForConstExt(MachineInstr *MI, bool UpdateState);
bool isCompoundPair(MachineInstr *MIa, MachineInstr *MIb);
bool doesMIDefinesPredicate(MachineInstr *MI, SmallVector<unsigned, 4> &Defs);
bool AnalyzeBBBranches(MachineBasicBlock *MBB, MachineBasicBlock *&TBB,
MachineInstr *&FirstTerm, MachineBasicBlock *&FBB,
MachineInstr *&SecondTerm);
inline bool multipleBranchesFromToBB(MachineBasicBlock *BB) const;
};
} // namespace
INITIALIZE_PASS_BEGIN(HexagonGlobalScheduler, "global-sched",
"Hexagon Global Scheduler", false, false)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(MachineLoopInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(MachineBlockFrequencyInfoWrapperPass)
INITIALIZE_PASS_END(HexagonGlobalScheduler, "global-sched",
"Hexagon Global Scheduler", false, false)
/// HexagonGlobalSchedulerImpl Ctor.
HexagonGlobalSchedulerImpl::HexagonGlobalSchedulerImpl(
MachineFunction &MF, MachineLoopInfo &MLI, MachineDominatorTree &MDT,
AliasAnalysis *AA, const MachineBranchProbabilityInfo *MBPI,
const MachineBlockFrequencyInfo *MBFI, const MachineRegisterInfo *MRI,
const MachineFrameInfo &MFI, const HexagonRegisterInfo *QRI)
: HexagonPacketizerList(MF, MLI, AA, nullptr, false), PullUpRegions(0),
CurrentState((const HexagonInstrInfo *)TII), AA(AA), MBPI(MBPI),
MBFI(MBFI), MRI(MRI), MFI(MFI), QRI(QRI), MLI(MLI), MDT(MDT),
PacketSize(MF.getSubtarget().getSchedModel().IssueWidth) {
QII = (const HexagonInstrInfo *)TII;
Ext = BuildMI(MF, DebugLoc(), QII->get(Hexagon::A4_ext));
Nop = BuildMI(MF, DebugLoc(), QII->get(Hexagon::A2_nop));
TSchedModel.init(&MF.getSubtarget());
}
// Return bundle size without debug instructions.
static unsigned nonDbgBundleSize(MachineBasicBlock::iterator &TargetPacket) {
MachineBasicBlock::instr_iterator MII = TargetPacket.getInstrIterator();
MachineBasicBlock::instr_iterator End = MII->getParent()->instr_end();
unsigned count = 0;
for (++MII; MII != End && MII->isInsideBundle(); ++MII) {
if (MII->isDebugInstr())
continue;
count++;
}
return count;
}
/// The pass main entry point.
bool HexagonGlobalScheduler::runOnMachineFunction(MachineFunction &Fn) {
auto &HST = Fn.getSubtarget<HexagonSubtarget>();
if (DisablePullUp || !HST.usePackets() || skipFunction(Fn.getFunction()))
return false;
const MachineRegisterInfo *MRI = &Fn.getRegInfo();
const MachineFrameInfo &MFI = Fn.getFrameInfo();
const HexagonRegisterInfo *QRI = HST.getRegisterInfo();
MachineLoopInfo &MLI = getAnalysis<MachineLoopInfoWrapperPass>().getLI();
MachineDominatorTree &MDT =
getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
const MachineBranchProbabilityInfo *MBPI =
&getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
const MachineBlockFrequencyInfo *MBFI =
&getAnalysis<MachineBlockFrequencyInfoWrapperPass>().getMBFI();
AliasAnalysis *AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
// Preserve comounds if Opt Size.
const Function &F = Fn.getFunction();
if (F.hasOptSize() && PreventCompoundSeparation.getNumOccurrences() == 0)
PreventCompoundSeparation = true;
// Instantiate the Scheduler.
HexagonGlobalSchedulerImpl GlobalSchedulerState(Fn, MLI, MDT, AA, MBPI, MBFI,
MRI, MFI, QRI);
// DFA state table should not be empty.
assert(GlobalSchedulerState.getResourceTracker() && "Empty DFA table!");
// Loop over all of the basic blocks.
// PullUp regions are basically traces with no side entrances.
// Might want to traverse BB by frequency.
GlobalSchedulerState.checkBundleCounts(Fn);
// Pullup does not handle hazards yet.
if (!DisablePullUp.getPosition() && ForceNoopHazards)
return true;
LLVM_DEBUG(GlobalSchedulerState.countCompounds(Fn));
GlobalSchedulerState.GenUseDefChain(Fn);
GlobalSchedulerState.formPullUpRegions(Fn);
GlobalSchedulerState.performPullUp();
GlobalSchedulerState.performPullUpCFG(Fn);
if (PostPullUpOpt) {
GlobalSchedulerState.formPullUpRegions(Fn);
GlobalSchedulerState.performExposedOptimizations(Fn);
}
LLVM_DEBUG(GlobalSchedulerState.countCompounds(Fn));
return true;
}
/// Allocate resources (i.e. 4 bytes) for constant extender. If succeess, return
/// true, otherwise, return false.
bool HexagonGlobalSchedulerImpl::tryAllocateResourcesForConstExt(
MachineInstr *MI, bool UpdateState = true) {
if (ResourceTracker->canReserveResources(*Ext)) {
// We do not always want to change the state of ResourceTracker.
// When we do not want to change it, we need to test for additional
// corner cases.
if (UpdateState)
ResourceTracker->reserveResources(*Ext);
else if (CurrentPacketMIs.size() >= PacketSize - 1)
return false;
return true;
}
return false;
}
static bool IsSchedBarrier(const MachineInstr *MI) {
return MI->getOpcode() == Hexagon::Y2_barrier;
}
static bool IsIndirectCall(const MachineInstr *MI) {
return MI->getOpcode() == Hexagon::J2_callr;
}
#ifndef NDEBUG
static void DumpLinked(MachineInstr *MI) {
if (MI->isBundledWithPred())
dbgs() << "^";
else
dbgs() << " ";
if (MI->isBundledWithSucc())
dbgs() << "v";
else
dbgs() << " ";
MI->dump();
}
static void DumpPacket(MachineBasicBlock::instr_iterator MII) {
if (MII == MachineBasicBlock::instr_iterator()) {
dbgs() << "\tNULL\n";
return;
}
MachineInstr *MI = &*MII;
MachineBasicBlock *MBB = MI->getParent();
// Uninserted instruction.
if (!MBB) {
dbgs() << "\tUnattached: ";
DumpLinked(MI);
return;
}
dbgs() << "\t";
DumpLinked(MI);
if (MI->isBundle()) {
MachineBasicBlock::instr_iterator MIE = MI->getParent()->instr_end();
for (++MII; MII != MIE && MII->isInsideBundle() && !MII->isBundle();
++MII) {
dbgs() << "\t\t*";
DumpLinked(&*MII);
}
}
}
static void DumpPacket(MachineBasicBlock::instr_iterator MII,
MachineBasicBlock::instr_iterator BBEnd) {
if (MII == BBEnd) {
dbgs() << "\tBBEnd\n";
return;
}
DumpPacket(MII);
}
#endif
static bool isBranch(MachineInstr *MI) {
if (MI->isBundle()) {
MachineBasicBlock::instr_iterator MII = MI->getIterator();
MachineBasicBlock::instr_iterator MIE = MI->getParent()->instr_end();
for (++MII; MII != MIE && MII->isInsideBundle() && !MII->isBundle();
++MII) {
if (MII->isBranch())
return true;
}
} else
return MI->isBranch();
return false;
}
/// Any of those must not be first dual jump. Everything else is OK.
bool HexagonGlobalSchedulerImpl::IsNotDualJumpFirstCandidate(MachineInstr *MI) {
if (MI->isCall() || (MI->isBranch() && !QII->isPredicated(*MI)) ||
MI->isReturn() || QII->isEndLoopN(MI->getOpcode()))
return true;
return false;
}
/// These four functions clearly belong in HexagonInstrInfo.cpp.
/// Is this MI could be first dual jump instruction?
bool HexagonGlobalSchedulerImpl::IsDualJumpFirstCandidate(MachineInstr *MI) {
if (!PerformDualJumps)
return false;
if (MI->isBranch() && QII->isPredicated(*MI) && !QII->isNewValueJump(*MI) &&
!MI->isIndirectBranch() && !QII->isEndLoopN(MI->getOpcode()))
return true;
// Missing loopN here, but not sure if there will be any benefit from it.
return false;
}
/// This version covers the whole packet.
bool HexagonGlobalSchedulerImpl::IsDualJumpFirstCandidate(
MachineBasicBlock::iterator &TargetPacket) {
if (!PerformDualJumps)
return false;
MachineInstr *MI = &*TargetPacket;
if (MI->isBundle()) {
// If this is a bundle, it must be the last bundle in BB.
if (&(*MI->getParent()->rbegin()) != MI)
return false;
MachineBasicBlock::instr_iterator MII = MI->getIterator();
MachineBasicBlock::instr_iterator BBEnd = MI->getParent()->instr_end();
// If there is a control flow op in this packet, this is the case
// we look for, even if they are dependent on other members.
for (++MII; MII != BBEnd && MII->isInsideBundle() && !MII->isBundle();
++MII)
if (IsNotDualJumpFirstCandidate(&*MII))
return false;
} else
return IsDualJumpFirstCandidate(MI);
return true;
}
/// This version cover whole BB. There could be a BB
/// with no control flow in it. In this case we can still pull-up a jump
/// into it. Negative proof.
bool HexagonGlobalSchedulerImpl::IsDualJumpFirstCandidate(
MachineBasicBlock *MBB) {
if (!PerformDualJumps)
return false;
for (MachineBasicBlock::instr_iterator MII = MBB->instr_begin(),
MBBEnd = MBB->instr_end();
MII != MBBEnd; ++MII) {
MachineInstr *MI = &*MII;
if (MI->isDebugInstr())
continue;
if (!MI->isBundle() && IsNotDualJumpFirstCandidate(MI))
return false;
}
return true;
}
/// Is this MI could be second dual jump instruction?
bool HexagonGlobalSchedulerImpl::IsDualJumpSecondCandidate(MachineInstr *MI) {
if (!PerformDualJumps)
return false;
if ((MI->isBranch() && !QII->isNewValueJump(*MI) && !MI->isIndirectBranch() &&
!QII->isEndLoopN(MI->getOpcode())) ||
(MI->isCall() && !IsIndirectCall(MI)))
return true;
return false;
}
// Since we have no exact knowledge of code layout,
// allow some safety buffer for jump target.
// This is measured in bytes.
static const unsigned SafetyBuffer = 200;
static MachineBasicBlock::instr_iterator
getHexagonFirstInstrTerminator(MachineBasicBlock *MBB) {
MachineBasicBlock::instr_iterator MIB = MBB->instr_begin();
MachineBasicBlock::instr_iterator MIE = MBB->instr_end();
MachineBasicBlock::instr_iterator MII = MIB;
while (MII != MIE) {
if (!MII->isBundle() && MII->isTerminator())
return MII;
++MII;
}
return MIE;
}
/// Check if a given instruction is:
/// - a jump to a distant target
/// - that exceeds its immediate range
/// If both conditions are true, it requires constant extension.
bool HexagonGlobalSchedulerImpl::isJumpOutOfRange(MachineInstr *MI) {
if (!MI || !MI->isBranch())
return false;
MachineBasicBlock *MBB = MI->getParent();
auto FirstTerm = getHexagonFirstInstrTerminator(MBB);
if (FirstTerm == MBB->instr_end())
return false;
unsigned InstOffset = BlockToInstOffset[MBB];
unsigned Distance = 0;
MachineBasicBlock::instr_iterator FTMII = FirstTerm;
// To save time, estimate exact position of a branch instruction
// as one at the end of the MBB.
// Number of instructions times typical instruction size.
InstOffset += (QII->nonDbgBBSize(MBB) * HEXAGON_INSTR_SIZE);
MachineBasicBlock *TBB = NULL, *FBB = NULL;
SmallVector<MachineOperand, 4> Cond;
// Try to analyze this branch.
if (QII->analyzeBranch(*MBB, TBB, FBB, Cond, false)) {
// Could not analyze it. See if this is something we can recognize.
// If it is a NVJ, it should always have its target in
// a fixed location.
if (QII->isNewValueJump(*FirstTerm))
TBB = FirstTerm->getOperand(QII->getCExtOpNum(*FirstTerm)).getMBB();
}
if (TBB && (MI == &*FirstTerm)) {
Distance =
(unsigned)std::abs((long long)InstOffset - BlockToInstOffset[TBB]) +
SafetyBuffer;
LLVM_DEBUG(dbgs() << "\tFirst term offset(" << Distance << "): ";
FirstTerm->dump());
return !QII->isJumpWithinBranchRange(*FirstTerm, Distance);
}
if (FBB) {
// Look for second terminator.
FTMII++;
MachineInstr *SecondTerm = &*FTMII;
assert(FTMII != MBB->instr_end() &&
(SecondTerm->isBranch() || SecondTerm->isCall()) &&
"Bad second terminator");
if (MI != SecondTerm)
return false;
// Analyze the second branch in the BB.
Distance =
(unsigned)std::abs((long long)InstOffset - BlockToInstOffset[FBB]) +
SafetyBuffer;
LLVM_DEBUG(dbgs() << "\tSecond term offset(" << Distance << "): ";
FirstTerm->dump());
return !QII->isJumpWithinBranchRange(*SecondTerm, Distance);
}
return false;
}
/// Returns true if an instruction can be promoted to .new predicate
/// or new-value store.
/// Performs implicit version checking.
bool HexagonGlobalSchedulerImpl::isNewifiable(
MachineBasicBlock::instr_iterator MII, unsigned DepReg,
MachineInstr *TargetPacket) {
MachineInstr *MI = &*MII;
if (QII->isDotNewInst(*MI) ||
!CanNewifiedBeUsedInBundle(MII, DepReg, TargetPacket))
return false;
return (QII->isPredicated(*MI) && QII->getDotNewPredOp(*MI, nullptr) > 0) ||
QII->mayBeNewStore(*MI);
}
bool HexagonGlobalSchedulerImpl::DemoteToDotOld(MachineInstr *MI) {
int NewOpcode = QII->getDotOldOp(*MI);
MI->setDesc(QII->get(NewOpcode));
return true;
}
// initPacketizerState - Initialize packetizer flags
void HexagonGlobalSchedulerImpl::initPacketizerState(void) {
CurrentPacketMIs.clear();
return;
}
// ignorePseudoInstruction - Ignore bundling of pseudo instructions.
bool HexagonGlobalSchedulerImpl::ignoreInstruction(MachineInstr *MI) {
if (MI->isDebugInstr())
return true;
// We must print out inline assembly
if (MI->isInlineAsm())
return false;
// We check if MI has any functional units mapped to it.
// If it doesn't, we ignore the instruction.
const MCInstrDesc &TID = MI->getDesc();
unsigned SchedClass = TID.getSchedClass();
const InstrStage *IS =
ResourceTracker->getInstrItins()->beginStage(SchedClass);
unsigned FuncUnits = IS->getUnits();
return !FuncUnits;
}
// isSoloInstruction: - Returns true for instructions that must be
// scheduled in their own packet.
bool HexagonGlobalSchedulerImpl::isSoloInstruction(const MachineInstr &MI) {
if (MI.isInlineAsm())
return true;
if (MI.isEHLabel())
return true;
// From Hexagon V4 Programmer's Reference Manual 3.4.4 Grouping constraints:
// trap, pause, barrier, icinva, isync, and syncht are solo instructions.
// They must not be grouped with other instructions in a packet.
if (IsSchedBarrier(&MI))
return true;
if (MI.getOpcode() == Hexagon::A2_nop)
return true;
return false;
}
/// Return region ptr or null if non found.
BasicBlockRegion *HexagonGlobalSchedulerImpl::getRegionForMBB(
std::vector<BasicBlockRegion *> &Regions, MachineBasicBlock *MBB) {
for (std::vector<BasicBlockRegion *>::iterator I = Regions.begin(),
E = Regions.end();
I != E; ++I) {
if ((*I)->findMBB(MBB))
return *I;
}
return NULL;
}
/// Select best candidate to form regions.
static inline bool selectBestBB(BlockFrequency &BBaFreq, unsigned BBaSize,
BlockFrequency &BBbFreq, unsigned BBbSize) {
if (BBaFreq.getFrequency() > BBbFreq.getFrequency())
return true;
// TODO: This needs fine tuning.
// if (BBaSize < BBbSize)
// return true;
if (BBaFreq.getFrequency() == BBbFreq.getFrequency())
return true;
return false;
}
/// Returns BB pointer if one of MBB successors should be added to the
/// current PullUp Region, NULL otherwise.
/// If SecondBest is defined, get next one after Best match.
/// Most of the time, since we practically always have only two successors,
/// this is "the other" BB successor which still matches original
/// selection criterion.
MachineBasicBlock *
HexagonGlobalSchedulerImpl::getNextPURBB(MachineBasicBlock *MBB,
bool SecondBest = false) {
if (!MBB)
return NULL;
BlockFrequency BestBlockFreq = BlockFrequency(0);
unsigned BestBlockSize = 0;
MachineBasicBlock *BestBB = NULL;
MachineBasicBlock *SecondBestBB = NULL;
// Catch single BB loops.
for (MachineBasicBlock *Succ : MBB->successors())
if (Succ == MBB)
return NULL;
// Iterate through successors to MBB.
for (MachineBasicBlock *Succ : MBB->successors()) {
BlockFrequency BlockFreq = MBFI->getBlockFreq(Succ);
LLVM_DEBUG(dbgs() << "\tsucc BB(" << Succ->getNumber() << ") freq("
<< BlockFreq.getFrequency() << ")");
if (!SecondBest && getRegionForMBB(PullUpRegions, Succ))
continue;
// If there is more then one predecessor to this block, do not include it.
// It means there is a side entrance to it.
if (Succ->pred_size() > 1)
continue;
// If this block is a target of an indirect branch, it should
// also not be included.
if (Succ->isEHPad() || Succ->hasAddressTaken())
continue;
// Get BB edge frequency.
BlockFrequency EdgeFreq = BlockFreq * MBPI->getEdgeProbability(MBB, Succ);
LLVM_DEBUG(dbgs() << "\tedge with freq(" << EdgeFreq.getFrequency()
<< ")\n");
if (selectBestBB(EdgeFreq, QII->nonDbgBBSize(Succ), BestBlockFreq,
BestBlockSize)) {
BestBlockFreq = EdgeFreq;
BestBlockSize = QII->nonDbgBBSize(Succ);
SecondBestBB = BestBB;
BestBB = Succ;
} else if (!SecondBestBB) {
SecondBestBB = Succ;
}
}
if (SecondBest)
return SecondBestBB;
else
return BestBB;
}
/// Form region to perform pull-up.
bool HexagonGlobalSchedulerImpl::formPullUpRegions(MachineFunction &Fn) {
const Function &F = Fn.getFunction();
// Check for single-block functions and skip them.
if (std::next(F.begin()) == F.end())
return false;
// Compute map for BB distances.
// Offset of the current instruction from the start.
unsigned InstOffset = 0;
LLVM_DEBUG(dbgs() << "****** Form PullUpRegions **************\n");
// Loop over all basic blocks.
// PullUp regions are basically traces with no side entrances.
for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end(); MBB != MBBe;
++MBB) {
if (MBB->getAlignment() > llvm::Align(1)) {
// Although we don't know the exact layout of the final code, we need
// to account for alignment padding somehow. This heuristic pads each
// aligned basic block according to the alignment value.
int ByteAlign = MBB->getAlignment().value() - 1;
InstOffset = (InstOffset + ByteAlign) & ~(ByteAlign);
}
// Remember BB layout offset.
BlockToInstOffset[&*MBB] = InstOffset;
for (MachineBasicBlock::instr_iterator MII = MBB->instr_begin(),
MIE = MBB->instr_end();
MII != MIE; ++MII)
if (!MII->isBundle())
InstOffset += QII->getSize(*MII);
// If this BB is already in a region, move on.
if (getRegionForMBB(PullUpRegions, &*MBB))
continue;
LLVM_DEBUG(dbgs() << "\nRoot BB(" << MBB->getNumber() << ") name("
<< MBB->getName() << ") size(" << QII->nonDbgBBSize(&*MBB)
<< ") freq(" << printBlockFreq(*MBFI, *MBB)
<< ") pred_size(" << MBB->pred_size() << ") in_func("
<< MBB->getParent()->getFunction().getName() << ")\n");
BasicBlockRegion *PUR = new BasicBlockRegion(TII, QRI, &*MBB);
PullUpRegions.push_back(PUR);
for (MachineBasicBlock *MBBR = getNextPURBB(&*MBB); MBBR;
MBBR = getNextPURBB(MBBR)) {
LLVM_DEBUG(dbgs() << "Add BB(" << MBBR->getNumber() << ") name("
<< MBBR->getName() << ") size("
<< QII->nonDbgBBSize(MBBR) << ") freq("
<< printBlockFreq(*MBFI, *MBBR) << ") in_func("
<< MBBR->getParent()->getFunction().getName() << ")\n");
PUR->addBBtoRegion(MBBR);
}
}
return true;
}
/// Return true if MI is an instruction we are unable to reason about
/// (like something with unmodeled memory side effects).
static inline bool isGlobalMemoryObject(MachineInstr *MI) {
if (MI->hasUnmodeledSideEffects() || MI->hasOrderedMemoryRef() ||
MI->isCall() ||
(MI->getOpcode() == Hexagon::J2_jump && !MI->getOperand(0).isMBB()))
return true;
return false;
}
// This MI might have either incomplete info, or known to be unsafe
// to deal with (i.e. volatile object).
static inline bool isUnsafeMemoryObject(MachineInstr *MI) {
if (!MI || MI->memoperands_empty())
return true;
// We purposefully do no check for hasOneMemOperand() here
// in hope to trigger an assert downstream in order to
// finish implementation.
if ((*MI->memoperands_begin())->isVolatile() || MI->hasUnmodeledSideEffects())
return true;
if (!(*MI->memoperands_begin())->getValue())
return true;
return false;
}
/// This returns true if the two MIs could be memory dependent.
static bool MIsNeedChainEdge(AliasAnalysis *AA, const TargetInstrInfo *TII,
MachineInstr *MIa, MachineInstr *MIb) {
// Cover a trivial case - no edge is need to itself.
if (MIa == MIb)
return false;
if (TII->areMemAccessesTriviallyDisjoint(*MIa, *MIb))
return false;
if (isUnsafeMemoryObject(MIa) || isUnsafeMemoryObject(MIb))
return true;
// If we are dealing with two "normal" loads, we do not need an edge
// between them - they could be reordered.
if (!MIa->mayStore() && !MIb->mayStore())
return false;
// To this point analysis is generic. From here on we do need AA.
if (!AA)
return true;
MachineMemOperand *MMOa = *MIa->memoperands_begin();
MachineMemOperand *MMOb = *MIb->memoperands_begin();
// TODO: Need to handle multiple memory operands.
// if either instruction has more than one memory operand, punt.
if (!(MIa->hasOneMemOperand() && MIb->hasOneMemOperand()))
return true;
if (!MMOa->getSize().hasValue() || !MMOb->getSize().hasValue())
return true;
assert((MMOa->getOffset() >= 0) && "Negative MachineMemOperand offset");
assert((MMOb->getOffset() >= 0) && "Negative MachineMemOperand offset");
assert((MMOa->getSize().hasValue() && MMOb->getSize().hasValue()) &&
"Size 0 memory access");
// If the base address of the two memoperands is the same. For instance,
// x and x+4, then we can easily reason about them using the offset and size
// of access.
if (MMOa->getValue() == MMOb->getValue()) {
if (MMOa->getOffset() > MMOb->getOffset()) {
uint64_t offDiff = MMOa->getOffset() - MMOb->getOffset();
return !(MMOb->getSize().getValue() <= offDiff);
} else if (MMOa->getOffset() < MMOb->getOffset()) {
uint64_t offDiff = MMOb->getOffset() - MMOa->getOffset();
return !(MMOa->getSize().getValue() <= offDiff);
}
// MMOa->getOffset() == MMOb->getOffset()
return true;
}
int64_t MinOffset = std::min(MMOa->getOffset(), MMOb->getOffset());
int64_t Overlapa = MMOa->getSize().getValue() + MMOa->getOffset() - MinOffset;
int64_t Overlapb = MMOb->getSize().getValue() + MMOb->getOffset() - MinOffset;
AliasResult AAResult =
AA->alias(MemoryLocation(MMOa->getValue(), Overlapa, MMOa->getAAInfo()),
MemoryLocation(MMOb->getValue(), Overlapb, MMOb->getAAInfo()));
return (AAResult != AliasResult::NoAlias);
}
/// Gather register def/uses from MI.
/// This treats possible (predicated) defs
/// as actually happening ones (conservatively).
static inline void parseOperands(MachineInstr *MI,
SmallVector<unsigned, 4> &Defs,
SmallVector<unsigned, 8> &Uses) {
Defs.clear();
Uses.clear();
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i);
if (MO.isReg()) {
unsigned Reg = MO.getReg();
if (!Reg)
continue;
assert(Register::isPhysicalRegister(Reg));
if (MO.isUse())
Uses.push_back(MO.getReg());
if (MO.isDef())
Defs.push_back(MO.getReg());
} else if (MO.isRegMask()) {
for (unsigned R = 1, NR = Hexagon::NUM_TARGET_REGS; R != NR; ++R)
if (MO.clobbersPhysReg(R))
Defs.push_back(R);
}
}
}
void HexagonGlobalSchedulerImpl::MIUseDefSet(MachineInstr *MI,
std::vector<unsigned> &Defs,
std::vector<unsigned> &Uses) {
Defs.clear();
Uses.clear();
assert(!MI->isBundle() && "Cannot parse regs of a bundle.");
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i);
if (MO.isReg()) {
unsigned Reg = MO.getReg();
if (!Reg)
continue;
assert(Register::isPhysicalRegister(Reg));
std::vector<unsigned> &Refs = MO.isUse() ? Uses : Defs;
for (MCRegAliasIterator AI(MO.getReg(), QRI, true); AI.isValid(); ++AI)
Refs.push_back(*AI);
} else if (MO.isRegMask()) {
for (unsigned R = 1, NR = Hexagon::NUM_TARGET_REGS; R != NR; ++R)
if (MO.clobbersPhysReg(R))
Defs.push_back(R);
}
}
}
/// Some apparent dependencies are not actually restricting us since there
/// is a delay between assignment and actual usage, like in case of a call.
/// There could be more cases here, but this one seems the most obvious.
static bool isDelayedUseException(MachineInstr *MIa, MachineInstr *MIb) {
if (MIa->isCall() && !MIb->isCall())
return true;
if (!MIa->isCall() && MIb->isCall())
return true;
return false;
}
/// This is a check for resources availability and dependency
/// for an MI being tried for an existing bundle.
/// This is needed because we can:
/// - save time by filtering out trivial cases
/// - we want to reuse infrastructure that does not really knows
/// how to deal with parallel semantics of a bundle that already
/// exists. For instance, the following case:
/// SI %R6<def> = L2_ploadrif_io %P0<kill>, %R7, 4;
/// SJ %R6<def> = A2_tfr %R0;
/// will be happily allowed by isLegalToPacketizeTogether since in serial
/// semantics it never happens, and even if it does, it is legal. Not so
/// for when we __speculatively__ trying and MI for a bundle.
///
/// Note: This is not equivalent to MIsAreDependent().
/// MIsAreDependent only understands serial semantics.
/// These are OK to packetize together:
/// %R0<def> = L2_loadri_io %R18, 76; mem:LD4[%sunkaddr226](tbaa=!"int")
/// %R2<def> = ASL %R0<kill>, 3; flags: Inside bundle
///
bool HexagonGlobalSchedulerImpl::canAddMIToThisPacket(
MachineInstr *MI,
SmallVector<MachineInstr *, HEXAGON_PACKET_SIZE> &Bundle) {
if (!MI)
return false;
LLVM_DEBUG(dbgs() << "\n\t[canAddMIToThisPacket]: "; MI->dump());
// Const extenders need custom resource checking...
// Should be OK if we can update the check everywhere.
if ((QII->isConstExtended(*MI) || QII->isExtended(*MI) ||
isJumpOutOfRange(MI)) &&
!tryAllocateResourcesForConstExt(MI, false))
return false;
// Ask DFA if machine resource is available for MI.
if (!ResourceTracker->canReserveResources(*MI) || !shouldAddToPacket(*MI)) {
LLVM_DEBUG(dbgs() << "\tNo DFA resources.\n");
return false;
}
SmallVector<unsigned, 4> BundleDefs;
SmallVector<unsigned, 8> BundleUses;
SmallVector<unsigned, 4> Defs;
SmallVector<unsigned, 8> Uses;
MachineInstr *FirstCompound = NULL, *SecondCompound = NULL;
MachineInstr *FirstDuplex = NULL, *SecondDuplex = NULL;
parseOperands(MI, Defs, Uses);
for (SmallVector<MachineInstr *, HEXAGON_PACKET_SIZE>::iterator
BI = Bundle.begin(),
BE = Bundle.end();
BI != BE; ++BI) {
BundleDefs.clear();
BundleUses.clear();
parseOperands(*BI, BundleDefs, BundleUses);
MachineInstr *Inst1 = *BI;
MachineInstr *Inst2 = MI;
if (Inst1->getParent() && OneFloatPerPacket && QII->isFloat(*Inst1) &&
QII->isFloat(*Inst2))
return false;
if (Inst1->getParent() && OneComplexPerPacket && QII->isComplex(*Inst1) &&
QII->isComplex(*Inst2))
return false;
if (PreventCompoundSeparation)
if (QII->getCompoundCandidateGroup(**BI)) {
if (!FirstCompound)
FirstCompound = *BI;
else {
SecondCompound = *BI;
if (isCompoundPair(FirstCompound, SecondCompound)) {
if (MI->mayLoad() || MI->mayStore()) {
LLVM_DEBUG(dbgs() << "\tPrevent compound destruction.\n");
return false;
}
}
}
}
if (PreventDuplexSeparation)
if (QII->getDuplexCandidateGroup(**BI)) {
if (!FirstDuplex)
FirstDuplex = *BI;
else {
SecondDuplex = *BI;
if (QII->isDuplexPair(*FirstDuplex, *SecondDuplex)) {
if (MI->mayLoad() || MI->mayStore()) {
LLVM_DEBUG(dbgs() << "\tPrevent duplex destruction.\n");
return false;
}
}
}
}
for (unsigned i = 0; i < Defs.size(); i++) {
// Check for multiple definitions in the same packet.
for (unsigned j = 0; j < BundleDefs.size(); j++)
// Multiple defs in the same packet.
// Calls are OK here.
// Also if we have multiple defs of PC, this simply means we are
// dealing with dual jumps.
if (AliasingRegs(Defs[i], BundleDefs[j]) &&
!isDelayedUseException(MI, *BI) &&
!(IsDualJumpFirstCandidate(*BI) && IsDualJumpSecondCandidate(MI))) {
LLVM_DEBUG(dbgs() << "\tMultiple defs.\n\t"; MI->dump();
dbgs() << "\t"; (*BI)->dump());
return false;
}
// See if we are creating a swap case as we go, and disallow
// it for now.
// Also, this is not OK:
// if (!p0) r7 = r5
// if (!p0) r5 = #0
// But this is fine:
// if (!p0) r7 = r5
// if (p0) r5 = #0
// Aslo - this is not a swap, but an opportunity to newify:
// %P1<def> = C2_cmpeqi %R0, 0; flags:
// %R0<def> = L2_ploadrif_io %P1<kill>, %R29, 8;
// TODO: Handle this.
for (unsigned j = 0; j < BundleUses.size(); j++)
if (AliasingRegs(Defs[i], BundleUses[j])) {
for (unsigned k = 0; k < BundleDefs.size(); k++)
for (unsigned l = 0; l < Uses.size(); l++) {
if (AliasingRegs(BundleDefs[k], Uses[l]) &&
!isDelayedUseException(MI, *BI)) {
LLVM_DEBUG(dbgs() << "\tSwap detected:\n\t"; MI->dump();
dbgs() << "\t"; (*BI)->dump());
return false;
}
}
}
}
for (unsigned i = 0; i < Uses.size(); i++) {
// Check for true data dependency.
for (unsigned j = 0; j < BundleDefs.size(); j++)
if (AliasingRegs(Uses[i], BundleDefs[j]) &&
!isDelayedUseException(MI, *BI)) {
LLVM_DEBUG(dbgs() << "\tImmediate Use detected on reg("
<< printReg(Uses[i], QRI) << ")\n\t";
MI->dump(); dbgs() << "\t"; (*BI)->dump());
// TODO: This could be an opportunity for newifying:
// %P0<def> = C2_cmpeqi %R26, 0
// %R26<def> = A2_tfr %R0<kill>
// if (CanPromoteToDotNew(MI, Uses[i]))
// LLVM_DEBUG(dbgs() << "\tCan promoto to .new form.\n");
// else
return false;
}
}
// For calls we also check callee save regs.
if ((*BI)->isCall()) {
for (const uint16_t *I = QRI->getCalleeSavedRegs(&MF); *I; ++I) {
for (unsigned i = 0; i < Defs.size(); i++) {
if (AliasingRegs(Defs[i], *I)) {
LLVM_DEBUG(dbgs() << "\tAlias with call.\n");
return false;
}
}
}
}
// If this is return, we are probably speculating (otherwise
// we could not pull in there) and will not win from pulling
// into this location anyhow.
// Example: a side exit.
// if (!p0) dealloc_return
// TODO: Can check that we do not overwrite return value
// and proceed.
if ((*BI)->isBarrier()) {
LLVM_DEBUG(dbgs() << "\tBarrier interference.\n");
return false;
}
// \ref-manual (7.3.4) A loop setup packet in loopN or spNloop0 cannot
// contain a speculative indirect jump,
// a new-value compare jump or a dealloc_return.
// Speculative indirect jumps (predicate + .new + indirect):
// if ([!]Ps.new) jumpr:t Rs
// if ([!]Ps.new) jumpr:nt Rs
// @note: We don't want to pull across a call to be on the safe side.
if (QII->isLoopN(*MI) &&
((QII->isPredicated(**BI) && QII->isPredicatedNew(**BI) &&
QII->isJumpR(**BI)) ||
QII->isNewValueJump(**BI) || QII->isDeallocRet(**BI) ||
(*BI)->isCall())) {
LLVM_DEBUG(dbgs() << "\tLoopN pull interference.\n");
return false;
}
// The opposite is also true.
if (QII->isLoopN(**BI) &&
((QII->isPredicated(*MI) && QII->isPredicatedNew(*MI) &&
QII->isJumpR(*MI)) ||
QII->isNewValueJump(*MI) || QII->isDeallocRet(*MI) || MI->isCall())) {
LLVM_DEBUG(dbgs() << "\tResident LoopN.\n");
return false;
}
// @todo \ref-manual 7.6.1
// Presence of NVJ adds more restrictions.
if (QII->isNewValueJump(**BI) &&
(MI->mayStore() || MI->getOpcode() == Hexagon::S2_allocframe ||
MI->isCall())) {
LLVM_DEBUG(dbgs() << "\tNew val Jump.\n");
return false;
}
// For memory operations, check aliasing.
// First, be conservative on these objects. Might be overly constraining,
// so recheck.
if (isGlobalMemoryObject(*BI) || isGlobalMemoryObject(MI))
// Currently it catches things like this:
// S2_storerinew_io %R29, 32, %R16
// S2_storeri_io %R29, 68, %R0
// which we can reason about.
// TODO: revisit.
return false;
// If packet has a new-value store, MI can't be a store instruction.
if (QII->isNewValueStore(**BI) && MI->mayStore()) {
LLVM_DEBUG(dbgs() << "\tNew Value Store to store.\n");
return false;
}
if ((QII->isMemOp(**BI) && MI->mayStore()) ||
(QII->isMemOp(*MI) && (*BI)->mayStore())) {
LLVM_DEBUG(
dbgs() << "\tSlot 0 not available for store because of memop.\n");
return false;
}
// If any of these is true, check aliasing.
if ((MI->mayLoad() && (*BI)->mayStore()) ||
(MI->mayStore() && (*BI)->mayLoad()) ||
(MI->mayStore() && (*BI)->mayStore())) {
if (MIsNeedChainEdge(AA, TII, MI, *BI)) {
LLVM_DEBUG(dbgs() << "\tAliasing detected:\n\t"; MI->dump();
dbgs() << "\t"; (*BI)->dump());
return false;
}
}
// Do not move an instruction to this packet if this packet
// already contains a speculated instruction.
std::map<MachineInstr *, MachineBasicBlock *>::iterator MIMoved;
MIMoved = SpeculatedIns.find(*BI);
if ((MIMoved != SpeculatedIns.end()) &&
(MIMoved->second != (*BI)->getParent())) {
LLVM_DEBUG(
dbgs() << "This packet already contains a speculated instruction";
(*BI)->dump(););
return false;
}
}
// Do not pull-up vector instructions because these instructions have
// multi-cycle latencies, and the pull-up pass doesn't correctly account
// for instructions that stall for more than one cycle.
if (QII->isHVXVec(*MI))
return false;
return true;
}
/// Test is true if the two MIs cannot be safely reordered.
bool HexagonGlobalSchedulerImpl::ReorderDependencyTest(MachineInstr *MIa,
MachineInstr *MIb) {
SmallVector<unsigned, 4> DefsA;
SmallVector<unsigned, 4> DefsB;
SmallVector<unsigned, 8> UsesA;
SmallVector<unsigned, 8> UsesB;
parseOperands(MIa, DefsA, UsesA);
parseOperands(MIb, DefsB, UsesB);
for (SmallVector<unsigned, 4>::iterator IDA = DefsA.begin(),
IDAE = DefsA.end();
IDA != IDAE; ++IDA) {
for (SmallVector<unsigned, 8>::iterator IUB = UsesB.begin(),
IUBE = UsesB.end();
IUB != IUBE; ++IUB)
// True data dependency.
if (AliasingRegs(*IDA, *IUB))
return true;
for (SmallVector<unsigned, 4>::iterator IDB = DefsB.begin(),
IDBE = DefsB.end();
IDB != IDBE; ++IDB)
// Output dependency.
if (AliasingRegs(*IDA, *IDB))
return true;
}
for (SmallVector<unsigned, 4>::iterator IDB = DefsB.begin(),
IDBE = DefsB.end();
IDB != IDBE; ++IDB) {
for (SmallVector<unsigned, 8>::iterator IUA = UsesA.begin(),
IUAE = UsesA.end();
IUA != IUAE; ++IUA)
// True data dependency.
if (AliasingRegs(*IDB, *IUA))
return true;
}
// Do not reorder two calls...
if (MIa->isCall() && MIb->isCall())
return true;
// For calls we also check callee save regs.
if (MIa->isCall())
for (const uint16_t *I = QRI->getCalleeSavedRegs(&MF); *I; ++I) {
for (unsigned i = 0; i < DefsB.size(); i++) {
if (AliasingRegs(DefsB[i], *I))
return true;
}
}
if (MIb->isCall())
for (const uint16_t *I = QRI->getCalleeSavedRegs(&MF); *I; ++I) {
for (unsigned i = 0; i < DefsA.size(); i++) {
if (AliasingRegs(DefsA[i], *I))
return true;
}
}
// For memory operations, check aliasing.
// First, be conservative on these objects.
// Might be overly constraining, so recheck.
if ((isGlobalMemoryObject(MIa)) || (isGlobalMemoryObject(MIb)))
return true;
// If any of these is true, check aliasing.
if (((MIa->mayLoad() && MIb->mayStore()) ||
(MIa->mayStore() && MIb->mayLoad()) ||
(MIa->mayStore() && MIb->mayStore())) &&
MIsNeedChainEdge(AA, TII, MIa, MIb))
return true;
return false;
}
/// Serial semantics.
bool HexagonGlobalSchedulerImpl::MIsAreDependent(MachineInstr *MIa,
MachineInstr *MIb) {
if (MIa == MIb)
return false;
if (ReorderDependencyTest(MIa, MIb)) {
LLVM_DEBUG(dbgs() << "\t\t[MIsAreDependent]:\n\t\t"; MIa->dump();
dbgs() << "\t\t"; MIb->dump());
return true;
}
return false;
}
/// Serial semantics.
bool HexagonGlobalSchedulerImpl::MIsHaveTrueDependency(MachineInstr *MIa,
MachineInstr *MIb) {
if (MIa == MIb)
return false;
SmallVector<unsigned, 4> DefsA;
SmallVector<unsigned, 4> DefsB;
SmallVector<unsigned, 8> UsesA;
SmallVector<unsigned, 8> UsesB;
parseOperands(MIa, DefsA, UsesA);
parseOperands(MIb, DefsB, UsesB);
for (SmallVector<unsigned, 4>::iterator IDA = DefsA.begin(),
IDAE = DefsA.end();
IDA != IDAE; ++IDA) {
for (SmallVector<unsigned, 8>::iterator IUB = UsesB.begin(),
IUBE = UsesB.end();
IUB != IUBE; ++IUB)
// True data dependency.
if (AliasingRegs(*IDA, *IUB))
return true;
}
return false;
}
/// Sequential semantics. Can these two MIs be reordered?
/// Moving MIa from "behind" to "in front" of MIb.
bool HexagonGlobalSchedulerImpl::canReorderMIs(MachineInstr *MIa,
MachineInstr *MIb) {
if (!MIa || !MIb)
return false;
// Within bundle semantics are parallel.
if (MIa->isBundle()) {
MachineBasicBlock::instr_iterator MII = MIa->getIterator();
MachineBasicBlock::instr_iterator MIIE = MIa->getParent()->instr_end();
for (++MII; MII != MIIE && MII->isInsideBundle(); ++MII) {
if (MII->isDebugInstr())
continue;
if (MIsAreDependent(&*MII, MIb))
return false;
}
return true;
}
return !MIsAreDependent(MIa, MIb);
}
static inline bool MIMustNotBePulledUp(MachineInstr *MI) {
if (MI->isInlineAsm() || MI->isEHLabel() || IsSchedBarrier(MI))
return true;
return false;
}
static inline bool MIShouldNotBePulledUp(MachineInstr *MI) {
if (MI->isBranch() || MI->isReturn() || MI->isCall() || MI->isBarrier() ||
MI->isTerminator() || MIMustNotBePulledUp(MI))
return true;
return false;
}
// Only approve dual jump candidate:
// It is a branch, and we move it to last packet of the target location.
bool HexagonGlobalSchedulerImpl::MIisDualJumpCandidate(
MachineInstr *MI, MachineBasicBlock::iterator &WorkPoint) {
if (!PerformDualJumps || !IsDualJumpSecondCandidate(MI) ||
MIMustNotBePulledUp(MI) || ignoreInstruction(MI))
return false;
MachineBasicBlock *FromThisBB = MI->getParent();
MachineBasicBlock *ToThisBB = WorkPoint->getParent();
LLVM_DEBUG(dbgs() << "\t\t[MIisDualJumpCandidate] To BB("
<< ToThisBB->getNumber() << ") From BB("
<< FromThisBB->getNumber() << ")\n");
// If the question is about the same BB, we do not want to get
// dual jump involved - it is a different case.
if (FromThisBB == ToThisBB)
return false;
// Dual jump could only be done on neigboring BBs.
// The FromThisBB must only have one predecessor - the basic
// block we are trying to merge.
if ((*(FromThisBB->pred_begin()) != ToThisBB) ||
(std::next(FromThisBB->pred_begin()) != FromThisBB->pred_end()))
return false;
// If this block is a target of an indirect branch, it should
// also not be included.
if (FromThisBB->isEHPad() || FromThisBB->hasAddressTaken())
return false;
// Now we must preserve original fall through paths. In fact we
// might be dealing with 3way branching.
MachineBasicBlock *ToTBB = NULL, *ToFBB = NULL;
if (ToThisBB->succ_size() == 2) {
// Check the branch from target block.
// If we have two successors, we must understand the branch.
SmallVector<MachineOperand, 4> ToCond;
if (!QII->analyzeBranch(*ToThisBB, ToTBB, ToFBB, ToCond, false)) {
// Have the branch. Check the topology.
LLVM_DEBUG(dbgs() << "\t\tToThisBB has two successors: TBB("
<< ToTBB->getNumber() << ") and FBB(";
if (ToFBB) dbgs() << ToFBB->getNumber() << ").\n";
else dbgs() << "None"
<< ").\n";);
if (ToTBB == FromThisBB) {
// If the from BB is not the fall through, we can only handle case
// when second branch is unconditional jump.
return false;
} else if (ToFBB == FromThisBB || !ToFBB) {
// If the fall through path of ToBB is our FromBB, we have more freedom
// of operation.
LLVM_DEBUG(dbgs() << "\t\tFall through jump target.\n");
}
} else {
LLVM_DEBUG(dbgs() << "\t\tUnable to analyze first branch.\n");
return false;
}
} else if (ToThisBB->succ_size() == 1) {
ToFBB = *ToThisBB->succ_begin();
assert(ToFBB == FromThisBB && "Bad CFG layout");
} else
return false;
// First unbundled control flow instruction in the BB.
if (!MI->isBundled() && MI == &*FromThisBB->getFirstNonDebugInstr())
return IsDualJumpFirstCandidate(WorkPoint);
return false;
}
// Check whether moving MI to MJ's packet would cause a stall from a previous
// packet.
bool HexagonGlobalSchedulerImpl::canCauseStall(MachineInstr *MI,
MachineInstr *MJ) {
SmallVector<unsigned, 4> DefsMJI;
SmallVector<unsigned, 8> UsesMJI;
SmallVector<unsigned, 4> DefsMI;
SmallVector<unsigned, 8> UsesMI;
parseOperands(MI, DefsMI, UsesMI);
for (auto Use : UsesMI) {
int UseIdx = MI->findRegisterUseOperandIdx(Use, /*TRI=*/nullptr);
if (UseIdx == -1)
continue;
bool ShouldBreak = false;
int BundleCount = 0;
for (MachineBasicBlock::instr_iterator
Begin = MJ->getParent()->instr_begin(),
MJI = MJ->getIterator();
MJI != Begin; --MJI) {
if (MJI->isBundle()) {
++BundleCount;
continue;
}
parseOperands(&*MJI, DefsMJI, UsesMJI);
for (auto Def : DefsMJI) {
if (Def == Use || AliasingRegs(Def, Use)) {
int DefIdx = MJI->findRegisterDefOperandIdx(Def, /*TRI=*/nullptr);
if (DefIdx >= 0) {
int Latency =
TSchedModel.computeOperandLatency(&*MJI, DefIdx, MI, UseIdx);
if (Latency > BundleCount)
// There will be a stall if MI is moved to MJ's packet.
return true;
// We found the def for the use and it does not cause a stall.
// Continue checking the next use for a potential stall.
ShouldBreak = true;
break;
}
}
}
if (ShouldBreak)
break;
if (!MJI->isBundled() && !MJI->isDebugInstr())
++BundleCount;
}
}
return false;
}
/// Analyze this instruction. If this is an unbundled instruction, see
/// if it in theory could be packetized.
/// If it is already part of a packet, see if it has internal
/// dependencies to this packet.
bool HexagonGlobalSchedulerImpl::canThisMIBeMoved(
MachineInstr *MI, MachineBasicBlock::iterator &WorkPoint,
bool &MovingDependentOp, int &Cost) {
if (!MI)
return false;
// By default, it is a normal move.
MovingDependentOp = false;
Cost = 0;
// If MI is a 'formed' compound not potential compound, bail out.
if (QII->isCompoundBranchInstr(*MI))
return false;
// See if we can potentially break potential compound candidates,
// and do not do it.
if (PreventCompoundSeparation && MI->isBundled()) {
enum HexagonII::CompoundGroup MICG = QII->getCompoundCandidateGroup(*MI);
if (MICG != HexagonII::HCG_None) {
// Check internal dependencies in the bundle.
// First, find the bundle header.
MachineBasicBlock::instr_iterator MII = MI->getIterator();
for (--MII; MII->isBundled(); --MII)
if (MII->isBundle())
break;
MachineBasicBlock::instr_iterator BBEnd = MI->getParent()->instr_end();
for (++MII; MII != BBEnd && MII->isInsideBundle() && !MII->isBundle();
++MII) {
if (&(*MII) == MI)
continue;
if (isCompoundPair(&*MII, MI)) {
LLVM_DEBUG(dbgs() << "\tPrevent Compound separation.\n");
return false;
}
}
}
}
// Same thing for duplex candidates.
if (PreventDuplexSeparation && MI->isBundled()) {
if (QII->getDuplexCandidateGroup(*MI) != HexagonII::HSIG_None) {
// Check internal dependencies in the bundle.
// First, find the bundle header.
MachineBasicBlock::instr_iterator MII = MI->getIterator();
for (--MII; MII->isBundled(); --MII)
if (MII->isBundle())
break;
MachineBasicBlock::instr_iterator BBEnd = MI->getParent()->instr_end();
for (++MII; MII != BBEnd && MII->isInsideBundle() && !MII->isBundle();
++MII) {
if ((&(*MII) != MI) && QII->isDuplexPair(*MII, *MI)) {
LLVM_DEBUG(dbgs() << "\tPrevent Duplex separation.\n");
return false;
}
}
}
}
// If we perform dual jump formation during the pull-up,
// then we want to consider several additional situations.
// a) Allow moving of dependent instruction from a packet
// b) Allow moving some control flow instructions if they meet
// dual jump criteria.
if (MIisDualJumpCandidate(MI, WorkPoint)) {
LLVM_DEBUG(dbgs() << "\t\tDual jump candidate:\t"; MI->dump());
// Here we are breaking our general assumption about not moving dependent
// instructions. To save us two more expensive checks down the line,
// propagate the information directly.
MovingDependentOp = true;
return true;
}
// Any of these should not even be tried.
if (MIShouldNotBePulledUp(MI) || ignoreInstruction(MI))
return false;
// Pulling up these instructions could put them
// out of jump range/offset size.
if (QII->isLoopN(*MI)) {
unsigned dist_looplabel =
BlockToInstOffset.find(MI->getOperand(0).getMBB())->second;
unsigned dist_newloop0 =
BlockToInstOffset.find(WorkPoint->getParent())->second;
// Check if the jump in the last instruction is within range.
unsigned Distance =
(unsigned)std::abs((long long)dist_looplabel - dist_newloop0) +
QII->nonDbgBBSize(WorkPoint->getParent()) * 4 + SafetyBuffer;
const HexagonInstrInfo *HII = (const HexagonInstrInfo *)TII;
if (!HII->isJumpWithinBranchRange(*MI, Distance)) {
LLVM_DEBUG(dbgs() << "\nloopN cannot be moved since Distance: "
<< Distance << " outside branch range.";);
return false;
}
LLVM_DEBUG(dbgs() << "\nloopN can be moved since Distance: " << Distance
<< " within branch range.";);
}
// If the def-set of an MI is one of the live-ins then MI should
// kill that reg and no instruction before MI should use it.
// For simplicity, allow only if MI is the first instruction in the MBB.
std::map<MachineInstr *, std::vector<unsigned>>::const_iterator DefIter =
MIDefSet.find(MI);
MachineBasicBlock *MBB = MI->getParent();
for (unsigned i = 0; DefIter != MIDefSet.end() && i < DefIter->second.size();
++i) {
if (MBB->isLiveIn(DefIter->second[i]) &&
&*MBB->getFirstNonDebugInstr() != MI)
return false;
}
// If it is part of a bundle, analyze it.
if (MI->isBundled()) {
// Cannot move bundle header itself. This function is about
// individual MI move.
if (MI->isBundle())
return false;
// Check internal dependencies in the bundle.
// First, find the bundle header.
MachineBasicBlock::instr_iterator MII = MI->getIterator();
for (--MII; MII->isBundled(); --MII)
if (MII->isBundle())
break;
MachineBasicBlock::instr_iterator BBEnd = MI->getParent()->instr_end();
for (++MII; MII != BBEnd && MII->isInsideBundle() && !MII->isBundle();
++MII) {
if (MII->isDebugInstr())
continue;
if (MIsAreDependent(&*MII, MI)) {
if (!AllowDependentPullUp) {
LLVM_DEBUG(dbgs() << "\t\tDependent.\n");
return false;
} else {
// There are a few cases that we can safely move a dependent
// instruction away from this packet.
// One example is an instruction setting a call operands.
if ((MII->isCall() && !IsIndirectCall(&*MII)) ||
IsDualJumpSecondCandidate(&*MII) || MI->isBranch()) {
LLVM_DEBUG(dbgs() << "\t\tDependent, but allow to move.\n");
MovingDependentOp = true;
Cost -= 10;
continue;
} else {
LLVM_DEBUG(dbgs() << "\t\tDependent, and do not allow for now.\n");
return false;
}
}
}
}
}
return true;
}
/// Return true if MI defines a predicate and parse all defs.
bool HexagonGlobalSchedulerImpl::doesMIDefinesPredicate(
MachineInstr *MI, SmallVector<unsigned, 4> &Defs) {
bool defsPredicate = false;
Defs.clear();
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i);
// Regmasks are considered "implicit".
if (!MO.isReg())
continue;
unsigned Reg = MO.getReg();
if (!Reg || QRI->isFakeReg(Reg))
continue;
assert(Register::isPhysicalRegister(Reg));
if (MO.isDef() && !MO.isImplicit()) {
const TargetRegisterClass *RC = QRI->getMinimalPhysRegClass(Reg);
if (RC == &Hexagon::PredRegsRegClass) {
defsPredicate = true;
Defs.push_back(MO.getReg());
}
}
}
return defsPredicate;
}
/// We have just tentatively added a predicated MI to an existing packet.
/// Now we need to determine if it needs to be changed to .new form.
/// It only handles compare/predicate right now.
/// TODO - clean this logic up.
/// TODO - generalize to handle any .new
bool HexagonGlobalSchedulerImpl::NeedToNewify(
MachineBasicBlock::instr_iterator NewMI, unsigned *DepReg,
MachineInstr *TargetPacket = NULL) {
MachineBasicBlock::instr_iterator MII = NewMI;
SmallVector<unsigned, 4> DefsA;
SmallVector<unsigned, 4> DefsB;
SmallVector<unsigned, 8> UsesB;
// If this is not a normal bundle, we are probably
// trying to size two lonesome instructions together,
// and trying to say if one of them will need to be
// newified. In this is the case we have something like this:
// BB#5:
// %P0<def> = CMPGEri %R4, 2
// S2_pstorerif_io %P0<kill>, %R29, 16, %R21<kill>
// BUNDLE %R7<imp-def>, %R4<imp-def>, %R7<imp-use>
parseOperands(&*NewMI, DefsB, UsesB);
if (TargetPacket && !TargetPacket->isBundled()) {
if (doesMIDefinesPredicate(TargetPacket, DefsA)) {
for (SmallVector<unsigned, 4>::iterator IA = DefsA.begin(),
IAE = DefsA.end();
IA != IAE; ++IA)
for (SmallVector<unsigned, 8>::iterator IB = UsesB.begin(),
IBE = UsesB.end();
IB != IBE; ++IB)
if (*IA == *IB) {
*DepReg = *IA;
return true;
}
}
return false;
}
// Find bundle header.
for (--MII; MII->isBundled(); --MII)
if (MII->isBundle())
break;
// Iterate down, if there is data dependent cmp found, need to .newify.
// Also, we can have the following:
// {
// p0 = r7
// if (!p0.new) jump:t .LBB4_18
// if (p0.new) r8 = zxth(r12)
// }
MachineBasicBlock::instr_iterator BBEnd = MII->getParent()->instr_end();
for (++MII; MII != BBEnd && MII->isBundled() && !MII->isBundle(); ++MII) {
if (MII == NewMI)
continue;
if (doesMIDefinesPredicate(&*MII, DefsA)) {
for (SmallVector<unsigned, 4>::iterator IA = DefsA.begin(),
IAE = DefsA.end();
IA != IAE; ++IA)
for (SmallVector<unsigned, 8>::iterator IB = UsesB.begin(),
IBE = UsesB.end();
IB != IBE; ++IB)
// We do not have multiple predicate regs defined in any instruction,
// if we ever will, this needs to be generalized.
if (*IA == *IB) {
*DepReg = *IA;
return true;
}
DefsA.clear();
}
}
LLVM_DEBUG(dbgs() << "\nNo need to newify:"; NewMI->dump());
return false;
}
/// We know this instruction needs to be newified to be added to the packet,
/// but not all combinations are legal.
/// It is a complimentary check to NeedToNewify().
/// The packet actually contains the new instruction during the check.
bool HexagonGlobalSchedulerImpl::CanNewifiedBeUsedInBundle(
MachineBasicBlock::instr_iterator NewMI, unsigned DepReg,
MachineInstr *TargetPacket) {
MachineBasicBlock::instr_iterator MII = NewMI;
if (!TargetPacket || !TargetPacket->isBundled())
return true;
// Find the bundle header.
for (--MII; MII->isBundled(); --MII)
if (MII->isBundle())
break;
MachineBasicBlock::instr_iterator BBEnd = MII->getParent()->instr_end();
for (++MII; MII != BBEnd && MII->isBundled() && !MII->isBundle(); ++MII) {
// Effectively we look for the case of late predicates.
// No additional checks at the time.
if (MII == NewMI || !QII->isPredicateLate(MII->getOpcode()))
continue;
SmallVector<unsigned, 4> DefsA;
if (!doesMIDefinesPredicate(&*MII, DefsA))
continue;
for (auto &IA : DefsA)
if (IA == DepReg)
return false;
}
return true;
}
/// setUsed - Set the register and its sub-registers as being used.
/// Similar to RegScavenger::setUsed().
void HexagonGlobalSchedulerImpl::setUsedRegs(BitVector &Set, unsigned Reg) {
Set.reset(Reg);
for (MCSubRegIterator SubRegs(Reg, QRI); SubRegs.isValid(); ++SubRegs)
Set.reset(*SubRegs);
}
/// Are these two registers overlaping?
bool HexagonGlobalSchedulerImpl::AliasingRegs(unsigned RegA, unsigned RegB) {
if (RegA == RegB)
return true;
for (MCSubRegIterator SubRegs(RegA, QRI); SubRegs.isValid(); ++SubRegs)
if (RegB == *SubRegs)
return true;
for (MCSubRegIterator SubRegs(RegB, QRI); SubRegs.isValid(); ++SubRegs)
if (RegA == *SubRegs)
return true;
return false;
}
/// Find use with this reg, and unmark the kill flag.
static inline void unmarkKillReg(MachineInstr *MI, unsigned Reg) {
if (MI->isDebugInstr())
return;
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
MachineOperand &MO = MI->getOperand(i);
if (!MO.isReg())
continue;
if (MO.isKill() && (MO.getReg() == Reg))
MO.setIsKill(false);
}
}
/// Find use with this reg, and unmark the kill flag.
static inline void markKillReg(MachineInstr *MI, unsigned Reg) {
if (MI->isDebugInstr())
return;
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
MachineOperand &MO = MI->getOperand(i);
if (!MO.isReg())
continue;
if (MO.isUse() && (MO.getReg() == Reg))
MO.setIsKill(true);
}
}
/// We have just moved an instruction that could have changed kill patterns
/// along the path it was moved. We need to update it.
void HexagonGlobalSchedulerImpl::updateKillAlongThePath(
MachineBasicBlock *HomeBB, MachineBasicBlock *OriginBB,
MachineBasicBlock::instr_iterator &Head,
MachineBasicBlock::instr_iterator &Tail,
MachineBasicBlock::iterator &SourcePacket,
MachineBasicBlock::iterator &TargetPacket,
std::vector<MachineInstr *> &backtrack) {
// This is the instruction being moved.
MachineInstr *MI = &*Head;
MachineBasicBlock *CurrentBB = OriginBB;
SmallSet<unsigned, 8> KilledUseSet;
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i);
if (!MO.isReg())
continue;
unsigned Reg = MO.getReg();
if (!Reg)
continue;
if (MO.isKill())
KilledUseSet.insert(Reg);
}
// If there are no kills here, we are done.
if (KilledUseSet.empty())
return;
LLVM_DEBUG(dbgs() << "\n[updateKillAlongThePath]\n");
LLVM_DEBUG(dbgs() << "\t\tInstrToMove :\t"; MI->dump());
LLVM_DEBUG(dbgs() << "\t\tSourceLocation:\n";
DumpPacket(SourcePacket.getInstrIterator()));
LLVM_DEBUG(dbgs() << "\t\tTargetPacket :\n";
DumpPacket(TargetPacket.getInstrIterator()));
LLVM_DEBUG(dbgs() << "\tUpdate Kills. Need to update (" << KilledUseSet.size()
<< ")kills. From BB (" << OriginBB->getNumber() << ")\n");
LLVM_DEBUG(dbgs() << "\tMove path:\n");
assert(!backtrack.empty() && "Empty back track");
// We have pulled up an instruction, with one of its uses marked as kill.
// If there is any other use of the same register along the move path,
// and there are no side exits with killed register live-in along them,
// we need to mark last use of that reg as kill.
for (signed i = backtrack.size() - 1; i >= 0; --i) {
LLVM_DEBUG(dbgs() << "\t\t[" << i << "]BB("
<< backtrack[i]->getParent()->getNumber() << ")\t";
backtrack[i]->dump());
if (CurrentBB != backtrack[i]->getParent()) {
LLVM_DEBUG(dbgs() << "\t\tChange BB from (" << CurrentBB->getNumber()
<< ") to(" << backtrack[i]->getParent()->getNumber()
<< ")\n");
for (MachineBasicBlock::const_succ_iterator
SI = backtrack[i]->getParent()->succ_begin(),
SE = backtrack[i]->getParent()->succ_end();
SI != SE; ++SI) {
if (*SI == CurrentBB)
continue;
LLVM_DEBUG(dbgs() << "\t\tSide Exit:\n\t"; (*SI)->dump());
// If any reg kill is live along this side exit, it is not
// a kill any more.
for (MachineBasicBlock::livein_iterator I = (*SI)->livein_begin(),
E = (*SI)->livein_end();
I != E; ++I) {
if (KilledUseSet.count((*I).PhysReg)) {
LLVM_DEBUG(dbgs() << "\t\tReg (" << printReg((*I).PhysReg, QRI)
<< ") is LiveIn along side exit.\n");
KilledUseSet.erase((*I).PhysReg);
unmarkKillReg(MI, (*I).PhysReg);
}
if (KilledUseSet.empty())
return;
}
}
CurrentBB = backtrack[i]->getParent();
}
// Done with the whole path.
if (backtrack[i] == &*TargetPacket)
return;
// Starting the tracking. Do not update source bundle.
// If TargetPacket == SourcePacket we have returned
// in the previous check.
if (backtrack[i] == &*SourcePacket)
continue;
// Ignore DBG_VALUE.
if (backtrack[i]->isDebugInstr())
continue;
// Encountered an intermediary bundle. Process it.
// Beware, sometimes check for backtrack[i] == TargetPacket
// does not work, so this instruction could be one from the target bundle.
SmallVector<unsigned, 4> Defs;
SmallVector<unsigned, 8> Uses;
MachineInstr *MIU = backtrack[i];
parseOperands(MIU, Defs, Uses);
for (SmallVector<unsigned, 8>::iterator IA = Uses.begin(), IAE = Uses.end();
IA != IAE; ++IA) {
if (KilledUseSet.count(*IA)) {
// Now this is new kill point for this Reg.
// Update the bundle, and any local uses.
markKillReg(MIU, *IA);
// Unmark the current MI.
unmarkKillReg(MI, *IA);
if (MIU->isBundle()) {
// TODO: Can do this cleaner and faster.
MachineBasicBlock::instr_iterator MII = MIU->getIterator();
MachineBasicBlock::instr_iterator End = CurrentBB->instr_end();
for (++MII; MII != End && MII->isInsideBundle(); ++MII)
markKillReg(&*MII, *IA);
}
// We have updated this kill reg, if there are more, keep on going.
KilledUseSet.erase(*IA);
// If the set is exhausted, just leave.
if (KilledUseSet.empty())
return;
}
}
}
}
/// This is houskeeping for bundle with instruction just added to it.
void HexagonGlobalSchedulerImpl::addInstructionToExistingBundle(
MachineBasicBlock *HomeBB, MachineBasicBlock::instr_iterator &Head,
MachineBasicBlock::instr_iterator &Tail,
MachineBasicBlock::instr_iterator &NewMI,
MachineBasicBlock::iterator &TargetPacket,
MachineBasicBlock::iterator &NextMI,
std::vector<MachineInstr *> &backtrack) {
Tail = getBundleEnd(Head);
LLVM_DEBUG(dbgs() << "\t\t\t[Add] Head home: "; DumpPacket(Head));
// Old header to be deleted shortly.
MachineBasicBlock::instr_iterator Outcast = Head;
// Unbundle old header.
if (Outcast->isBundle() && Outcast->isBundledWithSucc())
Outcast->unbundleFromSucc();
bool memShufDisabled = QII->getBundleNoShuf(*Outcast);
// Create new bundle header and update MI flags.
finalizeBundle(*HomeBB, ++Head, Tail);
MachineBasicBlock::instr_iterator BundleMII = std::prev(Head);
if (memShufDisabled)
QII->setBundleNoShuf(BundleMII);
--Head;
LLVM_DEBUG(dbgs() << "\t\t\t[Add] New Head : "; DumpPacket(Head));
// The old header could be listed in the back tracking,
// so if it is, we need to update it.
for (unsigned i = 0; i < backtrack.size(); ++i)
if (backtrack[i] == &*Outcast)
backtrack[i] = &*Head;
// Same for top MI iterator.
if (NextMI == Outcast)
NextMI = Head;
TargetPacket = Head;
HomeBB->erase(Outcast);
}
/// This handles houskeeping for bundle with instruction just deleted from it.
/// We do not see the original moved instruction in here.
void HexagonGlobalSchedulerImpl::removeInstructionFromExistingBundle(
MachineBasicBlock *HomeBB, MachineBasicBlock::instr_iterator &Head,
MachineBasicBlock::instr_iterator &Tail,
MachineBasicBlock::iterator &SourceLocation,
MachineBasicBlock::iterator &NextMI, bool MovingDependentOp,
std::vector<MachineInstr *> &backtrack) {
// Empty BBs will be deleted shortly.
if (HomeBB->empty()) {
Head = MachineBasicBlock::instr_iterator();
Tail = MachineBasicBlock::instr_iterator();
return;
}
if (!SourceLocation->isBundle()) {
LLVM_DEBUG(dbgs() << "\t\t\tOriginal instruction was not bundled.\n\t\t\t";
SourceLocation->dump());
// If original instruction was not bundled, and we have moved it
// and it is in the back track, we probably want to remove it from there.
LLVM_DEBUG(dbgs() << "\t\t\t[Rem] New head: "; backtrack.back()->dump());
for (unsigned i = 0; i < backtrack.size(); ++i) {
if (backtrack[i] == &*SourceLocation) {
// By definition, this should be the last instruction in the backtrack.
assert((backtrack[i] == backtrack.back()) && "Lost back track");
backtrack.pop_back();
}
// Point the main iterator to the next instruction.
if (NextMI == SourceLocation)
NextMI++;
}
SourceLocation = MachineBasicBlock::iterator();
Head = MachineBasicBlock::instr_iterator();
Tail = MachineBasicBlock::instr_iterator();
return;
}
// The old header, soon to be deleted.
MachineBasicBlock::instr_iterator Outcast = SourceLocation.getInstrIterator();
LLVM_DEBUG(dbgs() << "\t\t\t[Rem] SourceLocation after bundle update: ";
DumpPacket(Outcast));
// If bundle has been already destroyed. BB->splat seems to do it some times
// but not the other.
// We already know that SourceLocation is bundle header.
if (!SourceLocation->isBundledWithSucc()) {
assert(!Head->isBundledWithSucc() && !Head->isBundledWithPred() &&
"Bad bundle");
} else {
Head = SourceLocation.getInstrIterator();
Tail = getBundleEnd(Head);
unsigned Size = 0;
unsigned BBSizeWithDbg = 0;
MachineBasicBlock::const_instr_iterator I(Head);
MachineBasicBlock::const_instr_iterator E = Head->getParent()->instr_end();
for (++I; I != E && I->isBundledWithPred(); ++I) {
++BBSizeWithDbg;
if (!I->isDebugInstr())
++Size;
}
LLVM_DEBUG(dbgs() << "\t\t\t[Rem] Size(" << Size << ") Head orig: ";
DumpPacket(Head));
// The old header, soon to be deleted.
Outcast = Head;
// The old Header is still counted here.
if (Size > 1) {
if (Outcast->isBundle() && Outcast->isBundledWithSucc())
Outcast->unbundleFromSucc();
bool memShufDisabled = QII->getBundleNoShuf(*Outcast);
// The finalizeBundle() assumes that "original" sequence
// it is finalizing is sequentially correct. That basically
// means that swap case might not be handled properly.
// I find insert point for the pull-up instruction myself,
// and I should try to catch that swap case there, and refuse
// to insert if I cannot guarantee correct serial semantics.
// In the future, I need my own incremental "inserToBundle"
// function.
finalizeBundle(*HomeBB, ++Head, Tail);
MachineBasicBlock::instr_iterator BundleMII = std::prev(Head);
if (memShufDisabled)
QII->setBundleNoShuf(BundleMII);
--Head;
} else if (Size == 1) {
// There is only one non-debug instruction in the bundle.
if (BBSizeWithDbg > 1) {
// There are some debug instructions that should be unbundled too.
MachineBasicBlock::instr_iterator I(Head);
MachineBasicBlock::instr_iterator E = Head->getParent()->instr_end();
for (++I; I != E && I->isBundledWithPred(); ++I) {
I->unbundleFromPred();
// Set Head to the non-debug instruction.
if (!I->isDebugInstr())
Head = I;
}
} else {
// This means that only one original instruction is
// left in the bundle. We need to "unbundle" it because the
// rest of API will not like it.
++Head;
if (Head->isBundledWithPred())
Head->unbundleFromPred();
if (Head->isBundledWithSucc())
Head->unbundleFromSucc();
}
} else
llvm_unreachable("Corrupt bundle");
}
LLVM_DEBUG(dbgs() << "\t\t\t[Rem] New Head : "; DumpPacket(Head));
SourceLocation = Head;
// The old header could be listed in the back tracking,
// so if it is, we need to update it.
for (unsigned i = 0; i < backtrack.size(); ++i)
if (backtrack[i] == &*Outcast)
backtrack[i] = &*Head;
// Same for top MI iterator.
if (NextMI == Outcast)
NextMI = Head;
HomeBB->erase(Outcast);
}
#ifndef NDEBUG
static void debugLivenessForBB(const MachineBasicBlock *MBB,
const TargetRegisterInfo *TRI) {
LLVM_DEBUG(dbgs() << "\tLiveness for BB:\n"; MBB->dump());
for (MachineBasicBlock::const_succ_iterator SI = MBB->succ_begin(),
SE = MBB->succ_end();
SI != SE; ++SI) {
LLVM_DEBUG(dbgs() << "\tSuccessor BB (" << (*SI)->getNumber() << "):");
for (MachineBasicBlock::livein_iterator I = (*SI)->livein_begin(),
E = (*SI)->livein_end();
I != E; ++I)
LLVM_DEBUG(dbgs() << "\t" << printReg((*I).PhysReg, TRI));
LLVM_DEBUG(dbgs() << "\n");
}
}
#endif
// Blocks should be considered empty if they contain only debug info;
// else the debug info would affect codegen.
static bool IsEmptyBlock(MachineBasicBlock *MBB) {
if (MBB->empty())
return true;
for (MachineBasicBlock::iterator MBBI = MBB->begin(), MBBE = MBB->end();
MBBI != MBBE; ++MBBI) {
if (!MBBI->isDebugInstr())
return false;
}
return true;
}
/// Treat given instruction as a branch, go through its operands
/// and see if any of them is a BB address. If so, return it.
/// Return NULL otherwise.
static inline MachineBasicBlock *getBranchDestination(MachineInstr *MI) {
if (!MI || !MI->isBranch() || MI->isBundle())
return NULL;
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i);
if (MO.isMBB())
return MO.getMBB();
}
return NULL;
}
/// Similar to HexagonInstrInfo::analyzeBranch but handles
/// serveral more general cases including parsing empty BBs when possible.
bool HexagonGlobalSchedulerImpl::AnalyzeBBBranches(MachineBasicBlock *MBB,
MachineBasicBlock *&TBB,
MachineInstr *&FirstTerm,
MachineBasicBlock *&FBB,
MachineInstr *&SecondTerm) {
// Hexagon allowes up to two jumps in MBB.
FirstTerm = NULL;
SecondTerm = NULL;
LLVM_DEBUG(dbgs() << "\n\t\tAnalyze Branches in BB(" << MBB->getNumber()
<< ")\n");
if (MBB->succ_size() == 0) {
LLVM_DEBUG(dbgs() << "\n\t\tBlock has no successors.\n");
return true;
}
// Find both jumps.
// We largely rely on implied assumption that BB branching always
// looks like this:
// J2_jumpf %P0, <BB#60>, %PC<imp-def>;
// J2_jump <BB#49>
// Branches also could be in different packets.
MachineBasicBlock::instr_iterator MIB = MBB->instr_begin();
MachineBasicBlock::instr_iterator MIE = MBB->instr_end();
MachineBasicBlock::instr_iterator MII = MIB;
if (QII->nonDbgBBSize(MBB) == 1) {
MII = MBB->getFirstNonDebugInstr().getInstrIterator();
if (MII->isBranch())
FirstTerm = &*MII;
} else {
// We have already eliminated the case when MIB == MIE.
while (MII != MIE) {
if (!MII->isBundle() && MII->isBranch()) {
if (!FirstTerm)
FirstTerm = &*MII;
else
SecondTerm = &*MII;
}
++MII;
}
}
if ((FirstTerm && FirstTerm->isIndirectBranch()) ||
(SecondTerm && SecondTerm->isIndirectBranch())) {
LLVM_DEBUG(dbgs() << "\n\t\tCannot analyze BB with indirect branch.");
return true;
}
if ((FirstTerm && FirstTerm->getOpcode() == Hexagon::J2_jump &&
!FirstTerm->getOperand(0).isMBB()) ||
(SecondTerm && SecondTerm->getOpcode() == Hexagon::J2_jump &&
!SecondTerm->getOperand(0).isMBB())) {
LLVM_DEBUG(
dbgs() << "\n\t\tCannot analyze BB with a branch out of function.");
return true;
}
// Now try to analyze this branch.
SmallVector<MachineOperand, 4> Cond;
if (QII->analyzeBranch(*MBB, TBB, FBB, Cond, false)) {
LLVM_DEBUG(dbgs() << "\t\tFail to analyze with analyzeBranch.\n");
LLVM_DEBUG(dbgs() << "\t\tFirst term: "; if (FirstTerm) FirstTerm->dump();
else dbgs() << "None\n";);
// Could not analyze it. See if this is something we can recognize.
TBB = getBranchDestination(FirstTerm);
}
// There are several cases not handled by HexagonInstrInfo::analyzeBranch.
if (!TBB) {
LLVM_DEBUG(dbgs() << "\t\tMissing TBB.\n");
// There is a branch, but TBB is not found.
// The BB could also be empty at this point. See if it is a trivial
// layout case.
if (MBB->succ_size() == 1) {
TBB = *MBB->succ_begin();
LLVM_DEBUG(dbgs() << "\t\tFall through TBB(" << TBB->getNumber()
<< ").\n");
return false;
} else if (MBB->succ_size() == 2) {
// This should cover majority of remaining cases.
if (FirstTerm && SecondTerm &&
(QII->isPredicated(*FirstTerm) || QII->isNewValueJump(*FirstTerm)) &&
!QII->isPredicated(*SecondTerm)) {
TBB = getBranchDestination(FirstTerm);
FBB = getBranchDestination(SecondTerm);
LLVM_DEBUG(dbgs() << "\t\tCanonical dual jump layout: TBB("
<< TBB->getNumber() << ") FBB(" << FBB->getNumber()
<< ").\n");
return false;
} else if (SecondTerm && SecondTerm->getOpcode() == Hexagon::J2_jump &&
SecondTerm->getOperand(0).isMBB()) {
// Look at the second term if I know it, to find out what is the fall
// through for this BB.
FBB = SecondTerm->getOperand(0).getMBB();
assert(MBB->succ_size() == 2 && "Expected exactly 2 successors");
MachineBasicBlock *Succ0 = *MBB->succ_begin();
MachineBasicBlock *Succ1 = *std::next(MBB->succ_begin());
if (FBB == Succ0)
TBB = Succ1;
else
TBB = Succ0;
LLVM_DEBUG(dbgs() << "\t\tSecond br is J2_jump TBB(" << TBB->getNumber()
<< ") FBB(" << FBB->getNumber() << ").\n");
return false;
} else {
// This might be an empty BB but still with two
// successors set. Try to use CFG layout to sort it out.
// This could happen when last jump was pulled up from a BB, and
// CFG is being updated. At that point this method is called and
// returns best guess possible for TBB/FBB. Fortunately order of those
// is irrelevant, and rather used a worklist for CFG update.
MachineFunction::iterator MBBIter = MBB->getIterator();
MachineFunction &MF = *MBB->getParent();
(void)MF; // supress compiler warning
// If there are no other clues, assume next sequential BB
// in CFG as FBB.
++MBBIter;
assert(MBBIter != MF.end() && "I give up.");
FBB = &(*MBBIter);
assert(MBB->succ_size() == 2 && "Expected exactly 2 successors");
MachineBasicBlock *S0 = *MBB->succ_begin();
MachineBasicBlock *S1 = *std::next(MBB->succ_begin());
if (FBB == S0)
TBB = S1;
else if (FBB == S1) {
TBB = S0;
} else {
// This case can arise when the layout successor basic block (++IMBB)
// got empty during pull-up.
// As a result, ++IMBB is not one of MBB's successors.
MBBIter = MF.begin();
while (!MBB->isSuccessor(&*MBBIter) && (MBBIter != MF.end()))
++MBBIter;
assert(MBBIter != MF.end() && "Malformed BB with invalid successors");
FBB = &*MBBIter;
if (FBB == S0)
TBB = S1;
else
TBB = S0;
}
LLVM_DEBUG(dbgs() << "\t\tUse layout TBB(" << TBB->getNumber()
<< ") FBB(" << FBB->getNumber() << ").\n");
return false;
}
}
assert(!FirstTerm && "Bad BB");
return true;
}
// Ok, we have TBB, but maybe missing FBB.
if (!FBB && SecondTerm) {
LLVM_DEBUG(dbgs() << "\t\tMissing FBB.\n");
// analyzeBranch could lie to us, ignore it in this case.
// For the canonical case simply take known branch targets.
if ((QII->isPredicated(*FirstTerm) || QII->isNewValueJump(*FirstTerm)) &&
!QII->isPredicated(*SecondTerm)) {
FBB = getBranchDestination(SecondTerm);
} else {
// Second term is also predicated.
// Use CFG layout. Assign layout successor as FBB.
for (MachineBasicBlock *Succ : MBB->successors()) {
if (MBB->isLayoutSuccessor(Succ))
FBB = Succ;
}
if (FBB == NULL) {
LLVM_DEBUG(dbgs() << "\nNo layout successor found.");
LLVM_DEBUG(dbgs() << "Possibly the layout successor is an empty BB");
return true;
}
if (TBB == FBB)
LLVM_DEBUG(dbgs() << "Malformed branch with useless branch condition";);
}
LLVM_DEBUG(dbgs() << "\t\tSecond term: "; SecondTerm->dump());
} else if (TBB && !FBB) {
// If BB ends in endloop, and it is a single BB hw loop,
// we will have a single terminator, but we can figure FBB
// easily from CFG.
if (MBB->succ_size() == 2) {
MachineBasicBlock *S0 = *MBB->succ_begin();
MachineBasicBlock *S1 = *std::next(MBB->succ_begin());
if (TBB == S0)
FBB = S1;
else
FBB = S0;
}
}
LLVM_DEBUG(dbgs() << "\t\tFinal TBB(" << TBB->getNumber() << ").\n";
if (FBB) dbgs() << "\t\tFinal FBB(" << FBB->getNumber() << ").\n";
else dbgs() << "\t\tFinal FBB(None)\n";);
return false;
}
/// updateBranches - Updates all branches to \p From in the basic block \p
/// InBlock to branches to \p To.
static void updateBranches(MachineBasicBlock &InBlock, MachineBasicBlock *From,
MachineBasicBlock *To) {
for (MachineBasicBlock::instr_iterator BI = InBlock.instr_begin(),
E = InBlock.instr_end();
BI != E; ++BI) {
MachineInstr *Inst = &*BI;
// Ignore anything that is not a branch.
if (!Inst->isBranch())
continue;
for (MachineInstr::mop_iterator OI = Inst->operands_begin(),
OE = Inst->operands_end();
OI != OE; ++OI) {
MachineOperand &Opd = *OI;
// Look for basic block "From".
if (!Opd.isMBB() || Opd.getMBB() != From)
continue;
// Update it.
Opd.setMBB(To);
}
}
}
/// Rewrite all predecessors of the old block to go to the fallthrough
/// instead.
/// NB: Collect predecessors into a snapshot vector before iterating to
/// avoid iterator invalidation on MBB's predecessor list. Each call to
/// ReplaceUsesOfBlockWith modifies both the successor list of Pred and
/// the predecessor list of MBB, which invalidates debug-mode iterators
/// (detected by _GLIBCXX_DEBUG).
static void updatePredecessors(MachineBasicBlock &MBB,
MachineBasicBlock *MFBB) {
MachineFunction &MF = *MBB.getParent();
if (MFBB->getIterator() == MF.end())
return;
// Snapshot the predecessor list to avoid iterator invalidation.
SmallVector<MachineBasicBlock *, 4> Preds(MBB.pred_begin(), MBB.pred_end());
for (MachineBasicBlock *Pred : Preds) {
if (!Pred->isSuccessor(&MBB))
continue;
Pred->ReplaceUsesOfBlockWith(&MBB, MFBB);
updateBranches(*Pred, &MBB, MFBB);
}
}
static void UpdateCFG(MachineBasicBlock *HomeBB, MachineBasicBlock *OriginBB,
MachineInstr *MII, MachineBasicBlock *HomeTBB,
MachineBasicBlock *HomeFBB, MachineInstr *FTA,
MachineInstr *STA,
const MachineBranchProbabilityInfo *MBPI) {
MachineBasicBlock *S2Add = NULL, *S2Remove = NULL;
bool RemoveLSIfPresent = false;
if ((&*MII == FTA) && MII->isConditionalBranch()) {
LLVM_DEBUG(dbgs() << "\nNew firstterm conditional jump added to HomeBB";);
S2Add = HomeTBB;
S2Remove = HomeTBB;
} else if ((&*MII == STA) && MII->isConditionalBranch()) {
LLVM_DEBUG(dbgs() << "\nNew secondterm conditional jump added to HomeBB";);
// AnalyzeBBBranches might not give correct information in this case.
// The branch destination may be a symbol, not necessarily a block.
if (MachineBasicBlock *Dest = getBranchDestination(MII)) {
LLVM_DEBUG(dbgs() << "\nBranch destination for pulled instruction is BB#"
<< Dest->getNumber(););
S2Add = Dest;
S2Remove = Dest;
}
} else if ((&*MII == FTA) && MII->isUnconditionalBranch()) {
LLVM_DEBUG(dbgs() << "\nNew firstterm unconditional jump added to HomeBB";);
S2Add = HomeTBB;
S2Remove = HomeTBB;
RemoveLSIfPresent = true;
} else if ((&*MII == STA) && MII->isUnconditionalBranch()) {
LLVM_DEBUG(
dbgs() << "\nNew secondterm unconditional jump added to HomeBB";);
S2Add = HomeFBB;
S2Remove = HomeFBB;
RemoveLSIfPresent = true;
}
if (S2Add && !HomeBB->isSuccessor(S2Add)) {
HomeBB->addSuccessor(S2Add, MBPI->getEdgeProbability(OriginBB, S2Add));
}
if (S2Remove)
OriginBB->removeSuccessor(S2Remove);
if (RemoveLSIfPresent) {
MachineFunction::iterator HomeBBLS = HomeBB->getIterator();
++HomeBBLS;
if (HomeBBLS != HomeBB->getParent()->end() &&
HomeBB->isLayoutSuccessor(&*HomeBBLS)) {
LLVM_DEBUG(dbgs() << "\nRemoving LayoutSucc BB#" << HomeBBLS->getNumber()
<< "from list of successors";);
HomeBB->removeSuccessor(&*HomeBBLS);
}
}
}
/// Move instruction from/to BB, Update liveness info,
/// return pointer to the newly inserted and modified
/// instruction.
MachineInstr *HexagonGlobalSchedulerImpl::MoveAndUpdateLiveness(
BasicBlockRegion *CurrentRegion, MachineBasicBlock *HomeBB,
MachineInstr *InstrToMove, bool NeedToNewify, unsigned DepReg,
bool MovingDependentOp, MachineBasicBlock *OriginBB,
MachineInstr *OriginalInstruction, SmallVector<MachineOperand, 4> &Cond,
MachineBasicBlock::iterator &SourceLocation,
MachineBasicBlock::iterator &TargetPacket,
MachineBasicBlock::iterator &NextMI,
std::vector<MachineInstr *> &backtrack) {
LLVM_DEBUG(
dbgs() << "\n...............[MoveAndUpdateLiveness]..............\n");
LLVM_DEBUG(dbgs() << "\t\tInstrToMove :\t"; InstrToMove->dump());
LLVM_DEBUG(dbgs() << "\t\tOriginalInstruction:\t";
OriginalInstruction->dump());
LLVM_DEBUG(dbgs() << "\t\tSourceLocation :\t";
DumpPacket(SourceLocation.getInstrIterator()));
LLVM_DEBUG(dbgs() << "\t\tTargetPacket :\t";
DumpPacket(TargetPacket.getInstrIterator()));
MachineBasicBlock::instr_iterator OriginalHead =
SourceLocation.getInstrIterator();
MachineBasicBlock::instr_iterator OriginalTail = getBundleEnd(OriginalHead);
MachineBasicBlock::instr_iterator OutcastFrom =
OriginalInstruction->getIterator();
// Remove our temporary instruction.
MachineBasicBlock::instr_iterator kill_it(InstrToMove);
HomeBB->erase(kill_it);
MachineBasicBlock::instr_iterator TargetHead(TargetPacket.getInstrIterator());
MachineBasicBlock::instr_iterator TargetTail = getBundleEnd(TargetHead);
LLVM_DEBUG(dbgs() << "\n\tTo BB before:\n"; debugLivenessForBB(HomeBB, QRI));
LLVM_DEBUG(dbgs() << "\n\tFrom BB before:\n";
debugLivenessForBB(OriginBB, QRI));
// Before we perform the move, we need to collect the worklist
// of BBs for liveness updated.
std::list<MachineBasicBlock *> WorkList;
// Insert into the work list all BBs along the backtrace.
for (std::vector<MachineInstr *>::iterator RI = backtrack.begin(),
RIE = backtrack.end();
RI != RIE; RI++)
WorkList.push_back((*RI)->getParent());
// Only keep unique entries.
// TODO: Use a different container here.
WorkList.unique();
// Move the original instruction.
// If this instruction is inside a bundle, update the bundle.
MachineBasicBlock::instr_iterator BBEnd =
TargetHead->getParent()->instr_end();
bool LastInstructionInBundle = false;
MachineBasicBlock::instr_iterator MII = findInsertPositionInBundle(
TargetPacket, &*OutcastFrom, LastInstructionInBundle);
(void)BBEnd;
LLVM_DEBUG(dbgs() << "\n\t\t\tHead target : "; DumpPacket(TargetHead));
LLVM_DEBUG(dbgs() << "\t\t\tTail target : ";
DumpPacket(TargetTail, BBEnd));
LLVM_DEBUG(dbgs() << "\t\t\tInsert right before: "; DumpPacket(MII, BBEnd));
MIBundleBuilder Bundle(&*TargetHead);
// Actual move. One day liveness might be updated here.
if (OriginalInstruction->isBundled()) {
Bundle.insert(MII, OriginalInstruction->removeFromBundle());
--MII;
} else {
// This is one case currently unhandled by Bundle.insert
// and needs to be fixed upstream. Meanwhile use old way to handle
// this odd case.
if (OriginalInstruction->getIterator() == TargetTail) {
LLVM_DEBUG(dbgs() << "\t\t\tSpecial case move.\n");
MachineBasicBlock::instr_iterator MIIToPred = MII;
--MIIToPred;
LLVM_DEBUG(dbgs() << "\t\t\tInser after : ";
DumpPacket(MIIToPred, BBEnd));
// Unbundle it in its current location.
if (OutcastFrom->isBundledWithSucc()) {
OutcastFrom->clearFlag(MachineInstr::BundledSucc);
OutcastFrom->clearFlag(MachineInstr::BundledPred);
} else if (OutcastFrom->isBundledWithPred()) {
OutcastFrom->unbundleFromPred();
}
HomeBB->splice(MII, OriginBB, OutcastFrom);
if (!MII->isBundledWithPred())
MII->bundleWithPred();
if (!LastInstructionInBundle && !MII->isBundledWithSucc())
MII->bundleWithSucc();
// This is the instruction after which we have inserted.
if (!MIIToPred->isBundledWithSucc())
MIIToPred->bundleWithSucc();
} else {
Bundle.insert(MII, OriginalInstruction->removeFromParent());
--MII;
}
}
// Source location bundle is updated later in the
// removeInstructionFromExistingBundle().
LLVM_DEBUG(dbgs() << "\t\t\tNew packet head: "; DumpPacket(TargetHead));
LLVM_DEBUG(dbgs() << "\t\t\tInserted op : "; MII->dump());
LLVM_DEBUG(dbgs() << "\n\tTo BB after move:\n";
debugLivenessForBB(HomeBB, QRI));
LLVM_DEBUG(dbgs() << "\n\tFrom BB after:\n";
debugLivenessForBB(OriginBB, QRI));
// Update kill patterns. Do it before we have predicated the moved
// instruction.
updateKillAlongThePath(HomeBB, OriginBB, MII, TargetTail, SourceLocation,
TargetPacket, backtrack);
// I need to know:
// - true/false predication
// - do I need to .new it?
// - do I need to .old it?
// If the original instruction used new value operands,
// it might need to be changed to the generic form
// before further processing.
if (QII->isDotNewInst(*MII)) {
DemoteToDotOld(&*MII);
LLVM_DEBUG(dbgs() << "\t\t\tDemoted to .old\t:"; MII->dump());
}
// We have previously checked whether this instruction could
// be placed in this packet, including all possible transformations
// it might need, so if any request will fail now, something is wrong.
//
// Need for predication and the exact condition is determined by
// the path between original and current instruction location.
if (!Cond.empty()) { // To be predicated
LLVM_DEBUG(dbgs() << "\t\t\tPredicating:"; MII->dump());
assert(TII->isPredicable(*MII) && "MII is not predicable");
TII->PredicateInstruction(*MII, Cond);
if (NeedToNewify) {
assert((DepReg < std::numeric_limits<unsigned>::max()) &&
"Invalid pred reg value");
LLVM_DEBUG(dbgs() << "\t\t\tNeeds to NEWify on Reg("
<< printReg(DepReg, QRI) << ").\n");
int NewOpcode = QII->getDotNewPredOp(*MII, MBPI);
MII->setDesc(QII->get(NewOpcode));
// Now we need to mark newly created predicate operand as
// internal read.
// TODO: Better look for predicate operand.
for (unsigned i = 0, e = MII->getNumOperands(); i != e; ++i) {
MachineOperand &MO = MII->getOperand(i);
if (!MO.isReg())
continue;
if (MO.isDef())
continue;
if (DepReg == MO.getReg())
MO.setIsInternalRead();
}
}
LLVM_DEBUG(dbgs() << "\t\t\tNew predicated form:\t"; MII->dump());
// If the predicate has changed kill pattern, now we need to propagate
// that again. This is important for liveness computation.
updateKillAlongThePath(HomeBB, OriginBB, MII, TargetTail, SourceLocation,
TargetPacket, backtrack);
}
// Create new bundle header, remove the old one.
addInstructionToExistingBundle(HomeBB, TargetHead, TargetTail, MII,
TargetPacket, NextMI, backtrack);
// If moved instruction was inside a bundle, update that bundle.
removeInstructionFromExistingBundle(OriginBB, ++OriginalHead, OriginalTail,
SourceLocation, NextMI, MovingDependentOp,
backtrack);
// If removed instruction could have been dependent on any
// of the remaining ops, we need to oldify possible affected ones.
LLVM_DEBUG(dbgs() << "\t\tTargetHead:\t"; DumpPacket(TargetHead, BBEnd));
LLVM_DEBUG(dbgs() << "\t\tOriginalHead:\t"; DumpPacket(OriginalHead, BBEnd));
LLVM_DEBUG(dbgs() << "\t\tOriginalInstruction:\t";
DumpPacket(OriginalInstruction->getIterator(), BBEnd));
LLVM_DEBUG(dbgs() << "\t\tOutcastFrom:\t"; DumpPacket(OutcastFrom, BBEnd));
// Clean up the original source bundle on a global scope.
if (OriginalHead != MachineBasicBlock::instr_iterator() &&
QII->isEndLoopN(OriginalHead->getOpcode())) {
// Single endloop left. Since it is not a real instruction,
// we can simply add it to a non empty previous bundle, if one exist,
// or let assembler to produce a fake bundle for it.
LLVM_DEBUG(dbgs() << "\t\tOnly endloop in packet.\n");
MachineBasicBlock::instr_iterator I(OriginalHead);
if (OriginBB->begin() != I) {
--I;
if (I->isBundled()) {
if (!I->isBundledWithSucc())
I->bundleWithSucc();
if (!OriginalHead->isBundledWithPred())
OriginalHead->bundleWithPred();
}
// else we probably need to create a new bundle here.
// SourceLocation = NULL;
}
} else if (MovingDependentOp &&
OriginalHead != MachineBasicBlock::instr_iterator()) {
if (OriginalHead->isBundled()) {
for (MachineBasicBlock::instr_iterator J = ++OriginalHead;
J != OriginalTail && J->isInsideBundle() && !J->isBundle(); ++J) {
// Need to oldify it.
if (MIsHaveTrueDependency(OriginalInstruction, &*J) &&
QII->isDotNewInst(*J)) {
LLVM_DEBUG(dbgs() << "\t\tDemoting to .old:\t"; J->dump());
DemoteToDotOld(&*J);
}
}
} else {
// Single instruction left.
if (MIsHaveTrueDependency(OriginalInstruction, &*OriginalHead) &&
QII->isDotNewInst(*OriginalHead)) {
LLVM_DEBUG(dbgs() << "\t\tDemoting to .old op:\t";
OriginalHead->dump());
DemoteToDotOld(&*OriginalHead);
}
}
}
// Now we need to update liveness to all BBs involved
// including those we might have "passed" through on the way here.
LLVM_DEBUG(dbgs() << "\n\tTo BB after bundle update:\n"; HomeBB->dump());
LLVM_DEBUG(dbgs() << "\n\n\tFrom BB after bundle update:\n";
OriginBB->dump());
// Update global liveness.
LLVM_DEBUG(dbgs() << "\n\tWorkList:\t");
for (std::list<MachineBasicBlock *>::iterator BBI = WorkList.begin(),
BBIE = WorkList.end();
BBI != BBIE; BBI++) {
LLVM_DEBUG(dbgs() << "BB#" << (*BBI)->getNumber() << " ");
}
LLVM_DEBUG(dbgs() << "\n");
do {
MachineBasicBlock *BB = WorkList.back();
WorkList.pop_back();
CurrentRegion->getLivenessInfoForBB(BB)->UpdateLiveness(BB);
} while (!WorkList.empty());
// No need to analyze for empty BB or update CFG for same BB pullup.
if (OriginBB == HomeBB)
return &*TargetHead;
// If the instruction moved was a branch we need to update the
// successor/predecessor of OriginBB and HomeBB accordingly.
MachineBasicBlock *HomeTBB, *HomeFBB;
MachineInstr *FTA = NULL, *STA = NULL;
bool HomeBBAnalyzed = !AnalyzeBBBranches(HomeBB, HomeTBB, FTA, HomeFBB, STA);
if (MII->isBranch()) {
if (HomeBBAnalyzed) {
UpdateCFG(HomeBB, OriginBB, &*MII, HomeTBB, HomeFBB, FTA, STA, MBPI);
} else {
llvm_unreachable("Underimplememted AnalyzeBBBranches");
}
}
// If we have exhausted the OriginBB clean it up.
// Beware that we could have created dual conditional jumps, which
// ultimately means we can have three way jumps.
if (IsEmptyBlock(OriginBB) && !OriginBB->isEHPad() &&
!OriginBB->hasAddressTaken() && !OriginBB->succ_empty()) {
// Dead block? Unlikely, but check.
LLVM_DEBUG(dbgs() << "Empty BB(" << OriginBB->getNumber() << ").\n");
// Update region map.
CurrentRegion->RemoveBBFromRegion(OriginBB);
// Keep the list of empty basic blocks to be freed later.
EmptyBBs.push_back(OriginBB);
if (OriginBB->pred_empty() || OriginBB->succ_empty())
return &*TargetHead;
if (OriginBB->succ_size() == 1) {
// Find empty block's successor.
MachineBasicBlock *CommonFBB = *OriginBB->succ_begin();
updatePredecessors(*OriginBB, CommonFBB);
// Remove the only successor entry for empty BB.
OriginBB->removeSuccessor(CommonFBB);
} else {
// Three way branching is not yet fully supported.
assert((OriginBB->succ_size() == 2) && "Underimplemented 3way branch.");
MachineBasicBlock *OriginTBB, *OriginFBB;
MachineInstr *FTB = NULL, *STB = NULL;
LLVM_DEBUG(dbgs() << "\tComplex case.\n");
if (HomeBBAnalyzed &&
!AnalyzeBBBranches(OriginBB, OriginTBB, FTB, OriginFBB, STB)) {
assert(OriginFBB && "Missing Origin FBB");
if (HomeFBB == OriginBB) {
// OriginBB is FBB for HomeBB.
if (HomeTBB == OriginTBB) {
// Shared TBB target, common FBB.
updatePredecessors(*OriginBB, OriginFBB);
} else if (HomeTBB == OriginFBB) {
// Shared TBB target, common FBB.
updatePredecessors(*OriginBB, OriginTBB);
} else {
// Three way branch. Add new successor to HomeBB.
updatePredecessors(*OriginBB, OriginFBB);
// TODO: Update the weight as well.
// Adding the successor to make updatePredecessor happy.
HomeBB->addSuccessor(OriginBB);
updatePredecessors(*OriginBB, OriginTBB);
}
} else if (HomeTBB == OriginBB) {
// OriginBB is TBB for HomeBB.
if (HomeFBB == OriginTBB) {
// Shared TBB target, common FBB.
updatePredecessors(*OriginBB, OriginFBB);
} else if (HomeFBB == OriginFBB) {
// Shared TBB target, common FBB.
updatePredecessors(*OriginBB, OriginTBB);
} else {
// Three way branch. Add new successor to HomeBB.
updatePredecessors(*OriginBB, OriginFBB);
// TODO: Update the weight as well.
// Adding the successor to make updatePredecessor happy.
HomeBB->addSuccessor(OriginBB);
updatePredecessors(*OriginBB, OriginTBB);
}
} else
llvm_unreachable("CFG update failed");
// The empty BB can now be relieved of its successors.
OriginBB->removeSuccessor(OriginFBB);
OriginBB->removeSuccessor(OriginTBB);
} else
llvm_unreachable("Underimplemented analyzeBranch");
}
LLVM_DEBUG(dbgs() << "Updated BB(" << HomeBB->getNumber() << ").\n";
HomeBB->dump());
}
return &*TargetHead;
}
// Find where inside a given bundle current instruction should be inserted.
// Instruction will be inserted _before_ this position.
MachineBasicBlock::instr_iterator
HexagonGlobalSchedulerImpl::findInsertPositionInBundle(
MachineBasicBlock::iterator &Bundle, MachineInstr *MI, bool &LastInBundle) {
MachineBasicBlock::instr_iterator MII = Bundle.getInstrIterator();
MachineBasicBlock *MBB = MII->getParent();
MachineBasicBlock::instr_iterator BBEnd = MBB->instr_end();
MachineBasicBlock::instr_iterator FirstBranch = BBEnd;
MachineBasicBlock::instr_iterator LastBundledInstruction = BBEnd;
MachineBasicBlock::instr_iterator DualJumpFirstCandidate = BBEnd;
assert(MII->isBundle() && "Missing insert location");
bool isDualJumpSecondCandidate = IsDualJumpSecondCandidate(MI);
LastInBundle = false;
for (++MII; MII != BBEnd && MII->isInsideBundle() && !MII->isBundle();
++MII) {
if (MII->isBranch() && (FirstBranch == BBEnd))
FirstBranch = MII;
// If what we insert is a dual jump, we need to find
// first jump, and insert new instruction after it.
if (isDualJumpSecondCandidate && IsDualJumpFirstCandidate(&*MII))
DualJumpFirstCandidate = MII;
LastBundledInstruction = MII;
}
if (DualJumpFirstCandidate != BBEnd) {
// First respect dual jumps.
++DualJumpFirstCandidate;
if (DualJumpFirstCandidate == BBEnd ||
DualJumpFirstCandidate == LastBundledInstruction)
LastInBundle = true;
return DualJumpFirstCandidate;
} else if (FirstBranch != BBEnd) {
// If we have no dual jumps, but do have a single
// branch in the bundle, add our new instruction
// right before it.
return FirstBranch;
} else if (LastBundledInstruction != BBEnd) {
LastInBundle = true;
return ++LastBundledInstruction;
} else
llvm_unreachable("Lost in bundle");
return MBB->instr_begin();
}
/// This function for now needs to try to insert new instruction
/// in correct serial semantics fashion - i.e. find "correct" insert
/// point for instruction as if inserting in serial sequence.
MachineBasicBlock::instr_iterator HexagonGlobalSchedulerImpl::insertTempCopy(
MachineBasicBlock *MBB, MachineBasicBlock::iterator &TargetPacket,
MachineInstr *MI, bool DeleteOldCopy) {
MachineBasicBlock::instr_iterator MII;
MachineBasicBlock *CurrentBB = MI->getParent();
assert(CurrentBB && "Corrupt instruction");
// Create a temporary copy of the instruction we are considering.
// LLVM refuses to deal with an instruction which was not inserted
// to any BB. We can visit multiple BBs on the way "up", so we
// create a temp copy of the original instruction and delete it later.
// It is way cheaper than using splice and then
// needing to undo it most of the time.
MachineInstr *NewMI = MI->getParent()->getParent()->CloneMachineInstr(MI);
// Make sure all bundling flags are cleared.
if (NewMI->isBundledWithPred())
NewMI->unbundleFromPred();
if (NewMI->isBundledWithSucc())
NewMI->unbundleFromSucc();
if (DeleteOldCopy) {
// Remove our temporary instruction.
// MachineBasicBlock::erase method calls unbundleSingleMI()
// prior to deletion, so we do not have to do it here.
MachineBasicBlock::instr_iterator kill_it(MI);
CurrentBB->erase(kill_it);
}
// If the original instruction used new value operands,
// it might need to be changed to generic form
// before further processing.
if (QII->isDotNewInst(*NewMI))
DemoteToDotOld(NewMI);
// Insert new temporary instruction.
// If this is the destination packet, insert the tmp after
// its header. Otherwise, as second instr in BB.
if (TargetPacket->getParent() == MBB) {
MII = TargetPacket.getInstrIterator();
if (MII->isBundled()) {
bool LastInBundle = false;
MachineBasicBlock::instr_iterator InsertBefore =
findInsertPositionInBundle(TargetPacket, NewMI, LastInBundle);
MIBundleBuilder Bundle(&*TargetPacket);
Bundle.insert(InsertBefore, NewMI);
} else
MBB->insertAfter(MII, NewMI);
} else {
MII = MBB->instr_begin();
// Skip debug instructions.
while (MII->isDebugInstr())
MII++;
if (MII->isBundled()) {
MIBundleBuilder Bundle(&*MII);
Bundle.insert(++MII, NewMI);
} else
MBB->insertAfter(MII, NewMI);
}
return NewMI->getIterator();
}
// Check for a conditionally assigned register within the block.
bool HexagonGlobalSchedulerImpl::MIsCondAssign(MachineInstr *BMI,
MachineInstr *MI,
SmallVector<unsigned, 4> &Defs) {
if (!QII->isPredicated(*BMI))
return false;
// Its a conditional instruction, now is it the same registers as MI?
SmallVector<unsigned, 4> CondDefs;
SmallVector<unsigned, 8> CondUses;
parseOperands(BMI, CondDefs, CondUses);
for (SmallVector<unsigned, 4>::iterator ID = Defs.begin(), IDE = Defs.end();
ID != IDE; ++ID) {
for (SmallVector<unsigned, 4>::iterator CID = CondDefs.begin(),
CIDE = CondDefs.end();
CID != CIDE; ++CID) {
if (AliasingRegs(*CID, *ID)) {
LLVM_DEBUG(dbgs() << "\tFound conditional def, can't move\n";
BMI->dump());
return true;
}
}
}
return false;
}
// Returns the Union of all the elements in Set1 and
// Union of all the elements in Set2 separately.
// Constraints:
// Set1 and Set2 should contain an entry for each element in Range.
template <typename ElemType, typename IndexType>
void Unify(std::vector<ElemType> Range,
std::map<ElemType, std::vector<IndexType>> &Set1,
std::map<ElemType, std::vector<IndexType>> &Set2,
std::pair<std::vector<IndexType>, std::vector<IndexType>> &UnionSet,
unsigned union_size = 100) {
typedef
typename std::map<ElemType, std::vector<IndexType>>::iterator PosIter_t;
typedef typename std::vector<IndexType>::iterator IndexIter_t;
std::vector<IndexType> &Union1 = UnionSet.first;
std::vector<IndexType> &Union2 = UnionSet.second;
Union1.resize(union_size, 0);
Union2.resize(union_size, 0);
LLVM_DEBUG(dbgs() << "\n\t\tElements in the range:\n";);
typename std::vector<ElemType>::iterator iter = Range.begin();
while (iter != Range.end()) {
if ((*iter)->isDebugInstr()) {
++iter;
continue;
}
LLVM_DEBUG((*iter)->dump());
PosIter_t set1_pos = Set1.find(*iter);
assert(set1_pos != Set1.end() &&
"Set1 should contain an entry for each element in Range.");
IndexIter_t set1idx = set1_pos->second.begin();
while (set1idx != set1_pos->second.end()) {
Union1[*set1idx] = 1;
++set1idx;
}
PosIter_t set2_pos = Set2.find(*iter);
assert(set2_pos != Set2.end() &&
"Set2 should contain an entry for each element in Range.");
IndexIter_t set2idx = set2_pos->second.begin();
while (set2idx != set2_pos->second.end()) {
Union2[*set2idx] = 1;
++set2idx;
}
++iter;
}
}
static void UpdateBundle(MachineInstr *BundleHead) {
assert(BundleHead->isBundle() && "Not a bundle header");
if (!BundleHead)
return;
unsigned Size = BundleHead->getBundleSize();
if (Size >= 2)
return;
if (Size == 1) {
MachineBasicBlock::instr_iterator MIter = BundleHead->getIterator();
MachineInstr *MI = &*(++MIter);
MI->unbundleFromPred();
}
BundleHead->eraseFromParent();
}
/// Gatekeeper for instruction speculation.
/// If all MI defs are dead (not live-in) to any other
/// BB but the one we are moving into, and it could not cause
/// exception by early execution, allow it to be pulled up.
bool HexagonGlobalSchedulerImpl::canMIBeSpeculated(
MachineInstr *MI, MachineBasicBlock *ToBB, MachineBasicBlock *FromBB,
std::vector<MachineInstr *> &backtrack) {
// For now disallow memory accesses from speculation.
// Generally we can check if they potentially may trap/cause an exception.
if (!EnableSpeculativePullUp || !MI || MI->mayStore())
return false;
LLVM_DEBUG(dbgs() << "\t[canMIBeSpeculated] From BB(" << FromBB->getNumber()
<< "):\t";
MI->dump());
LLVM_DEBUG(dbgs() << "\tTo this BB:\n"; ToBB->dump());
if (!ToBB->isSuccessor(FromBB))
return false;
// This is a very tricky topic. Speculating arithmetic instructions with
// results dead out of a loop more times then required by number of
// iterations is safe, while speculating loads can cause an exception.
// Simplest of checks is to not cross loop exit edge, or in our case
// do not pull-in to a loop exit BB, but there are implications for
// non-natural loops (not recognized by LLVM as loops) and multi-threaded
// code.
if (AllowSpeculateLoads && MI->mayLoad()) {
// Invariant loads should always be safe.
if (!MI->isDereferenceableInvariantLoad())
return false;
LLVM_DEBUG(dbgs() << "\tSpeculating a Load.\n");
}
SmallVector<unsigned, 4> Defs;
SmallVector<unsigned, 8> Uses;
parseOperands(MI, Defs, Uses);
// Do not speculate instructions that modify reserved global registers.
for (unsigned R : Defs)
if (MRI->isReserved(R) && QRI->isGlobalReg(R))
return false;
for (MachineBasicBlock::const_succ_iterator SI = ToBB->succ_begin(),
SE = ToBB->succ_end();
SI != SE; ++SI) {
// TODO: Allow an instruction (I) which 'defines' the live-in reg (R)
// along the path when I is the first instruction to use the R.
// i.e., I kills R before any other instruction in the BB uses it.
// TODO: We have already parsed live sets - reuse them.
if (*SI == FromBB)
continue;
LLVM_DEBUG(dbgs() << "\tTarget succesor BB to check:\n"; (*SI)->dump());
LLVM_DEBUG(
for (MachineBasicBlock::const_succ_iterator SII = (*SI)->succ_begin(),
SIE = (*SI)->succ_end();
SII != SIE; ++SII)(*SII)
->dump());
for (MachineBasicBlock::livein_iterator I = (*SI)->livein_begin(),
E = (*SI)->livein_end();
I != E; ++I)
for (SmallVector<unsigned, 4>::iterator ID = Defs.begin(),
IDE = Defs.end();
ID != IDE; ++ID) {
if (AliasingRegs((*I).PhysReg, *ID))
return false;
}
// Check the successor blocks for conditional define.
// TODO: We should really test the whole path here.
for (MachineBasicBlock::instr_iterator BI = (*SI)->instr_begin(),
E = (*SI)->instr_end();
BI != E; ++BI) {
if (BI->isBundle() || BI->isDebugInstr())
continue;
LLVM_DEBUG(dbgs() << "\t\tcheck against:\t"; BI->dump());
if (MIsCondAssign(&*BI, MI, Defs))
return false;
}
}
// Taking a very conservative approach during speculation.
// Traverse the path (FromBB, ToBB] and make sure
// that the def-use set of the instruction to be moved
// are not modified.
std::vector<MachineBasicBlock *> PathBB;
for (unsigned i = 0; i < backtrack.size(); ++i) {
// Insert unique BB along the path but skip FromBB
MachineBasicBlock *MBB = backtrack[i]->getParent();
if ((MBB != FromBB) &&
(std::find(PathBB.begin(), PathBB.end(), MBB) == PathBB.end()))
PathBB.push_back(MBB);
}
bool WaitingForTargetPacket = true;
MachineBasicBlock::instr_iterator MII;
std::vector<MachineInstr *> TraversalRange;
LLVM_DEBUG(dbgs() << "\n\tElements in the range:");
// TODO: Use just the backtrack to get TraversalRange because it
// contains the path (only when speculated from a path in region).
// Note: We check the dependency of instruction-to-move with
// all the instructions (starting from backtrack[0]) in the parent BBs
// because a BB might have a branching from in between due to packetization
// and just checking packets in the backtrack won't be comprehensive.
for (unsigned i = 0; i < PathBB.size(); ++i) {
for (MII = PathBB[i]->instr_begin(); MII != PathBB[i]->instr_end(); ++MII) {
// Skip instructions until the target packet is found.
// although target packet is already checked for correctness,
// it is good to check here to validate intermediate pullups.
if (backtrack[0] == &*MII)
WaitingForTargetPacket = false;
if (WaitingForTargetPacket)
continue;
if (MII->isBundle())
continue;
// TODO: Ideally we should check that there is a `linear' control flow
// in the TraversalRange in all possible manner. For e.g.,
// BB0 { packet1: if(p0) indirect_jump BB1;
// packet2: jump BB2 }
// BB1 { i1 }. In this case we should not pull `i1' into packet2.
if (MII->isCall() || MII->isReturn() ||
(MII->getOpcode() == Hexagon::J2_jump && !MII->getOperand(0).isMBB()))
return false;
if (MI != &*MII) {
TraversalRange.push_back(&*MII);
LLVM_DEBUG(MII->dump(););
}
}
}
// Get the union of def/use set of all the instructions along TraversalRange.
std::pair<std::vector<unsigned>, std::vector<unsigned>> RangeDefUse;
Unify(TraversalRange, MIDefSet, MIUseSet, RangeDefUse, QRI->getNumRegs());
// No instruction (along TraversalRange) should 'define' the use set of MI
for (unsigned j = 0; j < Uses.size(); ++j)
if (RangeDefUse.first[Uses[j]]) {
LLVM_DEBUG(dbgs() << "\n\t\tUnresolved dependency along path to HOME for "
<< printReg(Uses[j], QRI););
return false;
}
// No instruction (along TraversalRange) should 'define' or 'use'
// the def set of MI
for (unsigned j = 0; j < Defs.size(); ++j)
if (RangeDefUse.first[Defs[j]] || RangeDefUse.second[Defs[j]]) {
LLVM_DEBUG(dbgs() << "\n\t\tUnresolved dependency along path to HOME for "
<< printReg(Defs[j], QRI););
return false;
}
return true;
}
/// Try to move InstrToMove to TargetPacket using path stored in backtrack.
/// SourceLocation is current iterator point. It must be updated to the new
/// iteration location after all updates.
/// Alogrithm:
/// To move an instruction (I) from OriginBB through HomeBB via backtrack.
/// for each packet (i) in backtrack, analyzeBranch
/// case 1 (success)
/// case Pulling from conditional branch:
/// if I is predicable
/// Try to predicate on the branch condition
/// else
/// Try to speculate I to backtrack[i].
/// case Pulling from unconditional branch:
/// Just pullup. (TODO: Speculate here as well)
/// case 2 (fails)
/// Try to speculate I backtrack[i].
bool HexagonGlobalSchedulerImpl::MoveMItoBundle(
BasicBlockRegion *CurrentRegion,
MachineBasicBlock::instr_iterator &InstrToMove,
MachineBasicBlock::iterator &NextMI,
MachineBasicBlock::iterator &TargetPacket,
MachineBasicBlock::iterator &SourceLocation,
std::vector<MachineInstr *> &backtrack, bool MovingDependentOp,
bool PathInRegion) {
MachineBasicBlock *HomeBB = TargetPacket->getParent();
MachineBasicBlock *OriginBB = InstrToMove->getParent();
MachineBasicBlock *CurrentBB = OriginBB;
MachineBasicBlock *CleanupBB = OriginBB;
MachineBasicBlock *PreviousBB = OriginBB;
MachineInstr *OriginalInstructionToMove = &*InstrToMove;
assert(HomeBB && "Missing HomeBB");
assert(OriginBB && "Missing OriginBB");
LLVM_DEBUG(dbgs() << "\n.........[MoveMItoBundle]..............\n");
LLVM_DEBUG(dbgs() << "\t\tInstrToMove :\t"; InstrToMove->dump());
LLVM_DEBUG(dbgs() << "\t\tTargetPacket :\t";
DumpPacket(TargetPacket.getInstrIterator()));
LLVM_DEBUG(dbgs() << "\t\tSourceLocation:\t";
DumpPacket(SourceLocation.getInstrIterator()));
// We do not allow to move instructions in the same BB.
if (HomeBB == OriginBB) {
LLVM_DEBUG(dbgs() << "\t\tSame BB pull-up.\n");
if (!EnableLocalPullUp)
return false;
}
if (OneFloatPerPacket && QII->isFloat(*TargetPacket) &&
QII->isFloat(*InstrToMove))
return false;
if (OneComplexPerPacket && QII->isComplex(*TargetPacket) &&
QII->isComplex(*InstrToMove))
return false;
LLVM_DEBUG(dbgs() << "\t\tWay home:\n");
// Test integrity of the back track.
for (unsigned i = 0; i < backtrack.size(); ++i) {
assert(backtrack[i]->getParent() && "Messed back track.");
LLVM_DEBUG(dbgs() << "\t\t[" << i << "] BB("
<< backtrack[i]->getParent()->getNumber() << ")\t";
backtrack[i]->dump());
}
LLVM_DEBUG(dbgs() << "\n");
bool NeedCleanup = false;
bool NeedToPredicate = false;
bool MINeedToNewify = false;
unsigned DepReg = std::numeric_limits<unsigned>::max();
bool isDualJump = false;
SmallVector<MachineOperand, 4> Cond;
SmallVector<MachineOperand, 4> PredCond;
std::vector<MachineInstr *> PullUpPath;
if (PathInRegion)
PullUpPath = backtrack;
else {
PullUpPath.push_back(&*TargetPacket);
PullUpPath.push_back(&*InstrToMove);
}
// Now start iterating over all instructions
// preceeding the one we are trying to move,
// and see if they could be reodered/bypassed.
for (std::vector<MachineInstr *>::reverse_iterator RI = backtrack.rbegin(),
RIE = backtrack.rend();
RI < RIE; ++RI) {
// Once most of debug will be gone, this will be a real assert.
// assert((backtrack.front() == ToThisBundle) && "Lost my way home.");
MachineInstr *MIWH = *RI;
if (QII->isDotNewInst(*InstrToMove)) {
LLVM_DEBUG(dbgs() << "Cannot move a dot new instruction:";
InstrToMove->dump());
if (NeedCleanup)
CleanupBB->erase(InstrToMove);
return false;
}
if (canCauseStall(&*InstrToMove, MIWH)) {
if (NeedCleanup)
CleanupBB->erase(InstrToMove);
return false;
}
LLVM_DEBUG(dbgs() << "\t> Step home BB(" << MIWH->getParent()->getNumber()
<< "):\t";
DumpPacket(MIWH->getIterator()));
// See if we cross a jump, and possibly change the form of instruction.
// Passing through BBs with dual jumps in different packets
// takes extra care.
bool isBranchMIWH = isBranch(MIWH);
if (((&*SourceLocation != MIWH) && isBranchMIWH) ||
(CurrentBB != MIWH->getParent())) {
LLVM_DEBUG(dbgs() << "\tChange BB from(" << CurrentBB->getNumber()
<< ") to (" << MIWH->getParent()->getNumber() << ")\n");
PreviousBB = CurrentBB;
CurrentBB = MIWH->getParent();
// See what kind of branch we are dealing with.
MachineBasicBlock *PredTBB = NULL;
MachineBasicBlock *PredFBB = NULL;
if (QII->analyzeBranch(*CurrentBB, PredTBB, PredFBB, Cond, false)) {
// We currently do not handle NV jumps of this kind:
// if (cmp.eq(r0.new, #0)) jump:t .LBB12_69
// TODO: Need to handle them.
LLVM_DEBUG(dbgs() << "\tCould not analyze branch.\n");
// This is the main point of lost performance.
// We could try to speculate here, but for that we need accurate
// liveness info, and it is not ready yet.
if (!canMIBeSpeculated(&*InstrToMove, CurrentBB, PreviousBB,
PullUpPath)) {
if (NeedCleanup)
CleanupBB->erase(InstrToMove);
return false;
} else {
// Save speculated instruction moved.
SpeculatedIns.insert(
std::make_pair(OriginalInstructionToMove, OriginBB));
LLVM_DEBUG(dbgs() << "\nSpeculatedInsToMove"; InstrToMove->dump());
}
LLVM_DEBUG(dbgs() << "\tSpeculating.\n");
// If we are speculating, we can come through a predication
// into an unconditional branch...
// For now simply bail out.
// TODO: See if this ever happens.
if (NeedToPredicate) {
LLVM_DEBUG(dbgs()
<< "\tUnderimplemented pred for speculative move.\n");
if (NeedCleanup)
CleanupBB->erase(InstrToMove);
return false;
}
InstrToMove =
insertTempCopy(CurrentBB, TargetPacket, &*InstrToMove, NeedCleanup);
NeedCleanup = true;
NeedToPredicate = false;
assert(!NeedToPredicate && "Need to handle predication for this case");
CleanupBB = CurrentBB;
// No need to recheck for resources - instruction did not change.
LLVM_DEBUG(dbgs() << "\tUpdated BB:\n"; CurrentBB->dump());
} else {
bool LocalNeedPredication = true;
// We were able to analyze the branch.
if (!isBranchMIWH && !PredTBB) {
LLVM_DEBUG(dbgs() << "\tDo not need predicate for this case.\n");
LocalNeedPredication = false;
}
// First see if this is a potential dual jump situation.
if (IsDualJumpSecondCandidate(&*InstrToMove) &&
IsDualJumpFirstCandidate(TargetPacket)) {
LLVM_DEBUG(dbgs() << "\tPerforming unrestricted dual jump.\n");
isDualJump = true;
} else if (LocalNeedPredication && (PredFBB != PreviousBB)) {
// Predicate instruction based on condition feeding it.
// This is generally a statefull pull-up path.
// Can this insn be predicated? If so, try to do it.
if (TII->isPredicable(*InstrToMove)) {
if (PredTBB) {
if (PreviousBB != PredTBB) {
// If we "came" not from TBB, we need to invert condition.
if (TII->reverseBranchCondition(Cond)) {
LLVM_DEBUG(dbgs() << "\tUnable to invert condition.\n");
if (NeedCleanup)
CleanupBB->erase(InstrToMove);
return false;
}
}
LLVM_DEBUG(dbgs() << "\tTBB(" << PredTBB->getNumber()
<< ")InvertCondition("
<< (PreviousBB != PredTBB) << ")\n");
}
// Create a new copy of the instruction we are trying to move.
// It changes enough (new BB, predicated form) and untill we
// reach home, we do not even know if it is going to work.
InstrToMove = insertTempCopy(CurrentBB, TargetPacket, &*InstrToMove,
NeedCleanup);
NeedCleanup = true;
NeedToPredicate = true;
CleanupBB = CurrentBB;
if (PredCond.empty() && // If not already predicated.
TII->PredicateInstruction(*InstrToMove, Cond)) {
LLVM_DEBUG(dbgs() << "\tNew predicated insn:\t";
InstrToMove->dump());
// After predication some instruction could become const extended:
// L2_loadrigp == "$dst=memw(#$global)"
// L4_ploadrit_abs == "if ($src1) $dst=memw(##$global)"
// Resource checking for those is different.
if ((QII->isExtended(*InstrToMove) ||
QII->isConstExtended(*InstrToMove) ||
isJumpOutOfRange(&*InstrToMove)) &&
!tryAllocateResourcesForConstExt(&*InstrToMove, false)) {
// If we cannot, do not modify the state.
LLVM_DEBUG(dbgs()
<< "\tEI Could not be added to the packet.\n");
CleanupBB->erase(InstrToMove);
return false;
}
if (!ResourceTracker->canReserveResources(*InstrToMove) ||
!shouldAddToPacket(*InstrToMove)) {
// It will not fit in its new form...
LLVM_DEBUG(dbgs() << "\tCould not be added in its new form.\n");
CurrentBB->erase(InstrToMove);
return false;
}
// Need also verify that we can newify it if we want to.
if (NeedToNewify(InstrToMove, &DepReg, &*TargetPacket)) {
if (isNewifiable(InstrToMove, DepReg, &*TargetPacket)) {
MINeedToNewify = true;
LLVM_DEBUG(dbgs() << "\t\t\tNeeds to NEWify on Reg("
<< printReg(DepReg, QRI) << ").\n");
} else {
LLVM_DEBUG(dbgs() << "\tNon newifiable in this bundle: ";
InstrToMove->dump());
CleanupBB->erase(InstrToMove);
return false;
}
}
LLVM_DEBUG(dbgs() << "\tUpdated BB:\n"; CurrentBB->dump());
PredCond = Cond;
// Now the instruction uses the pred-reg as well.
if (!Cond.empty() && (Cond.size() == 2)) {
MIUseSet[OriginalInstructionToMove].push_back(Cond[1].getReg());
}
assert(((Cond.size() <= 2) &&
!(QII->isNewValueJump(Cond[0].getImm()))) &&
"Update MIUseSet for new-value compare jumps");
} else {
LLVM_DEBUG(dbgs() << "\tCould not predicate it\n");
LLVM_DEBUG(dbgs() << "\tTrying to speculate!\t";
InstrToMove->dump());
bool DistantSpeculation = false;
std::vector<MachineInstr *> NonPredPullUpPath;
unsigned btidx = 0;
// Generate a backtrack path for instruction to be speculated.
// Original backtrack may start from a different (ancestor)
// target packet.
while (btidx < backtrack.size()) {
const MachineBasicBlock *btBB = backtrack[btidx]->getParent();
if ((btBB == PreviousBB) || (btBB == CurrentBB))
NonPredPullUpPath.push_back(backtrack[btidx]);
++btidx;
}
// Speculate only to immediate predecessor.
if (PreviousBB != CurrentBB) {
if (*(PreviousBB->pred_begin()) != CurrentBB) {
// In a region there are no side entries.
DistantSpeculation = true;
LLVM_DEBUG(dbgs()
<< "\n\tMI not in immediate successor of BB#"
<< CurrentBB->getNumber() << ", MI is in BB#"
<< PreviousBB->getNumber(););
}
assert((PreviousBB->pred_size() < 2) &&
"Region with a side entry");
}
// TODO: Speculate ins. when pulled from unlikely path.
if (DistantSpeculation || /*!PathInRegion ||*/
InstrToMove->mayLoad() || InstrToMove->mayStore() ||
InstrToMove->hasUnmodeledSideEffects() ||
!canMIBeSpeculated(&*InstrToMove, CurrentBB, PreviousBB,
NonPredPullUpPath)) {
CleanupBB->erase(InstrToMove);
return false;
} else {
// Save speculated instruction moved.
NeedToPredicate = false;
SpeculatedIns.insert(
std::make_pair(OriginalInstructionToMove, OriginBB));
LLVM_DEBUG(dbgs() << "\nPredicable+SpeculatedInsToMove";
InstrToMove->dump());
}
}
} else {
// This is a non-predicable instruction. We still can try to
// speculate it here.
LLVM_DEBUG(dbgs() << "\tNon predicable insn!\t";
InstrToMove->dump());
// TODO: Speculate ins. when pulled from unlikely path.
if (!SpeculateNonPredInsn || !PathInRegion ||
InstrToMove->mayLoad() || InstrToMove->mayStore() ||
InstrToMove->hasUnmodeledSideEffects() ||
!canMIBeSpeculated(&*InstrToMove, CurrentBB, PreviousBB,
PullUpPath)) {
if (NeedCleanup)
CleanupBB->erase(InstrToMove);
return false;
} else {
// Save speculated instruction moved.
SpeculatedIns.insert(
std::make_pair(OriginalInstructionToMove, OriginBB));
LLVM_DEBUG(dbgs() << "\nNonPredicable+SpeculatedInsToMove";
InstrToMove->dump());
}
InstrToMove = insertTempCopy(CurrentBB, TargetPacket, &*InstrToMove,
NeedCleanup);
NeedCleanup = true;
CleanupBB = CurrentBB;
}
} else {
// No branch. Fall through.
LLVM_DEBUG(dbgs() << "\tFall through BB.\n"
<< "\tCurrentBB:" << CurrentBB->getNumber()
<< "\tPreviousBB:" << PreviousBB->getNumber();
if (PredFBB) dbgs()
<< "\tPredFBB:" << PredFBB->getNumber(););
// Even though this is a fall though case, we still can
// have a dual jump situation here with a CALL involved.
// For now simply avoid it.
if (IsDualJumpSecondCandidate(&*InstrToMove)) {
llvm_unreachable("Dual jumps with known?");
LLVM_DEBUG(dbgs() << "\tUnderimplemented dual jump formation.\n");
if (NeedCleanup)
CleanupBB->erase(InstrToMove);
return false;
}
if (!CurrentBB->isSuccessor(PreviousBB)) {
LLVM_DEBUG(dbgs() << "\tNon-successor fall through.\n");
if (NeedCleanup)
CleanupBB->erase(InstrToMove);
return false;
}
SpeculatedIns.insert(
std::make_pair(OriginalInstructionToMove, OriginBB));
LLVM_DEBUG(dbgs() << "\nSpeculatedInsToMove+FallThroughBB";
InstrToMove->dump());
// Create a temp copy.
InstrToMove = insertTempCopy(CurrentBB, TargetPacket, &*InstrToMove,
NeedCleanup);
NeedCleanup = true;
NeedToPredicate = false;
CleanupBB = CurrentBB;
LLVM_DEBUG(dbgs() << "\tUpdated BB:\n"; CurrentBB->dump());
}
}
}
// If we have reached Home, great.
// Original check should have verified that instruction could be added
// to the target packet, so here we do nothing for deps.
if (MIWH == backtrack.front()) {
LLVM_DEBUG(dbgs() << "\tHOME!\n");
break;
}
// Test if we can reorder the two MIs.
// The exception is when we are forming dual jumps - we can pull up
// dependent instruction to the last bundle of an immediate predecesor
// of the current BB if control flow permits it.
// In this special case we also need to update the bundle we are moving
// from.
if (!(MovingDependentOp && (MIWH == &*SourceLocation)) &&
!canReorderMIs(MIWH, &*InstrToMove)) {
if (NeedCleanup)
CleanupBB->erase(InstrToMove);
return false;
}
}
// We have previously tested this instruction, but has not updated the state
// for it. Do it now.
if (QII->isExtended(*InstrToMove) || QII->isConstExtended(*InstrToMove) ||
isJumpOutOfRange(&*InstrToMove)) {
if (!tryAllocateResourcesForConstExt(&*InstrToMove))
llvm_unreachable("Missed dependency test");
}
// Ok. We can safely move this instruction all the way up.
// We also potentially have a slot for it.
// During move original instruction could have changed (becoming predicated).
// Now try to place the final instance of it into the current packet.
LLVM_DEBUG(dbgs() << "\nWant to move ";
if (MovingDependentOp) dbgs() << "dependent op"; dbgs() << ": ";
InstrToMove->dump(); dbgs() << "To BB:\n"; HomeBB->dump();
dbgs() << "From BB:\n"; OriginBB->dump());
// Keep these two statistics separately.
if (!isDualJump)
HexagonNumPullUps++;
else
HexagonNumDualJumps++;
// This means we have not yet inserted the temp copy of InstrToMove
// in the target bundle. We are probably inside the same BB.
if (!NeedCleanup) {
InstrToMove =
insertTempCopy(HomeBB, TargetPacket, &*InstrToMove, NeedCleanup);
NeedCleanup = true;
}
// No problems detected. Add it.
// If we were adding InstrToMove to a single, not yet packetized
// instruction, we need to create bundle header for it before proceeding.
// Be carefull since endPacket also resets the DFA state.
if (!TargetPacket->isBundle()) {
LLVM_DEBUG(dbgs() << "\tForm a new bundle.\n");
finalizeBundle(*HomeBB, TargetPacket.getInstrIterator(),
std::next(InstrToMove));
LLVM_DEBUG(HomeBB->dump());
// Now we need to adjust pointer to the newly created packet header.
MachineBasicBlock::instr_iterator MII = TargetPacket.getInstrIterator();
MII--;
// Is it also on the way home?
for (unsigned i = 0; i < backtrack.size(); ++i)
if (backtrack[i] == &*TargetPacket)
backtrack[i] = &*MII;
// Is it where our next MI is pointing?
if (NextMI == TargetPacket)
NextMI = MII;
TargetPacket = MII;
}
// Move and Update Liveness info.
MoveAndUpdateLiveness(CurrentRegion, HomeBB, &*InstrToMove, MINeedToNewify,
DepReg, MovingDependentOp, OriginBB,
OriginalInstructionToMove, PredCond, SourceLocation,
TargetPacket, NextMI, backtrack);
LLVM_DEBUG(dbgs() << "\n______Updated______\n"; HomeBB->dump();
OriginBB->dump());
return true;
}
/// Verify that we respect CFG layout during pull-up.
bool HexagonGlobalSchedulerImpl::isBranchWithinRegion(
BasicBlockRegion *CurrentRegion, MachineInstr *MI) {
assert(MI && MI->isBranch() && "Missing call info");
MachineBasicBlock *MBB = MI->getParent();
LLVM_DEBUG(dbgs() << "\t[isBranchWithinRegion] BB(" << MBB->getNumber()
<< ") Branch instr:\t";
MI->dump());
// If there is only one successor, it is safe to pull.
if (MBB->succ_size() <= 1)
return true;
// If there are multiple successors (jump table), we should
// not allow pull up over this instruction.
if (MBB->succ_size() > 2)
return false;
MachineBasicBlock *NextRegionBB;
MachineBasicBlock *TBB, *FBB;
MachineInstr *FirstTerm = NULL;
MachineInstr *SecondTerm = NULL;
if (AnalyzeBBBranches(MBB, TBB, FirstTerm, FBB, SecondTerm)) {
LLVM_DEBUG(dbgs() << "\t\tAnalyzeBBBranches failed!\n");
return false;
}
// If there is no jump in this BB, it simply falls through.
if (!FirstTerm) {
LLVM_DEBUG(dbgs() << "\t\tNo FirstTerm\n");
return true;
} else if (QII->isEndLoopN(FirstTerm->getOpcode())) {
// We can easily analyze where endloop would take us
// but here it would be pointless either way since
// the region will not cross it.
LLVM_DEBUG(dbgs() << "\t\tEndloop terminator\n");
return false;
}
// On some occasions we see code like this:
// BB#142: derived from LLVM BB %init, Align 4 (16 bytes)
// Live Ins: %R17 %R18
// Predecessors according to CFG: BB#2
// EH_LABEL <MCSym=.Ltmp35>
// J2_jump <BB#3>, %PC<imp-def>
// Successors according to CFG: BB#3(1048575) BB#138(1)
// It breaks most assumptions about CFG layout, so untill we know
// the source of it, let's have a safeguard.
if (MBB->succ_size() > 1 && !TII->isPredicated(*FirstTerm) &&
!QII->isNewValueJump(*FirstTerm)) {
LLVM_DEBUG(dbgs() << "\t\tBadly formed BB.\n");
return false;
}
LLVM_DEBUG(dbgs() << "\t\tFirstTerm: "; FirstTerm->dump());
LLVM_DEBUG(dbgs() << "\t\tSecondTerm: "; if (SecondTerm) SecondTerm->dump();
else dbgs() << "None\n";);
// All cases where there is only one branch in BB are OK to proceed.
if (!SecondTerm)
return true;
assert(!QII->isEndLoopN(SecondTerm->getOpcode()) && "Found endloop.");
// Find next BB in this region - if there is none, we will likely
// stop pulling in the next check outside of this function.
// This largely is don't care.
NextRegionBB = CurrentRegion->findNextMBB(MBB);
if (!NextRegionBB) {
LLVM_DEBUG(dbgs() << "\t\tNo next BB in the region...\n");
return true;
}
LLVM_DEBUG(dbgs() << "\t\tNextRegionBB(" << NextRegionBB->getNumber()
<< ")\n");
assert(TBB && "Corrupt BB layout");
// This means we are trying to pull into a packet _before_ the first
// branch in the MBB.
if (MI == FirstTerm) {
LLVM_DEBUG(dbgs() << "\t\tTBB(" << TBB->getNumber()
<< ") NextBB in the region(" << NextRegionBB->getNumber()
<< ")\n");
return (TBB == NextRegionBB);
}
assert(FBB && "Corrupt BB layout");
// This means we are trying to pull into the packet _after_ first branch,
// and it is OK if we pull from the second branch target.
// This pull is always speculative.
if ((MI != SecondTerm)) {
LLVM_DEBUG(dbgs() << "\t\tDual terminator not matching SecondTerm.\n");
return false;
}
// Analyze the second branch in the BB.
LLVM_DEBUG(dbgs() << "\t\tFBB(" << FBB->getNumber()
<< ") NextBB in the region(" << NextRegionBB->getNumber()
<< ")\n");
return (FBB == NextRegionBB);
}
/// Check if a given instruction is:
/// - a jump to a distant target
/// - that exceeds its immediate range
/// If both conditions are true, it requires constant extension.
bool HexagonGlobalSchedulerImpl::isJumpOutOfRange(MachineInstr *UnCond,
MachineInstr *Cond) {
if (!UnCond || !UnCond->isBranch())
return false;
MachineBasicBlock *UnCondBB = UnCond->getParent();
MachineBasicBlock *CondBB = Cond->getParent();
MachineInstr *FirstTerm = &*(CondBB->getFirstInstrTerminator());
// This might be worth an assert.
if (FirstTerm == &*CondBB->instr_end())
return false;
unsigned InstOffset = BlockToInstOffset[UnCondBB];
unsigned Distance = 0;
// To save time, estimate exact position of a branch instruction
// as one at the end of the UnCondBB.
// Number of instructions times typical instruction size.
InstOffset += (QII->nonDbgBBSize(UnCondBB) * HEXAGON_INSTR_SIZE);
MachineBasicBlock *TBB = NULL, *FBB = NULL;
SmallVector<MachineOperand, 4> CondList;
// Find the target of the unconditional branch in UnCondBB, which is returned
// in TBB. Then use the CondBB to extract the FirsTerm. We desire to replace
// the branch target in FirstTerm with the branch location from the UnCondBB,
// provided it is within the distance of the opcode in FirstTerm.
if (QII->analyzeBranch(*UnCondBB, TBB, FBB, CondList, false))
// Could not analyze it. give up.
return false;
if (TBB && (Cond == FirstTerm)) {
Distance =
(unsigned)std::abs((long long)InstOffset - BlockToInstOffset[TBB]) +
SafetyBuffer;
return !QII->isJumpWithinBranchRange(*FirstTerm, Distance);
}
return false;
}
// findBundleAndBranch returns the branch instruction and the
// bundle which contains it. Null is returned if not found.
MachineInstr *HexagonGlobalSchedulerImpl::findBundleAndBranch(
MachineBasicBlock *BB, MachineBasicBlock::iterator &Bundle) {
// Find the conditional branch out of BB.
if (!BB)
return NULL;
MachineInstr *CondBranch = NULL;
Bundle = BB->end();
for (MachineBasicBlock::instr_iterator MII = BB->getFirstInstrTerminator(),
MBBEnd = BB->instr_end();
MII != MBBEnd; ++MII) {
MachineInstr *MI = &*MII;
if (MII->isConditionalBranch()) {
CondBranch = MI;
}
}
if (!CondBranch)
return NULL;
MachineBasicBlock::instr_iterator MII = CondBranch->getIterator();
if (!MII->isBundled())
return NULL;
// Find bundle header.
for (--MII; MII->isBundled(); --MII)
if (MII->isBundle()) {
Bundle = MII;
break;
}
return CondBranch;
}
// pullUpPeelBBLoop
// A single BB loop with a register copy at the beginning in its
// own bundle, benefits from eliminating the extra bundle. We do
// this by predicating the register copy in the predecessor BB, and
// again in the last bundle of the loop.
bool HexagonGlobalSchedulerImpl::pullUpPeelBBLoop(MachineBasicBlock *PredBB,
MachineBasicBlock *LoopBB) {
if (!AllowBBPeelPullUp)
return false;
if (!LoopBB || !PredBB)
return false;
// We consider single BB loops only. Check for it here.
if (LoopBB->isEHPad() || LoopBB->hasAddressTaken())
return false;
if (LoopBB->succ_size() != 2)
return false;
if (LoopBB->pred_size() != 2)
return false;
// Make sure one of the successors and one of the predecssors is to self.
if (!(LoopBB->isSuccessor(LoopBB) && LoopBB->isPredecessor(LoopBB)))
return false;
// Find the none self successor block. We know we only have 2 successors.
MachineBasicBlock *SuccBB = NULL;
for (MachineBasicBlock::succ_iterator SI = LoopBB->succ_begin(),
SE = LoopBB->succ_end();
SI != SE; ++SI)
if (*SI != LoopBB) {
SuccBB = *SI;
break;
}
if (!SuccBB)
return false;
// Find the conditional branch and its bundle inside PredBB.
MachineBasicBlock::iterator PredBundle;
MachineInstr *PredCondBranch = NULL;
PredCondBranch = findBundleAndBranch(PredBB, PredBundle);
if (!PredCondBranch)
return false;
if (PredBundle == PredBB->end())
return false;
LLVM_DEBUG(dbgs() << "PredBB's Branch: ");
LLVM_DEBUG(dbgs() << *PredCondBranch);
// Look for leading reg copy as single bundle and make sure its live in.
MachineBasicBlock::instr_iterator FMI = LoopBB->instr_begin();
// Skip debug instructions.
while (FMI->isDebugInstr())
FMI++;
MachineInstr *RegMI = &*FMI;
if (RegMI->isBundle())
return false;
int TfrOpcode = RegMI->getOpcode();
if (TfrOpcode != Hexagon::A2_tfr && TfrOpcode != Hexagon::A2_tfr)
return false;
if (!(RegMI->getOperand(0).isReg() && RegMI->getOperand(1).isReg()))
return false;
unsigned InLoopReg = RegMI->getOperand(1).getReg();
if (!LoopBB->isLiveIn(InLoopReg))
return false;
// Create a region to pass to ResourcesAvailableInBundle.
BasicBlockRegion PUR(BasicBlockRegion(TII, QRI, PredBB));
PUR.addBBtoRegion(LoopBB);
PUR.addBBtoRegion(SuccBB);
// Make sure we have space in PredBB's last bundle.
if (!ResourcesAvailableInBundle(&PUR, PredBundle))
return false;
SmallVector<MachineInstr *, HEXAGON_PACKET_SIZE> PredBundlePkt(
CurrentState.HomeBundle);
// Find condition to use for predicating the reg copy into PredBB.
MachineBasicBlock *TBB = NULL, *FBB = NULL;
SmallVector<MachineOperand, 4> Cond;
if (QII->analyzeBranch(*PredBB, TBB, FBB, Cond, false))
return false;
if (Cond.empty())
return false;
// Find condition to use for predicating the reg copy at the end of LoopBB.
MachineBasicBlock *LTBB = NULL, *LFBB = NULL;
SmallVector<MachineOperand, 4> LCond;
if (QII->analyzeBranch(*LoopBB, LTBB, LFBB, LCond, false))
return false;
if (LCond.empty())
return false;
// Move predicated reg copy to previous BB's last bundle.
if (!TII->isPredicable(*RegMI))
return false;
MachineInstr *InstrToMove =
&*insertTempCopy(PredBB, PredBundle, RegMI, false);
if (!canAddMIToThisPacket(InstrToMove, PredBundlePkt)) {
PredBB->erase_instr(InstrToMove);
return false;
}
if (!TII->PredicateInstruction(*InstrToMove, Cond)) {
// Failed to predicate the copy reg.
PredBB->erase_instr(InstrToMove);
return false;
}
// Can we newify this instruction?
unsigned DepReg = 0;
if (NeedToNewify(InstrToMove->getIterator(), &DepReg, &*PredBundle) &&
!isNewifiable(InstrToMove->getIterator(), DepReg, &*PredBundle)) {
PredBB->erase_instr(InstrToMove);
return false;
}
// Newify it, and then undo it if we determine we are using a .old.
int NewOpcode = QII->getDotNewPredOp(*InstrToMove, MBPI);
// Undo newify if we have a non .new predicated jump we are matching.
if (!QII->isDotNewInst(*PredCondBranch))
NewOpcode = QII->getDotOldOp(*InstrToMove);
NewOpcode = QII->getInvertedPredicatedOpcode(NewOpcode);
// Properly set the opcode on the new hoisted reg copy instruction.
InstrToMove->setDesc(QII->get(NewOpcode));
if (!incrementalAddToPacket(*InstrToMove)) {
PredBB->erase_instr(InstrToMove);
return false;
}
// Find the conditional branch and its bundle for LoopBB.
MachineBasicBlock::iterator LoopBundle;
MachineInstr *LoopCondBranch = NULL;
LoopCondBranch = findBundleAndBranch(LoopBB, LoopBundle);
if (!LoopCondBranch)
return false;
if (LoopBundle == LoopBB->end())
return false;
LLVM_DEBUG(dbgs() << "LoopBB's Branch: ");
LLVM_DEBUG(dbgs() << *LoopCondBranch);
// Make sure we have space in LoopBB's last bundle.
if (!ResourcesAvailableInBundle(&PUR, LoopBundle))
return false;
SmallVector<MachineInstr *, HEXAGON_PACKET_SIZE> LoopBundlePkt(
CurrentState.HomeBundle);
// Move predicated reg copy to last bundle of LoopBB.
MachineInstr *InstrToSink =
&*insertTempCopy(LoopBB, LoopBundle, RegMI, false);
if (!canAddMIToThisPacket(InstrToSink, LoopBundlePkt)) {
// Get rid of previous instruction as well.
PredBB->erase_instr(InstrToMove);
LoopBB->erase_instr(InstrToSink);
return false;
}
if (!TII->PredicateInstruction(*InstrToSink, LCond)) {
// Get rid of previous instruction as well.
PredBB->erase_instr(InstrToMove);
LoopBB->erase_instr(InstrToSink);
return false;
}
// Can we newify this instruction?
if (NeedToNewify(InstrToSink->getIterator(), &DepReg, &*LoopBundle) &&
!isNewifiable(InstrToSink->getIterator(), DepReg, &*LoopBundle)) {
// Get rid of previous instruction as well.
PredBB->erase_instr(InstrToMove);
PredBB->erase_instr(InstrToSink);
return false;
}
NewOpcode = QII->getDotNewPredOp(*InstrToSink, MBPI);
// Undo newify if we have a non .new predicated jump we are matching.
if (!QII->isDotNewInst(*LoopCondBranch))
NewOpcode = QII->getDotOldOp(*InstrToSink);
InstrToSink->setDesc(QII->get(NewOpcode));
if (!incrementalAddToPacket(*InstrToSink)) {
// Get rid of previous instruction as well.
PredBB->erase_instr(InstrToMove);
LoopBB->erase_instr(InstrToSink);
return false;
}
// Remove old instruction.
LoopBB->erase_instr(RegMI);
// Set loop alignment to 32.
LoopBB->setAlignment(llvm::Align(32));
LLVM_DEBUG(dbgs() << "Peeled Single BBLoop copy\n");
LLVM_DEBUG(dbgs() << *InstrToMove);
LLVM_DEBUG(dbgs() << *InstrToSink);
LLVM_DEBUG(dbgs() << *PredBB);
LLVM_DEBUG(dbgs() << *LoopBB);
LLVM_DEBUG(dbgs() << *SuccBB);
LLVM_DEBUG(dbgs() << "--- BBLoop ---\n\n");
return true;
}
bool HexagonGlobalSchedulerImpl::performPullUpCFG(MachineFunction &Fn) {
const Function &F = Fn.getFunction();
// Check for single-block functions and skip them.
if (std::next(F.begin()) == F.end())
return false;
bool Changed = false;
LLVM_DEBUG(dbgs() << "****** PullUpCFG **************\n");
// Loop over all basic blocks, asking if 3 consecutive blocks are
// the jump opportunity.
MachineBasicBlock *PrevBlock = NULL;
MachineBasicBlock *JumpBlock = NULL;
for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end(); MBB != MBBe;
++MBB) {
MachineBasicBlock *FallBlock = &*MBB;
if (PrevBlock && JumpBlock) {
Changed |= pullUpPeelBBLoop(PrevBlock, JumpBlock);
}
PrevBlock = JumpBlock;
JumpBlock = FallBlock;
}
return Changed;
}
void HexagonGlobalSchedulerImpl::GenUseDefChain(MachineFunction &Fn) {
std::vector<unsigned> Defs;
std::vector<unsigned> Uses;
for (MachineFunction::iterator MBBIter = Fn.begin(); MBBIter != Fn.end();
++MBBIter) {
for (MachineBasicBlock::instr_iterator MIter = MBBIter->instr_begin();
MIter != MBBIter->instr_end(); ++MIter) {
if (MIter->isBundle() || MIter->isDebugInstr())
continue;
LLVM_DEBUG(dbgs() << "\n\nInserted Ins:"; MIter->dump());
MIUseDefSet(&*MIter, Defs, Uses);
LLVM_DEBUG(dbgs() << "\n\tDefs:";
for (unsigned i = 0; i < Defs.size(); ++i) dbgs()
<< printReg(Defs[i], QRI) << ",");
LLVM_DEBUG(dbgs() << "\n\tUses:";
for (unsigned i = 0; i < Uses.size(); ++i) dbgs()
<< printReg(Uses[i], QRI) << ",");
MIDefSet[&*MIter] = Defs;
MIUseSet[&*MIter] = Uses;
}
}
}
// optimizeBranching -
// 1. A conditional-jump transfers control to a BB with
// jump as the only instruction.
// if(p0) jump t1
// // ...
// t1: jump t2
// 2. When a BB with a single conditional jump, jumps to succ-of-succ and
// falls-through BB with only jump instruction.
// { if(p0) jump t1 }
// { jump t2 }
// t1: { ... }
MachineBasicBlock *HexagonGlobalSchedulerImpl::optimizeBranches(
MachineBasicBlock *MBB, MachineBasicBlock *TBB, MachineInstr *FirstTerm,
MachineBasicBlock *FBB) {
LLVM_DEBUG(dbgs() << "\n\t\t[optimizeBranching]\n");
if ((TBB == MBB) || (FBB == MBB))
LLVM_DEBUG(dbgs() << "Cannot deal with loops in BB#" << MBB->getNumber(););
// LLVM_DEBUG(dbgs() << "\n\t\tTBBMIb:"; MII->dump(););
// { if(p) jump t1; }
// t1: { jump t2; }
// --> { if(p) jump t2
// remove t1: { jump t2; }, if it's address is not taken/not a landing pad.
if (QII->nonDbgBBSize(TBB) == 1) {
MachineInstr *TBBMIb = &*TBB->getFirstNonDebugInstr();
if (TBBMIb->getOpcode() == Hexagon::J2_jump &&
TBBMIb->getOperand(0).isMBB()) {
MachineBasicBlock *NewTarget = TBBMIb->getOperand(0).getMBB();
if (TBB == NewTarget) // Infinite loop.
return NULL;
LLVM_DEBUG(dbgs() << "\nSuboptimal branching in TBB");
// Check if the jump in the last instruction is within range.
int64_t InstOffset =
BlockToInstOffset.find(MBB)->second + QII->nonDbgBBSize(MBB) * 4;
unsigned Distance = (unsigned)std::abs(
InstOffset - BlockToInstOffset.find(NewTarget)->second);
if (!QII->isJumpWithinBranchRange(*FirstTerm, Distance)) {
LLVM_DEBUG(dbgs() << "\nUnconditional jump target:" << Distance
<< " out of range.");
return NULL;
}
// We need to make sure that the TBB is _not_ also a target for another
// branch. This is suboptimal since theoretically we can update both
// branches.
if (!TBB->hasAddressTaken() && !TBB->isEHPad() && TBB->pred_size() == 1) {
updatePredecessors(*TBB, NewTarget);
// TBB has only one successor since only one J2_jump instr.
TBB->removeSuccessor(TBB->succ_begin());
TBBMIb->removeFromParent();
if (!TBB->empty()) {
// There are only debug instructions in TBB now. Move them to
// the beginning of NewTarget.
NewTarget->splice(NewTarget->getFirstNonPHI(), TBB, TBB->begin(),
TBB->end());
}
return TBB;
} else {
MBB->ReplaceUsesOfBlockWith(TBB, NewTarget);
return NULL;
}
}
}
// { if(p) jump t1; } may contain more instructions
// { jump t2; } --only one instruction
// t1: {...}
// TBB is layout successor of FBB, then we can change the branch target
// for conditional jump and invert the predicate to remove jump t2.
// { if(!p) jump t2; }
// t1: {...}
if (QII->nonDbgBBSize(FBB) == 1) {
MachineInstr *FBBMIb = &*FBB->getFirstNonDebugInstr();
if (FBBMIb->getOpcode() == Hexagon::J2_jump &&
FBBMIb->getOperand(0).isMBB()) {
MachineBasicBlock *NewTarget = FBBMIb->getOperand(0).getMBB();
if (FBB->hasAddressTaken() || FBB->isEHPad() ||
!FBB->isLayoutSuccessor(TBB) || (FBB == NewTarget /*Infinite loop*/))
return NULL;
LLVM_DEBUG(dbgs() << "\nSuboptimal branching in FBB");
// Check if the jump in the last instruction is within range.
int64_t InstOffset =
BlockToInstOffset.find(MBB)->second + QII->nonDbgBBSize(MBB) * 4;
unsigned Distance = (unsigned)std::abs(
InstOffset - BlockToInstOffset.find(NewTarget)->second);
if (!QII->isJumpWithinBranchRange(*FirstTerm, Distance)) {
LLVM_DEBUG(dbgs() << "\nUnconditional jump target:" << Distance
<< " out of range.");
return NULL;
}
if (!QII->invertAndChangeJumpTarget(*FirstTerm, NewTarget))
return NULL;
LLVM_DEBUG(dbgs() << "\nNew instruction:"; FirstTerm->dump(););
updatePredecessors(*FBB, NewTarget);
// Only one successor remains for FBB
FBB->removeSuccessor(FBB->succ_begin());
FBBMIb->removeFromParent();
return FBB;
}
}
return NULL;
}
// performExposedOptimizations -
// look for optimization opportunities after pullup.
// e.g. jump to adjacent targets
bool HexagonGlobalSchedulerImpl::performExposedOptimizations(
MachineFunction &Fn) {
// Check for single-block functions and skip them.
if (std::next(Fn.getFunction().begin()) == Fn.getFunction().end())
return true;
LLVM_DEBUG(dbgs() << "\n\t\t[performExposedOptimizations]\n");
// Erasing the empty basic blocks formed during pullup.
std::vector<MachineBasicBlock *>::iterator ebb = EmptyBBs.begin();
while (ebb != EmptyBBs.end()) {
assert(IsEmptyBlock(*ebb) && "Pullup inserted packets into an empty BB");
LLVM_DEBUG(dbgs() << "Removing BB(" << (*ebb)->getNumber()
<< ") from parent.\n");
(*ebb)->eraseFromParent();
++ebb;
}
MachineBasicBlock *TBB = NULL, *FBB = NULL;
MachineInstr *FirstTerm = NULL, *SecondTerm = NULL;
SmallVector<MachineBasicBlock *, 4> Erase;
for (MachineBasicBlock &MBB : Fn) {
if (MBB.succ_size() > 2 ||
AnalyzeBBBranches(&MBB, TBB, FirstTerm, FBB, SecondTerm)) {
LLVM_DEBUG(dbgs() << "\nAnalyzeBBBranches failed in BB#"
<< MBB.getNumber() << "\n";);
continue;
}
if (FirstTerm && QII->isCompoundBranchInstr(*FirstTerm))
continue;
if (TBB && FirstTerm &&
removeRedundantBranches(&MBB, TBB, FirstTerm, FBB, SecondTerm)) {
LLVM_DEBUG(dbgs() << "\nRemoved redundant branches in BB#"
<< MBB.getNumber(););
continue;
}
if (FirstTerm && SecondTerm &&
optimizeDualJumps(&MBB, TBB, FirstTerm, FBB, SecondTerm)) {
LLVM_DEBUG(dbgs() << "\nRemoved dual jumps in in BB#"
<< MBB.getNumber(););
continue;
}
if (TBB && FBB && FirstTerm && !SecondTerm) {
MachineBasicBlock *MBBToErase =
optimizeBranches(&MBB, TBB, FirstTerm, FBB);
if (MBBToErase) {
assert(IsEmptyBlock(MBBToErase) && "Erasing non-empty BB");
Erase.push_back(MBBToErase);
LLVM_DEBUG(dbgs() << "\nOptimized jump from BB#" << MBB.getNumber());
}
}
}
for (MachineBasicBlock *MBB : Erase)
MBB->eraseFromParent();
return false;
}
// 1. Remove jump to the layout successor.
// 2. Remove multiple (dual) jump to the same target.
bool HexagonGlobalSchedulerImpl::removeRedundantBranches(
MachineBasicBlock *MBB, MachineBasicBlock *TBB, MachineInstr *FirstTerm,
MachineBasicBlock *FBB, MachineInstr *SecondTerm) {
bool Analyzed = false;
LLVM_DEBUG(dbgs() << "\n\t\t[removeRedundantBranches]\n");
MachineInstr *Head = NULL, *ToErase = NULL;
if (!FBB && (FirstTerm->getOpcode() == Hexagon::J2_jump) &&
MBB->isLayoutSuccessor(TBB)) {
// Jmp layout_succ_basic_block <-- Remove
LLVM_DEBUG(
dbgs() << "\nRemoving Uncond. jump to the layout successor in BB#"
<< MBB->getNumber());
ToErase = FirstTerm;
} else if (SecondTerm && (TBB == FBB) &&
(SecondTerm->getOpcode() == Hexagon::J2_jump)) {
// If both branching instructions in same packet or are consecutive.
// Jmp_c t1 <-- Remove
// Jmp t1
// @Note: If they are in different packets or if they are separated
// by packet(s), this opt. cannot be done.
MachineBasicBlock::instr_iterator FirstTermIter = FirstTerm->getIterator();
MachineBasicBlock::instr_iterator SecondTermIter =
SecondTerm->getIterator();
if (++FirstTermIter == SecondTermIter) {
LLVM_DEBUG(dbgs() << "\nRemoving multiple branching to same target in BB#"
<< MBB->getNumber());
// TODO: This might make the `p' register assignment instruction dead.
// and can be removed.
ToErase = FirstTerm;
}
} else if (SecondTerm && (SecondTerm->getOpcode() == Hexagon::J2_jump) &&
FBB && MBB->isLayoutSuccessor(FBB)) {
// Jmp_c t1
// Jmp layout_succ_basic_block <-- Remove
LLVM_DEBUG(dbgs() << "\nRemoving fall through branch in BB#"
<< MBB->getNumber());
ToErase = SecondTerm;
} else if (SecondTerm && QII->PredOpcodeHasJMP_c(SecondTerm->getOpcode()) &&
MBB->isLayoutSuccessor(getBranchDestination(SecondTerm))) {
// Jmp_c t1
// Jmp_c layout_succ_basic_block <-- Remove
// In this case AnalyzeBBBranches might assign FBB to some other BB.
// So using the jump target of SecondTerm to check.
LLVM_DEBUG(dbgs() << "\nRemoving Cond. jump to the layout successor in BB#"
<< MBB->getNumber());
ToErase = SecondTerm;
}
// Remove the instruction from the BB
if (ToErase) {
if (ToErase->isBundled()) {
Head = &*getBundleStart(ToErase->getIterator());
ToErase->eraseFromBundle();
UpdateBundle(Head);
} else
ToErase->eraseFromParent();
Analyzed = true;
}
return Analyzed;
}
// ----- convert
// p = <expr>
// if(p) jump layout_succ_basic_block
// jump t
// ----- to
// p = <expr>
// if(!p) jump t
// for now only looking at the dual jump
bool HexagonGlobalSchedulerImpl::optimizeDualJumps(MachineBasicBlock *MBB,
MachineBasicBlock *TBB,
MachineInstr *FirstTerm,
MachineBasicBlock *FBB,
MachineInstr *SecondTerm) {
LLVM_DEBUG(dbgs() << "\n******* optimizeDualJumps *******");
bool Analyzed = false;
if (QII->PredOpcodeHasJMP_c(FirstTerm->getOpcode()) &&
(SecondTerm->getOpcode() == Hexagon::J2_jump)) {
if (TBB == FBB) {
LLVM_DEBUG(dbgs() << "\nBoth successors are the same.");
return Analyzed;
}
// Do not optimize for dual jumps if this MBB
// contains a speculatively pulled-up instruction.
// A speculated instruction is more likely to be at the end of MBB.
MachineBasicBlock::reverse_instr_iterator SII = MBB->instr_rbegin();
while (SII != MBB->instr_rend()) {
MachineInstr *SI = &*SII;
std::map<MachineInstr *, MachineBasicBlock *>::iterator MIMoved;
MIMoved = SpeculatedIns.find(SI);
if ((MIMoved != SpeculatedIns.end()) &&
(MIMoved->second != SI->getParent())) {
return Analyzed;
}
++SII;
}
LLVM_DEBUG(dbgs() << "\nCandidate for jump optimization in BB("
<< MBB->getNumber() << ").\n";);
// Predicated jump to layout successor followed by an unconditional jump.
if (MBB->isLayoutSuccessor(TBB)) {
// Check if the jump in the last instruction is within range.
int64_t InstOffset =
BlockToInstOffset.find(&*MBB)->second + QII->nonDbgBBSize(MBB) * 4;
unsigned Distance =
(unsigned)std::abs(InstOffset - BlockToInstOffset.find(FBB)->second) +
SafetyBuffer;
if (!QII->isJumpWithinBranchRange(*FirstTerm, Distance)) {
LLVM_DEBUG(dbgs() << "\nUnconditional jump target:" << Distance
<< " out of range.");
return Analyzed;
}
// modify the second last -predicated- instruction (sense and target)
LLVM_DEBUG(dbgs() << "\nFirst Instr:" << *FirstTerm;);
LLVM_DEBUG(dbgs() << "\nSecond Instr:" << *SecondTerm;);
LLVM_DEBUG(dbgs() << "\nOld Succ BB(" << TBB->getNumber() << ").";);
QII->invertAndChangeJumpTarget(*FirstTerm, FBB);
LLVM_DEBUG(dbgs() << "\nNew First Instruction:" << *FirstTerm;);
// unbundle if there is only one instruction left
MachineInstr *SecondHead, *FirstHead;
FirstHead = FirstTerm->isBundled()
? &*getBundleStart(FirstTerm->getIterator())
: nullptr;
SecondHead = SecondTerm->isBundled()
? &*getBundleStart(SecondTerm->getIterator())
: nullptr;
// 1. Both unbundled, 2. FirstTerm inside bundle, second outside.
if (!SecondHead)
SecondTerm->eraseFromParent();
else if (!FirstHead) {
// 3. FirstHead outside, SecondHead inside.
SecondTerm->eraseFromBundle();
UpdateBundle(SecondHead);
} else if (FirstHead == SecondHead) {
// 4. Both are in the same bundle
assert((FirstHead && SecondHead) && "Unbundled Instruction");
SecondTerm->eraseFromBundle();
if (SecondHead->getBundleSize() < 2)
UpdateBundle(SecondHead);
} else {
// 5. Both are in different bundles
SecondTerm->eraseFromBundle();
UpdateBundle(SecondHead);
}
Analyzed = true;
}
}
return Analyzed;
}
/// Are there any resources left in this bundle?
bool HexagonGlobalSchedulerImpl::ResourcesAvailableInBundle(
BasicBlockRegion *CurrentRegion,
MachineBasicBlock::iterator &TargetPacket) {
MachineBasicBlock::instr_iterator MII = TargetPacket.getInstrIterator();
// If this is a single instruction, form new packet around it.
if (!TargetPacket->isBundle()) {
if (ignoreInstruction(&*MII) || isSoloInstruction(*MII))
return false;
// Before we begin, we need to make sure that we do not
// look at an unconditional jump outside the current region.
if (MII->isBranch() && !isBranchWithinRegion(CurrentRegion, &*MII))
return false;
// Build up state for this new packet.
// Note, we cannot create a bundle header for it,
// so this "bundle" only exist in DFA state, and not in code.
initPacketizerState();
ResourceTracker->clearResources();
CurrentState.addHomeLocation(MII);
return incrementalAddToPacket(*MII);
}
MachineBasicBlock::instr_iterator End = MII->getParent()->instr_end();
// Build up state for this packet.
initPacketizerState();
ResourceTracker->clearResources();
CurrentState.addHomeLocation(MII);
for (++MII; MII != End && MII->isInsideBundle(); ++MII) {
if (MII->getOpcode() == TargetOpcode::DBG_VALUE ||
MII->getOpcode() == TargetOpcode::IMPLICIT_DEF ||
MII->getOpcode() == TargetOpcode::CFI_INSTRUCTION || MII->isEHLabel())
continue;
// Before we begin, we need to make sure that we do not
// look at an unconditional jump outside the current region.
// TODO: See if we can profit from handling this kind of cases:
// B#15: derived from LLVM BB %if.then22
// Predecessors according to CFG: BB#13
// BUNDLE %PC<imp-def>, %P2<imp-use,kill>
// * J2_jumpf %P2<kill,internal>, <BB#17>, %PC<imp-def>; flags:
// * J2_jump <BB#18>, %PC<imp-def>; flags:
// Successors according to CFG: BB#18(62) BB#17(62)
// Curently we do not allow them.
if (MII->isBranch() && !isBranchWithinRegion(CurrentRegion, &*MII))
return false;
if (!incrementalAddToPacket(*MII))
return false;
}
return ResourceTracker->canReserveResources(*Nop);
}
/// Symmetrical. See if these two instructions are fit for compound pair.
bool HexagonGlobalSchedulerImpl::isCompoundPair(MachineInstr *MIa,
MachineInstr *MIb) {
enum HexagonII::CompoundGroup MIaG = QII->getCompoundCandidateGroup(*MIa),
MIbG = QII->getCompoundCandidateGroup(*MIb);
// We have two candidates - check that this is the same register
// we are talking about.
unsigned Opcb = MIb->getOpcode();
if (MIaG == HexagonII::HCG_C && MIbG == HexagonII::HCG_A &&
(Opcb == Hexagon::A2_tfr || Opcb == Hexagon::A2_tfrsi))
return true;
unsigned Opca = MIa->getOpcode();
if (MIbG == HexagonII::HCG_C && MIaG == HexagonII::HCG_A &&
(Opca == Hexagon::A2_tfr || Opca == Hexagon::A2_tfrsi))
return true;
return (((MIaG == HexagonII::HCG_A && MIbG == HexagonII::HCG_B) ||
(MIbG == HexagonII::HCG_A && MIaG == HexagonII::HCG_B)) &&
(MIa->getOperand(0).getReg() == MIb->getOperand(0).getReg()));
}
// This is a weird situation when BB conditionally branches + falls through
// to layout successor. \ref bug17792
inline bool HexagonGlobalSchedulerImpl::multipleBranchesFromToBB(
MachineBasicBlock *BB) const {
if (BB->succ_size() != 1)
return false;
SmallVector<MachineInstr *, 2> Jumpers = QII->getBranchingInstrs(*BB);
return ((Jumpers.size() == 1) && !Jumpers[0]->isUnconditionalBranch());
}
/// Gather a worklist of MaxCandidates pull-up candidates.
/// Compute relative cost.
bool HexagonGlobalSchedulerImpl::findPullUpCandidates(
MachineBasicBlock::iterator &WorkPoint,
MachineBasicBlock::iterator &FromHere,
std::vector<MachineInstr *> &backtrack, unsigned MaxCandidates = 1) {
const HexagonInstrInfo *QII = (const HexagonInstrInfo *)TII;
MachineBasicBlock *FromThisBB = FromHere->getParent();
bool MovingDependentOp = false;
signed CostBenefit = 0;
// Do not collect more than that many candidates.
if (CurrentState.haveCandidates() >= MaxCandidates)
return false;
LLVM_DEBUG(dbgs() << "\n\tTry from BB(" << FromThisBB->getNumber() << "):\n";
DumpPacket(FromHere.getInstrIterator()));
if (FromHere->isBundle()) {
MachineBasicBlock::instr_iterator MII = FromHere.getInstrIterator();
for (++MII; MII != FromThisBB->instr_end() && MII->isInsideBundle();
++MII) {
if (MII->isDebugInstr())
continue;
LLVM_DEBUG(dbgs() << "\tCandidate from BB("
<< MII->getParent()->getNumber() << "): ";
MII->dump());
// See if this instruction could be moved.
if (!canThisMIBeMoved(&*MII, WorkPoint, MovingDependentOp, CostBenefit))
continue;
MachineBasicBlock::instr_iterator InstrToMove = MII;
if (canAddMIToThisPacket(&*InstrToMove, CurrentState.HomeBundle)) {
CostBenefit -= (backtrack.size() * 4);
// Prefer instructions in empty packets.
CostBenefit += (PacketSize - nonDbgBundleSize(FromHere)) * 2;
// Prefer Compares.
if (MII->isCompare())
CostBenefit += 10;
// Check duplex conditions;
for (unsigned i = 0; i < CurrentState.HomeBundle.size(); i++) {
if (QII->isDuplexPair(*CurrentState.HomeBundle[i], *MII)) {
LLVM_DEBUG(dbgs() << "\tGot real Duplex (bundle).\n");
CostBenefit += 20;
}
if (isCompoundPair(CurrentState.HomeBundle[i], &*MII)) {
LLVM_DEBUG(dbgs() << "\tGot compound (bundle).\n");
CostBenefit += 40;
}
}
// Create a record for this location.
CurrentState.addPullUpCandidate(InstrToMove, WorkPoint, backtrack,
MovingDependentOp, CostBenefit);
} else
LLVM_DEBUG(dbgs() << "\tNo resources in the target packet.\n");
}
}
// This is a standalone instruction.
// First see if this MI can even be moved. Cost model for a single instruction
// should be rather different from moving something out of a bundle.
else if (canThisMIBeMoved(&*FromHere, WorkPoint, MovingDependentOp,
CostBenefit)) {
MachineBasicBlock::instr_iterator InstrToMove = FromHere.getInstrIterator();
if (canAddMIToThisPacket(&*InstrToMove, CurrentState.HomeBundle)) {
CostBenefit -= (backtrack.size() * 4);
// Prefer Compares.
if (InstrToMove->isCompare())
CostBenefit += 10;
// It is better to pull a single instruction in to a bundle - save
// a cycle immediately.
CostBenefit += 10;
// Search for duplex match.
for (unsigned i = 0; i < CurrentState.HomeBundle.size(); i++) {
if (QII->isDuplexPair(*CurrentState.HomeBundle[i], *InstrToMove)) {
LLVM_DEBUG(dbgs() << "\tGot real Duplex (single).\n");
CostBenefit += 30;
}
if (isCompoundPair(CurrentState.HomeBundle[i], &*InstrToMove)) {
LLVM_DEBUG(dbgs() << "\tGot compound (single).\n");
CostBenefit += 50;
}
}
// Create a record for this location.
CurrentState.addPullUpCandidate(InstrToMove, WorkPoint, backtrack,
MovingDependentOp, CostBenefit);
} else
LLVM_DEBUG(dbgs() << "\tNo resources for single in the target packet.\n");
}
return true;
}
/// Try to move a candidate MI.
/// The move can destroy all iterator system, so we have to drag them
/// around to keep them up to date.
bool HexagonGlobalSchedulerImpl::tryMultipleInstructions(
MachineBasicBlock::iterator &RetVal, /* output parameter */
std::vector<BasicBlockRegion *>::iterator &CurrentRegion,
MachineBasicBlock::iterator &NextMI,
MachineBasicBlock::iterator &ToThisBBEnd,
MachineBasicBlock::iterator &FromThisBBEnd, bool PathInRegion) {
MachineBasicBlock::instr_iterator MII;
MachineBasicBlock::iterator WorkPoint;
bool MovingDependentOp = false;
std::vector<MachineInstr *> backtrack;
LLVM_DEBUG(dbgs() << "\n\tTry Multiple candidates: \n");
std::sort(CurrentState.PullUpCandidates.begin(),
CurrentState.PullUpCandidates.end(), PullUpCandidateSorter());
LLVM_DEBUG(CurrentState.dump());
// Iterate through candidates in sorted order.
for (SmallVector<PullUpCandidate *, 4>::iterator
I = CurrentState.PullUpCandidates.begin(),
E = CurrentState.PullUpCandidates.end();
I != E; ++I) {
(*I)->populate(MII, WorkPoint, backtrack, MovingDependentOp);
MachineBasicBlock *FromThisBB = MII->getParent();
MachineBasicBlock *ToThisBB = WorkPoint->getParent();
LLVM_DEBUG(dbgs() << "\n\tCandidate: "; MII->dump());
LLVM_DEBUG(dbgs() << "\tDependent(" << MovingDependentOp << ") FromBB("
<< FromThisBB->getNumber() << ") ToBB("
<< ToThisBB->getNumber() << ") to this packet:\n";
DumpPacket(WorkPoint.getInstrIterator()));
MachineBasicBlock::instr_iterator FromHereII = MII;
if (MII->isInsideBundle()) {
while (!FromHereII->isBundle())
--FromHereII;
LLVM_DEBUG(dbgs() << "\tFrom here:\n"; DumpPacket(FromHereII));
MachineBasicBlock::iterator FromHere(FromHereII);
// We have instruction that could be moved from its current position.
if (MoveMItoBundle(*CurrentRegion, MII, NextMI, WorkPoint, FromHere,
backtrack, MovingDependentOp, PathInRegion)) {
// If BB from which we pull is now empty, move on.
if (IsEmptyBlock(FromThisBB)) {
LLVM_DEBUG(dbgs() << "\n\tExhosted BB (bundle).\n");
return false;
}
FromThisBBEnd = FromThisBB->end();
ToThisBBEnd = ToThisBB->end();
LLVM_DEBUG(dbgs() << "\n\tAfter updates(bundle to bundle):\n");
LLVM_DEBUG(dbgs() << "\t\tWorkPoint: ";
DumpPacket(WorkPoint.getInstrIterator()));
// We should not increment current position,
// but rather try one more time to pull from the same bundle.
RetVal = WorkPoint;
return true;
} else
LLVM_DEBUG(dbgs() << "\tCould not move packetized instr.\n");
} else {
MachineBasicBlock::iterator FromHere(FromHereII);
if (MoveMItoBundle(*CurrentRegion, MII, NextMI, WorkPoint, FromHere,
backtrack, MovingDependentOp, PathInRegion)) {
// If BB from which we pull is now empty, move on.
if (IsEmptyBlock(FromThisBB)) {
LLVM_DEBUG(dbgs() << "\n\tExhosted BB (single).\n");
return false;
}
FromThisBBEnd = FromThisBB->end();
ToThisBBEnd = ToThisBB->end();
LLVM_DEBUG(dbgs() << "\tAfter updates (single to bundle):\n");
LLVM_DEBUG(dbgs() << "\t\tWorkPoint: ";
DumpPacket(WorkPoint.getInstrIterator()));
// We should not increment current position,
// but rather try one more time to pull from the same bundle.
RetVal = WorkPoint;
return true;
} else
LLVM_DEBUG(dbgs() << "\tCould not move single.\n");
}
}
LLVM_DEBUG(dbgs() << "\tNot a single candidate fit.\n");
return false;
}
/// Main function. Iterate all current regions one at a time,
/// and look for pull-up opportunities.
/// Pseudo sequence:
/// - for all bundles and single instructions in region:
/// - see if resources are available (in the same cycle) - this is HOME.
/// - Starting from next BB in region, find an instruction that could be:
/// - removed from its current location
/// - added to underutilized bundle (including bundles with only one op)
/// - If so, trace path back to HOME and check that candidate could be
/// reordered with all the intermediate instructions.
bool HexagonGlobalSchedulerImpl::performPullUp() {
std::vector<MachineInstr *> backtrack;
MachineBasicBlock::iterator FromHere;
MachineBasicBlock::iterator FromThisBBEnd;
LLVM_DEBUG(dbgs() << "****** PullUpRegions ***********\n");
// For all regions...
for (std::vector<BasicBlockRegion *>::iterator
CurrentRegion = PullUpRegions.begin(),
E = PullUpRegions.end();
CurrentRegion != E; ++CurrentRegion) {
LLVM_DEBUG(dbgs() << "\n\nRegion with(" << (*CurrentRegion)->size()
<< ")BBs\n");
if (!EnableLocalPullUp && (*CurrentRegion)->size() < 2)
continue;
// For all MBB in the region... except the last one.
// ...except when we want to allow local pull-up.
for (auto ToThisBB = (*CurrentRegion)->getRootMBB(),
LastBBInRegion = (*CurrentRegion)->getLastMBB();
ToThisBB != LastBBInRegion; ++ToThisBB) {
// If we do not want to allow same BB pull-up, take an early exit.
if (!EnableLocalPullUp && (std::next(ToThisBB) == LastBBInRegion))
break;
if (multipleBranchesFromToBB(*ToThisBB))
break;
auto FromThisBB = ToThisBB;
MachineBasicBlock::iterator ToThisBBEnd = (*ToThisBB)->end();
MachineBasicBlock::iterator MI = (*ToThisBB)->begin();
LLVM_DEBUG(dbgs() << "\n\tHome iterator moved to new BB("
<< (*ToThisBB)->getNumber() << ")\n";
(*ToThisBB)->dump());
// For all instructions in the BB.
while (MI != ToThisBBEnd) {
MachineBasicBlock::iterator WorkPoint = MI;
++MI;
// Trivial check that there are unused resources
// in the current location (cycle).
while (ResourcesAvailableInBundle(*CurrentRegion, WorkPoint)) {
LLVM_DEBUG(dbgs() << "\nxxxx Next Home in BB("
<< (*ToThisBB)->getNumber() << "):\n";
DumpPacket(WorkPoint.getInstrIterator()));
// Keep the path to the candidate.
// It is the traveled path between home and work point.
// Reset it for the new iteration.
backtrack.clear();
// The point of pull-up source (WorkPoint) could begin from the
// current BB, but only if we allow pull-up in the same BB.
// At the moment we do not.
// We also do not process last block in the region,
// so it is safe to always begin with the next BB in the region.
// Start from "next" BB in the region.
if (EnableLocalPullUp) {
FromThisBB = ToThisBB;
FromHere = WorkPoint;
++FromHere;
FromThisBBEnd = (*FromThisBB)->end();
// Initialize backtrack.
// These are instructions between Home location
// and the WorkPoint.
for (MachineBasicBlock::iterator I = WorkPoint, IE = FromHere;
I != IE; ++I)
backtrack.push_back(&*I);
} else {
FromThisBB = ToThisBB;
++FromThisBB;
FromHere = (*FromThisBB)->begin();
FromThisBBEnd = (*FromThisBB)->end();
// Initialize backtrack.
// These are instructions between Home location
// and the end of the home BB.
for (MachineBasicBlock::iterator I = WorkPoint, IE = ToThisBBEnd;
I != IE; ++I)
backtrack.push_back(&*I);
}
// Search for pull-up candidate.
while (true) {
// If this BB is over, move onto the next one
// in this region.
if (FromHere == FromThisBBEnd) {
++FromThisBB;
// Refresh LastBBInRegion in case tryMultipleInstructions modified
// the regions Elements vector, invalidating the iterator.
LastBBInRegion = (*CurrentRegion)->getLastMBB();
if (FromThisBB == LastBBInRegion)
break;
else {
LLVM_DEBUG(dbgs() << "\n\tNext BB in this region\n";
(*FromThisBB)->dump());
FromThisBBEnd = (*FromThisBB)->end();
FromHere = (*FromThisBB)->begin();
if (FromThisBBEnd == FromHere)
break;
}
}
if ((*FromHere).isDebugInstr()) {
++FromHere;
continue;
}
// This is a step Home.
backtrack.push_back(&*FromHere);
if (!findPullUpCandidates(WorkPoint, FromHere, backtrack,
MainCandidateQueueSize))
break;
++FromHere;
}
// Try to pull-up one of the selected candidates.
if (!tryMultipleInstructions(/*output*/ WorkPoint, CurrentRegion, MI,
ToThisBBEnd, FromThisBBEnd))
break;
}
}
// Refresh LastBBInRegion after potential CFG modifications.
LastBBInRegion = (*CurrentRegion)->getLastMBB();
}
// AllowUnlikelyPath is on by default,
// if we wish to disable it, we can do so here.
if (!AllowUnlikelyPath)
continue;
// We have parsed the likely path through the region.
// Now traverse the other (unlikely) path.
//
// Note: BasicBlockRegion uses a vector for MBB storage, so adding BBs to
// the region while iterating could invalidate iterators. Collect the work
// items first, then process them.
std::vector<std::pair<MachineBasicBlock *, MachineBasicBlock *>>
UnlikelyWork;
UnlikelyWork.reserve((*CurrentRegion)->size());
for (auto ToIt = (*CurrentRegion)->getRootMBB(),
End = (*CurrentRegion)->getLastMBB();
ToIt != End; ++ToIt) {
MachineBasicBlock *ToBB = *ToIt;
MachineBasicBlock *SecondBest = getNextPURBB(ToBB, true);
if (SecondBest)
UnlikelyWork.emplace_back(ToBB, SecondBest);
}
for (auto [ToBB, SecondBest] : UnlikelyWork) {
LLVM_DEBUG(dbgs() << "\tFor BB:\n"; ToBB->dump());
LLVM_DEBUG(dbgs() << "\tHave SecondBest:\n"; SecondBest->dump());
// Adding this BB to the region should not be done if we
// plan to reuse it(the region) again. For now it is OK.
(*CurrentRegion)->addBBtoRegion(SecondBest);
LLVM_DEBUG(dbgs() << "\tHome iterator moved to new BB("
<< ToBB->getNumber() << ")\n";
ToBB->dump());
MachineBasicBlock::iterator ToThisBBEnd = ToBB->end();
MachineBasicBlock::iterator MI = ToBB->begin();
// For all instructions in the BB.
while (MI != ToThisBBEnd) {
MachineBasicBlock::iterator WorkPoint = MI;
++MI;
// Trivial check that there are unused resources
// in the current location (cycle).
while (ResourcesAvailableInBundle(*CurrentRegion, WorkPoint)) {
LLVM_DEBUG(dbgs() << "\nxxxx Second visit Home in BB("
<< ToBB->getNumber() << "):\n";
DumpPacket(WorkPoint.getInstrIterator()));
FromHere = SecondBest->begin();
FromThisBBEnd = SecondBest->end();
// Keep the path to the candidate.
backtrack.clear();
// This is Home location.
for (MachineBasicBlock::iterator I = WorkPoint, IE = ToThisBBEnd;
I != IE; ++I)
backtrack.push_back(&*I);
while (true) {
// If this BB is over, move onto the next one
// in this region.
if (FromHere == FromThisBBEnd) {
LLVM_DEBUG(dbgs()
<< "\tOnly do one successor for the second try\n");
break;
}
if ((*FromHere).isDebugInstr()) {
++FromHere;
continue;
}
// This is a step Home.
backtrack.push_back(&*FromHere);
if (!findPullUpCandidates(WorkPoint, FromHere, backtrack,
SecondaryCandidateQueueSize))
break;
++FromHere;
}
// Try to pull-up one of selected candidate.
if (!tryMultipleInstructions(/*output*/ WorkPoint, CurrentRegion, MI,
ToThisBBEnd, FromThisBBEnd, false))
break;
}
}
}
}
return true;
}
bool HexagonGlobalSchedulerImpl::incrementalAddToPacket(MachineInstr &MI) {
LLVM_DEBUG(dbgs() << "\t[AddToPacket] (" << CurrentPacketMIs.size()
<< ") adding:\t";
MI.dump());
if (!ResourceTracker->canReserveResources(MI) || !shouldAddToPacket(MI))
return false;
ResourceTracker->reserveResources(MI);
CurrentPacketMIs.push_back(&MI);
CurrentState.HomeBundle.push_back(&MI);
if (QII->isExtended(MI) || QII->isConstExtended(MI) ||
isJumpOutOfRange(&MI)) {
// If at this point of time we cannot reserve resources,
// this might mean that the packet came into the pull-up
// pass already in danger of overflowing.
// Nevertheless, since this is only a possibility of overflow
// no error should be issued here.
if (ResourceTracker->canReserveResources(*Ext)) {
ResourceTracker->reserveResources(*Ext);
LLVM_DEBUG(dbgs() << "\t[AddToPacket] (" << CurrentPacketMIs.size()
<< ") adding:\t immext_i\n");
CurrentPacketMIs.push_back(Ext);
CurrentState.HomeBundle.push_back(Ext);
return true;
} else {
LLVM_DEBUG(dbgs() << "\t Previous overflow possible.\n");
return false;
}
}
return true;
}
void HexagonGlobalSchedulerImpl::checkBundleCounts(MachineFunction &Fn) {
if (DisableCheckBundles)
return;
unsigned BundleLimit = 4;
for (MachineFunction::iterator MBBi = Fn.begin(), MBBe = Fn.end();
MBBi != MBBe; ++MBBi) {
for (MachineBasicBlock::iterator MI = MBBi->instr_begin(),
ME = MBBi->instr_end();
MI != ME; ++MI) {
if (MI->isBundle()) {
MachineBasicBlock::instr_iterator MII = MI.getInstrIterator();
MachineBasicBlock::instr_iterator End = MII->getParent()->instr_end();
unsigned InstrCount = 0;
for (++MII; MII != End && MII->isInsideBundle(); ++MII) {
if (MII->getOpcode() == TargetOpcode::DBG_VALUE ||
MII->getOpcode() == TargetOpcode::IMPLICIT_DEF ||
MII->getOpcode() == TargetOpcode::CFI_INSTRUCTION ||
MII->isEHLabel() || QII->isEndLoopN(MII->getOpcode())) {
continue;
} else {
InstrCount++;
}
}
if (InstrCount > BundleLimit) {
if (WarnOnBundleSize) {
LLVM_DEBUG(dbgs() << "Warning bundle size exceeded " << *MI);
} else {
assert(0 && "Bundle size exceeded");
}
}
}
}
}
}
/// Debugging only. Count compound and duplex opportunities.
unsigned HexagonGlobalSchedulerImpl::countCompounds(MachineFunction &Fn) {
unsigned CompoundCount = 0;
[[maybe_unused]] unsigned DuplexCount = 0;
[[maybe_unused]] unsigned InstOffset = 0;
// Loop over all basic blocks.
for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end(); MBB != MBBe;
++MBB) {
LLVM_DEBUG(dbgs() << "\n BB#" << MBB->getNumber() << " " << MBB->getName()
<< " in_func "
<< MBB->getParent()->getFunction().getName() << " \n");
for (MachineBasicBlock::iterator MI = MBB->instr_begin(),
ME = MBB->instr_end();
MI != ME; ++MI) {
if (MI->isDebugInstr())
continue;
if (MI->isBundle()) {
MachineBasicBlock::instr_iterator MII = MI.getInstrIterator();
MachineBasicBlock::instr_iterator MIE = MI->getParent()->instr_end();
MachineInstr *FirstCompound = NULL, *SecondCompound = NULL;
MachineInstr *FirstDuplex = NULL, *SecondDuplex = NULL;
LLVM_DEBUG(dbgs() << "{\n");
for (++MII; MII != MIE && MII->isInsideBundle() && !MII->isBundle();
++MII) {
if (MII->isDebugInstr())
continue;
LLVM_DEBUG(dbgs() << "(" << InstOffset << ")\t");
InstOffset += QII->getSize(*MII);
if (QII->getCompoundCandidateGroup(*MII)) {
if (!FirstCompound) {
FirstCompound = &*MII;
LLVM_DEBUG(dbgs() << "XX ");
} else {
SecondCompound = &*MII;
LLVM_DEBUG(dbgs() << "YY ");
}
}
if (QII->getDuplexCandidateGroup(*MII)) {
if (!FirstDuplex) {
FirstDuplex = &*MII;
LLVM_DEBUG(dbgs() << "AA ");
} else {
SecondDuplex = &*MII;
LLVM_DEBUG(dbgs() << "VV ");
}
}
LLVM_DEBUG(MII->dump());
}
LLVM_DEBUG(dbgs() << "}\n");
if (SecondCompound) {
if (isCompoundPair(FirstCompound, SecondCompound)) {
LLVM_DEBUG(dbgs() << "Compound pair (" << CompoundCount << ")\n");
CompoundCount++;
}
}
if (SecondDuplex) {
if (QII->isDuplexPair(*FirstDuplex, *SecondDuplex)) {
LLVM_DEBUG(dbgs() << "Duplex pair (" << DuplexCount << ")\n");
DuplexCount++;
}
}
} else {
LLVM_DEBUG(dbgs() << "(" << InstOffset << ")\t");
if (QII->getCompoundCandidateGroup(*MI))
LLVM_DEBUG(dbgs() << "XX ");
if (QII->getDuplexCandidateGroup(*MI))
LLVM_DEBUG(dbgs() << "AA ");
InstOffset += QII->getSize(*MI);
LLVM_DEBUG(MI->dump());
}
}
}
LLVM_DEBUG(dbgs() << "Total compound(" << CompoundCount << ") duplex("
<< DuplexCount << ")\n");
return CompoundCount;
}
//===----------------------------------------------------------------------===//
// Public Constructor Functions
//===----------------------------------------------------------------------===//
FunctionPass *llvm::createHexagonGlobalScheduler() {
return new HexagonGlobalScheduler();
}