|  | //===- HexagonRDFOpt.cpp --------------------------------------------------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "HexagonInstrInfo.h" | 
|  | #include "HexagonSubtarget.h" | 
|  | #include "MCTargetDesc/HexagonBaseInfo.h" | 
|  | #include "RDFCopy.h" | 
|  | #include "RDFDeadCode.h" | 
|  | #include "RDFGraph.h" | 
|  | #include "RDFLiveness.h" | 
|  | #include "RDFRegisters.h" | 
|  | #include "llvm/ADT/DenseMap.h" | 
|  | #include "llvm/ADT/STLExtras.h" | 
|  | #include "llvm/ADT/SetVector.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/MachineOperand.h" | 
|  | #include "llvm/CodeGen/MachineRegisterInfo.h" | 
|  | #include "llvm/Pass.h" | 
|  | #include "llvm/Support/CommandLine.h" | 
|  | #include "llvm/Support/Compiler.h" | 
|  | #include "llvm/Support/Debug.h" | 
|  | #include "llvm/Support/ErrorHandling.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  | #include <cassert> | 
|  | #include <limits> | 
|  | #include <utility> | 
|  |  | 
|  | using namespace llvm; | 
|  | using namespace rdf; | 
|  |  | 
|  | namespace llvm { | 
|  |  | 
|  | void initializeHexagonRDFOptPass(PassRegistry&); | 
|  | FunctionPass *createHexagonRDFOpt(); | 
|  |  | 
|  | } // end namespace llvm | 
|  |  | 
|  | static unsigned RDFCount = 0; | 
|  |  | 
|  | static cl::opt<unsigned> RDFLimit("rdf-limit", | 
|  | cl::init(std::numeric_limits<unsigned>::max())); | 
|  | static cl::opt<bool> RDFDump("rdf-dump", cl::init(false)); | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class HexagonRDFOpt : public MachineFunctionPass { | 
|  | public: | 
|  | HexagonRDFOpt() : MachineFunctionPass(ID) { | 
|  | initializeHexagonRDFOptPass(*PassRegistry::getPassRegistry()); | 
|  | } | 
|  |  | 
|  | void getAnalysisUsage(AnalysisUsage &AU) const override { | 
|  | AU.addRequired<MachineDominatorTree>(); | 
|  | AU.addRequired<MachineDominanceFrontier>(); | 
|  | AU.setPreservesAll(); | 
|  | MachineFunctionPass::getAnalysisUsage(AU); | 
|  | } | 
|  |  | 
|  | StringRef getPassName() const override { | 
|  | return "Hexagon RDF optimizations"; | 
|  | } | 
|  |  | 
|  | bool runOnMachineFunction(MachineFunction &MF) override; | 
|  |  | 
|  | MachineFunctionProperties getRequiredProperties() const override { | 
|  | return MachineFunctionProperties().set( | 
|  | MachineFunctionProperties::Property::NoVRegs); | 
|  | } | 
|  |  | 
|  | static char ID; | 
|  |  | 
|  | private: | 
|  | MachineDominatorTree *MDT; | 
|  | MachineRegisterInfo *MRI; | 
|  | }; | 
|  |  | 
|  | struct HexagonCP : public CopyPropagation { | 
|  | HexagonCP(DataFlowGraph &G) : CopyPropagation(G) {} | 
|  |  | 
|  | bool interpretAsCopy(const MachineInstr *MI, EqualityMap &EM) override; | 
|  | }; | 
|  |  | 
|  | struct HexagonDCE : public DeadCodeElimination { | 
|  | HexagonDCE(DataFlowGraph &G, MachineRegisterInfo &MRI) | 
|  | : DeadCodeElimination(G, MRI) {} | 
|  |  | 
|  | bool rewrite(NodeAddr<InstrNode*> IA, SetVector<NodeId> &Remove); | 
|  | void removeOperand(NodeAddr<InstrNode*> IA, unsigned OpNum); | 
|  |  | 
|  | bool run(); | 
|  | }; | 
|  |  | 
|  | } // end anonymous namespace | 
|  |  | 
|  | char HexagonRDFOpt::ID = 0; | 
|  |  | 
|  | INITIALIZE_PASS_BEGIN(HexagonRDFOpt, "rdfopt", "Hexagon RDF opt", false, false) | 
|  | INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree) | 
|  | INITIALIZE_PASS_DEPENDENCY(MachineDominanceFrontier) | 
|  | INITIALIZE_PASS_END(HexagonRDFOpt, "rdfopt", "Hexagon RDF opt", false, false) | 
|  |  | 
|  | bool HexagonCP::interpretAsCopy(const MachineInstr *MI, EqualityMap &EM) { | 
|  | auto mapRegs = [&EM] (RegisterRef DstR, RegisterRef SrcR) -> void { | 
|  | EM.insert(std::make_pair(DstR, SrcR)); | 
|  | }; | 
|  |  | 
|  | DataFlowGraph &DFG = getDFG(); | 
|  | unsigned Opc = MI->getOpcode(); | 
|  | switch (Opc) { | 
|  | case Hexagon::A2_combinew: { | 
|  | const MachineOperand &DstOp = MI->getOperand(0); | 
|  | const MachineOperand &HiOp = MI->getOperand(1); | 
|  | const MachineOperand &LoOp = MI->getOperand(2); | 
|  | assert(DstOp.getSubReg() == 0 && "Unexpected subregister"); | 
|  | mapRegs(DFG.makeRegRef(DstOp.getReg(), Hexagon::isub_hi), | 
|  | DFG.makeRegRef(HiOp.getReg(),  HiOp.getSubReg())); | 
|  | mapRegs(DFG.makeRegRef(DstOp.getReg(), Hexagon::isub_lo), | 
|  | DFG.makeRegRef(LoOp.getReg(), LoOp.getSubReg())); | 
|  | return true; | 
|  | } | 
|  | case Hexagon::A2_addi: { | 
|  | const MachineOperand &A = MI->getOperand(2); | 
|  | if (!A.isImm() || A.getImm() != 0) | 
|  | return false; | 
|  | LLVM_FALLTHROUGH; | 
|  | } | 
|  | case Hexagon::A2_tfr: { | 
|  | const MachineOperand &DstOp = MI->getOperand(0); | 
|  | const MachineOperand &SrcOp = MI->getOperand(1); | 
|  | mapRegs(DFG.makeRegRef(DstOp.getReg(), DstOp.getSubReg()), | 
|  | DFG.makeRegRef(SrcOp.getReg(), SrcOp.getSubReg())); | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | return CopyPropagation::interpretAsCopy(MI, EM); | 
|  | } | 
|  |  | 
|  | bool HexagonDCE::run() { | 
|  | bool Collected = collect(); | 
|  | if (!Collected) | 
|  | return false; | 
|  |  | 
|  | const SetVector<NodeId> &DeadNodes = getDeadNodes(); | 
|  | const SetVector<NodeId> &DeadInstrs = getDeadInstrs(); | 
|  |  | 
|  | using RefToInstrMap = DenseMap<NodeId, NodeId>; | 
|  |  | 
|  | RefToInstrMap R2I; | 
|  | SetVector<NodeId> PartlyDead; | 
|  | DataFlowGraph &DFG = getDFG(); | 
|  |  | 
|  | for (NodeAddr<BlockNode*> BA : DFG.getFunc().Addr->members(DFG)) { | 
|  | for (auto TA : BA.Addr->members_if(DFG.IsCode<NodeAttrs::Stmt>, DFG)) { | 
|  | NodeAddr<StmtNode*> SA = TA; | 
|  | for (NodeAddr<RefNode*> RA : SA.Addr->members(DFG)) { | 
|  | R2I.insert(std::make_pair(RA.Id, SA.Id)); | 
|  | if (DFG.IsDef(RA) && DeadNodes.count(RA.Id)) | 
|  | if (!DeadInstrs.count(SA.Id)) | 
|  | PartlyDead.insert(SA.Id); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Nodes to remove. | 
|  | SetVector<NodeId> Remove = DeadInstrs; | 
|  |  | 
|  | bool Changed = false; | 
|  | for (NodeId N : PartlyDead) { | 
|  | auto SA = DFG.addr<StmtNode*>(N); | 
|  | if (trace()) | 
|  | dbgs() << "Partly dead: " << *SA.Addr->getCode(); | 
|  | Changed |= rewrite(SA, Remove); | 
|  | } | 
|  |  | 
|  | return erase(Remove) || Changed; | 
|  | } | 
|  |  | 
|  | void HexagonDCE::removeOperand(NodeAddr<InstrNode*> IA, unsigned OpNum) { | 
|  | MachineInstr *MI = NodeAddr<StmtNode*>(IA).Addr->getCode(); | 
|  |  | 
|  | auto getOpNum = [MI] (MachineOperand &Op) -> unsigned { | 
|  | for (unsigned i = 0, n = MI->getNumOperands(); i != n; ++i) | 
|  | if (&MI->getOperand(i) == &Op) | 
|  | return i; | 
|  | llvm_unreachable("Invalid operand"); | 
|  | }; | 
|  | DenseMap<NodeId,unsigned> OpMap; | 
|  | DataFlowGraph &DFG = getDFG(); | 
|  | NodeList Refs = IA.Addr->members(DFG); | 
|  | for (NodeAddr<RefNode*> RA : Refs) | 
|  | OpMap.insert(std::make_pair(RA.Id, getOpNum(RA.Addr->getOp()))); | 
|  |  | 
|  | MI->RemoveOperand(OpNum); | 
|  |  | 
|  | for (NodeAddr<RefNode*> RA : Refs) { | 
|  | unsigned N = OpMap[RA.Id]; | 
|  | if (N < OpNum) | 
|  | RA.Addr->setRegRef(&MI->getOperand(N), DFG); | 
|  | else if (N > OpNum) | 
|  | RA.Addr->setRegRef(&MI->getOperand(N-1), DFG); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool HexagonDCE::rewrite(NodeAddr<InstrNode*> IA, SetVector<NodeId> &Remove) { | 
|  | if (!getDFG().IsCode<NodeAttrs::Stmt>(IA)) | 
|  | return false; | 
|  | DataFlowGraph &DFG = getDFG(); | 
|  | MachineInstr &MI = *NodeAddr<StmtNode*>(IA).Addr->getCode(); | 
|  | auto &HII = static_cast<const HexagonInstrInfo&>(DFG.getTII()); | 
|  | if (HII.getAddrMode(MI) != HexagonII::PostInc) | 
|  | return false; | 
|  | unsigned Opc = MI.getOpcode(); | 
|  | unsigned OpNum, NewOpc; | 
|  | switch (Opc) { | 
|  | case Hexagon::L2_loadri_pi: | 
|  | NewOpc = Hexagon::L2_loadri_io; | 
|  | OpNum = 1; | 
|  | break; | 
|  | case Hexagon::L2_loadrd_pi: | 
|  | NewOpc = Hexagon::L2_loadrd_io; | 
|  | OpNum = 1; | 
|  | break; | 
|  | case Hexagon::V6_vL32b_pi: | 
|  | NewOpc = Hexagon::V6_vL32b_ai; | 
|  | OpNum = 1; | 
|  | break; | 
|  | case Hexagon::S2_storeri_pi: | 
|  | NewOpc = Hexagon::S2_storeri_io; | 
|  | OpNum = 0; | 
|  | break; | 
|  | case Hexagon::S2_storerd_pi: | 
|  | NewOpc = Hexagon::S2_storerd_io; | 
|  | OpNum = 0; | 
|  | break; | 
|  | case Hexagon::V6_vS32b_pi: | 
|  | NewOpc = Hexagon::V6_vS32b_ai; | 
|  | OpNum = 0; | 
|  | break; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | auto IsDead = [this] (NodeAddr<DefNode*> DA) -> bool { | 
|  | return getDeadNodes().count(DA.Id); | 
|  | }; | 
|  | NodeList Defs; | 
|  | MachineOperand &Op = MI.getOperand(OpNum); | 
|  | for (NodeAddr<DefNode*> DA : IA.Addr->members_if(DFG.IsDef, DFG)) { | 
|  | if (&DA.Addr->getOp() != &Op) | 
|  | continue; | 
|  | Defs = DFG.getRelatedRefs(IA, DA); | 
|  | if (!llvm::all_of(Defs, IsDead)) | 
|  | return false; | 
|  | break; | 
|  | } | 
|  |  | 
|  | // Mark all nodes in Defs for removal. | 
|  | for (auto D : Defs) | 
|  | Remove.insert(D.Id); | 
|  |  | 
|  | if (trace()) | 
|  | dbgs() << "Rewriting: " << MI; | 
|  | MI.setDesc(HII.get(NewOpc)); | 
|  | MI.getOperand(OpNum+2).setImm(0); | 
|  | removeOperand(IA, OpNum); | 
|  | if (trace()) | 
|  | dbgs() << "       to: " << MI; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool HexagonRDFOpt::runOnMachineFunction(MachineFunction &MF) { | 
|  | if (skipFunction(*MF.getFunction())) | 
|  | return false; | 
|  |  | 
|  | if (RDFLimit.getPosition()) { | 
|  | if (RDFCount >= RDFLimit) | 
|  | return false; | 
|  | RDFCount++; | 
|  | } | 
|  |  | 
|  | MDT = &getAnalysis<MachineDominatorTree>(); | 
|  | const auto &MDF = getAnalysis<MachineDominanceFrontier>(); | 
|  | const auto &HII = *MF.getSubtarget<HexagonSubtarget>().getInstrInfo(); | 
|  | const auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo(); | 
|  | MRI = &MF.getRegInfo(); | 
|  | bool Changed; | 
|  |  | 
|  | if (RDFDump) | 
|  | MF.print(dbgs() << "Before " << getPassName() << "\n", nullptr); | 
|  |  | 
|  | TargetOperandInfo TOI(HII); | 
|  | DataFlowGraph G(MF, HII, HRI, *MDT, MDF, TOI); | 
|  | // Dead phi nodes are necessary for copy propagation: we can add a use | 
|  | // of a register in a block where it would need a phi node, but which | 
|  | // was dead (and removed) during the graph build time. | 
|  | G.build(BuildOptions::KeepDeadPhis); | 
|  |  | 
|  | if (RDFDump) | 
|  | dbgs() << "Starting copy propagation on: " << MF.getName() << '\n' | 
|  | << PrintNode<FuncNode*>(G.getFunc(), G) << '\n'; | 
|  | HexagonCP CP(G); | 
|  | CP.trace(RDFDump); | 
|  | Changed = CP.run(); | 
|  |  | 
|  | if (RDFDump) | 
|  | dbgs() << "Starting dead code elimination on: " << MF.getName() << '\n' | 
|  | << PrintNode<FuncNode*>(G.getFunc(), G) << '\n'; | 
|  | HexagonDCE DCE(G, *MRI); | 
|  | DCE.trace(RDFDump); | 
|  | Changed |= DCE.run(); | 
|  |  | 
|  | if (Changed) { | 
|  | if (RDFDump) | 
|  | dbgs() << "Starting liveness recomputation on: " << MF.getName() << '\n'; | 
|  | Liveness LV(*MRI, G); | 
|  | LV.trace(RDFDump); | 
|  | LV.computeLiveIns(); | 
|  | LV.resetLiveIns(); | 
|  | LV.resetKills(); | 
|  | } | 
|  |  | 
|  | if (RDFDump) | 
|  | MF.print(dbgs() << "After " << getPassName() << "\n", nullptr); | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | FunctionPass *llvm::createHexagonRDFOpt() { | 
|  | return new HexagonRDFOpt(); | 
|  | } |