003 File Manager
Current Path:
/usr/src/contrib/llvm-project/llvm/lib/Target/Hexagon
usr
/
src
/
contrib
/
llvm-project
/
llvm
/
lib
/
Target
/
Hexagon
/
📁
..
📁
AsmParser
📄
BitTracker.cpp
(35.36 KB)
📄
BitTracker.h
(17.25 KB)
📁
Disassembler
📄
Hexagon.h
(1004 B)
📄
Hexagon.td
(17.33 KB)
📄
HexagonArch.h
(1.2 KB)
📄
HexagonAsmPrinter.cpp
(26.65 KB)
📄
HexagonAsmPrinter.h
(2.03 KB)
📄
HexagonBitSimplify.cpp
(107.45 KB)
📄
HexagonBitTracker.cpp
(39.88 KB)
📄
HexagonBitTracker.h
(2.5 KB)
📄
HexagonBlockRanges.cpp
(15.85 KB)
📄
HexagonBlockRanges.h
(6.97 KB)
📄
HexagonBranchRelaxation.cpp
(7.78 KB)
📄
HexagonCFGOptimizer.cpp
(8.4 KB)
📄
HexagonCallingConv.td
(4.46 KB)
📄
HexagonCommonGEP.cpp
(41.47 KB)
📄
HexagonConstExtenders.cpp
(70.64 KB)
📄
HexagonConstPropagation.cpp
(97.75 KB)
📄
HexagonCopyToCombine.cpp
(32.2 KB)
📄
HexagonDepArch.h
(2.04 KB)
📄
HexagonDepArch.td
(1.87 KB)
📄
HexagonDepDecoders.inc
(2.55 KB)
📄
HexagonDepIICHVX.td
(113.05 KB)
📄
HexagonDepIICScalar.td
(224.12 KB)
📄
HexagonDepITypes.h
(1.51 KB)
📄
HexagonDepITypes.td
(1.91 KB)
📄
HexagonDepInstrFormats.td
(91.89 KB)
📄
HexagonDepInstrInfo.td
(1021.44 KB)
📄
HexagonDepMapAsm2Intrin.td
(255.17 KB)
📄
HexagonDepMappings.td
(64.27 KB)
📄
HexagonDepMask.h
(51.94 KB)
📄
HexagonDepOperands.td
(12.12 KB)
📄
HexagonDepTimingClasses.h
(4.69 KB)
📄
HexagonEarlyIfConv.cpp
(37.36 KB)
📄
HexagonExpandCondsets.cpp
(48.55 KB)
📄
HexagonFixupHwLoops.cpp
(6.54 KB)
📄
HexagonFrameLowering.cpp
(97.16 KB)
📄
HexagonFrameLowering.h
(7.85 KB)
📄
HexagonGenExtract.cpp
(8.61 KB)
📄
HexagonGenInsert.cpp
(53.24 KB)
📄
HexagonGenMux.cpp
(12.71 KB)
📄
HexagonGenPredicate.cpp
(16.25 KB)
📄
HexagonHardwareLoops.cpp
(70.32 KB)
📄
HexagonHazardRecognizer.cpp
(5.85 KB)
📄
HexagonHazardRecognizer.h
(3.58 KB)
📄
HexagonIICHVX.td
(1.21 KB)
📄
HexagonIICScalar.td
(1.34 KB)
📄
HexagonISelDAGToDAG.cpp
(78.63 KB)
📄
HexagonISelDAGToDAG.h
(5.88 KB)
📄
HexagonISelDAGToDAGHVX.cpp
(68.26 KB)
📄
HexagonISelLowering.cpp
(134.65 KB)
📄
HexagonISelLowering.h
(22.5 KB)
📄
HexagonISelLoweringHVX.cpp
(70.57 KB)
📄
HexagonInstrFormats.td
(12.04 KB)
📄
HexagonInstrFormatsV60.td
(1.03 KB)
📄
HexagonInstrFormatsV65.td
(1.54 KB)
📄
HexagonInstrInfo.cpp
(161.08 KB)
📄
HexagonInstrInfo.h
(25.31 KB)
📄
HexagonIntrinsics.td
(19.21 KB)
📄
HexagonIntrinsicsV5.td
(16.8 KB)
📄
HexagonIntrinsicsV60.td
(28.9 KB)
📄
HexagonLoopIdiomRecognition.cpp
(79.16 KB)
📄
HexagonMCInstLower.cpp
(6.25 KB)
📄
HexagonMachineFunctionInfo.cpp
(507 B)
📄
HexagonMachineFunctionInfo.h
(3.32 KB)
📄
HexagonMachineScheduler.cpp
(34.25 KB)
📄
HexagonMachineScheduler.h
(8.66 KB)
📄
HexagonMapAsm2IntrinV62.gen.td
(8.71 KB)
📄
HexagonMapAsm2IntrinV65.gen.td
(12.43 KB)
📄
HexagonNewValueJump.cpp
(25.57 KB)
📄
HexagonOperands.td
(1.62 KB)
📄
HexagonOptAddrMode.cpp
(29.37 KB)
📄
HexagonOptimizeSZextends.cpp
(4.74 KB)
📄
HexagonPatterns.td
(142.35 KB)
📄
HexagonPatternsHVX.td
(22.06 KB)
📄
HexagonPatternsV65.td
(2.96 KB)
📄
HexagonPeephole.cpp
(10.18 KB)
📄
HexagonPseudo.td
(21.62 KB)
📄
HexagonRDFOpt.cpp
(9.94 KB)
📄
HexagonRegisterInfo.cpp
(12.03 KB)
📄
HexagonRegisterInfo.h
(2.88 KB)
📄
HexagonRegisterInfo.td
(20.42 KB)
📄
HexagonSchedule.td
(2.33 KB)
📄
HexagonScheduleV5.td
(1.73 KB)
📄
HexagonScheduleV55.td
(1.81 KB)
📄
HexagonScheduleV60.td
(4.31 KB)
📄
HexagonScheduleV62.td
(1.53 KB)
📄
HexagonScheduleV65.td
(1.57 KB)
📄
HexagonScheduleV66.td
(1.57 KB)
📄
HexagonScheduleV67.td
(1.57 KB)
📄
HexagonScheduleV67T.td
(2.51 KB)
📄
HexagonSelectionDAGInfo.cpp
(2.35 KB)
📄
HexagonSelectionDAGInfo.h
(1.24 KB)
📄
HexagonSplitConst32AndConst64.cpp
(4.15 KB)
📄
HexagonSplitDouble.cpp
(37.86 KB)
📄
HexagonStoreWidening.cpp
(20.47 KB)
📄
HexagonSubtarget.cpp
(20.97 KB)
📄
HexagonSubtarget.h
(10.59 KB)
📄
HexagonTargetMachine.cpp
(16 KB)
📄
HexagonTargetMachine.h
(1.77 KB)
📄
HexagonTargetObjectFile.cpp
(16.8 KB)
📄
HexagonTargetObjectFile.h
(2.17 KB)
📄
HexagonTargetStreamer.h
(1.2 KB)
📄
HexagonTargetTransformInfo.cpp
(13.11 KB)
📄
HexagonTargetTransformInfo.h
(6.27 KB)
📄
HexagonVExtract.cpp
(6.64 KB)
📄
HexagonVLIWPacketizer.cpp
(67.01 KB)
📄
HexagonVLIWPacketizer.h
(6.09 KB)
📄
HexagonVectorLoopCarriedReuse.cpp
(23.99 KB)
📄
HexagonVectorPrint.cpp
(7.06 KB)
📁
MCTargetDesc
📄
RDFCopy.cpp
(6.37 KB)
📄
RDFCopy.h
(1.69 KB)
📄
RDFDeadCode.cpp
(7.5 KB)
📄
RDFDeadCode.h
(2.33 KB)
📁
TargetInfo
Editing: HexagonOptAddrMode.cpp
//===- HexagonOptAddrMode.cpp ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // This implements a Hexagon-specific pass to optimize addressing mode for // load/store instructions. //===----------------------------------------------------------------------===// #include "HexagonInstrInfo.h" #include "HexagonSubtarget.h" #include "MCTargetDesc/HexagonBaseInfo.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringRef.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineDominanceFrontier.h" #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/RDFGraph.h" #include "llvm/CodeGen/RDFLiveness.h" #include "llvm/CodeGen/RDFRegisters.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/InitializePasses.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include <cassert> #include <cstdint> #define DEBUG_TYPE "opt-addr-mode" using namespace llvm; using namespace rdf; static cl::opt<int> CodeGrowthLimit("hexagon-amode-growth-limit", cl::Hidden, cl::init(0), cl::desc("Code growth limit for address mode " "optimization")); namespace llvm { FunctionPass *createHexagonOptAddrMode(); void initializeHexagonOptAddrModePass(PassRegistry&); } // end namespace llvm namespace { class HexagonOptAddrMode : public MachineFunctionPass { public: static char ID; HexagonOptAddrMode() : MachineFunctionPass(ID) {} StringRef getPassName() const override { return "Optimize addressing mode of load/store"; } void getAnalysisUsage(AnalysisUsage &AU) const override { MachineFunctionPass::getAnalysisUsage(AU); AU.addRequired<MachineDominatorTree>(); AU.addRequired<MachineDominanceFrontier>(); AU.setPreservesAll(); } bool runOnMachineFunction(MachineFunction &MF) override; private: using MISetType = DenseSet<MachineInstr *>; using InstrEvalMap = DenseMap<MachineInstr *, bool>; MachineRegisterInfo *MRI = nullptr; const HexagonInstrInfo *HII = nullptr; const HexagonRegisterInfo *HRI = nullptr; MachineDominatorTree *MDT = nullptr; DataFlowGraph *DFG = nullptr; DataFlowGraph::DefStackMap DefM; Liveness *LV = nullptr; MISetType Deleted; bool processBlock(NodeAddr<BlockNode *> BA); bool xformUseMI(MachineInstr *TfrMI, MachineInstr *UseMI, NodeAddr<UseNode *> UseN, unsigned UseMOnum); bool processAddUses(NodeAddr<StmtNode *> AddSN, MachineInstr *AddMI, const NodeList &UNodeList); bool updateAddUses(MachineInstr *AddMI, MachineInstr *UseMI); bool analyzeUses(unsigned DefR, const NodeList &UNodeList, InstrEvalMap &InstrEvalResult, short &SizeInc); bool hasRepForm(MachineInstr &MI, unsigned TfrDefR); bool canRemoveAddasl(NodeAddr<StmtNode *> AddAslSN, MachineInstr &MI, const NodeList &UNodeList); bool isSafeToExtLR(NodeAddr<StmtNode *> SN, MachineInstr *MI, unsigned LRExtReg, const NodeList &UNodeList); void getAllRealUses(NodeAddr<StmtNode *> SN, NodeList &UNodeList); bool allValidCandidates(NodeAddr<StmtNode *> SA, NodeList &UNodeList); short getBaseWithLongOffset(const MachineInstr &MI) const; bool changeStore(MachineInstr *OldMI, MachineOperand ImmOp, unsigned ImmOpNum); bool changeLoad(MachineInstr *OldMI, MachineOperand ImmOp, unsigned ImmOpNum); bool changeAddAsl(NodeAddr<UseNode *> AddAslUN, MachineInstr *AddAslMI, const MachineOperand &ImmOp, unsigned ImmOpNum); bool isValidOffset(MachineInstr *MI, int Offset); }; } // end anonymous namespace char HexagonOptAddrMode::ID = 0; INITIALIZE_PASS_BEGIN(HexagonOptAddrMode, "amode-opt", "Optimize addressing mode", false, false) INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree) INITIALIZE_PASS_DEPENDENCY(MachineDominanceFrontier) INITIALIZE_PASS_END(HexagonOptAddrMode, "amode-opt", "Optimize addressing mode", false, false) bool HexagonOptAddrMode::hasRepForm(MachineInstr &MI, unsigned TfrDefR) { const MCInstrDesc &MID = MI.getDesc(); if ((!MID.mayStore() && !MID.mayLoad()) || HII->isPredicated(MI)) return false; if (MID.mayStore()) { MachineOperand StOp = MI.getOperand(MI.getNumOperands() - 1); if (StOp.isReg() && StOp.getReg() == TfrDefR) return false; } if (HII->getAddrMode(MI) == HexagonII::BaseRegOffset) // Tranform to Absolute plus register offset. return (HII->changeAddrMode_rr_ur(MI) >= 0); else if (HII->getAddrMode(MI) == HexagonII::BaseImmOffset) // Tranform to absolute addressing mode. return (HII->changeAddrMode_io_abs(MI) >= 0); return false; } // Check if addasl instruction can be removed. This is possible only // if it's feeding to only load/store instructions with base + register // offset as these instruction can be tranformed to use 'absolute plus // shifted register offset'. // ex: // Rs = ##foo // Rx = addasl(Rs, Rt, #2) // Rd = memw(Rx + #28) // Above three instructions can be replaced with Rd = memw(Rt<<#2 + ##foo+28) bool HexagonOptAddrMode::canRemoveAddasl(NodeAddr<StmtNode *> AddAslSN, MachineInstr &MI, const NodeList &UNodeList) { // check offset size in addasl. if 'offset > 3' return false const MachineOperand &OffsetOp = MI.getOperand(3); if (!OffsetOp.isImm() || OffsetOp.getImm() > 3) return false; Register OffsetReg = MI.getOperand(2).getReg(); RegisterRef OffsetRR; NodeId OffsetRegRD = 0; for (NodeAddr<UseNode *> UA : AddAslSN.Addr->members_if(DFG->IsUse, *DFG)) { RegisterRef RR = UA.Addr->getRegRef(*DFG); if (OffsetReg == RR.Reg) { OffsetRR = RR; OffsetRegRD = UA.Addr->getReachingDef(); } } for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E; ++I) { NodeAddr<UseNode *> UA = *I; NodeAddr<InstrNode *> IA = UA.Addr->getOwner(*DFG); if (UA.Addr->getFlags() & NodeAttrs::PhiRef) return false; NodeAddr<RefNode*> AA = LV->getNearestAliasedRef(OffsetRR, IA); if ((DFG->IsDef(AA) && AA.Id != OffsetRegRD) || AA.Addr->getReachingDef() != OffsetRegRD) return false; MachineInstr &UseMI = *NodeAddr<StmtNode *>(IA).Addr->getCode(); NodeAddr<DefNode *> OffsetRegDN = DFG->addr<DefNode *>(OffsetRegRD); // Reaching Def to an offset register can't be a phi. if ((OffsetRegDN.Addr->getFlags() & NodeAttrs::PhiRef) && MI.getParent() != UseMI.getParent()) return false; const MCInstrDesc &UseMID = UseMI.getDesc(); if ((!UseMID.mayLoad() && !UseMID.mayStore()) || HII->getAddrMode(UseMI) != HexagonII::BaseImmOffset || getBaseWithLongOffset(UseMI) < 0) return false; // Addasl output can't be a store value. if (UseMID.mayStore() && UseMI.getOperand(2).isReg() && UseMI.getOperand(2).getReg() == MI.getOperand(0).getReg()) return false; for (auto &Mo : UseMI.operands()) if (Mo.isFI()) return false; } return true; } bool HexagonOptAddrMode::allValidCandidates(NodeAddr<StmtNode *> SA, NodeList &UNodeList) { for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E; ++I) { NodeAddr<UseNode *> UN = *I; RegisterRef UR = UN.Addr->getRegRef(*DFG); NodeSet Visited, Defs; const auto &P = LV->getAllReachingDefsRec(UR, UN, Visited, Defs); if (!P.second) { LLVM_DEBUG({ dbgs() << "*** Unable to collect all reaching defs for use ***\n" << PrintNode<UseNode*>(UN, *DFG) << '\n' << "The program's complexity may exceed the limits.\n"; }); return false; } const auto &ReachingDefs = P.first; if (ReachingDefs.size() > 1) { LLVM_DEBUG({ dbgs() << "*** Multiple Reaching Defs found!!! ***\n"; for (auto DI : ReachingDefs) { NodeAddr<UseNode *> DA = DFG->addr<UseNode *>(DI); NodeAddr<StmtNode *> TempIA = DA.Addr->getOwner(*DFG); dbgs() << "\t\t[Reaching Def]: " << Print<NodeAddr<InstrNode *>>(TempIA, *DFG) << "\n"; } }); return false; } } return true; } void HexagonOptAddrMode::getAllRealUses(NodeAddr<StmtNode *> SA, NodeList &UNodeList) { for (NodeAddr<DefNode *> DA : SA.Addr->members_if(DFG->IsDef, *DFG)) { LLVM_DEBUG(dbgs() << "\t\t[DefNode]: " << Print<NodeAddr<DefNode *>>(DA, *DFG) << "\n"); RegisterRef DR = DFG->getPRI().normalize(DA.Addr->getRegRef(*DFG)); auto UseSet = LV->getAllReachedUses(DR, DA); for (auto UI : UseSet) { NodeAddr<UseNode *> UA = DFG->addr<UseNode *>(UI); LLVM_DEBUG({ NodeAddr<StmtNode *> TempIA = UA.Addr->getOwner(*DFG); dbgs() << "\t\t\t[Reached Use]: " << Print<NodeAddr<InstrNode *>>(TempIA, *DFG) << "\n"; }); if (UA.Addr->getFlags() & NodeAttrs::PhiRef) { NodeAddr<PhiNode *> PA = UA.Addr->getOwner(*DFG); NodeId id = PA.Id; const Liveness::RefMap &phiUse = LV->getRealUses(id); LLVM_DEBUG(dbgs() << "\t\t\t\tphi real Uses" << Print<Liveness::RefMap>(phiUse, *DFG) << "\n"); if (!phiUse.empty()) { for (auto I : phiUse) { if (!DFG->getPRI().alias(RegisterRef(I.first), DR)) continue; auto phiUseSet = I.second; for (auto phiUI : phiUseSet) { NodeAddr<UseNode *> phiUA = DFG->addr<UseNode *>(phiUI.first); UNodeList.push_back(phiUA); } } } } else UNodeList.push_back(UA); } } } bool HexagonOptAddrMode::isSafeToExtLR(NodeAddr<StmtNode *> SN, MachineInstr *MI, unsigned LRExtReg, const NodeList &UNodeList) { RegisterRef LRExtRR; NodeId LRExtRegRD = 0; // Iterate through all the UseNodes in SN and find the reaching def // for the LRExtReg. for (NodeAddr<UseNode *> UA : SN.Addr->members_if(DFG->IsUse, *DFG)) { RegisterRef RR = UA.Addr->getRegRef(*DFG); if (LRExtReg == RR.Reg) { LRExtRR = RR; LRExtRegRD = UA.Addr->getReachingDef(); } } for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E; ++I) { NodeAddr<UseNode *> UA = *I; NodeAddr<InstrNode *> IA = UA.Addr->getOwner(*DFG); // The reaching def of LRExtRR at load/store node should be same as the // one reaching at the SN. if (UA.Addr->getFlags() & NodeAttrs::PhiRef) return false; NodeAddr<RefNode*> AA = LV->getNearestAliasedRef(LRExtRR, IA); if ((DFG->IsDef(AA) && AA.Id != LRExtRegRD) || AA.Addr->getReachingDef() != LRExtRegRD) { LLVM_DEBUG( dbgs() << "isSafeToExtLR: Returning false; another reaching def\n"); return false; } MachineInstr *UseMI = NodeAddr<StmtNode *>(IA).Addr->getCode(); NodeAddr<DefNode *> LRExtRegDN = DFG->addr<DefNode *>(LRExtRegRD); // Reaching Def to LRExtReg can't be a phi. if ((LRExtRegDN.Addr->getFlags() & NodeAttrs::PhiRef) && MI->getParent() != UseMI->getParent()) return false; } return true; } bool HexagonOptAddrMode::isValidOffset(MachineInstr *MI, int Offset) { unsigned AlignMask = 0; switch (HII->getMemAccessSize(*MI)) { case HexagonII::MemAccessSize::DoubleWordAccess: AlignMask = 0x7; break; case HexagonII::MemAccessSize::WordAccess: AlignMask = 0x3; break; case HexagonII::MemAccessSize::HalfWordAccess: AlignMask = 0x1; break; case HexagonII::MemAccessSize::ByteAccess: AlignMask = 0x0; break; default: return false; } if ((AlignMask & Offset) != 0) return false; return HII->isValidOffset(MI->getOpcode(), Offset, HRI, false); } bool HexagonOptAddrMode::processAddUses(NodeAddr<StmtNode *> AddSN, MachineInstr *AddMI, const NodeList &UNodeList) { Register AddDefR = AddMI->getOperand(0).getReg(); for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E; ++I) { NodeAddr<UseNode *> UN = *I; NodeAddr<StmtNode *> SN = UN.Addr->getOwner(*DFG); MachineInstr *MI = SN.Addr->getCode(); const MCInstrDesc &MID = MI->getDesc(); if ((!MID.mayLoad() && !MID.mayStore()) || HII->getAddrMode(*MI) != HexagonII::BaseImmOffset || HII->isHVXVec(*MI)) return false; MachineOperand BaseOp = MID.mayLoad() ? MI->getOperand(1) : MI->getOperand(0); if (!BaseOp.isReg() || BaseOp.getReg() != AddDefR) return false; MachineOperand OffsetOp = MID.mayLoad() ? MI->getOperand(2) : MI->getOperand(1); if (!OffsetOp.isImm()) return false; int64_t newOffset = OffsetOp.getImm() + AddMI->getOperand(2).getImm(); if (!isValidOffset(MI, newOffset)) return false; // Since we'll be extending the live range of Rt in the following example, // make sure that is safe. another definition of Rt doesn't exist between 'add' // and load/store instruction. // // Ex: Rx= add(Rt,#10) // memw(Rx+#0) = Rs // will be replaced with => memw(Rt+#10) = Rs Register BaseReg = AddMI->getOperand(1).getReg(); if (!isSafeToExtLR(AddSN, AddMI, BaseReg, UNodeList)) return false; } // Update all the uses of 'add' with the appropriate base and offset // values. bool Changed = false; for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E; ++I) { NodeAddr<UseNode *> UseN = *I; assert(!(UseN.Addr->getFlags() & NodeAttrs::PhiRef) && "Found a PhiRef node as a real reached use!!"); NodeAddr<StmtNode *> OwnerN = UseN.Addr->getOwner(*DFG); MachineInstr *UseMI = OwnerN.Addr->getCode(); LLVM_DEBUG(dbgs() << "\t\t[MI <BB#" << UseMI->getParent()->getNumber() << ">]: " << *UseMI << "\n"); Changed |= updateAddUses(AddMI, UseMI); } if (Changed) Deleted.insert(AddMI); return Changed; } bool HexagonOptAddrMode::updateAddUses(MachineInstr *AddMI, MachineInstr *UseMI) { const MachineOperand ImmOp = AddMI->getOperand(2); const MachineOperand AddRegOp = AddMI->getOperand(1); Register newReg = AddRegOp.getReg(); const MCInstrDesc &MID = UseMI->getDesc(); MachineOperand &BaseOp = MID.mayLoad() ? UseMI->getOperand(1) : UseMI->getOperand(0); MachineOperand &OffsetOp = MID.mayLoad() ? UseMI->getOperand(2) : UseMI->getOperand(1); BaseOp.setReg(newReg); BaseOp.setIsUndef(AddRegOp.isUndef()); BaseOp.setImplicit(AddRegOp.isImplicit()); OffsetOp.setImm(ImmOp.getImm() + OffsetOp.getImm()); MRI->clearKillFlags(newReg); return true; } bool HexagonOptAddrMode::analyzeUses(unsigned tfrDefR, const NodeList &UNodeList, InstrEvalMap &InstrEvalResult, short &SizeInc) { bool KeepTfr = false; bool HasRepInstr = false; InstrEvalResult.clear(); for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E; ++I) { bool CanBeReplaced = false; NodeAddr<UseNode *> UN = *I; NodeAddr<StmtNode *> SN = UN.Addr->getOwner(*DFG); MachineInstr &MI = *SN.Addr->getCode(); const MCInstrDesc &MID = MI.getDesc(); if ((MID.mayLoad() || MID.mayStore())) { if (!hasRepForm(MI, tfrDefR)) { KeepTfr = true; continue; } SizeInc++; CanBeReplaced = true; } else if (MI.getOpcode() == Hexagon::S2_addasl_rrri) { NodeList AddaslUseList; LLVM_DEBUG(dbgs() << "\nGetting ReachedUses for === " << MI << "\n"); getAllRealUses(SN, AddaslUseList); // Process phi nodes. if (allValidCandidates(SN, AddaslUseList) && canRemoveAddasl(SN, MI, AddaslUseList)) { SizeInc += AddaslUseList.size(); SizeInc -= 1; // Reduce size by 1 as addasl itself can be removed. CanBeReplaced = true; } else SizeInc++; } else // Currently, only load/store and addasl are handled. // Some other instructions to consider - // A2_add -> A2_addi // M4_mpyrr_addr -> M4_mpyrr_addi KeepTfr = true; InstrEvalResult[&MI] = CanBeReplaced; HasRepInstr |= CanBeReplaced; } // Reduce total size by 2 if original tfr can be deleted. if (!KeepTfr) SizeInc -= 2; return HasRepInstr; } bool HexagonOptAddrMode::changeLoad(MachineInstr *OldMI, MachineOperand ImmOp, unsigned ImmOpNum) { bool Changed = false; MachineBasicBlock *BB = OldMI->getParent(); auto UsePos = MachineBasicBlock::iterator(OldMI); MachineBasicBlock::instr_iterator InsertPt = UsePos.getInstrIterator(); ++InsertPt; unsigned OpStart; unsigned OpEnd = OldMI->getNumOperands(); MachineInstrBuilder MIB; if (ImmOpNum == 1) { if (HII->getAddrMode(*OldMI) == HexagonII::BaseRegOffset) { short NewOpCode = HII->changeAddrMode_rr_ur(*OldMI); assert(NewOpCode >= 0 && "Invalid New opcode\n"); MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode)); MIB.add(OldMI->getOperand(0)); MIB.add(OldMI->getOperand(2)); MIB.add(OldMI->getOperand(3)); MIB.add(ImmOp); OpStart = 4; Changed = true; } else if (HII->getAddrMode(*OldMI) == HexagonII::BaseImmOffset && OldMI->getOperand(2).isImm()) { short NewOpCode = HII->changeAddrMode_io_abs(*OldMI); assert(NewOpCode >= 0 && "Invalid New opcode\n"); MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode)) .add(OldMI->getOperand(0)); const GlobalValue *GV = ImmOp.getGlobal(); int64_t Offset = ImmOp.getOffset() + OldMI->getOperand(2).getImm(); MIB.addGlobalAddress(GV, Offset, ImmOp.getTargetFlags()); OpStart = 3; Changed = true; } else Changed = false; LLVM_DEBUG(dbgs() << "[Changing]: " << *OldMI << "\n"); LLVM_DEBUG(dbgs() << "[TO]: " << *MIB << "\n"); } else if (ImmOpNum == 2) { if (OldMI->getOperand(3).isImm() && OldMI->getOperand(3).getImm() == 0) { short NewOpCode = HII->changeAddrMode_rr_io(*OldMI); assert(NewOpCode >= 0 && "Invalid New opcode\n"); MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode)); MIB.add(OldMI->getOperand(0)); MIB.add(OldMI->getOperand(1)); MIB.add(ImmOp); OpStart = 4; Changed = true; LLVM_DEBUG(dbgs() << "[Changing]: " << *OldMI << "\n"); LLVM_DEBUG(dbgs() << "[TO]: " << *MIB << "\n"); } } if (Changed) for (unsigned i = OpStart; i < OpEnd; ++i) MIB.add(OldMI->getOperand(i)); return Changed; } bool HexagonOptAddrMode::changeStore(MachineInstr *OldMI, MachineOperand ImmOp, unsigned ImmOpNum) { bool Changed = false; unsigned OpStart = 0; unsigned OpEnd = OldMI->getNumOperands(); MachineBasicBlock *BB = OldMI->getParent(); auto UsePos = MachineBasicBlock::iterator(OldMI); MachineBasicBlock::instr_iterator InsertPt = UsePos.getInstrIterator(); ++InsertPt; MachineInstrBuilder MIB; if (ImmOpNum == 0) { if (HII->getAddrMode(*OldMI) == HexagonII::BaseRegOffset) { short NewOpCode = HII->changeAddrMode_rr_ur(*OldMI); assert(NewOpCode >= 0 && "Invalid New opcode\n"); MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode)); MIB.add(OldMI->getOperand(1)); MIB.add(OldMI->getOperand(2)); MIB.add(ImmOp); MIB.add(OldMI->getOperand(3)); OpStart = 4; Changed = true; } else if (HII->getAddrMode(*OldMI) == HexagonII::BaseImmOffset) { short NewOpCode = HII->changeAddrMode_io_abs(*OldMI); assert(NewOpCode >= 0 && "Invalid New opcode\n"); MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode)); const GlobalValue *GV = ImmOp.getGlobal(); int64_t Offset = ImmOp.getOffset() + OldMI->getOperand(1).getImm(); MIB.addGlobalAddress(GV, Offset, ImmOp.getTargetFlags()); MIB.add(OldMI->getOperand(2)); OpStart = 3; Changed = true; } } else if (ImmOpNum == 1 && OldMI->getOperand(2).getImm() == 0) { short NewOpCode = HII->changeAddrMode_rr_io(*OldMI); assert(NewOpCode >= 0 && "Invalid New opcode\n"); MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode)); MIB.add(OldMI->getOperand(0)); MIB.add(ImmOp); OpStart = 3; Changed = true; } if (Changed) { LLVM_DEBUG(dbgs() << "[Changing]: " << *OldMI << "\n"); LLVM_DEBUG(dbgs() << "[TO]: " << *MIB << "\n"); for (unsigned i = OpStart; i < OpEnd; ++i) MIB.add(OldMI->getOperand(i)); } return Changed; } short HexagonOptAddrMode::getBaseWithLongOffset(const MachineInstr &MI) const { if (HII->getAddrMode(MI) == HexagonII::BaseImmOffset) { short TempOpCode = HII->changeAddrMode_io_rr(MI); return HII->changeAddrMode_rr_ur(TempOpCode); } return HII->changeAddrMode_rr_ur(MI); } bool HexagonOptAddrMode::changeAddAsl(NodeAddr<UseNode *> AddAslUN, MachineInstr *AddAslMI, const MachineOperand &ImmOp, unsigned ImmOpNum) { NodeAddr<StmtNode *> SA = AddAslUN.Addr->getOwner(*DFG); LLVM_DEBUG(dbgs() << "Processing addasl :" << *AddAslMI << "\n"); NodeList UNodeList; getAllRealUses(SA, UNodeList); for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E; ++I) { NodeAddr<UseNode *> UseUN = *I; assert(!(UseUN.Addr->getFlags() & NodeAttrs::PhiRef) && "Can't transform this 'AddAsl' instruction!"); NodeAddr<StmtNode *> UseIA = UseUN.Addr->getOwner(*DFG); LLVM_DEBUG(dbgs() << "[InstrNode]: " << Print<NodeAddr<InstrNode *>>(UseIA, *DFG) << "\n"); MachineInstr *UseMI = UseIA.Addr->getCode(); LLVM_DEBUG(dbgs() << "[MI <" << printMBBReference(*UseMI->getParent()) << ">]: " << *UseMI << "\n"); const MCInstrDesc &UseMID = UseMI->getDesc(); assert(HII->getAddrMode(*UseMI) == HexagonII::BaseImmOffset); auto UsePos = MachineBasicBlock::iterator(UseMI); MachineBasicBlock::instr_iterator InsertPt = UsePos.getInstrIterator(); short NewOpCode = getBaseWithLongOffset(*UseMI); assert(NewOpCode >= 0 && "Invalid New opcode\n"); unsigned OpStart; unsigned OpEnd = UseMI->getNumOperands(); MachineBasicBlock *BB = UseMI->getParent(); MachineInstrBuilder MIB = BuildMI(*BB, InsertPt, UseMI->getDebugLoc(), HII->get(NewOpCode)); // change mem(Rs + # ) -> mem(Rt << # + ##) if (UseMID.mayLoad()) { MIB.add(UseMI->getOperand(0)); MIB.add(AddAslMI->getOperand(2)); MIB.add(AddAslMI->getOperand(3)); const GlobalValue *GV = ImmOp.getGlobal(); MIB.addGlobalAddress(GV, UseMI->getOperand(2).getImm()+ImmOp.getOffset(), ImmOp.getTargetFlags()); OpStart = 3; } else if (UseMID.mayStore()) { MIB.add(AddAslMI->getOperand(2)); MIB.add(AddAslMI->getOperand(3)); const GlobalValue *GV = ImmOp.getGlobal(); MIB.addGlobalAddress(GV, UseMI->getOperand(1).getImm()+ImmOp.getOffset(), ImmOp.getTargetFlags()); MIB.add(UseMI->getOperand(2)); OpStart = 3; } else llvm_unreachable("Unhandled instruction"); for (unsigned i = OpStart; i < OpEnd; ++i) MIB.add(UseMI->getOperand(i)); Deleted.insert(UseMI); } return true; } bool HexagonOptAddrMode::xformUseMI(MachineInstr *TfrMI, MachineInstr *UseMI, NodeAddr<UseNode *> UseN, unsigned UseMOnum) { const MachineOperand ImmOp = TfrMI->getOperand(1); const MCInstrDesc &MID = UseMI->getDesc(); unsigned Changed = false; if (MID.mayLoad()) Changed = changeLoad(UseMI, ImmOp, UseMOnum); else if (MID.mayStore()) Changed = changeStore(UseMI, ImmOp, UseMOnum); else if (UseMI->getOpcode() == Hexagon::S2_addasl_rrri) Changed = changeAddAsl(UseN, UseMI, ImmOp, UseMOnum); if (Changed) Deleted.insert(UseMI); return Changed; } bool HexagonOptAddrMode::processBlock(NodeAddr<BlockNode *> BA) { bool Changed = false; for (auto IA : BA.Addr->members(*DFG)) { if (!DFG->IsCode<NodeAttrs::Stmt>(IA)) continue; NodeAddr<StmtNode *> SA = IA; MachineInstr *MI = SA.Addr->getCode(); if ((MI->getOpcode() != Hexagon::A2_tfrsi || !MI->getOperand(1).isGlobal()) && (MI->getOpcode() != Hexagon::A2_addi || !MI->getOperand(2).isImm() || HII->isConstExtended(*MI))) continue; LLVM_DEBUG(dbgs() << "[Analyzing " << HII->getName(MI->getOpcode()) << "]: " << *MI << "\n\t[InstrNode]: " << Print<NodeAddr<InstrNode *>>(IA, *DFG) << '\n'); NodeList UNodeList; getAllRealUses(SA, UNodeList); if (!allValidCandidates(SA, UNodeList)) continue; // Analyze all uses of 'add'. If the output of 'add' is used as an address // in the base+immediate addressing mode load/store instructions, see if // they can be updated to use the immediate value as an offet. Thus, // providing us the opportunity to eliminate 'add'. // Ex: Rx= add(Rt,#12) // memw(Rx+#0) = Rs // This can be replaced with memw(Rt+#12) = Rs // // This transformation is only performed if all uses can be updated and // the offset isn't required to be constant extended. if (MI->getOpcode() == Hexagon::A2_addi) { Changed |= processAddUses(SA, MI, UNodeList); continue; } short SizeInc = 0; Register DefR = MI->getOperand(0).getReg(); InstrEvalMap InstrEvalResult; // Analyze all uses and calculate increase in size. Perform the optimization // only if there is no increase in size. if (!analyzeUses(DefR, UNodeList, InstrEvalResult, SizeInc)) continue; if (SizeInc > CodeGrowthLimit) continue; bool KeepTfr = false; LLVM_DEBUG(dbgs() << "\t[Total reached uses] : " << UNodeList.size() << "\n"); LLVM_DEBUG(dbgs() << "\t[Processing Reached Uses] ===\n"); for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E; ++I) { NodeAddr<UseNode *> UseN = *I; assert(!(UseN.Addr->getFlags() & NodeAttrs::PhiRef) && "Found a PhiRef node as a real reached use!!"); NodeAddr<StmtNode *> OwnerN = UseN.Addr->getOwner(*DFG); MachineInstr *UseMI = OwnerN.Addr->getCode(); LLVM_DEBUG(dbgs() << "\t\t[MI <" << printMBBReference(*UseMI->getParent()) << ">]: " << *UseMI << "\n"); int UseMOnum = -1; unsigned NumOperands = UseMI->getNumOperands(); for (unsigned j = 0; j < NumOperands - 1; ++j) { const MachineOperand &op = UseMI->getOperand(j); if (op.isReg() && op.isUse() && DefR == op.getReg()) UseMOnum = j; } // It is possible that the register will not be found in any operand. // This could happen, for example, when DefR = R4, but the used // register is D2. // Change UseMI if replacement is possible. If any replacement failed, // or wasn't attempted, make sure to keep the TFR. bool Xformed = false; if (UseMOnum >= 0 && InstrEvalResult[UseMI]) Xformed = xformUseMI(MI, UseMI, UseN, UseMOnum); Changed |= Xformed; KeepTfr |= !Xformed; } if (!KeepTfr) Deleted.insert(MI); } return Changed; } bool HexagonOptAddrMode::runOnMachineFunction(MachineFunction &MF) { if (skipFunction(MF.getFunction())) return false; bool Changed = false; auto &HST = MF.getSubtarget<HexagonSubtarget>(); MRI = &MF.getRegInfo(); HII = HST.getInstrInfo(); HRI = HST.getRegisterInfo(); const auto &MDF = getAnalysis<MachineDominanceFrontier>(); MDT = &getAnalysis<MachineDominatorTree>(); const TargetOperandInfo TOI(*HII); DataFlowGraph G(MF, *HII, *HRI, *MDT, MDF, TOI); // Need to keep dead phis because we can propagate uses of registers into // nodes dominated by those would-be phis. G.build(BuildOptions::KeepDeadPhis); DFG = &G; Liveness L(*MRI, *DFG); L.computePhiInfo(); LV = &L; Deleted.clear(); NodeAddr<FuncNode *> FA = DFG->getFunc(); LLVM_DEBUG(dbgs() << "==== [RefMap#]=====:\n " << Print<NodeAddr<FuncNode *>>(FA, *DFG) << "\n"); for (NodeAddr<BlockNode *> BA : FA.Addr->members(*DFG)) Changed |= processBlock(BA); for (auto MI : Deleted) MI->eraseFromParent(); if (Changed) { G.build(); L.computeLiveIns(); L.resetLiveIns(); L.resetKills(); } return Changed; } //===----------------------------------------------------------------------===// // Public Constructor Functions //===----------------------------------------------------------------------===// FunctionPass *llvm::createHexagonOptAddrMode() { return new HexagonOptAddrMode(); }
Upload File
Create Folder