/// Find the nearest ref node aliased to RefRR, going upwards in the data /// flow, starting from the instruction immediately preceding Inst. NodeAddr<RefNode*> Liveness::getNearestAliasedRef(RegisterRef RefRR, NodeAddr<InstrNode*> IA) { NodeAddr<BlockNode*> BA = IA.Addr->getOwner(DFG); NodeList Ins = BA.Addr->members(DFG); NodeId FindId = IA.Id; auto E = Ins.rend(); auto B = std::find_if(Ins.rbegin(), E, [FindId] (const NodeAddr<InstrNode*> T) { return T.Id == FindId; }); // Do not scan IA (which is what B would point to). if (B != E) ++B; do { // Process the range of instructions from B to E. for (NodeAddr<InstrNode*> I : make_range(B, E)) { NodeList Refs = I.Addr->members(DFG); NodeAddr<RefNode*> Clob, Use; // Scan all the refs in I aliased to RefRR, and return the one that // is the closest to the output of I, i.e. def > clobber > use. for (NodeAddr<RefNode*> R : Refs) { if (!PRI.alias(R.Addr->getRegRef(DFG), RefRR)) continue; if (DFG.IsDef(R)) { // If it's a non-clobbering def, just return it. if (!(R.Addr->getFlags() & NodeAttrs::Clobbering)) return R; Clob = R; } else { Use = R; } } if (Clob.Id != 0) return Clob; if (Use.Id != 0) return Use; } // Go up to the immediate dominator, if any. MachineBasicBlock *BB = BA.Addr->getCode(); BA = NodeAddr<BlockNode*>(); if (MachineDomTreeNode *N = MDT.getNode(BB)) { if ((N = N->getIDom())) BA = DFG.findBlock(N->getBlock()); } if (!BA.Id) break; Ins = BA.Addr->members(DFG); B = Ins.rbegin(); E = Ins.rend(); } while (true); return NodeAddr<RefNode*>(); }
// warning nodes that are dynamically created during the traversal, but that have not been traversed during the top-down, won't be traversed during the bottom-up // TODO is it what we want? // otherwise it is possible to restart from top, go to leaves and running bottom-up action while going up void DAGNode::executeVisitorBottomUp( simulation::Visitor* action, NodeList& executedNodes ) { for( NodeList::reverse_iterator it = executedNodes.rbegin(), itend = executedNodes.rend() ; it != itend ; ++it ) { (*it)->updateDescendancy(); action->processNodeBottomUp( *it ); } }
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; 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::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; unsigned 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(); 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) || RDefMap[OffsetRR][IA.Id] != 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(); NodeSet Visited, Defs; const auto &ReachingDefs = LV->getAllReachingDefsRec(UR, UN, Visited, Defs); if (ReachingDefs.size() > 1) { 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; }
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()) continue; DEBUG(dbgs() << "[Analyzing A2_tfrsi]: " << *MI << "\n"); DEBUG(dbgs() << "\t[InstrNode]: " << Print<NodeAddr<InstrNode *>>(IA, *DFG) << "\n"); NodeList UNodeList; getAllRealUses(SA, UNodeList); if (!allValidCandidates(SA, UNodeList)) continue; short SizeInc = 0; unsigned 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; DEBUG(dbgs() << "\t[Total reached uses] : " << UNodeList.size() << "\n"); 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(); unsigned BBNum = UseMI->getParent()->getNumber(); (void)BBNum; DEBUG(dbgs() << "\t\t[MI <BB#" << BBNum << ">]: " << *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; } assert(UseMOnum >= 0 && "Invalid reached use!"); if (InstrEvalResult[UseMI]) // Change UseMI if replacement is possible. Changed |= xformUseMI(MI, UseMI, UseN, UseMOnum); else KeepTfr = true; } if (!KeepTfr) Deleted.insert(MI); } return Changed; }
bool HexagonOptAddrMode::changeAddAsl(NodeAddr<UseNode *> AddAslUN, MachineInstr *AddAslMI, const MachineOperand &ImmOp, unsigned ImmOpNum) { NodeAddr<StmtNode *> SA = AddAslUN.Addr->getOwner(*DFG); 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); DEBUG(dbgs() << "[InstrNode]: " << Print<NodeAddr<InstrNode *>>(UseIA, *DFG) << "\n"); MachineInstr *UseMI = UseIA.Addr->getCode(); DEBUG(dbgs() << "[MI <BB#" << UseMI->getParent()->getNumber() << ">]: " << *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.addOperand(UseMI->getOperand(0)); MIB.addOperand(AddAslMI->getOperand(2)); MIB.addOperand(AddAslMI->getOperand(3)); const GlobalValue *GV = ImmOp.getGlobal(); MIB.addGlobalAddress(GV, UseMI->getOperand(2).getImm(), ImmOp.getTargetFlags()); OpStart = 3; } else if (UseMID.mayStore()) { MIB.addOperand(AddAslMI->getOperand(2)); MIB.addOperand(AddAslMI->getOperand(3)); const GlobalValue *GV = ImmOp.getGlobal(); MIB.addGlobalAddress(GV, UseMI->getOperand(1).getImm(), ImmOp.getTargetFlags()); MIB.addOperand(UseMI->getOperand(2)); OpStart = 3; } else llvm_unreachable("Unhandled instruction"); for (unsigned i = OpStart; i < OpEnd; ++i) MIB.addOperand(UseMI->getOperand(i)); Deleted.insert(UseMI); } return true; }