| |
| //===----- 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(); |
| } |