10b57cec5SDimitry Andric //===- HexagonPacketizer.cpp - VLIW packetizer ----------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This implements a simple VLIW packetizer using DFA. The packetizer works on 100b57cec5SDimitry Andric // machine basic blocks. For each instruction I in BB, the packetizer consults 110b57cec5SDimitry Andric // the DFA to see if machine resources are available to execute I. If so, the 120b57cec5SDimitry Andric // packetizer checks if I depends on any instruction J in the current packet. 130b57cec5SDimitry Andric // If no dependency is found, I is added to current packet and machine resource 140b57cec5SDimitry Andric // is marked as taken. If any dependency is found, a target API call is made to 150b57cec5SDimitry Andric // prune the dependence. 160b57cec5SDimitry Andric // 170b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric #include "HexagonVLIWPacketizer.h" 200b57cec5SDimitry Andric #include "Hexagon.h" 210b57cec5SDimitry Andric #include "HexagonInstrInfo.h" 220b57cec5SDimitry Andric #include "HexagonRegisterInfo.h" 230b57cec5SDimitry Andric #include "HexagonSubtarget.h" 240b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h" 250b57cec5SDimitry Andric #include "llvm/ADT/DenseSet.h" 260b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 27*8bcb0991SDimitry Andric #include "llvm/ADT/StringExtras.h" 280b57cec5SDimitry Andric #include "llvm/Analysis/AliasAnalysis.h" 290b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 300b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBranchProbabilityInfo.h" 310b57cec5SDimitry Andric #include "llvm/CodeGen/MachineDominators.h" 320b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 330b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 340b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 350b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 360b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBundle.h" 370b57cec5SDimitry Andric #include "llvm/CodeGen/MachineLoopInfo.h" 380b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 390b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDAG.h" 400b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 410b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 420b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h" 430b57cec5SDimitry Andric #include "llvm/MC/MCInstrDesc.h" 440b57cec5SDimitry Andric #include "llvm/Pass.h" 450b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 460b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 470b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 480b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 490b57cec5SDimitry Andric #include <cassert> 500b57cec5SDimitry Andric #include <cstdint> 510b57cec5SDimitry Andric #include <iterator> 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric using namespace llvm; 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric #define DEBUG_TYPE "packets" 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric static cl::opt<bool> DisablePacketizer("disable-packetizer", cl::Hidden, 580b57cec5SDimitry Andric cl::ZeroOrMore, cl::init(false), 590b57cec5SDimitry Andric cl::desc("Disable Hexagon packetizer pass")); 600b57cec5SDimitry Andric 61*8bcb0991SDimitry Andric static cl::opt<bool> Slot1Store("slot1-store-slot0-load", cl::Hidden, 620b57cec5SDimitry Andric cl::ZeroOrMore, cl::init(true), 630b57cec5SDimitry Andric cl::desc("Allow slot1 store and slot0 load")); 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric static cl::opt<bool> PacketizeVolatiles("hexagon-packetize-volatiles", 660b57cec5SDimitry Andric cl::ZeroOrMore, cl::Hidden, cl::init(true), 670b57cec5SDimitry Andric cl::desc("Allow non-solo packetization of volatile memory references")); 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric static cl::opt<bool> EnableGenAllInsnClass("enable-gen-insn", cl::init(false), 700b57cec5SDimitry Andric cl::Hidden, cl::ZeroOrMore, cl::desc("Generate all instruction with TC")); 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric static cl::opt<bool> DisableVecDblNVStores("disable-vecdbl-nv-stores", 730b57cec5SDimitry Andric cl::init(false), cl::Hidden, cl::ZeroOrMore, 740b57cec5SDimitry Andric cl::desc("Disable vector double new-value-stores")); 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric extern cl::opt<bool> ScheduleInlineAsm; 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric namespace llvm { 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric FunctionPass *createHexagonPacketizer(bool Minimal); 810b57cec5SDimitry Andric void initializeHexagonPacketizerPass(PassRegistry&); 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric } // end namespace llvm 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric namespace { 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric class HexagonPacketizer : public MachineFunctionPass { 880b57cec5SDimitry Andric public: 890b57cec5SDimitry Andric static char ID; 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric HexagonPacketizer(bool Min = false) 920b57cec5SDimitry Andric : MachineFunctionPass(ID), Minimal(Min) {} 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 950b57cec5SDimitry Andric AU.setPreservesCFG(); 960b57cec5SDimitry Andric AU.addRequired<AAResultsWrapperPass>(); 970b57cec5SDimitry Andric AU.addRequired<MachineBranchProbabilityInfo>(); 980b57cec5SDimitry Andric AU.addRequired<MachineDominatorTree>(); 990b57cec5SDimitry Andric AU.addRequired<MachineLoopInfo>(); 1000b57cec5SDimitry Andric AU.addPreserved<MachineDominatorTree>(); 1010b57cec5SDimitry Andric AU.addPreserved<MachineLoopInfo>(); 1020b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric StringRef getPassName() const override { return "Hexagon Packetizer"; } 1060b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &Fn) override; 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric MachineFunctionProperties getRequiredProperties() const override { 1090b57cec5SDimitry Andric return MachineFunctionProperties().set( 1100b57cec5SDimitry Andric MachineFunctionProperties::Property::NoVRegs); 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric private: 1140b57cec5SDimitry Andric const HexagonInstrInfo *HII; 1150b57cec5SDimitry Andric const HexagonRegisterInfo *HRI; 1160b57cec5SDimitry Andric const bool Minimal; 1170b57cec5SDimitry Andric }; 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric } // end anonymous namespace 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric char HexagonPacketizer::ID = 0; 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(HexagonPacketizer, "hexagon-packetizer", 1240b57cec5SDimitry Andric "Hexagon Packetizer", false, false) 1250b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree) 1260b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo) 1270b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo) 1280b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) 1290b57cec5SDimitry Andric INITIALIZE_PASS_END(HexagonPacketizer, "hexagon-packetizer", 1300b57cec5SDimitry Andric "Hexagon Packetizer", false, false) 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric HexagonPacketizerList::HexagonPacketizerList(MachineFunction &MF, 133*8bcb0991SDimitry Andric MachineLoopInfo &MLI, AAResults *AA, 1340b57cec5SDimitry Andric const MachineBranchProbabilityInfo *MBPI, bool Minimal) 1350b57cec5SDimitry Andric : VLIWPacketizerList(MF, MLI, AA), MBPI(MBPI), MLI(&MLI), 1360b57cec5SDimitry Andric Minimal(Minimal) { 1370b57cec5SDimitry Andric HII = MF.getSubtarget<HexagonSubtarget>().getInstrInfo(); 1380b57cec5SDimitry Andric HRI = MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); 1390b57cec5SDimitry Andric 140*8bcb0991SDimitry Andric addMutation(std::make_unique<HexagonSubtarget::UsrOverflowMutation>()); 141*8bcb0991SDimitry Andric addMutation(std::make_unique<HexagonSubtarget::HVXMemLatencyMutation>()); 142*8bcb0991SDimitry Andric addMutation(std::make_unique<HexagonSubtarget::BankConflictMutation>()); 1430b57cec5SDimitry Andric } 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric // Check if FirstI modifies a register that SecondI reads. 1460b57cec5SDimitry Andric static bool hasWriteToReadDep(const MachineInstr &FirstI, 1470b57cec5SDimitry Andric const MachineInstr &SecondI, 1480b57cec5SDimitry Andric const TargetRegisterInfo *TRI) { 1490b57cec5SDimitry Andric for (auto &MO : FirstI.operands()) { 1500b57cec5SDimitry Andric if (!MO.isReg() || !MO.isDef()) 1510b57cec5SDimitry Andric continue; 152*8bcb0991SDimitry Andric Register R = MO.getReg(); 1530b57cec5SDimitry Andric if (SecondI.readsRegister(R, TRI)) 1540b57cec5SDimitry Andric return true; 1550b57cec5SDimitry Andric } 1560b57cec5SDimitry Andric return false; 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric static MachineBasicBlock::iterator moveInstrOut(MachineInstr &MI, 1610b57cec5SDimitry Andric MachineBasicBlock::iterator BundleIt, bool Before) { 1620b57cec5SDimitry Andric MachineBasicBlock::instr_iterator InsertPt; 1630b57cec5SDimitry Andric if (Before) 1640b57cec5SDimitry Andric InsertPt = BundleIt.getInstrIterator(); 1650b57cec5SDimitry Andric else 1660b57cec5SDimitry Andric InsertPt = std::next(BundleIt).getInstrIterator(); 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric MachineBasicBlock &B = *MI.getParent(); 1690b57cec5SDimitry Andric // The instruction should at least be bundled with the preceding instruction 1700b57cec5SDimitry Andric // (there will always be one, i.e. BUNDLE, if nothing else). 1710b57cec5SDimitry Andric assert(MI.isBundledWithPred()); 1720b57cec5SDimitry Andric if (MI.isBundledWithSucc()) { 1730b57cec5SDimitry Andric MI.clearFlag(MachineInstr::BundledSucc); 1740b57cec5SDimitry Andric MI.clearFlag(MachineInstr::BundledPred); 1750b57cec5SDimitry Andric } else { 1760b57cec5SDimitry Andric // If it's not bundled with the successor (i.e. it is the last one 1770b57cec5SDimitry Andric // in the bundle), then we can simply unbundle it from the predecessor, 1780b57cec5SDimitry Andric // which will take care of updating the predecessor's flag. 1790b57cec5SDimitry Andric MI.unbundleFromPred(); 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric B.splice(InsertPt, &B, MI.getIterator()); 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric // Get the size of the bundle without asserting. 1840b57cec5SDimitry Andric MachineBasicBlock::const_instr_iterator I = BundleIt.getInstrIterator(); 1850b57cec5SDimitry Andric MachineBasicBlock::const_instr_iterator E = B.instr_end(); 1860b57cec5SDimitry Andric unsigned Size = 0; 1870b57cec5SDimitry Andric for (++I; I != E && I->isBundledWithPred(); ++I) 1880b57cec5SDimitry Andric ++Size; 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric // If there are still two or more instructions, then there is nothing 1910b57cec5SDimitry Andric // else to be done. 1920b57cec5SDimitry Andric if (Size > 1) 1930b57cec5SDimitry Andric return BundleIt; 1940b57cec5SDimitry Andric 1950b57cec5SDimitry Andric // Otherwise, extract the single instruction out and delete the bundle. 1960b57cec5SDimitry Andric MachineBasicBlock::iterator NextIt = std::next(BundleIt); 1970b57cec5SDimitry Andric MachineInstr &SingleI = *BundleIt->getNextNode(); 1980b57cec5SDimitry Andric SingleI.unbundleFromPred(); 1990b57cec5SDimitry Andric assert(!SingleI.isBundledWithSucc()); 2000b57cec5SDimitry Andric BundleIt->eraseFromParent(); 2010b57cec5SDimitry Andric return NextIt; 2020b57cec5SDimitry Andric } 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric bool HexagonPacketizer::runOnMachineFunction(MachineFunction &MF) { 2050b57cec5SDimitry Andric auto &HST = MF.getSubtarget<HexagonSubtarget>(); 2060b57cec5SDimitry Andric HII = HST.getInstrInfo(); 2070b57cec5SDimitry Andric HRI = HST.getRegisterInfo(); 2080b57cec5SDimitry Andric auto &MLI = getAnalysis<MachineLoopInfo>(); 2090b57cec5SDimitry Andric auto *AA = &getAnalysis<AAResultsWrapperPass>().getAAResults(); 2100b57cec5SDimitry Andric auto *MBPI = &getAnalysis<MachineBranchProbabilityInfo>(); 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric if (EnableGenAllInsnClass) 2130b57cec5SDimitry Andric HII->genAllInsnTimingClasses(MF); 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric // Instantiate the packetizer. 2160b57cec5SDimitry Andric bool MinOnly = Minimal || DisablePacketizer || !HST.usePackets() || 2170b57cec5SDimitry Andric skipFunction(MF.getFunction()); 2180b57cec5SDimitry Andric HexagonPacketizerList Packetizer(MF, MLI, AA, MBPI, MinOnly); 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric // DFA state table should not be empty. 2210b57cec5SDimitry Andric assert(Packetizer.getResourceTracker() && "Empty DFA table!"); 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric // Loop over all basic blocks and remove KILL pseudo-instructions 2240b57cec5SDimitry Andric // These instructions confuse the dependence analysis. Consider: 2250b57cec5SDimitry Andric // D0 = ... (Insn 0) 2260b57cec5SDimitry Andric // R0 = KILL R0, D0 (Insn 1) 2270b57cec5SDimitry Andric // R0 = ... (Insn 2) 2280b57cec5SDimitry Andric // Here, Insn 1 will result in the dependence graph not emitting an output 2290b57cec5SDimitry Andric // dependence between Insn 0 and Insn 2. This can lead to incorrect 2300b57cec5SDimitry Andric // packetization 2310b57cec5SDimitry Andric for (MachineBasicBlock &MB : MF) { 2320b57cec5SDimitry Andric auto End = MB.end(); 2330b57cec5SDimitry Andric auto MI = MB.begin(); 2340b57cec5SDimitry Andric while (MI != End) { 2350b57cec5SDimitry Andric auto NextI = std::next(MI); 2360b57cec5SDimitry Andric if (MI->isKill()) { 2370b57cec5SDimitry Andric MB.erase(MI); 2380b57cec5SDimitry Andric End = MB.end(); 2390b57cec5SDimitry Andric } 2400b57cec5SDimitry Andric MI = NextI; 2410b57cec5SDimitry Andric } 2420b57cec5SDimitry Andric } 2430b57cec5SDimitry Andric 2440b57cec5SDimitry Andric // Loop over all of the basic blocks. 2450b57cec5SDimitry Andric for (auto &MB : MF) { 2460b57cec5SDimitry Andric auto Begin = MB.begin(), End = MB.end(); 2470b57cec5SDimitry Andric while (Begin != End) { 2480b57cec5SDimitry Andric // Find the first non-boundary starting from the end of the last 2490b57cec5SDimitry Andric // scheduling region. 2500b57cec5SDimitry Andric MachineBasicBlock::iterator RB = Begin; 2510b57cec5SDimitry Andric while (RB != End && HII->isSchedulingBoundary(*RB, &MB, MF)) 2520b57cec5SDimitry Andric ++RB; 2530b57cec5SDimitry Andric // Find the first boundary starting from the beginning of the new 2540b57cec5SDimitry Andric // region. 2550b57cec5SDimitry Andric MachineBasicBlock::iterator RE = RB; 2560b57cec5SDimitry Andric while (RE != End && !HII->isSchedulingBoundary(*RE, &MB, MF)) 2570b57cec5SDimitry Andric ++RE; 2580b57cec5SDimitry Andric // Add the scheduling boundary if it's not block end. 2590b57cec5SDimitry Andric if (RE != End) 2600b57cec5SDimitry Andric ++RE; 2610b57cec5SDimitry Andric // If RB == End, then RE == End. 2620b57cec5SDimitry Andric if (RB != End) 2630b57cec5SDimitry Andric Packetizer.PacketizeMIs(&MB, RB, RE); 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric Begin = RE; 2660b57cec5SDimitry Andric } 2670b57cec5SDimitry Andric } 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric Packetizer.unpacketizeSoloInstrs(MF); 2700b57cec5SDimitry Andric return true; 2710b57cec5SDimitry Andric } 2720b57cec5SDimitry Andric 2730b57cec5SDimitry Andric // Reserve resources for a constant extender. Trigger an assertion if the 2740b57cec5SDimitry Andric // reservation fails. 2750b57cec5SDimitry Andric void HexagonPacketizerList::reserveResourcesForConstExt() { 2760b57cec5SDimitry Andric if (!tryAllocateResourcesForConstExt(true)) 2770b57cec5SDimitry Andric llvm_unreachable("Resources not available"); 2780b57cec5SDimitry Andric } 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric bool HexagonPacketizerList::canReserveResourcesForConstExt() { 2810b57cec5SDimitry Andric return tryAllocateResourcesForConstExt(false); 2820b57cec5SDimitry Andric } 2830b57cec5SDimitry Andric 2840b57cec5SDimitry Andric // Allocate resources (i.e. 4 bytes) for constant extender. If succeeded, 2850b57cec5SDimitry Andric // return true, otherwise, return false. 2860b57cec5SDimitry Andric bool HexagonPacketizerList::tryAllocateResourcesForConstExt(bool Reserve) { 2870b57cec5SDimitry Andric auto *ExtMI = MF.CreateMachineInstr(HII->get(Hexagon::A4_ext), DebugLoc()); 2880b57cec5SDimitry Andric bool Avail = ResourceTracker->canReserveResources(*ExtMI); 2890b57cec5SDimitry Andric if (Reserve && Avail) 2900b57cec5SDimitry Andric ResourceTracker->reserveResources(*ExtMI); 2910b57cec5SDimitry Andric MF.DeleteMachineInstr(ExtMI); 2920b57cec5SDimitry Andric return Avail; 2930b57cec5SDimitry Andric } 2940b57cec5SDimitry Andric 2950b57cec5SDimitry Andric bool HexagonPacketizerList::isCallDependent(const MachineInstr &MI, 2960b57cec5SDimitry Andric SDep::Kind DepType, unsigned DepReg) { 2970b57cec5SDimitry Andric // Check for LR dependence. 2980b57cec5SDimitry Andric if (DepReg == HRI->getRARegister()) 2990b57cec5SDimitry Andric return true; 3000b57cec5SDimitry Andric 3010b57cec5SDimitry Andric if (HII->isDeallocRet(MI)) 3020b57cec5SDimitry Andric if (DepReg == HRI->getFrameRegister() || DepReg == HRI->getStackRegister()) 3030b57cec5SDimitry Andric return true; 3040b57cec5SDimitry Andric 3050b57cec5SDimitry Andric // Call-like instructions can be packetized with preceding instructions 3060b57cec5SDimitry Andric // that define registers implicitly used or modified by the call. Explicit 3070b57cec5SDimitry Andric // uses are still prohibited, as in the case of indirect calls: 3080b57cec5SDimitry Andric // r0 = ... 3090b57cec5SDimitry Andric // J2_jumpr r0 3100b57cec5SDimitry Andric if (DepType == SDep::Data) { 3110b57cec5SDimitry Andric for (const MachineOperand MO : MI.operands()) 3120b57cec5SDimitry Andric if (MO.isReg() && MO.getReg() == DepReg && !MO.isImplicit()) 3130b57cec5SDimitry Andric return true; 3140b57cec5SDimitry Andric } 3150b57cec5SDimitry Andric 3160b57cec5SDimitry Andric return false; 3170b57cec5SDimitry Andric } 3180b57cec5SDimitry Andric 3190b57cec5SDimitry Andric static bool isRegDependence(const SDep::Kind DepType) { 3200b57cec5SDimitry Andric return DepType == SDep::Data || DepType == SDep::Anti || 3210b57cec5SDimitry Andric DepType == SDep::Output; 3220b57cec5SDimitry Andric } 3230b57cec5SDimitry Andric 3240b57cec5SDimitry Andric static bool isDirectJump(const MachineInstr &MI) { 3250b57cec5SDimitry Andric return MI.getOpcode() == Hexagon::J2_jump; 3260b57cec5SDimitry Andric } 3270b57cec5SDimitry Andric 3280b57cec5SDimitry Andric static bool isSchedBarrier(const MachineInstr &MI) { 3290b57cec5SDimitry Andric switch (MI.getOpcode()) { 3300b57cec5SDimitry Andric case Hexagon::Y2_barrier: 3310b57cec5SDimitry Andric return true; 3320b57cec5SDimitry Andric } 3330b57cec5SDimitry Andric return false; 3340b57cec5SDimitry Andric } 3350b57cec5SDimitry Andric 3360b57cec5SDimitry Andric static bool isControlFlow(const MachineInstr &MI) { 3370b57cec5SDimitry Andric return MI.getDesc().isTerminator() || MI.getDesc().isCall(); 3380b57cec5SDimitry Andric } 3390b57cec5SDimitry Andric 3400b57cec5SDimitry Andric /// Returns true if the instruction modifies a callee-saved register. 3410b57cec5SDimitry Andric static bool doesModifyCalleeSavedReg(const MachineInstr &MI, 3420b57cec5SDimitry Andric const TargetRegisterInfo *TRI) { 3430b57cec5SDimitry Andric const MachineFunction &MF = *MI.getParent()->getParent(); 3440b57cec5SDimitry Andric for (auto *CSR = TRI->getCalleeSavedRegs(&MF); CSR && *CSR; ++CSR) 3450b57cec5SDimitry Andric if (MI.modifiesRegister(*CSR, TRI)) 3460b57cec5SDimitry Andric return true; 3470b57cec5SDimitry Andric return false; 3480b57cec5SDimitry Andric } 3490b57cec5SDimitry Andric 3500b57cec5SDimitry Andric // Returns true if an instruction can be promoted to .new predicate or 3510b57cec5SDimitry Andric // new-value store. 3520b57cec5SDimitry Andric bool HexagonPacketizerList::isNewifiable(const MachineInstr &MI, 3530b57cec5SDimitry Andric const TargetRegisterClass *NewRC) { 3540b57cec5SDimitry Andric // Vector stores can be predicated, and can be new-value stores, but 3550b57cec5SDimitry Andric // they cannot be predicated on a .new predicate value. 3560b57cec5SDimitry Andric if (NewRC == &Hexagon::PredRegsRegClass) { 3570b57cec5SDimitry Andric if (HII->isHVXVec(MI) && MI.mayStore()) 3580b57cec5SDimitry Andric return false; 3590b57cec5SDimitry Andric return HII->isPredicated(MI) && HII->getDotNewPredOp(MI, nullptr) > 0; 3600b57cec5SDimitry Andric } 3610b57cec5SDimitry Andric // If the class is not PredRegs, it could only apply to new-value stores. 3620b57cec5SDimitry Andric return HII->mayBeNewStore(MI); 3630b57cec5SDimitry Andric } 3640b57cec5SDimitry Andric 3650b57cec5SDimitry Andric // Promote an instructiont to its .cur form. 3660b57cec5SDimitry Andric // At this time, we have already made a call to canPromoteToDotCur and made 3670b57cec5SDimitry Andric // sure that it can *indeed* be promoted. 3680b57cec5SDimitry Andric bool HexagonPacketizerList::promoteToDotCur(MachineInstr &MI, 3690b57cec5SDimitry Andric SDep::Kind DepType, MachineBasicBlock::iterator &MII, 3700b57cec5SDimitry Andric const TargetRegisterClass* RC) { 3710b57cec5SDimitry Andric assert(DepType == SDep::Data); 3720b57cec5SDimitry Andric int CurOpcode = HII->getDotCurOp(MI); 3730b57cec5SDimitry Andric MI.setDesc(HII->get(CurOpcode)); 3740b57cec5SDimitry Andric return true; 3750b57cec5SDimitry Andric } 3760b57cec5SDimitry Andric 3770b57cec5SDimitry Andric void HexagonPacketizerList::cleanUpDotCur() { 3780b57cec5SDimitry Andric MachineInstr *MI = nullptr; 3790b57cec5SDimitry Andric for (auto BI : CurrentPacketMIs) { 3800b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Cleanup packet has "; BI->dump();); 3810b57cec5SDimitry Andric if (HII->isDotCurInst(*BI)) { 3820b57cec5SDimitry Andric MI = BI; 3830b57cec5SDimitry Andric continue; 3840b57cec5SDimitry Andric } 3850b57cec5SDimitry Andric if (MI) { 3860b57cec5SDimitry Andric for (auto &MO : BI->operands()) 3870b57cec5SDimitry Andric if (MO.isReg() && MO.getReg() == MI->getOperand(0).getReg()) 3880b57cec5SDimitry Andric return; 3890b57cec5SDimitry Andric } 3900b57cec5SDimitry Andric } 3910b57cec5SDimitry Andric if (!MI) 3920b57cec5SDimitry Andric return; 3930b57cec5SDimitry Andric // We did not find a use of the CUR, so de-cur it. 3940b57cec5SDimitry Andric MI->setDesc(HII->get(HII->getNonDotCurOp(*MI))); 3950b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Demoted CUR "; MI->dump();); 3960b57cec5SDimitry Andric } 3970b57cec5SDimitry Andric 3980b57cec5SDimitry Andric // Check to see if an instruction can be dot cur. 3990b57cec5SDimitry Andric bool HexagonPacketizerList::canPromoteToDotCur(const MachineInstr &MI, 4000b57cec5SDimitry Andric const SUnit *PacketSU, unsigned DepReg, MachineBasicBlock::iterator &MII, 4010b57cec5SDimitry Andric const TargetRegisterClass *RC) { 4020b57cec5SDimitry Andric if (!HII->isHVXVec(MI)) 4030b57cec5SDimitry Andric return false; 4040b57cec5SDimitry Andric if (!HII->isHVXVec(*MII)) 4050b57cec5SDimitry Andric return false; 4060b57cec5SDimitry Andric 4070b57cec5SDimitry Andric // Already a dot new instruction. 4080b57cec5SDimitry Andric if (HII->isDotCurInst(MI) && !HII->mayBeCurLoad(MI)) 4090b57cec5SDimitry Andric return false; 4100b57cec5SDimitry Andric 4110b57cec5SDimitry Andric if (!HII->mayBeCurLoad(MI)) 4120b57cec5SDimitry Andric return false; 4130b57cec5SDimitry Andric 4140b57cec5SDimitry Andric // The "cur value" cannot come from inline asm. 4150b57cec5SDimitry Andric if (PacketSU->getInstr()->isInlineAsm()) 4160b57cec5SDimitry Andric return false; 4170b57cec5SDimitry Andric 4180b57cec5SDimitry Andric // Make sure candidate instruction uses cur. 4190b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Can we DOT Cur Vector MI\n"; MI.dump(); 4200b57cec5SDimitry Andric dbgs() << "in packet\n";); 4210b57cec5SDimitry Andric MachineInstr &MJ = *MII; 4220b57cec5SDimitry Andric LLVM_DEBUG({ 4230b57cec5SDimitry Andric dbgs() << "Checking CUR against "; 4240b57cec5SDimitry Andric MJ.dump(); 4250b57cec5SDimitry Andric }); 426*8bcb0991SDimitry Andric Register DestReg = MI.getOperand(0).getReg(); 4270b57cec5SDimitry Andric bool FoundMatch = false; 4280b57cec5SDimitry Andric for (auto &MO : MJ.operands()) 4290b57cec5SDimitry Andric if (MO.isReg() && MO.getReg() == DestReg) 4300b57cec5SDimitry Andric FoundMatch = true; 4310b57cec5SDimitry Andric if (!FoundMatch) 4320b57cec5SDimitry Andric return false; 4330b57cec5SDimitry Andric 4340b57cec5SDimitry Andric // Check for existing uses of a vector register within the packet which 4350b57cec5SDimitry Andric // would be affected by converting a vector load into .cur formt. 4360b57cec5SDimitry Andric for (auto BI : CurrentPacketMIs) { 4370b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "packet has "; BI->dump();); 4380b57cec5SDimitry Andric if (BI->readsRegister(DepReg, MF.getSubtarget().getRegisterInfo())) 4390b57cec5SDimitry Andric return false; 4400b57cec5SDimitry Andric } 4410b57cec5SDimitry Andric 4420b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Can Dot CUR MI\n"; MI.dump();); 4430b57cec5SDimitry Andric // We can convert the opcode into a .cur. 4440b57cec5SDimitry Andric return true; 4450b57cec5SDimitry Andric } 4460b57cec5SDimitry Andric 4470b57cec5SDimitry Andric // Promote an instruction to its .new form. At this time, we have already 4480b57cec5SDimitry Andric // made a call to canPromoteToDotNew and made sure that it can *indeed* be 4490b57cec5SDimitry Andric // promoted. 4500b57cec5SDimitry Andric bool HexagonPacketizerList::promoteToDotNew(MachineInstr &MI, 4510b57cec5SDimitry Andric SDep::Kind DepType, MachineBasicBlock::iterator &MII, 4520b57cec5SDimitry Andric const TargetRegisterClass* RC) { 4530b57cec5SDimitry Andric assert(DepType == SDep::Data); 4540b57cec5SDimitry Andric int NewOpcode; 4550b57cec5SDimitry Andric if (RC == &Hexagon::PredRegsRegClass) 4560b57cec5SDimitry Andric NewOpcode = HII->getDotNewPredOp(MI, MBPI); 4570b57cec5SDimitry Andric else 4580b57cec5SDimitry Andric NewOpcode = HII->getDotNewOp(MI); 4590b57cec5SDimitry Andric MI.setDesc(HII->get(NewOpcode)); 4600b57cec5SDimitry Andric return true; 4610b57cec5SDimitry Andric } 4620b57cec5SDimitry Andric 4630b57cec5SDimitry Andric bool HexagonPacketizerList::demoteToDotOld(MachineInstr &MI) { 4640b57cec5SDimitry Andric int NewOpcode = HII->getDotOldOp(MI); 4650b57cec5SDimitry Andric MI.setDesc(HII->get(NewOpcode)); 4660b57cec5SDimitry Andric return true; 4670b57cec5SDimitry Andric } 4680b57cec5SDimitry Andric 4690b57cec5SDimitry Andric bool HexagonPacketizerList::useCallersSP(MachineInstr &MI) { 4700b57cec5SDimitry Andric unsigned Opc = MI.getOpcode(); 4710b57cec5SDimitry Andric switch (Opc) { 4720b57cec5SDimitry Andric case Hexagon::S2_storerd_io: 4730b57cec5SDimitry Andric case Hexagon::S2_storeri_io: 4740b57cec5SDimitry Andric case Hexagon::S2_storerh_io: 4750b57cec5SDimitry Andric case Hexagon::S2_storerb_io: 4760b57cec5SDimitry Andric break; 4770b57cec5SDimitry Andric default: 4780b57cec5SDimitry Andric llvm_unreachable("Unexpected instruction"); 4790b57cec5SDimitry Andric } 4800b57cec5SDimitry Andric unsigned FrameSize = MF.getFrameInfo().getStackSize(); 4810b57cec5SDimitry Andric MachineOperand &Off = MI.getOperand(1); 4820b57cec5SDimitry Andric int64_t NewOff = Off.getImm() - (FrameSize + HEXAGON_LRFP_SIZE); 4830b57cec5SDimitry Andric if (HII->isValidOffset(Opc, NewOff, HRI)) { 4840b57cec5SDimitry Andric Off.setImm(NewOff); 4850b57cec5SDimitry Andric return true; 4860b57cec5SDimitry Andric } 4870b57cec5SDimitry Andric return false; 4880b57cec5SDimitry Andric } 4890b57cec5SDimitry Andric 4900b57cec5SDimitry Andric void HexagonPacketizerList::useCalleesSP(MachineInstr &MI) { 4910b57cec5SDimitry Andric unsigned Opc = MI.getOpcode(); 4920b57cec5SDimitry Andric switch (Opc) { 4930b57cec5SDimitry Andric case Hexagon::S2_storerd_io: 4940b57cec5SDimitry Andric case Hexagon::S2_storeri_io: 4950b57cec5SDimitry Andric case Hexagon::S2_storerh_io: 4960b57cec5SDimitry Andric case Hexagon::S2_storerb_io: 4970b57cec5SDimitry Andric break; 4980b57cec5SDimitry Andric default: 4990b57cec5SDimitry Andric llvm_unreachable("Unexpected instruction"); 5000b57cec5SDimitry Andric } 5010b57cec5SDimitry Andric unsigned FrameSize = MF.getFrameInfo().getStackSize(); 5020b57cec5SDimitry Andric MachineOperand &Off = MI.getOperand(1); 5030b57cec5SDimitry Andric Off.setImm(Off.getImm() + FrameSize + HEXAGON_LRFP_SIZE); 5040b57cec5SDimitry Andric } 5050b57cec5SDimitry Andric 5060b57cec5SDimitry Andric /// Return true if we can update the offset in MI so that MI and MJ 5070b57cec5SDimitry Andric /// can be packetized together. 5080b57cec5SDimitry Andric bool HexagonPacketizerList::updateOffset(SUnit *SUI, SUnit *SUJ) { 5090b57cec5SDimitry Andric assert(SUI->getInstr() && SUJ->getInstr()); 5100b57cec5SDimitry Andric MachineInstr &MI = *SUI->getInstr(); 5110b57cec5SDimitry Andric MachineInstr &MJ = *SUJ->getInstr(); 5120b57cec5SDimitry Andric 5130b57cec5SDimitry Andric unsigned BPI, OPI; 5140b57cec5SDimitry Andric if (!HII->getBaseAndOffsetPosition(MI, BPI, OPI)) 5150b57cec5SDimitry Andric return false; 5160b57cec5SDimitry Andric unsigned BPJ, OPJ; 5170b57cec5SDimitry Andric if (!HII->getBaseAndOffsetPosition(MJ, BPJ, OPJ)) 5180b57cec5SDimitry Andric return false; 519*8bcb0991SDimitry Andric Register Reg = MI.getOperand(BPI).getReg(); 5200b57cec5SDimitry Andric if (Reg != MJ.getOperand(BPJ).getReg()) 5210b57cec5SDimitry Andric return false; 5220b57cec5SDimitry Andric // Make sure that the dependences do not restrict adding MI to the packet. 5230b57cec5SDimitry Andric // That is, ignore anti dependences, and make sure the only data dependence 5240b57cec5SDimitry Andric // involves the specific register. 5250b57cec5SDimitry Andric for (const auto &PI : SUI->Preds) 5260b57cec5SDimitry Andric if (PI.getKind() != SDep::Anti && 5270b57cec5SDimitry Andric (PI.getKind() != SDep::Data || PI.getReg() != Reg)) 5280b57cec5SDimitry Andric return false; 5290b57cec5SDimitry Andric int Incr; 5300b57cec5SDimitry Andric if (!HII->getIncrementValue(MJ, Incr)) 5310b57cec5SDimitry Andric return false; 5320b57cec5SDimitry Andric 5330b57cec5SDimitry Andric int64_t Offset = MI.getOperand(OPI).getImm(); 5340b57cec5SDimitry Andric if (!HII->isValidOffset(MI.getOpcode(), Offset+Incr, HRI)) 5350b57cec5SDimitry Andric return false; 5360b57cec5SDimitry Andric 5370b57cec5SDimitry Andric MI.getOperand(OPI).setImm(Offset + Incr); 5380b57cec5SDimitry Andric ChangedOffset = Offset; 5390b57cec5SDimitry Andric return true; 5400b57cec5SDimitry Andric } 5410b57cec5SDimitry Andric 5420b57cec5SDimitry Andric /// Undo the changed offset. This is needed if the instruction cannot be 5430b57cec5SDimitry Andric /// added to the current packet due to a different instruction. 5440b57cec5SDimitry Andric void HexagonPacketizerList::undoChangedOffset(MachineInstr &MI) { 5450b57cec5SDimitry Andric unsigned BP, OP; 5460b57cec5SDimitry Andric if (!HII->getBaseAndOffsetPosition(MI, BP, OP)) 5470b57cec5SDimitry Andric llvm_unreachable("Unable to find base and offset operands."); 5480b57cec5SDimitry Andric MI.getOperand(OP).setImm(ChangedOffset); 5490b57cec5SDimitry Andric } 5500b57cec5SDimitry Andric 5510b57cec5SDimitry Andric enum PredicateKind { 5520b57cec5SDimitry Andric PK_False, 5530b57cec5SDimitry Andric PK_True, 5540b57cec5SDimitry Andric PK_Unknown 5550b57cec5SDimitry Andric }; 5560b57cec5SDimitry Andric 5570b57cec5SDimitry Andric /// Returns true if an instruction is predicated on p0 and false if it's 5580b57cec5SDimitry Andric /// predicated on !p0. 5590b57cec5SDimitry Andric static PredicateKind getPredicateSense(const MachineInstr &MI, 5600b57cec5SDimitry Andric const HexagonInstrInfo *HII) { 5610b57cec5SDimitry Andric if (!HII->isPredicated(MI)) 5620b57cec5SDimitry Andric return PK_Unknown; 5630b57cec5SDimitry Andric if (HII->isPredicatedTrue(MI)) 5640b57cec5SDimitry Andric return PK_True; 5650b57cec5SDimitry Andric return PK_False; 5660b57cec5SDimitry Andric } 5670b57cec5SDimitry Andric 5680b57cec5SDimitry Andric static const MachineOperand &getPostIncrementOperand(const MachineInstr &MI, 5690b57cec5SDimitry Andric const HexagonInstrInfo *HII) { 5700b57cec5SDimitry Andric assert(HII->isPostIncrement(MI) && "Not a post increment operation."); 5710b57cec5SDimitry Andric #ifndef NDEBUG 5720b57cec5SDimitry Andric // Post Increment means duplicates. Use dense map to find duplicates in the 5730b57cec5SDimitry Andric // list. Caution: Densemap initializes with the minimum of 64 buckets, 5740b57cec5SDimitry Andric // whereas there are at most 5 operands in the post increment. 5750b57cec5SDimitry Andric DenseSet<unsigned> DefRegsSet; 5760b57cec5SDimitry Andric for (auto &MO : MI.operands()) 5770b57cec5SDimitry Andric if (MO.isReg() && MO.isDef()) 5780b57cec5SDimitry Andric DefRegsSet.insert(MO.getReg()); 5790b57cec5SDimitry Andric 5800b57cec5SDimitry Andric for (auto &MO : MI.operands()) 5810b57cec5SDimitry Andric if (MO.isReg() && MO.isUse() && DefRegsSet.count(MO.getReg())) 5820b57cec5SDimitry Andric return MO; 5830b57cec5SDimitry Andric #else 5840b57cec5SDimitry Andric if (MI.mayLoad()) { 5850b57cec5SDimitry Andric const MachineOperand &Op1 = MI.getOperand(1); 5860b57cec5SDimitry Andric // The 2nd operand is always the post increment operand in load. 5870b57cec5SDimitry Andric assert(Op1.isReg() && "Post increment operand has be to a register."); 5880b57cec5SDimitry Andric return Op1; 5890b57cec5SDimitry Andric } 5900b57cec5SDimitry Andric if (MI.getDesc().mayStore()) { 5910b57cec5SDimitry Andric const MachineOperand &Op0 = MI.getOperand(0); 5920b57cec5SDimitry Andric // The 1st operand is always the post increment operand in store. 5930b57cec5SDimitry Andric assert(Op0.isReg() && "Post increment operand has be to a register."); 5940b57cec5SDimitry Andric return Op0; 5950b57cec5SDimitry Andric } 5960b57cec5SDimitry Andric #endif 5970b57cec5SDimitry Andric // we should never come here. 5980b57cec5SDimitry Andric llvm_unreachable("mayLoad or mayStore not set for Post Increment operation"); 5990b57cec5SDimitry Andric } 6000b57cec5SDimitry Andric 6010b57cec5SDimitry Andric // Get the value being stored. 6020b57cec5SDimitry Andric static const MachineOperand& getStoreValueOperand(const MachineInstr &MI) { 6030b57cec5SDimitry Andric // value being stored is always the last operand. 6040b57cec5SDimitry Andric return MI.getOperand(MI.getNumOperands()-1); 6050b57cec5SDimitry Andric } 6060b57cec5SDimitry Andric 6070b57cec5SDimitry Andric static bool isLoadAbsSet(const MachineInstr &MI) { 6080b57cec5SDimitry Andric unsigned Opc = MI.getOpcode(); 6090b57cec5SDimitry Andric switch (Opc) { 6100b57cec5SDimitry Andric case Hexagon::L4_loadrd_ap: 6110b57cec5SDimitry Andric case Hexagon::L4_loadrb_ap: 6120b57cec5SDimitry Andric case Hexagon::L4_loadrh_ap: 6130b57cec5SDimitry Andric case Hexagon::L4_loadrub_ap: 6140b57cec5SDimitry Andric case Hexagon::L4_loadruh_ap: 6150b57cec5SDimitry Andric case Hexagon::L4_loadri_ap: 6160b57cec5SDimitry Andric return true; 6170b57cec5SDimitry Andric } 6180b57cec5SDimitry Andric return false; 6190b57cec5SDimitry Andric } 6200b57cec5SDimitry Andric 6210b57cec5SDimitry Andric static const MachineOperand &getAbsSetOperand(const MachineInstr &MI) { 6220b57cec5SDimitry Andric assert(isLoadAbsSet(MI)); 6230b57cec5SDimitry Andric return MI.getOperand(1); 6240b57cec5SDimitry Andric } 6250b57cec5SDimitry Andric 6260b57cec5SDimitry Andric // Can be new value store? 6270b57cec5SDimitry Andric // Following restrictions are to be respected in convert a store into 6280b57cec5SDimitry Andric // a new value store. 6290b57cec5SDimitry Andric // 1. If an instruction uses auto-increment, its address register cannot 6300b57cec5SDimitry Andric // be a new-value register. Arch Spec 5.4.2.1 6310b57cec5SDimitry Andric // 2. If an instruction uses absolute-set addressing mode, its address 6320b57cec5SDimitry Andric // register cannot be a new-value register. Arch Spec 5.4.2.1. 6330b57cec5SDimitry Andric // 3. If an instruction produces a 64-bit result, its registers cannot be used 6340b57cec5SDimitry Andric // as new-value registers. Arch Spec 5.4.2.2. 6350b57cec5SDimitry Andric // 4. If the instruction that sets the new-value register is conditional, then 6360b57cec5SDimitry Andric // the instruction that uses the new-value register must also be conditional, 6370b57cec5SDimitry Andric // and both must always have their predicates evaluate identically. 6380b57cec5SDimitry Andric // Arch Spec 5.4.2.3. 6390b57cec5SDimitry Andric // 5. There is an implied restriction that a packet cannot have another store, 6400b57cec5SDimitry Andric // if there is a new value store in the packet. Corollary: if there is 6410b57cec5SDimitry Andric // already a store in a packet, there can not be a new value store. 6420b57cec5SDimitry Andric // Arch Spec: 3.4.4.2 6430b57cec5SDimitry Andric bool HexagonPacketizerList::canPromoteToNewValueStore(const MachineInstr &MI, 6440b57cec5SDimitry Andric const MachineInstr &PacketMI, unsigned DepReg) { 6450b57cec5SDimitry Andric // Make sure we are looking at the store, that can be promoted. 6460b57cec5SDimitry Andric if (!HII->mayBeNewStore(MI)) 6470b57cec5SDimitry Andric return false; 6480b57cec5SDimitry Andric 6490b57cec5SDimitry Andric // Make sure there is dependency and can be new value'd. 6500b57cec5SDimitry Andric const MachineOperand &Val = getStoreValueOperand(MI); 6510b57cec5SDimitry Andric if (Val.isReg() && Val.getReg() != DepReg) 6520b57cec5SDimitry Andric return false; 6530b57cec5SDimitry Andric 6540b57cec5SDimitry Andric const MCInstrDesc& MCID = PacketMI.getDesc(); 6550b57cec5SDimitry Andric 6560b57cec5SDimitry Andric // First operand is always the result. 6570b57cec5SDimitry Andric const TargetRegisterClass *PacketRC = HII->getRegClass(MCID, 0, HRI, MF); 6580b57cec5SDimitry Andric // Double regs can not feed into new value store: PRM section: 5.4.2.2. 6590b57cec5SDimitry Andric if (PacketRC == &Hexagon::DoubleRegsRegClass) 6600b57cec5SDimitry Andric return false; 6610b57cec5SDimitry Andric 6620b57cec5SDimitry Andric // New-value stores are of class NV (slot 0), dual stores require class ST 6630b57cec5SDimitry Andric // in slot 0 (PRM 5.5). 6640b57cec5SDimitry Andric for (auto I : CurrentPacketMIs) { 6650b57cec5SDimitry Andric SUnit *PacketSU = MIToSUnit.find(I)->second; 6660b57cec5SDimitry Andric if (PacketSU->getInstr()->mayStore()) 6670b57cec5SDimitry Andric return false; 6680b57cec5SDimitry Andric } 6690b57cec5SDimitry Andric 6700b57cec5SDimitry Andric // Make sure it's NOT the post increment register that we are going to 6710b57cec5SDimitry Andric // new value. 6720b57cec5SDimitry Andric if (HII->isPostIncrement(MI) && 6730b57cec5SDimitry Andric getPostIncrementOperand(MI, HII).getReg() == DepReg) { 6740b57cec5SDimitry Andric return false; 6750b57cec5SDimitry Andric } 6760b57cec5SDimitry Andric 6770b57cec5SDimitry Andric if (HII->isPostIncrement(PacketMI) && PacketMI.mayLoad() && 6780b57cec5SDimitry Andric getPostIncrementOperand(PacketMI, HII).getReg() == DepReg) { 6790b57cec5SDimitry Andric // If source is post_inc, or absolute-set addressing, it can not feed 6800b57cec5SDimitry Andric // into new value store 6810b57cec5SDimitry Andric // r3 = memw(r2++#4) 6820b57cec5SDimitry Andric // memw(r30 + #-1404) = r2.new -> can not be new value store 6830b57cec5SDimitry Andric // arch spec section: 5.4.2.1. 6840b57cec5SDimitry Andric return false; 6850b57cec5SDimitry Andric } 6860b57cec5SDimitry Andric 6870b57cec5SDimitry Andric if (isLoadAbsSet(PacketMI) && getAbsSetOperand(PacketMI).getReg() == DepReg) 6880b57cec5SDimitry Andric return false; 6890b57cec5SDimitry Andric 6900b57cec5SDimitry Andric // If the source that feeds the store is predicated, new value store must 6910b57cec5SDimitry Andric // also be predicated. 6920b57cec5SDimitry Andric if (HII->isPredicated(PacketMI)) { 6930b57cec5SDimitry Andric if (!HII->isPredicated(MI)) 6940b57cec5SDimitry Andric return false; 6950b57cec5SDimitry Andric 6960b57cec5SDimitry Andric // Check to make sure that they both will have their predicates 6970b57cec5SDimitry Andric // evaluate identically. 6980b57cec5SDimitry Andric unsigned predRegNumSrc = 0; 6990b57cec5SDimitry Andric unsigned predRegNumDst = 0; 7000b57cec5SDimitry Andric const TargetRegisterClass* predRegClass = nullptr; 7010b57cec5SDimitry Andric 7020b57cec5SDimitry Andric // Get predicate register used in the source instruction. 7030b57cec5SDimitry Andric for (auto &MO : PacketMI.operands()) { 7040b57cec5SDimitry Andric if (!MO.isReg()) 7050b57cec5SDimitry Andric continue; 7060b57cec5SDimitry Andric predRegNumSrc = MO.getReg(); 7070b57cec5SDimitry Andric predRegClass = HRI->getMinimalPhysRegClass(predRegNumSrc); 7080b57cec5SDimitry Andric if (predRegClass == &Hexagon::PredRegsRegClass) 7090b57cec5SDimitry Andric break; 7100b57cec5SDimitry Andric } 7110b57cec5SDimitry Andric assert((predRegClass == &Hexagon::PredRegsRegClass) && 7120b57cec5SDimitry Andric "predicate register not found in a predicated PacketMI instruction"); 7130b57cec5SDimitry Andric 7140b57cec5SDimitry Andric // Get predicate register used in new-value store instruction. 7150b57cec5SDimitry Andric for (auto &MO : MI.operands()) { 7160b57cec5SDimitry Andric if (!MO.isReg()) 7170b57cec5SDimitry Andric continue; 7180b57cec5SDimitry Andric predRegNumDst = MO.getReg(); 7190b57cec5SDimitry Andric predRegClass = HRI->getMinimalPhysRegClass(predRegNumDst); 7200b57cec5SDimitry Andric if (predRegClass == &Hexagon::PredRegsRegClass) 7210b57cec5SDimitry Andric break; 7220b57cec5SDimitry Andric } 7230b57cec5SDimitry Andric assert((predRegClass == &Hexagon::PredRegsRegClass) && 7240b57cec5SDimitry Andric "predicate register not found in a predicated MI instruction"); 7250b57cec5SDimitry Andric 7260b57cec5SDimitry Andric // New-value register producer and user (store) need to satisfy these 7270b57cec5SDimitry Andric // constraints: 7280b57cec5SDimitry Andric // 1) Both instructions should be predicated on the same register. 7290b57cec5SDimitry Andric // 2) If producer of the new-value register is .new predicated then store 7300b57cec5SDimitry Andric // should also be .new predicated and if producer is not .new predicated 7310b57cec5SDimitry Andric // then store should not be .new predicated. 7320b57cec5SDimitry Andric // 3) Both new-value register producer and user should have same predicate 7330b57cec5SDimitry Andric // sense, i.e, either both should be negated or both should be non-negated. 7340b57cec5SDimitry Andric if (predRegNumDst != predRegNumSrc || 7350b57cec5SDimitry Andric HII->isDotNewInst(PacketMI) != HII->isDotNewInst(MI) || 7360b57cec5SDimitry Andric getPredicateSense(MI, HII) != getPredicateSense(PacketMI, HII)) 7370b57cec5SDimitry Andric return false; 7380b57cec5SDimitry Andric } 7390b57cec5SDimitry Andric 7400b57cec5SDimitry Andric // Make sure that other than the new-value register no other store instruction 7410b57cec5SDimitry Andric // register has been modified in the same packet. Predicate registers can be 7420b57cec5SDimitry Andric // modified by they should not be modified between the producer and the store 7430b57cec5SDimitry Andric // instruction as it will make them both conditional on different values. 7440b57cec5SDimitry Andric // We already know this to be true for all the instructions before and 7450b57cec5SDimitry Andric // including PacketMI. Howerver, we need to perform the check for the 7460b57cec5SDimitry Andric // remaining instructions in the packet. 7470b57cec5SDimitry Andric 7480b57cec5SDimitry Andric unsigned StartCheck = 0; 7490b57cec5SDimitry Andric 7500b57cec5SDimitry Andric for (auto I : CurrentPacketMIs) { 7510b57cec5SDimitry Andric SUnit *TempSU = MIToSUnit.find(I)->second; 7520b57cec5SDimitry Andric MachineInstr &TempMI = *TempSU->getInstr(); 7530b57cec5SDimitry Andric 7540b57cec5SDimitry Andric // Following condition is true for all the instructions until PacketMI is 7550b57cec5SDimitry Andric // reached (StartCheck is set to 0 before the for loop). 7560b57cec5SDimitry Andric // StartCheck flag is 1 for all the instructions after PacketMI. 7570b57cec5SDimitry Andric if (&TempMI != &PacketMI && !StartCheck) // Start processing only after 7580b57cec5SDimitry Andric continue; // encountering PacketMI. 7590b57cec5SDimitry Andric 7600b57cec5SDimitry Andric StartCheck = 1; 7610b57cec5SDimitry Andric if (&TempMI == &PacketMI) // We don't want to check PacketMI for dependence. 7620b57cec5SDimitry Andric continue; 7630b57cec5SDimitry Andric 7640b57cec5SDimitry Andric for (auto &MO : MI.operands()) 7650b57cec5SDimitry Andric if (MO.isReg() && TempSU->getInstr()->modifiesRegister(MO.getReg(), HRI)) 7660b57cec5SDimitry Andric return false; 7670b57cec5SDimitry Andric } 7680b57cec5SDimitry Andric 7690b57cec5SDimitry Andric // Make sure that for non-POST_INC stores: 7700b57cec5SDimitry Andric // 1. The only use of reg is DepReg and no other registers. 7710b57cec5SDimitry Andric // This handles base+index registers. 7720b57cec5SDimitry Andric // The following store can not be dot new. 7730b57cec5SDimitry Andric // Eg. r0 = add(r0, #3) 7740b57cec5SDimitry Andric // memw(r1+r0<<#2) = r0 7750b57cec5SDimitry Andric if (!HII->isPostIncrement(MI)) { 7760b57cec5SDimitry Andric for (unsigned opNum = 0; opNum < MI.getNumOperands()-1; opNum++) { 7770b57cec5SDimitry Andric const MachineOperand &MO = MI.getOperand(opNum); 7780b57cec5SDimitry Andric if (MO.isReg() && MO.getReg() == DepReg) 7790b57cec5SDimitry Andric return false; 7800b57cec5SDimitry Andric } 7810b57cec5SDimitry Andric } 7820b57cec5SDimitry Andric 7830b57cec5SDimitry Andric // If data definition is because of implicit definition of the register, 7840b57cec5SDimitry Andric // do not newify the store. Eg. 7850b57cec5SDimitry Andric // %r9 = ZXTH %r12, implicit %d6, implicit-def %r12 7860b57cec5SDimitry Andric // S2_storerh_io %r8, 2, killed %r12; mem:ST2[%scevgep343] 7870b57cec5SDimitry Andric for (auto &MO : PacketMI.operands()) { 7880b57cec5SDimitry Andric if (MO.isRegMask() && MO.clobbersPhysReg(DepReg)) 7890b57cec5SDimitry Andric return false; 7900b57cec5SDimitry Andric if (!MO.isReg() || !MO.isDef() || !MO.isImplicit()) 7910b57cec5SDimitry Andric continue; 792*8bcb0991SDimitry Andric Register R = MO.getReg(); 7930b57cec5SDimitry Andric if (R == DepReg || HRI->isSuperRegister(DepReg, R)) 7940b57cec5SDimitry Andric return false; 7950b57cec5SDimitry Andric } 7960b57cec5SDimitry Andric 7970b57cec5SDimitry Andric // Handle imp-use of super reg case. There is a target independent side 7980b57cec5SDimitry Andric // change that should prevent this situation but I am handling it for 7990b57cec5SDimitry Andric // just-in-case. For example, we cannot newify R2 in the following case: 8000b57cec5SDimitry Andric // %r3 = A2_tfrsi 0; 8010b57cec5SDimitry Andric // S2_storeri_io killed %r0, 0, killed %r2, implicit killed %d1; 8020b57cec5SDimitry Andric for (auto &MO : MI.operands()) { 8030b57cec5SDimitry Andric if (MO.isReg() && MO.isUse() && MO.isImplicit() && MO.getReg() == DepReg) 8040b57cec5SDimitry Andric return false; 8050b57cec5SDimitry Andric } 8060b57cec5SDimitry Andric 8070b57cec5SDimitry Andric // Can be dot new store. 8080b57cec5SDimitry Andric return true; 8090b57cec5SDimitry Andric } 8100b57cec5SDimitry Andric 8110b57cec5SDimitry Andric // Can this MI to promoted to either new value store or new value jump. 8120b57cec5SDimitry Andric bool HexagonPacketizerList::canPromoteToNewValue(const MachineInstr &MI, 8130b57cec5SDimitry Andric const SUnit *PacketSU, unsigned DepReg, 8140b57cec5SDimitry Andric MachineBasicBlock::iterator &MII) { 8150b57cec5SDimitry Andric if (!HII->mayBeNewStore(MI)) 8160b57cec5SDimitry Andric return false; 8170b57cec5SDimitry Andric 8180b57cec5SDimitry Andric // Check to see the store can be new value'ed. 8190b57cec5SDimitry Andric MachineInstr &PacketMI = *PacketSU->getInstr(); 8200b57cec5SDimitry Andric if (canPromoteToNewValueStore(MI, PacketMI, DepReg)) 8210b57cec5SDimitry Andric return true; 8220b57cec5SDimitry Andric 8230b57cec5SDimitry Andric // Check to see the compare/jump can be new value'ed. 8240b57cec5SDimitry Andric // This is done as a pass on its own. Don't need to check it here. 8250b57cec5SDimitry Andric return false; 8260b57cec5SDimitry Andric } 8270b57cec5SDimitry Andric 8280b57cec5SDimitry Andric static bool isImplicitDependency(const MachineInstr &I, bool CheckDef, 8290b57cec5SDimitry Andric unsigned DepReg) { 8300b57cec5SDimitry Andric for (auto &MO : I.operands()) { 8310b57cec5SDimitry Andric if (CheckDef && MO.isRegMask() && MO.clobbersPhysReg(DepReg)) 8320b57cec5SDimitry Andric return true; 8330b57cec5SDimitry Andric if (!MO.isReg() || MO.getReg() != DepReg || !MO.isImplicit()) 8340b57cec5SDimitry Andric continue; 8350b57cec5SDimitry Andric if (CheckDef == MO.isDef()) 8360b57cec5SDimitry Andric return true; 8370b57cec5SDimitry Andric } 8380b57cec5SDimitry Andric return false; 8390b57cec5SDimitry Andric } 8400b57cec5SDimitry Andric 8410b57cec5SDimitry Andric // Check to see if an instruction can be dot new. 8420b57cec5SDimitry Andric bool HexagonPacketizerList::canPromoteToDotNew(const MachineInstr &MI, 8430b57cec5SDimitry Andric const SUnit *PacketSU, unsigned DepReg, MachineBasicBlock::iterator &MII, 8440b57cec5SDimitry Andric const TargetRegisterClass* RC) { 8450b57cec5SDimitry Andric // Already a dot new instruction. 8460b57cec5SDimitry Andric if (HII->isDotNewInst(MI) && !HII->mayBeNewStore(MI)) 8470b57cec5SDimitry Andric return false; 8480b57cec5SDimitry Andric 8490b57cec5SDimitry Andric if (!isNewifiable(MI, RC)) 8500b57cec5SDimitry Andric return false; 8510b57cec5SDimitry Andric 8520b57cec5SDimitry Andric const MachineInstr &PI = *PacketSU->getInstr(); 8530b57cec5SDimitry Andric 8540b57cec5SDimitry Andric // The "new value" cannot come from inline asm. 8550b57cec5SDimitry Andric if (PI.isInlineAsm()) 8560b57cec5SDimitry Andric return false; 8570b57cec5SDimitry Andric 8580b57cec5SDimitry Andric // IMPLICIT_DEFs won't materialize as real instructions, so .new makes no 8590b57cec5SDimitry Andric // sense. 8600b57cec5SDimitry Andric if (PI.isImplicitDef()) 8610b57cec5SDimitry Andric return false; 8620b57cec5SDimitry Andric 8630b57cec5SDimitry Andric // If dependency is trough an implicitly defined register, we should not 8640b57cec5SDimitry Andric // newify the use. 8650b57cec5SDimitry Andric if (isImplicitDependency(PI, true, DepReg) || 8660b57cec5SDimitry Andric isImplicitDependency(MI, false, DepReg)) 8670b57cec5SDimitry Andric return false; 8680b57cec5SDimitry Andric 8690b57cec5SDimitry Andric const MCInstrDesc& MCID = PI.getDesc(); 8700b57cec5SDimitry Andric const TargetRegisterClass *VecRC = HII->getRegClass(MCID, 0, HRI, MF); 8710b57cec5SDimitry Andric if (DisableVecDblNVStores && VecRC == &Hexagon::HvxWRRegClass) 8720b57cec5SDimitry Andric return false; 8730b57cec5SDimitry Andric 8740b57cec5SDimitry Andric // predicate .new 8750b57cec5SDimitry Andric if (RC == &Hexagon::PredRegsRegClass) 8760b57cec5SDimitry Andric return HII->predCanBeUsedAsDotNew(PI, DepReg); 8770b57cec5SDimitry Andric 8780b57cec5SDimitry Andric if (RC != &Hexagon::PredRegsRegClass && !HII->mayBeNewStore(MI)) 8790b57cec5SDimitry Andric return false; 8800b57cec5SDimitry Andric 8810b57cec5SDimitry Andric // Create a dot new machine instruction to see if resources can be 8820b57cec5SDimitry Andric // allocated. If not, bail out now. 8830b57cec5SDimitry Andric int NewOpcode = HII->getDotNewOp(MI); 8840b57cec5SDimitry Andric const MCInstrDesc &D = HII->get(NewOpcode); 8850b57cec5SDimitry Andric MachineInstr *NewMI = MF.CreateMachineInstr(D, DebugLoc()); 8860b57cec5SDimitry Andric bool ResourcesAvailable = ResourceTracker->canReserveResources(*NewMI); 8870b57cec5SDimitry Andric MF.DeleteMachineInstr(NewMI); 8880b57cec5SDimitry Andric if (!ResourcesAvailable) 8890b57cec5SDimitry Andric return false; 8900b57cec5SDimitry Andric 8910b57cec5SDimitry Andric // New Value Store only. New Value Jump generated as a separate pass. 8920b57cec5SDimitry Andric if (!canPromoteToNewValue(MI, PacketSU, DepReg, MII)) 8930b57cec5SDimitry Andric return false; 8940b57cec5SDimitry Andric 8950b57cec5SDimitry Andric return true; 8960b57cec5SDimitry Andric } 8970b57cec5SDimitry Andric 8980b57cec5SDimitry Andric // Go through the packet instructions and search for an anti dependency between 8990b57cec5SDimitry Andric // them and DepReg from MI. Consider this case: 9000b57cec5SDimitry Andric // Trying to add 9010b57cec5SDimitry Andric // a) %r1 = TFRI_cdNotPt %p3, 2 9020b57cec5SDimitry Andric // to this packet: 9030b57cec5SDimitry Andric // { 9040b57cec5SDimitry Andric // b) %p0 = C2_or killed %p3, killed %p0 9050b57cec5SDimitry Andric // c) %p3 = C2_tfrrp %r23 9060b57cec5SDimitry Andric // d) %r1 = C2_cmovenewit %p3, 4 9070b57cec5SDimitry Andric // } 9080b57cec5SDimitry Andric // The P3 from a) and d) will be complements after 9090b57cec5SDimitry Andric // a)'s P3 is converted to .new form 9100b57cec5SDimitry Andric // Anti-dep between c) and b) is irrelevant for this case 9110b57cec5SDimitry Andric bool HexagonPacketizerList::restrictingDepExistInPacket(MachineInstr &MI, 9120b57cec5SDimitry Andric unsigned DepReg) { 9130b57cec5SDimitry Andric SUnit *PacketSUDep = MIToSUnit.find(&MI)->second; 9140b57cec5SDimitry Andric 9150b57cec5SDimitry Andric for (auto I : CurrentPacketMIs) { 9160b57cec5SDimitry Andric // We only care for dependencies to predicated instructions 9170b57cec5SDimitry Andric if (!HII->isPredicated(*I)) 9180b57cec5SDimitry Andric continue; 9190b57cec5SDimitry Andric 9200b57cec5SDimitry Andric // Scheduling Unit for current insn in the packet 9210b57cec5SDimitry Andric SUnit *PacketSU = MIToSUnit.find(I)->second; 9220b57cec5SDimitry Andric 9230b57cec5SDimitry Andric // Look at dependencies between current members of the packet and 9240b57cec5SDimitry Andric // predicate defining instruction MI. Make sure that dependency is 9250b57cec5SDimitry Andric // on the exact register we care about. 9260b57cec5SDimitry Andric if (PacketSU->isSucc(PacketSUDep)) { 9270b57cec5SDimitry Andric for (unsigned i = 0; i < PacketSU->Succs.size(); ++i) { 9280b57cec5SDimitry Andric auto &Dep = PacketSU->Succs[i]; 9290b57cec5SDimitry Andric if (Dep.getSUnit() == PacketSUDep && Dep.getKind() == SDep::Anti && 9300b57cec5SDimitry Andric Dep.getReg() == DepReg) 9310b57cec5SDimitry Andric return true; 9320b57cec5SDimitry Andric } 9330b57cec5SDimitry Andric } 9340b57cec5SDimitry Andric } 9350b57cec5SDimitry Andric 9360b57cec5SDimitry Andric return false; 9370b57cec5SDimitry Andric } 9380b57cec5SDimitry Andric 9390b57cec5SDimitry Andric /// Gets the predicate register of a predicated instruction. 9400b57cec5SDimitry Andric static unsigned getPredicatedRegister(MachineInstr &MI, 9410b57cec5SDimitry Andric const HexagonInstrInfo *QII) { 9420b57cec5SDimitry Andric /// We use the following rule: The first predicate register that is a use is 9430b57cec5SDimitry Andric /// the predicate register of a predicated instruction. 9440b57cec5SDimitry Andric assert(QII->isPredicated(MI) && "Must be predicated instruction"); 9450b57cec5SDimitry Andric 9460b57cec5SDimitry Andric for (auto &Op : MI.operands()) { 9470b57cec5SDimitry Andric if (Op.isReg() && Op.getReg() && Op.isUse() && 9480b57cec5SDimitry Andric Hexagon::PredRegsRegClass.contains(Op.getReg())) 9490b57cec5SDimitry Andric return Op.getReg(); 9500b57cec5SDimitry Andric } 9510b57cec5SDimitry Andric 9520b57cec5SDimitry Andric llvm_unreachable("Unknown instruction operand layout"); 9530b57cec5SDimitry Andric return 0; 9540b57cec5SDimitry Andric } 9550b57cec5SDimitry Andric 9560b57cec5SDimitry Andric // Given two predicated instructions, this function detects whether 9570b57cec5SDimitry Andric // the predicates are complements. 9580b57cec5SDimitry Andric bool HexagonPacketizerList::arePredicatesComplements(MachineInstr &MI1, 9590b57cec5SDimitry Andric MachineInstr &MI2) { 9600b57cec5SDimitry Andric // If we don't know the predicate sense of the instructions bail out early, we 9610b57cec5SDimitry Andric // need it later. 9620b57cec5SDimitry Andric if (getPredicateSense(MI1, HII) == PK_Unknown || 9630b57cec5SDimitry Andric getPredicateSense(MI2, HII) == PK_Unknown) 9640b57cec5SDimitry Andric return false; 9650b57cec5SDimitry Andric 9660b57cec5SDimitry Andric // Scheduling unit for candidate. 9670b57cec5SDimitry Andric SUnit *SU = MIToSUnit[&MI1]; 9680b57cec5SDimitry Andric 9690b57cec5SDimitry Andric // One corner case deals with the following scenario: 9700b57cec5SDimitry Andric // Trying to add 9710b57cec5SDimitry Andric // a) %r24 = A2_tfrt %p0, %r25 9720b57cec5SDimitry Andric // to this packet: 9730b57cec5SDimitry Andric // { 9740b57cec5SDimitry Andric // b) %r25 = A2_tfrf %p0, %r24 9750b57cec5SDimitry Andric // c) %p0 = C2_cmpeqi %r26, 1 9760b57cec5SDimitry Andric // } 9770b57cec5SDimitry Andric // 9780b57cec5SDimitry Andric // On general check a) and b) are complements, but presence of c) will 9790b57cec5SDimitry Andric // convert a) to .new form, and then it is not a complement. 9800b57cec5SDimitry Andric // We attempt to detect it by analyzing existing dependencies in the packet. 9810b57cec5SDimitry Andric 9820b57cec5SDimitry Andric // Analyze relationships between all existing members of the packet. 9830b57cec5SDimitry Andric // Look for Anti dependecy on the same predicate reg as used in the 9840b57cec5SDimitry Andric // candidate. 9850b57cec5SDimitry Andric for (auto I : CurrentPacketMIs) { 9860b57cec5SDimitry Andric // Scheduling Unit for current insn in the packet. 9870b57cec5SDimitry Andric SUnit *PacketSU = MIToSUnit.find(I)->second; 9880b57cec5SDimitry Andric 9890b57cec5SDimitry Andric // If this instruction in the packet is succeeded by the candidate... 9900b57cec5SDimitry Andric if (PacketSU->isSucc(SU)) { 9910b57cec5SDimitry Andric for (unsigned i = 0; i < PacketSU->Succs.size(); ++i) { 9920b57cec5SDimitry Andric auto Dep = PacketSU->Succs[i]; 9930b57cec5SDimitry Andric // The corner case exist when there is true data dependency between 9940b57cec5SDimitry Andric // candidate and one of current packet members, this dep is on 9950b57cec5SDimitry Andric // predicate reg, and there already exist anti dep on the same pred in 9960b57cec5SDimitry Andric // the packet. 9970b57cec5SDimitry Andric if (Dep.getSUnit() == SU && Dep.getKind() == SDep::Data && 9980b57cec5SDimitry Andric Hexagon::PredRegsRegClass.contains(Dep.getReg())) { 9990b57cec5SDimitry Andric // Here I know that I is predicate setting instruction with true 10000b57cec5SDimitry Andric // data dep to candidate on the register we care about - c) in the 10010b57cec5SDimitry Andric // above example. Now I need to see if there is an anti dependency 10020b57cec5SDimitry Andric // from c) to any other instruction in the same packet on the pred 10030b57cec5SDimitry Andric // reg of interest. 10040b57cec5SDimitry Andric if (restrictingDepExistInPacket(*I, Dep.getReg())) 10050b57cec5SDimitry Andric return false; 10060b57cec5SDimitry Andric } 10070b57cec5SDimitry Andric } 10080b57cec5SDimitry Andric } 10090b57cec5SDimitry Andric } 10100b57cec5SDimitry Andric 10110b57cec5SDimitry Andric // If the above case does not apply, check regular complement condition. 10120b57cec5SDimitry Andric // Check that the predicate register is the same and that the predicate 10130b57cec5SDimitry Andric // sense is different We also need to differentiate .old vs. .new: !p0 10140b57cec5SDimitry Andric // is not complementary to p0.new. 10150b57cec5SDimitry Andric unsigned PReg1 = getPredicatedRegister(MI1, HII); 10160b57cec5SDimitry Andric unsigned PReg2 = getPredicatedRegister(MI2, HII); 10170b57cec5SDimitry Andric return PReg1 == PReg2 && 10180b57cec5SDimitry Andric Hexagon::PredRegsRegClass.contains(PReg1) && 10190b57cec5SDimitry Andric Hexagon::PredRegsRegClass.contains(PReg2) && 10200b57cec5SDimitry Andric getPredicateSense(MI1, HII) != getPredicateSense(MI2, HII) && 10210b57cec5SDimitry Andric HII->isDotNewInst(MI1) == HII->isDotNewInst(MI2); 10220b57cec5SDimitry Andric } 10230b57cec5SDimitry Andric 10240b57cec5SDimitry Andric // Initialize packetizer flags. 10250b57cec5SDimitry Andric void HexagonPacketizerList::initPacketizerState() { 10260b57cec5SDimitry Andric Dependence = false; 10270b57cec5SDimitry Andric PromotedToDotNew = false; 10280b57cec5SDimitry Andric GlueToNewValueJump = false; 10290b57cec5SDimitry Andric GlueAllocframeStore = false; 10300b57cec5SDimitry Andric FoundSequentialDependence = false; 10310b57cec5SDimitry Andric ChangedOffset = INT64_MAX; 10320b57cec5SDimitry Andric } 10330b57cec5SDimitry Andric 10340b57cec5SDimitry Andric // Ignore bundling of pseudo instructions. 10350b57cec5SDimitry Andric bool HexagonPacketizerList::ignorePseudoInstruction(const MachineInstr &MI, 10360b57cec5SDimitry Andric const MachineBasicBlock *) { 10370b57cec5SDimitry Andric if (MI.isDebugInstr()) 10380b57cec5SDimitry Andric return true; 10390b57cec5SDimitry Andric 10400b57cec5SDimitry Andric if (MI.isCFIInstruction()) 10410b57cec5SDimitry Andric return false; 10420b57cec5SDimitry Andric 10430b57cec5SDimitry Andric // We must print out inline assembly. 10440b57cec5SDimitry Andric if (MI.isInlineAsm()) 10450b57cec5SDimitry Andric return false; 10460b57cec5SDimitry Andric 10470b57cec5SDimitry Andric if (MI.isImplicitDef()) 10480b57cec5SDimitry Andric return false; 10490b57cec5SDimitry Andric 10500b57cec5SDimitry Andric // We check if MI has any functional units mapped to it. If it doesn't, 10510b57cec5SDimitry Andric // we ignore the instruction. 10520b57cec5SDimitry Andric const MCInstrDesc& TID = MI.getDesc(); 10530b57cec5SDimitry Andric auto *IS = ResourceTracker->getInstrItins()->beginStage(TID.getSchedClass()); 10540b57cec5SDimitry Andric unsigned FuncUnits = IS->getUnits(); 10550b57cec5SDimitry Andric return !FuncUnits; 10560b57cec5SDimitry Andric } 10570b57cec5SDimitry Andric 10580b57cec5SDimitry Andric bool HexagonPacketizerList::isSoloInstruction(const MachineInstr &MI) { 10590b57cec5SDimitry Andric // Ensure any bundles created by gather packetize remain seperate. 10600b57cec5SDimitry Andric if (MI.isBundle()) 10610b57cec5SDimitry Andric return true; 10620b57cec5SDimitry Andric 10630b57cec5SDimitry Andric if (MI.isEHLabel() || MI.isCFIInstruction()) 10640b57cec5SDimitry Andric return true; 10650b57cec5SDimitry Andric 10660b57cec5SDimitry Andric // Consider inline asm to not be a solo instruction by default. 10670b57cec5SDimitry Andric // Inline asm will be put in a packet temporarily, but then it will be 10680b57cec5SDimitry Andric // removed, and placed outside of the packet (before or after, depending 10690b57cec5SDimitry Andric // on dependencies). This is to reduce the impact of inline asm as a 10700b57cec5SDimitry Andric // "packet splitting" instruction. 10710b57cec5SDimitry Andric if (MI.isInlineAsm() && !ScheduleInlineAsm) 10720b57cec5SDimitry Andric return true; 10730b57cec5SDimitry Andric 10740b57cec5SDimitry Andric if (isSchedBarrier(MI)) 10750b57cec5SDimitry Andric return true; 10760b57cec5SDimitry Andric 10770b57cec5SDimitry Andric if (HII->isSolo(MI)) 10780b57cec5SDimitry Andric return true; 10790b57cec5SDimitry Andric 10800b57cec5SDimitry Andric if (MI.getOpcode() == Hexagon::A2_nop) 10810b57cec5SDimitry Andric return true; 10820b57cec5SDimitry Andric 10830b57cec5SDimitry Andric return false; 10840b57cec5SDimitry Andric } 10850b57cec5SDimitry Andric 10860b57cec5SDimitry Andric // Quick check if instructions MI and MJ cannot coexist in the same packet. 10870b57cec5SDimitry Andric // Limit the tests to be "one-way", e.g. "if MI->isBranch and MJ->isInlineAsm", 10880b57cec5SDimitry Andric // but not the symmetric case: "if MJ->isBranch and MI->isInlineAsm". 10890b57cec5SDimitry Andric // For full test call this function twice: 10900b57cec5SDimitry Andric // cannotCoexistAsymm(MI, MJ) || cannotCoexistAsymm(MJ, MI) 10910b57cec5SDimitry Andric // Doing the test only one way saves the amount of code in this function, 10920b57cec5SDimitry Andric // since every test would need to be repeated with the MI and MJ reversed. 10930b57cec5SDimitry Andric static bool cannotCoexistAsymm(const MachineInstr &MI, const MachineInstr &MJ, 10940b57cec5SDimitry Andric const HexagonInstrInfo &HII) { 10950b57cec5SDimitry Andric const MachineFunction *MF = MI.getParent()->getParent(); 10960b57cec5SDimitry Andric if (MF->getSubtarget<HexagonSubtarget>().hasV60OpsOnly() && 10970b57cec5SDimitry Andric HII.isHVXMemWithAIndirect(MI, MJ)) 10980b57cec5SDimitry Andric return true; 10990b57cec5SDimitry Andric 11000b57cec5SDimitry Andric // An inline asm cannot be together with a branch, because we may not be 11010b57cec5SDimitry Andric // able to remove the asm out after packetizing (i.e. if the asm must be 11020b57cec5SDimitry Andric // moved past the bundle). Similarly, two asms cannot be together to avoid 11030b57cec5SDimitry Andric // complications when determining their relative order outside of a bundle. 11040b57cec5SDimitry Andric if (MI.isInlineAsm()) 11050b57cec5SDimitry Andric return MJ.isInlineAsm() || MJ.isBranch() || MJ.isBarrier() || 11060b57cec5SDimitry Andric MJ.isCall() || MJ.isTerminator(); 11070b57cec5SDimitry Andric 11080b57cec5SDimitry Andric // New-value stores cannot coexist with any other stores. 11090b57cec5SDimitry Andric if (HII.isNewValueStore(MI) && MJ.mayStore()) 11100b57cec5SDimitry Andric return true; 11110b57cec5SDimitry Andric 11120b57cec5SDimitry Andric switch (MI.getOpcode()) { 11130b57cec5SDimitry Andric case Hexagon::S2_storew_locked: 11140b57cec5SDimitry Andric case Hexagon::S4_stored_locked: 11150b57cec5SDimitry Andric case Hexagon::L2_loadw_locked: 11160b57cec5SDimitry Andric case Hexagon::L4_loadd_locked: 11170b57cec5SDimitry Andric case Hexagon::Y2_dccleana: 11180b57cec5SDimitry Andric case Hexagon::Y2_dccleaninva: 11190b57cec5SDimitry Andric case Hexagon::Y2_dcinva: 11200b57cec5SDimitry Andric case Hexagon::Y2_dczeroa: 11210b57cec5SDimitry Andric case Hexagon::Y4_l2fetch: 11220b57cec5SDimitry Andric case Hexagon::Y5_l2fetch: { 11230b57cec5SDimitry Andric // These instructions can only be grouped with ALU32 or non-floating-point 11240b57cec5SDimitry Andric // XTYPE instructions. Since there is no convenient way of identifying fp 11250b57cec5SDimitry Andric // XTYPE instructions, only allow grouping with ALU32 for now. 11260b57cec5SDimitry Andric unsigned TJ = HII.getType(MJ); 11270b57cec5SDimitry Andric if (TJ != HexagonII::TypeALU32_2op && 11280b57cec5SDimitry Andric TJ != HexagonII::TypeALU32_3op && 11290b57cec5SDimitry Andric TJ != HexagonII::TypeALU32_ADDI) 11300b57cec5SDimitry Andric return true; 11310b57cec5SDimitry Andric break; 11320b57cec5SDimitry Andric } 11330b57cec5SDimitry Andric default: 11340b57cec5SDimitry Andric break; 11350b57cec5SDimitry Andric } 11360b57cec5SDimitry Andric 11370b57cec5SDimitry Andric // "False" really means that the quick check failed to determine if 11380b57cec5SDimitry Andric // I and J cannot coexist. 11390b57cec5SDimitry Andric return false; 11400b57cec5SDimitry Andric } 11410b57cec5SDimitry Andric 11420b57cec5SDimitry Andric // Full, symmetric check. 11430b57cec5SDimitry Andric bool HexagonPacketizerList::cannotCoexist(const MachineInstr &MI, 11440b57cec5SDimitry Andric const MachineInstr &MJ) { 11450b57cec5SDimitry Andric return cannotCoexistAsymm(MI, MJ, *HII) || cannotCoexistAsymm(MJ, MI, *HII); 11460b57cec5SDimitry Andric } 11470b57cec5SDimitry Andric 11480b57cec5SDimitry Andric void HexagonPacketizerList::unpacketizeSoloInstrs(MachineFunction &MF) { 11490b57cec5SDimitry Andric for (auto &B : MF) { 11500b57cec5SDimitry Andric MachineBasicBlock::iterator BundleIt; 11510b57cec5SDimitry Andric MachineBasicBlock::instr_iterator NextI; 11520b57cec5SDimitry Andric for (auto I = B.instr_begin(), E = B.instr_end(); I != E; I = NextI) { 11530b57cec5SDimitry Andric NextI = std::next(I); 11540b57cec5SDimitry Andric MachineInstr &MI = *I; 11550b57cec5SDimitry Andric if (MI.isBundle()) 11560b57cec5SDimitry Andric BundleIt = I; 11570b57cec5SDimitry Andric if (!MI.isInsideBundle()) 11580b57cec5SDimitry Andric continue; 11590b57cec5SDimitry Andric 11600b57cec5SDimitry Andric // Decide on where to insert the instruction that we are pulling out. 11610b57cec5SDimitry Andric // Debug instructions always go before the bundle, but the placement of 11620b57cec5SDimitry Andric // INLINE_ASM depends on potential dependencies. By default, try to 11630b57cec5SDimitry Andric // put it before the bundle, but if the asm writes to a register that 11640b57cec5SDimitry Andric // other instructions in the bundle read, then we need to place it 11650b57cec5SDimitry Andric // after the bundle (to preserve the bundle semantics). 11660b57cec5SDimitry Andric bool InsertBeforeBundle; 11670b57cec5SDimitry Andric if (MI.isInlineAsm()) 11680b57cec5SDimitry Andric InsertBeforeBundle = !hasWriteToReadDep(MI, *BundleIt, HRI); 11690b57cec5SDimitry Andric else if (MI.isDebugValue()) 11700b57cec5SDimitry Andric InsertBeforeBundle = true; 11710b57cec5SDimitry Andric else 11720b57cec5SDimitry Andric continue; 11730b57cec5SDimitry Andric 11740b57cec5SDimitry Andric BundleIt = moveInstrOut(MI, BundleIt, InsertBeforeBundle); 11750b57cec5SDimitry Andric } 11760b57cec5SDimitry Andric } 11770b57cec5SDimitry Andric } 11780b57cec5SDimitry Andric 11790b57cec5SDimitry Andric // Check if a given instruction is of class "system". 11800b57cec5SDimitry Andric static bool isSystemInstr(const MachineInstr &MI) { 11810b57cec5SDimitry Andric unsigned Opc = MI.getOpcode(); 11820b57cec5SDimitry Andric switch (Opc) { 11830b57cec5SDimitry Andric case Hexagon::Y2_barrier: 11840b57cec5SDimitry Andric case Hexagon::Y2_dcfetchbo: 11850b57cec5SDimitry Andric case Hexagon::Y4_l2fetch: 11860b57cec5SDimitry Andric case Hexagon::Y5_l2fetch: 11870b57cec5SDimitry Andric return true; 11880b57cec5SDimitry Andric } 11890b57cec5SDimitry Andric return false; 11900b57cec5SDimitry Andric } 11910b57cec5SDimitry Andric 11920b57cec5SDimitry Andric bool HexagonPacketizerList::hasDeadDependence(const MachineInstr &I, 11930b57cec5SDimitry Andric const MachineInstr &J) { 11940b57cec5SDimitry Andric // The dependence graph may not include edges between dead definitions, 11950b57cec5SDimitry Andric // so without extra checks, we could end up packetizing two instruction 11960b57cec5SDimitry Andric // defining the same (dead) register. 11970b57cec5SDimitry Andric if (I.isCall() || J.isCall()) 11980b57cec5SDimitry Andric return false; 11990b57cec5SDimitry Andric if (HII->isPredicated(I) || HII->isPredicated(J)) 12000b57cec5SDimitry Andric return false; 12010b57cec5SDimitry Andric 12020b57cec5SDimitry Andric BitVector DeadDefs(Hexagon::NUM_TARGET_REGS); 12030b57cec5SDimitry Andric for (auto &MO : I.operands()) { 12040b57cec5SDimitry Andric if (!MO.isReg() || !MO.isDef() || !MO.isDead()) 12050b57cec5SDimitry Andric continue; 12060b57cec5SDimitry Andric DeadDefs[MO.getReg()] = true; 12070b57cec5SDimitry Andric } 12080b57cec5SDimitry Andric 12090b57cec5SDimitry Andric for (auto &MO : J.operands()) { 12100b57cec5SDimitry Andric if (!MO.isReg() || !MO.isDef() || !MO.isDead()) 12110b57cec5SDimitry Andric continue; 1212*8bcb0991SDimitry Andric Register R = MO.getReg(); 12130b57cec5SDimitry Andric if (R != Hexagon::USR_OVF && DeadDefs[R]) 12140b57cec5SDimitry Andric return true; 12150b57cec5SDimitry Andric } 12160b57cec5SDimitry Andric return false; 12170b57cec5SDimitry Andric } 12180b57cec5SDimitry Andric 12190b57cec5SDimitry Andric bool HexagonPacketizerList::hasControlDependence(const MachineInstr &I, 12200b57cec5SDimitry Andric const MachineInstr &J) { 12210b57cec5SDimitry Andric // A save callee-save register function call can only be in a packet 12220b57cec5SDimitry Andric // with instructions that don't write to the callee-save registers. 12230b57cec5SDimitry Andric if ((HII->isSaveCalleeSavedRegsCall(I) && 12240b57cec5SDimitry Andric doesModifyCalleeSavedReg(J, HRI)) || 12250b57cec5SDimitry Andric (HII->isSaveCalleeSavedRegsCall(J) && 12260b57cec5SDimitry Andric doesModifyCalleeSavedReg(I, HRI))) 12270b57cec5SDimitry Andric return true; 12280b57cec5SDimitry Andric 12290b57cec5SDimitry Andric // Two control flow instructions cannot go in the same packet. 12300b57cec5SDimitry Andric if (isControlFlow(I) && isControlFlow(J)) 12310b57cec5SDimitry Andric return true; 12320b57cec5SDimitry Andric 12330b57cec5SDimitry Andric // \ref-manual (7.3.4) A loop setup packet in loopN or spNloop0 cannot 12340b57cec5SDimitry Andric // contain a speculative indirect jump, 12350b57cec5SDimitry Andric // a new-value compare jump or a dealloc_return. 12360b57cec5SDimitry Andric auto isBadForLoopN = [this] (const MachineInstr &MI) -> bool { 12370b57cec5SDimitry Andric if (MI.isCall() || HII->isDeallocRet(MI) || HII->isNewValueJump(MI)) 12380b57cec5SDimitry Andric return true; 12390b57cec5SDimitry Andric if (HII->isPredicated(MI) && HII->isPredicatedNew(MI) && HII->isJumpR(MI)) 12400b57cec5SDimitry Andric return true; 12410b57cec5SDimitry Andric return false; 12420b57cec5SDimitry Andric }; 12430b57cec5SDimitry Andric 12440b57cec5SDimitry Andric if (HII->isLoopN(I) && isBadForLoopN(J)) 12450b57cec5SDimitry Andric return true; 12460b57cec5SDimitry Andric if (HII->isLoopN(J) && isBadForLoopN(I)) 12470b57cec5SDimitry Andric return true; 12480b57cec5SDimitry Andric 12490b57cec5SDimitry Andric // dealloc_return cannot appear in the same packet as a conditional or 12500b57cec5SDimitry Andric // unconditional jump. 12510b57cec5SDimitry Andric return HII->isDeallocRet(I) && 12520b57cec5SDimitry Andric (J.isBranch() || J.isCall() || J.isBarrier()); 12530b57cec5SDimitry Andric } 12540b57cec5SDimitry Andric 12550b57cec5SDimitry Andric bool HexagonPacketizerList::hasRegMaskDependence(const MachineInstr &I, 12560b57cec5SDimitry Andric const MachineInstr &J) { 12570b57cec5SDimitry Andric // Adding I to a packet that has J. 12580b57cec5SDimitry Andric 12590b57cec5SDimitry Andric // Regmasks are not reflected in the scheduling dependency graph, so 12600b57cec5SDimitry Andric // we need to check them manually. This code assumes that regmasks only 12610b57cec5SDimitry Andric // occur on calls, and the problematic case is when we add an instruction 12620b57cec5SDimitry Andric // defining a register R to a packet that has a call that clobbers R via 12630b57cec5SDimitry Andric // a regmask. Those cannot be packetized together, because the call will 12640b57cec5SDimitry Andric // be executed last. That's also a reson why it is ok to add a call 12650b57cec5SDimitry Andric // clobbering R to a packet that defines R. 12660b57cec5SDimitry Andric 12670b57cec5SDimitry Andric // Look for regmasks in J. 12680b57cec5SDimitry Andric for (const MachineOperand &OpJ : J.operands()) { 12690b57cec5SDimitry Andric if (!OpJ.isRegMask()) 12700b57cec5SDimitry Andric continue; 12710b57cec5SDimitry Andric assert((J.isCall() || HII->isTailCall(J)) && "Regmask on a non-call"); 12720b57cec5SDimitry Andric for (const MachineOperand &OpI : I.operands()) { 12730b57cec5SDimitry Andric if (OpI.isReg()) { 12740b57cec5SDimitry Andric if (OpJ.clobbersPhysReg(OpI.getReg())) 12750b57cec5SDimitry Andric return true; 12760b57cec5SDimitry Andric } else if (OpI.isRegMask()) { 12770b57cec5SDimitry Andric // Both are regmasks. Assume that they intersect. 12780b57cec5SDimitry Andric return true; 12790b57cec5SDimitry Andric } 12800b57cec5SDimitry Andric } 12810b57cec5SDimitry Andric } 12820b57cec5SDimitry Andric return false; 12830b57cec5SDimitry Andric } 12840b57cec5SDimitry Andric 12850b57cec5SDimitry Andric bool HexagonPacketizerList::hasDualStoreDependence(const MachineInstr &I, 12860b57cec5SDimitry Andric const MachineInstr &J) { 12870b57cec5SDimitry Andric bool SysI = isSystemInstr(I), SysJ = isSystemInstr(J); 12880b57cec5SDimitry Andric bool StoreI = I.mayStore(), StoreJ = J.mayStore(); 12890b57cec5SDimitry Andric if ((SysI && StoreJ) || (SysJ && StoreI)) 12900b57cec5SDimitry Andric return true; 12910b57cec5SDimitry Andric 12920b57cec5SDimitry Andric if (StoreI && StoreJ) { 12930b57cec5SDimitry Andric if (HII->isNewValueInst(J) || HII->isMemOp(J) || HII->isMemOp(I)) 12940b57cec5SDimitry Andric return true; 12950b57cec5SDimitry Andric } else { 12960b57cec5SDimitry Andric // A memop cannot be in the same packet with another memop or a store. 12970b57cec5SDimitry Andric // Two stores can be together, but here I and J cannot both be stores. 12980b57cec5SDimitry Andric bool MopStI = HII->isMemOp(I) || StoreI; 12990b57cec5SDimitry Andric bool MopStJ = HII->isMemOp(J) || StoreJ; 13000b57cec5SDimitry Andric if (MopStI && MopStJ) 13010b57cec5SDimitry Andric return true; 13020b57cec5SDimitry Andric } 13030b57cec5SDimitry Andric 13040b57cec5SDimitry Andric return (StoreJ && HII->isDeallocRet(I)) || (StoreI && HII->isDeallocRet(J)); 13050b57cec5SDimitry Andric } 13060b57cec5SDimitry Andric 13070b57cec5SDimitry Andric // SUI is the current instruction that is out side of the current packet. 13080b57cec5SDimitry Andric // SUJ is the current instruction inside the current packet against which that 13090b57cec5SDimitry Andric // SUI will be packetized. 13100b57cec5SDimitry Andric bool HexagonPacketizerList::isLegalToPacketizeTogether(SUnit *SUI, SUnit *SUJ) { 13110b57cec5SDimitry Andric assert(SUI->getInstr() && SUJ->getInstr()); 13120b57cec5SDimitry Andric MachineInstr &I = *SUI->getInstr(); 13130b57cec5SDimitry Andric MachineInstr &J = *SUJ->getInstr(); 13140b57cec5SDimitry Andric 13150b57cec5SDimitry Andric // Clear IgnoreDepMIs when Packet starts. 13160b57cec5SDimitry Andric if (CurrentPacketMIs.size() == 1) 13170b57cec5SDimitry Andric IgnoreDepMIs.clear(); 13180b57cec5SDimitry Andric 13190b57cec5SDimitry Andric MachineBasicBlock::iterator II = I.getIterator(); 13200b57cec5SDimitry Andric 13210b57cec5SDimitry Andric // Solo instructions cannot go in the packet. 13220b57cec5SDimitry Andric assert(!isSoloInstruction(I) && "Unexpected solo instr!"); 13230b57cec5SDimitry Andric 13240b57cec5SDimitry Andric if (cannotCoexist(I, J)) 13250b57cec5SDimitry Andric return false; 13260b57cec5SDimitry Andric 13270b57cec5SDimitry Andric Dependence = hasDeadDependence(I, J) || hasControlDependence(I, J); 13280b57cec5SDimitry Andric if (Dependence) 13290b57cec5SDimitry Andric return false; 13300b57cec5SDimitry Andric 13310b57cec5SDimitry Andric // Regmasks are not accounted for in the scheduling graph, so we need 13320b57cec5SDimitry Andric // to explicitly check for dependencies caused by them. They should only 13330b57cec5SDimitry Andric // appear on calls, so it's not too pessimistic to reject all regmask 13340b57cec5SDimitry Andric // dependencies. 13350b57cec5SDimitry Andric Dependence = hasRegMaskDependence(I, J); 13360b57cec5SDimitry Andric if (Dependence) 13370b57cec5SDimitry Andric return false; 13380b57cec5SDimitry Andric 13390b57cec5SDimitry Andric // Dual-store does not allow second store, if the first store is not 13400b57cec5SDimitry Andric // in SLOT0. New value store, new value jump, dealloc_return and memop 13410b57cec5SDimitry Andric // always take SLOT0. Arch spec 3.4.4.2. 13420b57cec5SDimitry Andric Dependence = hasDualStoreDependence(I, J); 13430b57cec5SDimitry Andric if (Dependence) 13440b57cec5SDimitry Andric return false; 13450b57cec5SDimitry Andric 13460b57cec5SDimitry Andric // If an instruction feeds new value jump, glue it. 13470b57cec5SDimitry Andric MachineBasicBlock::iterator NextMII = I.getIterator(); 13480b57cec5SDimitry Andric ++NextMII; 13490b57cec5SDimitry Andric if (NextMII != I.getParent()->end() && HII->isNewValueJump(*NextMII)) { 13500b57cec5SDimitry Andric MachineInstr &NextMI = *NextMII; 13510b57cec5SDimitry Andric 13520b57cec5SDimitry Andric bool secondRegMatch = false; 13530b57cec5SDimitry Andric const MachineOperand &NOp0 = NextMI.getOperand(0); 13540b57cec5SDimitry Andric const MachineOperand &NOp1 = NextMI.getOperand(1); 13550b57cec5SDimitry Andric 13560b57cec5SDimitry Andric if (NOp1.isReg() && I.getOperand(0).getReg() == NOp1.getReg()) 13570b57cec5SDimitry Andric secondRegMatch = true; 13580b57cec5SDimitry Andric 13590b57cec5SDimitry Andric for (MachineInstr *PI : CurrentPacketMIs) { 13600b57cec5SDimitry Andric // NVJ can not be part of the dual jump - Arch Spec: section 7.8. 13610b57cec5SDimitry Andric if (PI->isCall()) { 13620b57cec5SDimitry Andric Dependence = true; 13630b57cec5SDimitry Andric break; 13640b57cec5SDimitry Andric } 13650b57cec5SDimitry Andric // Validate: 13660b57cec5SDimitry Andric // 1. Packet does not have a store in it. 13670b57cec5SDimitry Andric // 2. If the first operand of the nvj is newified, and the second 13680b57cec5SDimitry Andric // operand is also a reg, it (second reg) is not defined in 13690b57cec5SDimitry Andric // the same packet. 13700b57cec5SDimitry Andric // 3. If the second operand of the nvj is newified, (which means 13710b57cec5SDimitry Andric // first operand is also a reg), first reg is not defined in 13720b57cec5SDimitry Andric // the same packet. 13730b57cec5SDimitry Andric if (PI->getOpcode() == Hexagon::S2_allocframe || PI->mayStore() || 13740b57cec5SDimitry Andric HII->isLoopN(*PI)) { 13750b57cec5SDimitry Andric Dependence = true; 13760b57cec5SDimitry Andric break; 13770b57cec5SDimitry Andric } 13780b57cec5SDimitry Andric // Check #2/#3. 13790b57cec5SDimitry Andric const MachineOperand &OpR = secondRegMatch ? NOp0 : NOp1; 13800b57cec5SDimitry Andric if (OpR.isReg() && PI->modifiesRegister(OpR.getReg(), HRI)) { 13810b57cec5SDimitry Andric Dependence = true; 13820b57cec5SDimitry Andric break; 13830b57cec5SDimitry Andric } 13840b57cec5SDimitry Andric } 13850b57cec5SDimitry Andric 13860b57cec5SDimitry Andric GlueToNewValueJump = true; 13870b57cec5SDimitry Andric if (Dependence) 13880b57cec5SDimitry Andric return false; 13890b57cec5SDimitry Andric } 13900b57cec5SDimitry Andric 13910b57cec5SDimitry Andric // There no dependency between a prolog instruction and its successor. 13920b57cec5SDimitry Andric if (!SUJ->isSucc(SUI)) 13930b57cec5SDimitry Andric return true; 13940b57cec5SDimitry Andric 13950b57cec5SDimitry Andric for (unsigned i = 0; i < SUJ->Succs.size(); ++i) { 13960b57cec5SDimitry Andric if (FoundSequentialDependence) 13970b57cec5SDimitry Andric break; 13980b57cec5SDimitry Andric 13990b57cec5SDimitry Andric if (SUJ->Succs[i].getSUnit() != SUI) 14000b57cec5SDimitry Andric continue; 14010b57cec5SDimitry Andric 14020b57cec5SDimitry Andric SDep::Kind DepType = SUJ->Succs[i].getKind(); 14030b57cec5SDimitry Andric // For direct calls: 14040b57cec5SDimitry Andric // Ignore register dependences for call instructions for packetization 14050b57cec5SDimitry Andric // purposes except for those due to r31 and predicate registers. 14060b57cec5SDimitry Andric // 14070b57cec5SDimitry Andric // For indirect calls: 14080b57cec5SDimitry Andric // Same as direct calls + check for true dependences to the register 14090b57cec5SDimitry Andric // used in the indirect call. 14100b57cec5SDimitry Andric // 14110b57cec5SDimitry Andric // We completely ignore Order dependences for call instructions. 14120b57cec5SDimitry Andric // 14130b57cec5SDimitry Andric // For returns: 14140b57cec5SDimitry Andric // Ignore register dependences for return instructions like jumpr, 14150b57cec5SDimitry Andric // dealloc return unless we have dependencies on the explicit uses 14160b57cec5SDimitry Andric // of the registers used by jumpr (like r31) or dealloc return 14170b57cec5SDimitry Andric // (like r29 or r30). 14180b57cec5SDimitry Andric unsigned DepReg = 0; 14190b57cec5SDimitry Andric const TargetRegisterClass *RC = nullptr; 14200b57cec5SDimitry Andric if (DepType == SDep::Data) { 14210b57cec5SDimitry Andric DepReg = SUJ->Succs[i].getReg(); 14220b57cec5SDimitry Andric RC = HRI->getMinimalPhysRegClass(DepReg); 14230b57cec5SDimitry Andric } 14240b57cec5SDimitry Andric 14250b57cec5SDimitry Andric if (I.isCall() || HII->isJumpR(I) || I.isReturn() || HII->isTailCall(I)) { 14260b57cec5SDimitry Andric if (!isRegDependence(DepType)) 14270b57cec5SDimitry Andric continue; 14280b57cec5SDimitry Andric if (!isCallDependent(I, DepType, SUJ->Succs[i].getReg())) 14290b57cec5SDimitry Andric continue; 14300b57cec5SDimitry Andric } 14310b57cec5SDimitry Andric 14320b57cec5SDimitry Andric if (DepType == SDep::Data) { 14330b57cec5SDimitry Andric if (canPromoteToDotCur(J, SUJ, DepReg, II, RC)) 14340b57cec5SDimitry Andric if (promoteToDotCur(J, DepType, II, RC)) 14350b57cec5SDimitry Andric continue; 14360b57cec5SDimitry Andric } 14370b57cec5SDimitry Andric 14380b57cec5SDimitry Andric // Data dpendence ok if we have load.cur. 14390b57cec5SDimitry Andric if (DepType == SDep::Data && HII->isDotCurInst(J)) { 14400b57cec5SDimitry Andric if (HII->isHVXVec(I)) 14410b57cec5SDimitry Andric continue; 14420b57cec5SDimitry Andric } 14430b57cec5SDimitry Andric 14440b57cec5SDimitry Andric // For instructions that can be promoted to dot-new, try to promote. 14450b57cec5SDimitry Andric if (DepType == SDep::Data) { 14460b57cec5SDimitry Andric if (canPromoteToDotNew(I, SUJ, DepReg, II, RC)) { 14470b57cec5SDimitry Andric if (promoteToDotNew(I, DepType, II, RC)) { 14480b57cec5SDimitry Andric PromotedToDotNew = true; 14490b57cec5SDimitry Andric if (cannotCoexist(I, J)) 14500b57cec5SDimitry Andric FoundSequentialDependence = true; 14510b57cec5SDimitry Andric continue; 14520b57cec5SDimitry Andric } 14530b57cec5SDimitry Andric } 14540b57cec5SDimitry Andric if (HII->isNewValueJump(I)) 14550b57cec5SDimitry Andric continue; 14560b57cec5SDimitry Andric } 14570b57cec5SDimitry Andric 14580b57cec5SDimitry Andric // For predicated instructions, if the predicates are complements then 14590b57cec5SDimitry Andric // there can be no dependence. 14600b57cec5SDimitry Andric if (HII->isPredicated(I) && HII->isPredicated(J) && 14610b57cec5SDimitry Andric arePredicatesComplements(I, J)) { 14620b57cec5SDimitry Andric // Not always safe to do this translation. 14630b57cec5SDimitry Andric // DAG Builder attempts to reduce dependence edges using transitive 14640b57cec5SDimitry Andric // nature of dependencies. Here is an example: 14650b57cec5SDimitry Andric // 14660b57cec5SDimitry Andric // r0 = tfr_pt ... (1) 14670b57cec5SDimitry Andric // r0 = tfr_pf ... (2) 14680b57cec5SDimitry Andric // r0 = tfr_pt ... (3) 14690b57cec5SDimitry Andric // 14700b57cec5SDimitry Andric // There will be an output dependence between (1)->(2) and (2)->(3). 14710b57cec5SDimitry Andric // However, there is no dependence edge between (1)->(3). This results 14720b57cec5SDimitry Andric // in all 3 instructions going in the same packet. We ignore dependce 14730b57cec5SDimitry Andric // only once to avoid this situation. 14740b57cec5SDimitry Andric auto Itr = find(IgnoreDepMIs, &J); 14750b57cec5SDimitry Andric if (Itr != IgnoreDepMIs.end()) { 14760b57cec5SDimitry Andric Dependence = true; 14770b57cec5SDimitry Andric return false; 14780b57cec5SDimitry Andric } 14790b57cec5SDimitry Andric IgnoreDepMIs.push_back(&I); 14800b57cec5SDimitry Andric continue; 14810b57cec5SDimitry Andric } 14820b57cec5SDimitry Andric 14830b57cec5SDimitry Andric // Ignore Order dependences between unconditional direct branches 14840b57cec5SDimitry Andric // and non-control-flow instructions. 14850b57cec5SDimitry Andric if (isDirectJump(I) && !J.isBranch() && !J.isCall() && 14860b57cec5SDimitry Andric DepType == SDep::Order) 14870b57cec5SDimitry Andric continue; 14880b57cec5SDimitry Andric 14890b57cec5SDimitry Andric // Ignore all dependences for jumps except for true and output 14900b57cec5SDimitry Andric // dependences. 14910b57cec5SDimitry Andric if (I.isConditionalBranch() && DepType != SDep::Data && 14920b57cec5SDimitry Andric DepType != SDep::Output) 14930b57cec5SDimitry Andric continue; 14940b57cec5SDimitry Andric 14950b57cec5SDimitry Andric if (DepType == SDep::Output) { 14960b57cec5SDimitry Andric FoundSequentialDependence = true; 14970b57cec5SDimitry Andric break; 14980b57cec5SDimitry Andric } 14990b57cec5SDimitry Andric 15000b57cec5SDimitry Andric // For Order dependences: 15010b57cec5SDimitry Andric // 1. Volatile loads/stores can be packetized together, unless other 15020b57cec5SDimitry Andric // rules prevent is. 15030b57cec5SDimitry Andric // 2. Store followed by a load is not allowed. 15040b57cec5SDimitry Andric // 3. Store followed by a store is valid. 15050b57cec5SDimitry Andric // 4. Load followed by any memory operation is allowed. 15060b57cec5SDimitry Andric if (DepType == SDep::Order) { 15070b57cec5SDimitry Andric if (!PacketizeVolatiles) { 15080b57cec5SDimitry Andric bool OrdRefs = I.hasOrderedMemoryRef() || J.hasOrderedMemoryRef(); 15090b57cec5SDimitry Andric if (OrdRefs) { 15100b57cec5SDimitry Andric FoundSequentialDependence = true; 15110b57cec5SDimitry Andric break; 15120b57cec5SDimitry Andric } 15130b57cec5SDimitry Andric } 15140b57cec5SDimitry Andric // J is first, I is second. 15150b57cec5SDimitry Andric bool LoadJ = J.mayLoad(), StoreJ = J.mayStore(); 15160b57cec5SDimitry Andric bool LoadI = I.mayLoad(), StoreI = I.mayStore(); 15170b57cec5SDimitry Andric bool NVStoreJ = HII->isNewValueStore(J); 15180b57cec5SDimitry Andric bool NVStoreI = HII->isNewValueStore(I); 15190b57cec5SDimitry Andric bool IsVecJ = HII->isHVXVec(J); 15200b57cec5SDimitry Andric bool IsVecI = HII->isHVXVec(I); 15210b57cec5SDimitry Andric 15220b57cec5SDimitry Andric if (Slot1Store && MF.getSubtarget<HexagonSubtarget>().hasV65Ops() && 15230b57cec5SDimitry Andric ((LoadJ && StoreI && !NVStoreI) || 15240b57cec5SDimitry Andric (StoreJ && LoadI && !NVStoreJ)) && 15250b57cec5SDimitry Andric (J.getOpcode() != Hexagon::S2_allocframe && 15260b57cec5SDimitry Andric I.getOpcode() != Hexagon::S2_allocframe) && 15270b57cec5SDimitry Andric (J.getOpcode() != Hexagon::L2_deallocframe && 15280b57cec5SDimitry Andric I.getOpcode() != Hexagon::L2_deallocframe) && 15290b57cec5SDimitry Andric (!HII->isMemOp(J) && !HII->isMemOp(I)) && (!IsVecJ && !IsVecI)) 15300b57cec5SDimitry Andric setmemShufDisabled(true); 15310b57cec5SDimitry Andric else 15320b57cec5SDimitry Andric if (StoreJ && LoadI && alias(J, I)) { 15330b57cec5SDimitry Andric FoundSequentialDependence = true; 15340b57cec5SDimitry Andric break; 15350b57cec5SDimitry Andric } 15360b57cec5SDimitry Andric 15370b57cec5SDimitry Andric if (!StoreJ) 15380b57cec5SDimitry Andric if (!LoadJ || (!LoadI && !StoreI)) { 15390b57cec5SDimitry Andric // If J is neither load nor store, assume a dependency. 15400b57cec5SDimitry Andric // If J is a load, but I is neither, also assume a dependency. 15410b57cec5SDimitry Andric FoundSequentialDependence = true; 15420b57cec5SDimitry Andric break; 15430b57cec5SDimitry Andric } 15440b57cec5SDimitry Andric // Store followed by store: not OK on V2. 15450b57cec5SDimitry Andric // Store followed by load: not OK on all. 15460b57cec5SDimitry Andric // Load followed by store: OK on all. 15470b57cec5SDimitry Andric // Load followed by load: OK on all. 15480b57cec5SDimitry Andric continue; 15490b57cec5SDimitry Andric } 15500b57cec5SDimitry Andric 15510b57cec5SDimitry Andric // Special case for ALLOCFRAME: even though there is dependency 15520b57cec5SDimitry Andric // between ALLOCFRAME and subsequent store, allow it to be packetized 15530b57cec5SDimitry Andric // in a same packet. This implies that the store is using the caller's 15540b57cec5SDimitry Andric // SP. Hence, offset needs to be updated accordingly. 15550b57cec5SDimitry Andric if (DepType == SDep::Data && J.getOpcode() == Hexagon::S2_allocframe) { 15560b57cec5SDimitry Andric unsigned Opc = I.getOpcode(); 15570b57cec5SDimitry Andric switch (Opc) { 15580b57cec5SDimitry Andric case Hexagon::S2_storerd_io: 15590b57cec5SDimitry Andric case Hexagon::S2_storeri_io: 15600b57cec5SDimitry Andric case Hexagon::S2_storerh_io: 15610b57cec5SDimitry Andric case Hexagon::S2_storerb_io: 15620b57cec5SDimitry Andric if (I.getOperand(0).getReg() == HRI->getStackRegister()) { 15630b57cec5SDimitry Andric // Since this store is to be glued with allocframe in the same 15640b57cec5SDimitry Andric // packet, it will use SP of the previous stack frame, i.e. 15650b57cec5SDimitry Andric // caller's SP. Therefore, we need to recalculate offset 15660b57cec5SDimitry Andric // according to this change. 15670b57cec5SDimitry Andric GlueAllocframeStore = useCallersSP(I); 15680b57cec5SDimitry Andric if (GlueAllocframeStore) 15690b57cec5SDimitry Andric continue; 15700b57cec5SDimitry Andric } 15710b57cec5SDimitry Andric break; 15720b57cec5SDimitry Andric default: 15730b57cec5SDimitry Andric break; 15740b57cec5SDimitry Andric } 15750b57cec5SDimitry Andric } 15760b57cec5SDimitry Andric 15770b57cec5SDimitry Andric // There are certain anti-dependencies that cannot be ignored. 15780b57cec5SDimitry Andric // Specifically: 15790b57cec5SDimitry Andric // J2_call ... implicit-def %r0 ; SUJ 15800b57cec5SDimitry Andric // R0 = ... ; SUI 15810b57cec5SDimitry Andric // Those cannot be packetized together, since the call will observe 15820b57cec5SDimitry Andric // the effect of the assignment to R0. 15830b57cec5SDimitry Andric if ((DepType == SDep::Anti || DepType == SDep::Output) && J.isCall()) { 15840b57cec5SDimitry Andric // Check if I defines any volatile register. We should also check 15850b57cec5SDimitry Andric // registers that the call may read, but these happen to be a 15860b57cec5SDimitry Andric // subset of the volatile register set. 15870b57cec5SDimitry Andric for (const MachineOperand &Op : I.operands()) { 15880b57cec5SDimitry Andric if (Op.isReg() && Op.isDef()) { 1589*8bcb0991SDimitry Andric Register R = Op.getReg(); 15900b57cec5SDimitry Andric if (!J.readsRegister(R, HRI) && !J.modifiesRegister(R, HRI)) 15910b57cec5SDimitry Andric continue; 15920b57cec5SDimitry Andric } else if (!Op.isRegMask()) { 15930b57cec5SDimitry Andric // If I has a regmask assume dependency. 15940b57cec5SDimitry Andric continue; 15950b57cec5SDimitry Andric } 15960b57cec5SDimitry Andric FoundSequentialDependence = true; 15970b57cec5SDimitry Andric break; 15980b57cec5SDimitry Andric } 15990b57cec5SDimitry Andric } 16000b57cec5SDimitry Andric 16010b57cec5SDimitry Andric // Skip over remaining anti-dependences. Two instructions that are 16020b57cec5SDimitry Andric // anti-dependent can share a packet, since in most such cases all 16030b57cec5SDimitry Andric // operands are read before any modifications take place. 16040b57cec5SDimitry Andric // The exceptions are branch and call instructions, since they are 16050b57cec5SDimitry Andric // executed after all other instructions have completed (at least 16060b57cec5SDimitry Andric // conceptually). 16070b57cec5SDimitry Andric if (DepType != SDep::Anti) { 16080b57cec5SDimitry Andric FoundSequentialDependence = true; 16090b57cec5SDimitry Andric break; 16100b57cec5SDimitry Andric } 16110b57cec5SDimitry Andric } 16120b57cec5SDimitry Andric 16130b57cec5SDimitry Andric if (FoundSequentialDependence) { 16140b57cec5SDimitry Andric Dependence = true; 16150b57cec5SDimitry Andric return false; 16160b57cec5SDimitry Andric } 16170b57cec5SDimitry Andric 16180b57cec5SDimitry Andric return true; 16190b57cec5SDimitry Andric } 16200b57cec5SDimitry Andric 16210b57cec5SDimitry Andric bool HexagonPacketizerList::isLegalToPruneDependencies(SUnit *SUI, SUnit *SUJ) { 16220b57cec5SDimitry Andric assert(SUI->getInstr() && SUJ->getInstr()); 16230b57cec5SDimitry Andric MachineInstr &I = *SUI->getInstr(); 16240b57cec5SDimitry Andric MachineInstr &J = *SUJ->getInstr(); 16250b57cec5SDimitry Andric 16260b57cec5SDimitry Andric bool Coexist = !cannotCoexist(I, J); 16270b57cec5SDimitry Andric 16280b57cec5SDimitry Andric if (Coexist && !Dependence) 16290b57cec5SDimitry Andric return true; 16300b57cec5SDimitry Andric 16310b57cec5SDimitry Andric // Check if the instruction was promoted to a dot-new. If so, demote it 16320b57cec5SDimitry Andric // back into a dot-old. 16330b57cec5SDimitry Andric if (PromotedToDotNew) 16340b57cec5SDimitry Andric demoteToDotOld(I); 16350b57cec5SDimitry Andric 16360b57cec5SDimitry Andric cleanUpDotCur(); 16370b57cec5SDimitry Andric // Check if the instruction (must be a store) was glued with an allocframe 16380b57cec5SDimitry Andric // instruction. If so, restore its offset to its original value, i.e. use 16390b57cec5SDimitry Andric // current SP instead of caller's SP. 16400b57cec5SDimitry Andric if (GlueAllocframeStore) { 16410b57cec5SDimitry Andric useCalleesSP(I); 16420b57cec5SDimitry Andric GlueAllocframeStore = false; 16430b57cec5SDimitry Andric } 16440b57cec5SDimitry Andric 16450b57cec5SDimitry Andric if (ChangedOffset != INT64_MAX) 16460b57cec5SDimitry Andric undoChangedOffset(I); 16470b57cec5SDimitry Andric 16480b57cec5SDimitry Andric if (GlueToNewValueJump) { 16490b57cec5SDimitry Andric // Putting I and J together would prevent the new-value jump from being 16500b57cec5SDimitry Andric // packetized with the producer. In that case I and J must be separated. 16510b57cec5SDimitry Andric GlueToNewValueJump = false; 16520b57cec5SDimitry Andric return false; 16530b57cec5SDimitry Andric } 16540b57cec5SDimitry Andric 16550b57cec5SDimitry Andric if (!Coexist) 16560b57cec5SDimitry Andric return false; 16570b57cec5SDimitry Andric 16580b57cec5SDimitry Andric if (ChangedOffset == INT64_MAX && updateOffset(SUI, SUJ)) { 16590b57cec5SDimitry Andric FoundSequentialDependence = false; 16600b57cec5SDimitry Andric Dependence = false; 16610b57cec5SDimitry Andric return true; 16620b57cec5SDimitry Andric } 16630b57cec5SDimitry Andric 16640b57cec5SDimitry Andric return false; 16650b57cec5SDimitry Andric } 16660b57cec5SDimitry Andric 16670b57cec5SDimitry Andric 16680b57cec5SDimitry Andric bool HexagonPacketizerList::foundLSInPacket() { 16690b57cec5SDimitry Andric bool FoundLoad = false; 16700b57cec5SDimitry Andric bool FoundStore = false; 16710b57cec5SDimitry Andric 16720b57cec5SDimitry Andric for (auto MJ : CurrentPacketMIs) { 16730b57cec5SDimitry Andric unsigned Opc = MJ->getOpcode(); 16740b57cec5SDimitry Andric if (Opc == Hexagon::S2_allocframe || Opc == Hexagon::L2_deallocframe) 16750b57cec5SDimitry Andric continue; 16760b57cec5SDimitry Andric if (HII->isMemOp(*MJ)) 16770b57cec5SDimitry Andric continue; 16780b57cec5SDimitry Andric if (MJ->mayLoad()) 16790b57cec5SDimitry Andric FoundLoad = true; 16800b57cec5SDimitry Andric if (MJ->mayStore() && !HII->isNewValueStore(*MJ)) 16810b57cec5SDimitry Andric FoundStore = true; 16820b57cec5SDimitry Andric } 16830b57cec5SDimitry Andric return FoundLoad && FoundStore; 16840b57cec5SDimitry Andric } 16850b57cec5SDimitry Andric 16860b57cec5SDimitry Andric 16870b57cec5SDimitry Andric MachineBasicBlock::iterator 16880b57cec5SDimitry Andric HexagonPacketizerList::addToPacket(MachineInstr &MI) { 16890b57cec5SDimitry Andric MachineBasicBlock::iterator MII = MI.getIterator(); 16900b57cec5SDimitry Andric MachineBasicBlock *MBB = MI.getParent(); 16910b57cec5SDimitry Andric 16920b57cec5SDimitry Andric if (CurrentPacketMIs.empty()) 16930b57cec5SDimitry Andric PacketStalls = false; 16940b57cec5SDimitry Andric PacketStalls |= producesStall(MI); 16950b57cec5SDimitry Andric 16960b57cec5SDimitry Andric if (MI.isImplicitDef()) { 16970b57cec5SDimitry Andric // Add to the packet to allow subsequent instructions to be checked 16980b57cec5SDimitry Andric // properly. 16990b57cec5SDimitry Andric CurrentPacketMIs.push_back(&MI); 17000b57cec5SDimitry Andric return MII; 17010b57cec5SDimitry Andric } 17020b57cec5SDimitry Andric assert(ResourceTracker->canReserveResources(MI)); 17030b57cec5SDimitry Andric 17040b57cec5SDimitry Andric bool ExtMI = HII->isExtended(MI) || HII->isConstExtended(MI); 17050b57cec5SDimitry Andric bool Good = true; 17060b57cec5SDimitry Andric 17070b57cec5SDimitry Andric if (GlueToNewValueJump) { 17080b57cec5SDimitry Andric MachineInstr &NvjMI = *++MII; 17090b57cec5SDimitry Andric // We need to put both instructions in the same packet: MI and NvjMI. 17100b57cec5SDimitry Andric // Either of them can require a constant extender. Try to add both to 17110b57cec5SDimitry Andric // the current packet, and if that fails, end the packet and start a 17120b57cec5SDimitry Andric // new one. 17130b57cec5SDimitry Andric ResourceTracker->reserveResources(MI); 17140b57cec5SDimitry Andric if (ExtMI) 17150b57cec5SDimitry Andric Good = tryAllocateResourcesForConstExt(true); 17160b57cec5SDimitry Andric 17170b57cec5SDimitry Andric bool ExtNvjMI = HII->isExtended(NvjMI) || HII->isConstExtended(NvjMI); 17180b57cec5SDimitry Andric if (Good) { 17190b57cec5SDimitry Andric if (ResourceTracker->canReserveResources(NvjMI)) 17200b57cec5SDimitry Andric ResourceTracker->reserveResources(NvjMI); 17210b57cec5SDimitry Andric else 17220b57cec5SDimitry Andric Good = false; 17230b57cec5SDimitry Andric } 17240b57cec5SDimitry Andric if (Good && ExtNvjMI) 17250b57cec5SDimitry Andric Good = tryAllocateResourcesForConstExt(true); 17260b57cec5SDimitry Andric 17270b57cec5SDimitry Andric if (!Good) { 17280b57cec5SDimitry Andric endPacket(MBB, MI); 17290b57cec5SDimitry Andric assert(ResourceTracker->canReserveResources(MI)); 17300b57cec5SDimitry Andric ResourceTracker->reserveResources(MI); 17310b57cec5SDimitry Andric if (ExtMI) { 17320b57cec5SDimitry Andric assert(canReserveResourcesForConstExt()); 17330b57cec5SDimitry Andric tryAllocateResourcesForConstExt(true); 17340b57cec5SDimitry Andric } 17350b57cec5SDimitry Andric assert(ResourceTracker->canReserveResources(NvjMI)); 17360b57cec5SDimitry Andric ResourceTracker->reserveResources(NvjMI); 17370b57cec5SDimitry Andric if (ExtNvjMI) { 17380b57cec5SDimitry Andric assert(canReserveResourcesForConstExt()); 17390b57cec5SDimitry Andric reserveResourcesForConstExt(); 17400b57cec5SDimitry Andric } 17410b57cec5SDimitry Andric } 17420b57cec5SDimitry Andric CurrentPacketMIs.push_back(&MI); 17430b57cec5SDimitry Andric CurrentPacketMIs.push_back(&NvjMI); 17440b57cec5SDimitry Andric return MII; 17450b57cec5SDimitry Andric } 17460b57cec5SDimitry Andric 17470b57cec5SDimitry Andric ResourceTracker->reserveResources(MI); 17480b57cec5SDimitry Andric if (ExtMI && !tryAllocateResourcesForConstExt(true)) { 17490b57cec5SDimitry Andric endPacket(MBB, MI); 17500b57cec5SDimitry Andric if (PromotedToDotNew) 17510b57cec5SDimitry Andric demoteToDotOld(MI); 17520b57cec5SDimitry Andric if (GlueAllocframeStore) { 17530b57cec5SDimitry Andric useCalleesSP(MI); 17540b57cec5SDimitry Andric GlueAllocframeStore = false; 17550b57cec5SDimitry Andric } 17560b57cec5SDimitry Andric ResourceTracker->reserveResources(MI); 17570b57cec5SDimitry Andric reserveResourcesForConstExt(); 17580b57cec5SDimitry Andric } 17590b57cec5SDimitry Andric 17600b57cec5SDimitry Andric CurrentPacketMIs.push_back(&MI); 17610b57cec5SDimitry Andric return MII; 17620b57cec5SDimitry Andric } 17630b57cec5SDimitry Andric 17640b57cec5SDimitry Andric void HexagonPacketizerList::endPacket(MachineBasicBlock *MBB, 17650b57cec5SDimitry Andric MachineBasicBlock::iterator EndMI) { 17660b57cec5SDimitry Andric // Replace VLIWPacketizerList::endPacket(MBB, EndMI). 1767*8bcb0991SDimitry Andric LLVM_DEBUG({ 1768*8bcb0991SDimitry Andric if (!CurrentPacketMIs.empty()) { 1769*8bcb0991SDimitry Andric dbgs() << "Finalizing packet:\n"; 1770*8bcb0991SDimitry Andric unsigned Idx = 0; 1771*8bcb0991SDimitry Andric for (MachineInstr *MI : CurrentPacketMIs) { 1772*8bcb0991SDimitry Andric unsigned R = ResourceTracker->getUsedResources(Idx++); 1773*8bcb0991SDimitry Andric dbgs() << " * [res:0x" << utohexstr(R) << "] " << *MI; 1774*8bcb0991SDimitry Andric } 1775*8bcb0991SDimitry Andric } 1776*8bcb0991SDimitry Andric }); 17770b57cec5SDimitry Andric 17780b57cec5SDimitry Andric bool memShufDisabled = getmemShufDisabled(); 17790b57cec5SDimitry Andric if (memShufDisabled && !foundLSInPacket()) { 17800b57cec5SDimitry Andric setmemShufDisabled(false); 17810b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Not added to NoShufPacket\n"); 17820b57cec5SDimitry Andric } 17830b57cec5SDimitry Andric memShufDisabled = getmemShufDisabled(); 17840b57cec5SDimitry Andric 17850b57cec5SDimitry Andric OldPacketMIs.clear(); 17860b57cec5SDimitry Andric for (MachineInstr *MI : CurrentPacketMIs) { 17870b57cec5SDimitry Andric MachineBasicBlock::instr_iterator NextMI = std::next(MI->getIterator()); 17880b57cec5SDimitry Andric for (auto &I : make_range(HII->expandVGatherPseudo(*MI), NextMI)) 17890b57cec5SDimitry Andric OldPacketMIs.push_back(&I); 17900b57cec5SDimitry Andric } 17910b57cec5SDimitry Andric CurrentPacketMIs.clear(); 17920b57cec5SDimitry Andric 17930b57cec5SDimitry Andric if (OldPacketMIs.size() > 1) { 17940b57cec5SDimitry Andric MachineBasicBlock::instr_iterator FirstMI(OldPacketMIs.front()); 17950b57cec5SDimitry Andric MachineBasicBlock::instr_iterator LastMI(EndMI.getInstrIterator()); 17960b57cec5SDimitry Andric finalizeBundle(*MBB, FirstMI, LastMI); 17970b57cec5SDimitry Andric auto BundleMII = std::prev(FirstMI); 17980b57cec5SDimitry Andric if (memShufDisabled) 17990b57cec5SDimitry Andric HII->setBundleNoShuf(BundleMII); 18000b57cec5SDimitry Andric 18010b57cec5SDimitry Andric setmemShufDisabled(false); 18020b57cec5SDimitry Andric } 18030b57cec5SDimitry Andric 18040b57cec5SDimitry Andric ResourceTracker->clearResources(); 18050b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "End packet\n"); 18060b57cec5SDimitry Andric } 18070b57cec5SDimitry Andric 18080b57cec5SDimitry Andric bool HexagonPacketizerList::shouldAddToPacket(const MachineInstr &MI) { 18090b57cec5SDimitry Andric if (Minimal) 18100b57cec5SDimitry Andric return false; 18110b57cec5SDimitry Andric return !producesStall(MI); 18120b57cec5SDimitry Andric } 18130b57cec5SDimitry Andric 18140b57cec5SDimitry Andric // V60 forward scheduling. 18150b57cec5SDimitry Andric bool HexagonPacketizerList::producesStall(const MachineInstr &I) { 18160b57cec5SDimitry Andric // If the packet already stalls, then ignore the stall from a subsequent 18170b57cec5SDimitry Andric // instruction in the same packet. 18180b57cec5SDimitry Andric if (PacketStalls) 18190b57cec5SDimitry Andric return false; 18200b57cec5SDimitry Andric 18210b57cec5SDimitry Andric // Check whether the previous packet is in a different loop. If this is the 18220b57cec5SDimitry Andric // case, there is little point in trying to avoid a stall because that would 18230b57cec5SDimitry Andric // favor the rare case (loop entry) over the common case (loop iteration). 18240b57cec5SDimitry Andric // 18250b57cec5SDimitry Andric // TODO: We should really be able to check all the incoming edges if this is 18260b57cec5SDimitry Andric // the first packet in a basic block, so we can avoid stalls from the loop 18270b57cec5SDimitry Andric // backedge. 18280b57cec5SDimitry Andric if (!OldPacketMIs.empty()) { 18290b57cec5SDimitry Andric auto *OldBB = OldPacketMIs.front()->getParent(); 18300b57cec5SDimitry Andric auto *ThisBB = I.getParent(); 18310b57cec5SDimitry Andric if (MLI->getLoopFor(OldBB) != MLI->getLoopFor(ThisBB)) 18320b57cec5SDimitry Andric return false; 18330b57cec5SDimitry Andric } 18340b57cec5SDimitry Andric 18350b57cec5SDimitry Andric SUnit *SUI = MIToSUnit[const_cast<MachineInstr *>(&I)]; 18360b57cec5SDimitry Andric 18370b57cec5SDimitry Andric // If the latency is 0 and there is a data dependence between this 18380b57cec5SDimitry Andric // instruction and any instruction in the current packet, we disregard any 18390b57cec5SDimitry Andric // potential stalls due to the instructions in the previous packet. Most of 18400b57cec5SDimitry Andric // the instruction pairs that can go together in the same packet have 0 18410b57cec5SDimitry Andric // latency between them. The exceptions are 18420b57cec5SDimitry Andric // 1. NewValueJumps as they're generated much later and the latencies can't 18430b57cec5SDimitry Andric // be changed at that point. 18440b57cec5SDimitry Andric // 2. .cur instructions, if its consumer has a 0 latency successor (such as 18450b57cec5SDimitry Andric // .new). In this case, the latency between .cur and the consumer stays 18460b57cec5SDimitry Andric // non-zero even though we can have both .cur and .new in the same packet. 18470b57cec5SDimitry Andric // Changing the latency to 0 is not an option as it causes software pipeliner 18480b57cec5SDimitry Andric // to not pipeline in some cases. 18490b57cec5SDimitry Andric 18500b57cec5SDimitry Andric // For Example: 18510b57cec5SDimitry Andric // { 18520b57cec5SDimitry Andric // I1: v6.cur = vmem(r0++#1) 18530b57cec5SDimitry Andric // I2: v7 = valign(v6,v4,r2) 18540b57cec5SDimitry Andric // I3: vmem(r5++#1) = v7.new 18550b57cec5SDimitry Andric // } 18560b57cec5SDimitry Andric // Here I2 and I3 has 0 cycle latency, but I1 and I2 has 2. 18570b57cec5SDimitry Andric 18580b57cec5SDimitry Andric for (auto J : CurrentPacketMIs) { 18590b57cec5SDimitry Andric SUnit *SUJ = MIToSUnit[J]; 18600b57cec5SDimitry Andric for (auto &Pred : SUI->Preds) 18610b57cec5SDimitry Andric if (Pred.getSUnit() == SUJ) 18620b57cec5SDimitry Andric if ((Pred.getLatency() == 0 && Pred.isAssignedRegDep()) || 18630b57cec5SDimitry Andric HII->isNewValueJump(I) || HII->isToBeScheduledASAP(*J, I)) 18640b57cec5SDimitry Andric return false; 18650b57cec5SDimitry Andric } 18660b57cec5SDimitry Andric 18670b57cec5SDimitry Andric // Check if the latency is greater than one between this instruction and any 18680b57cec5SDimitry Andric // instruction in the previous packet. 18690b57cec5SDimitry Andric for (auto J : OldPacketMIs) { 18700b57cec5SDimitry Andric SUnit *SUJ = MIToSUnit[J]; 18710b57cec5SDimitry Andric for (auto &Pred : SUI->Preds) 18720b57cec5SDimitry Andric if (Pred.getSUnit() == SUJ && Pred.getLatency() > 1) 18730b57cec5SDimitry Andric return true; 18740b57cec5SDimitry Andric } 18750b57cec5SDimitry Andric 18760b57cec5SDimitry Andric return false; 18770b57cec5SDimitry Andric } 18780b57cec5SDimitry Andric 18790b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 18800b57cec5SDimitry Andric // Public Constructor Functions 18810b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 18820b57cec5SDimitry Andric 18830b57cec5SDimitry Andric FunctionPass *llvm::createHexagonPacketizer(bool Minimal) { 18840b57cec5SDimitry Andric return new HexagonPacketizer(Minimal); 18850b57cec5SDimitry Andric } 1886