/** * Checks if there is a side effect between throw_inst and init_inst instructions. * @param throw_inst - the exception object throw instruction * @param init_inst - the exception object constructor call instruction * @return <code>true</code> if there is side effect; * <code>false<code> if there is no side effect. */ bool LazyExceptionOpt::checkInSideEff(Inst* throw_inst, Inst* init_inst) { Node* node = throw_inst->getNode(); Inst* instfirst = (Inst*)node->getFirstInst();; Inst* instlast = throw_inst; Inst* inst; bool dofind = true; bool inSE = false; if (throw_inst!=instfirst) instlast=throw_inst->getPrevInst(); else { node = node->getInEdges().front()->getSourceNode(); instlast = (Inst*)node->getLastInst(); } while (dofind && node!=NULL) { instfirst = (Inst*)node->getFirstInst(); for (inst = instlast; inst!=instfirst; inst=inst->getPrevInst()) { #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " checkInSE: see "; inst->print(Log::out()); Log::out() << std::endl; } #endif if (inst==init_inst) { dofind=false; break; } if (!inSE) { if (instHasSideEffect(inst)) { inSE=true; #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " checkInSE: sideEff "; inst->print(Log::out()); Log::out() << std::endl; } #endif break; } } } if (dofind) { node = node->getInEdges().front()->getSourceNode(); instlast = (Inst*)node->getLastInst(); } } if (dofind) return true; // call init wasn't found return inSE; }
SsaOpnd* OSR::reduce(Type* type, Opcode opcode, Operation op, SsaOpnd* iv, SsaOpnd* rc) { if (Log::isEnabled()) { Log::out() << "Reducing: "; iv->print(Log::out()); Log::out() << std::endl; rc->print(Log::out()); Log::out() << std::endl; } Inst* newinst = hashTable->lookup(op.encodeForHashing(), iv->getId(), rc->getId()); if (!newinst) { Inst* newDef = insertNewDef(type, iv, rc); if (Log::isEnabled()) { Log::out() << "NewDef" << std::endl; newDef->print(Log::out()); Log::out() << std::endl; } SsaOpnd* result = newDef->getDst()->asSsaOpnd(); writeLeadingOperand(result, getLeadingOperand(iv)); hashTable->insert(op.encodeForHashing(), iv->getId(), rc->getId(), newDef); writeLFTR(iv, op, rc, newDef->getDst()->asSsaOpnd()); replaceOperands(type, newDef, iv, rc, opcode, op); return result; } else { SsaOpnd* result = newinst->getDst()->asSsaOpnd(); return result; } }
/** * Checks if Op_TauStInd (stind) instruction has a side effect. * @param inst - checked instruction * @return <code>true</code> if an instruction has side effect; * <code>false<code> if an instruction has no side effect. */ bool LazyExceptionOpt::fieldUsageHasSideEffect(Inst* inst) { Opnd* insOp = inst->getSrc(0); Inst* instDef = insOp->getInst(); if (instDef->getOpcode() == Op_DefArg) { #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " fieldUsageHasSideEffect: "; inst->print(Log::out()); Log::out() << std::endl; Log::out() << " fieldUsageHasSideEffect: "; instDef->print(Log::out()); Log::out() << std::endl; Log::out() << " fieldUsageHasSideEffect: "; Log::out() << (int)(instDef->getDefArgModifier()) << " " << (instDef->getDefArgModifier()==DefArgNoModifier) << " " << (instDef->getDefArgModifier()==NonNullThisArg) << " " << (instDef->getDefArgModifier()==DefArgBothModifiers) << std::endl; } #endif if (instDef->getDefArgModifier()==NonNullThisArg && isExceptionInit) return false; } return true; }
/** * Prints information about optimization candidates. * @param os - output stream */ void LazyExceptionOpt::printOptCandidates(::std::ostream& os) { OptCandidates::iterator it; Inst* oinst; Inst* iinst; Inst* tinst; if (optCandidates == NULL) { return; } for (it = optCandidates->begin( ); it != optCandidates->end( ); it++ ) { os << "~~ opndId " << (*it)->opndId << std::endl; oinst = (*it)->objInst; os << " obj "; if (oinst != NULL) oinst->print(os); else os << "newobj NULL"; os << std::endl; iinst = (*it)->initInst; os << " init "; if (iinst != NULL) iinst->print(os); else os << "call init NULL"; os << std::endl; if ((*it)->throwInsts == NULL) { os << " thr throw NULL"; os << std::endl; continue; } ThrowInsts::iterator it1; for (it1 = (*it)->throwInsts->begin(); it1 !=(*it)->throwInsts->end(); it1++) { tinst = *it1; assert(tinst != NULL); os << " thr "; tinst->print(os); os << std::endl; } } os << "end~~" << std::endl; }
Inst* CSEHashTable::lookupKeyBase(CSEHashKey* key) { Inst* inst = (Inst*)hashTable.lookup(key); if (inst != NULL) { numCSE++; if(Log::isEnabled()) { Log::out() << "***** CSEHashTable::Lookup succeeded: "; inst->print(Log::out()); Log::out() << ::std::endl; } } return inst; }
void SSABuilder::checkForTrivialPhis2(Node *node, const StlVectorSet<VarOpnd *> *lookatVars, StlVector<VarOpnd *> *changedVars, StlVector<Opnd *> *removedVars) { // Check that phi insts can start from the second or third position only // and goes in a row assert(phiInstsOnRightPositionsInBB(node)); Inst* phi = (Inst*)node->getSecondInst(); if(phi && !phi->isPhi()) { // try the next one (third) phi = phi->getNextInst(); } Inst *nextphi = NULL; #ifdef DEBUG_SSA if (Log::isEnabled()) { Log::out() << "Checking node " << (int)node->getId() << " for trivial phis2" << ::std::endl; } #endif for (;phi->isPhi(); phi = nextphi) { nextphi = phi->getNextInst(); #ifdef _DEBUG PhiInst *phiInst = phi->asPhiInst(); assert(phiInst); #endif U_32 nSrcs = phi->getNumSrcOperands(); if (nSrcs <= 1) { // phi must be trivial #ifdef DEBUG_SSA ::std::ostream &cout = Log::out(); if (Log::isEnabled()) { cout << "removing trivial2 instruction "; phi->print(cout); cout << ::std::endl; } #endif Opnd *dstOp = phi->getDst(); VarOpnd *varOp = dstOp->asVarOpnd(); if (!varOp) { SsaVarOpnd *ssaOp = dstOp->asSsaVarOpnd(); assert(ssaOp); varOp = ssaOp->getVar(); } assert(!lookatVars || (lookatVars->has(varOp))); changedVars->push_back(varOp); removedVars->push_back(dstOp); phi->unlink(); } } }
static OpndLoopInfo processOpnd(LoopNode* loopHead, LoopTree* lt, InstStack& defStack, Opnd* opnd) { OpndLoopInfo result; Inst* defInst = opnd->getInst(); if (Log::isEnabled()) { log_ident(defStack.size()); defInst->print(Log::out()); Log::out()<<"]"<<std::endl; } if (std::find(defStack.begin(), defStack.end(), defInst)!=defStack.end()) { result.setType(OpndLoopInfo::COUNTER); result.setIncrement(0); if (Log::isEnabled()) { log_ident(defStack.size()); Log::out()<<"Found duplicate in def stack -> stopping recursion. ";result.print(Log::out()); Log::out()<<std::endl; } return result; } Node* defNode = defInst->getNode(); Opcode opcode = defInst->getOpcode(); if (opcode == Op_LdConstant) { result.setType(OpndLoopInfo::LD_CONST); result.setConst(defInst->asConstInst()->getValue().i4); if (Log::isEnabled()) { log_ident(defStack.size()); Log::out()<<"assigning to const -> stopping recursion. ";result.print(Log::out());Log::out()<<std::endl; } return result; } if (!loopHead->inLoop(defNode)) { if (Log::isEnabled()) { log_ident(defStack.size()); Log::out()<<"Inst out of the loop -> stopping recursion. ";result.print(Log::out()); Log::out()<<std::endl; } return result; } defStack.push_back(defInst); if (opcode == Op_Phi) { OpndLoopInfo info1 = processOpnd(loopHead, lt, defStack, defInst->getSrc(0)); OpndLoopInfo info2 = processOpnd(loopHead, lt, defStack, defInst->getSrc(1)); if (Log::isEnabled()) { log_ident(defStack.size()); Log::out()<<"PHI(";info1.print(Log::out());Log::out()<<",";info2.print(Log::out());Log::out()<<")"<<std::endl; } if ( ((info1.isCounter() && !info1.isPhiSplit()) && (info2.isDOL() || info2.isLDConst())) || ((info2.isCounter() && !info2.isPhiSplit()) && (info1.isDOL() || info1.isLDConst())) ) { result.setType(OpndLoopInfo::COUNTER); result.setIncrement(info1.isCounter() ? info1.getIncrement() : info2.getIncrement()); result.markPhiSplit(); } else { result.setType(OpndLoopInfo::UNDEF); } } else if (opcode == Op_Add || opcode == Op_Sub) { //todo: LADD Opnd *op1 = defInst->getSrc(0); Opnd *op2 = defInst->getSrc(1); OpndLoopInfo info1 = processOpnd(loopHead, lt, defStack, op1); OpndLoopInfo info2 = processOpnd(loopHead, lt, defStack, op2); if ((info1.isLDConst() || info1.isDOL()) && (info2.isLDConst() || info2.isDOL())) { if (info1.isLDConst() && info2.isLDConst() && info1.getConst() == info2.getConst()) { result.setType(OpndLoopInfo::LD_CONST); result.setConst(info1.getConst()); } else { //result is DOL (default type) } } else if ((info1.isCounter() && info2.isLDConst()) || (info2.isCounter() && info1.isLDConst())) { int increment = info1.isCounter()? info1.getIncrement(): info2.getIncrement(); int diff = info1.isLDConst()? info1.getConst(): info2.getConst(); //we use SSA form to analyze how opnd changes in loop and we do not analyze actual control flow, // so we can unroll loops with monotonically changing 'counters' only. //Example: when 'counter' changes not monotonically and we can't unroll: //idx=0; loop {idx+=100; if(idx>=100) break; idx-=99;} ->'increment'=1 but not monotonicaly. bool monotonousFlag = increment == 0 || diff == 0 || (opcode == Op_Add && signof(diff) == signof(increment)) || (opcode == Op_Sub && signof(diff) != signof(increment)); if (monotonousFlag) { result.setType(OpndLoopInfo::COUNTER); if ((info1.isCounter() && info1.isPhiSplit()) || (info2.isCounter() && info2.isPhiSplit())) { result.markPhiSplit(); } //TO IMPROVE: for loops like: for (; length-1>=0;length--){...} //we have 2 SUBs by -1 => "-2", but real counter is changed by "-1". //Loop unroll will use "-2". It's ok, because this value is used in a guard inst //and ABS(increment_in_unroll) >= ABS(real_increment). This work only for monotonous loops. //To make increment_in_unroll == real_increment we must track modifications (SUB,ADD) that affects vars only. if (opcode == Op_Add) { result.setIncrement(increment + diff); } else { result.setIncrement(increment - diff); } } else { result.setType(OpndLoopInfo::UNDEF); } } else { result.setType(OpndLoopInfo::UNDEF); } } else if (opcode == Op_StVar || opcode == Op_LdVar) { Opnd* newOpnd = defInst->getSrc(0); result = processOpnd(loopHead, lt, defStack, newOpnd); } else if (opcode == Op_TauArrayLen) { Opnd* arrayOpnd = defInst->getSrc(0); result = processOpnd(loopHead, lt, defStack, arrayOpnd); } else { //unsupported op result.setType(OpndLoopInfo::UNDEF); if (Log::isEnabled()) { log_ident(defStack.size()); Log::out()<<"unknown op -> stopping recursion. "; } } defStack.pop_back(); if (Log::isEnabled()) { log_ident(defStack.size()); result.print(Log::out());Log::out()<<std::endl; } return result; }
/** * Checks that exception edges are equal for newobj instruction node and * throw instruction node. * @param bs - bit set of operands that may be optimized */ void LazyExceptionOpt::fixOptCandidates(BitSet* bs) { OptCandidates::iterator it; Inst* oinst; MethodCallInst* iinst; Inst* tinst; Inst* tlinst; U_32 opcount; Opnd **opnds = NULL; if (optCandidates == NULL) { return; } for (it = optCandidates->begin( ); it != optCandidates->end( ); it++ ) { if (bs->getBit((*it)->opndId)) { oinst = (*it)->objInst; assert(oinst != NULL); #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " to remove "; oinst->print(Log::out()); Log::out() << std::endl; } #endif if ((*it)->initInst == NULL) { #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " init inst is null "; Log::out() << std::endl; } #endif continue; } iinst = (*it)->initInst->asMethodCallInst(); // inline info from constructor should be propagated to lazy // exception if any #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " to remove "; iinst->print(Log::out()); Log::out() << std::endl; } #endif assert((*it)->throwInsts != NULL); assert(iinst->getNumSrcOperands() >= 3); if (!removeInsts(oinst,iinst)) continue; // to null bitset? TypeManager& tm = irManager.getTypeManager(); Opnd* mpt = irManager.getOpndManager().createSsaTmpOpnd( tm.getMethodPtrType(iinst->getMethodDesc())); opcount = iinst->getNumSrcOperands()-2; //numSrc-3+1 if (opcount >0) { opnds = new (leMemManager) Opnd*[opcount]; //local mem should be used opnds[0] = mpt; for (U_32 i = 0; i < opcount-1; i++) opnds[i+1] = iinst->getSrc(i+3); } Inst* mptinst = irManager.getInstFactory().makeLdFunAddr(mpt,iinst->getMethodDesc()); #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " 1st "; mptinst->print(Log::out()); Log::out() << std::endl; } #endif ThrowInsts::iterator it1; for (it1 = (*it)->throwInsts->begin(); it1 !=(*it)->throwInsts->end(); it1++) { tinst = *it1; assert(tinst != NULL); tlinst=irManager.getInstFactory().makeVMHelperCall( OpndManager::getNullOpnd(), VM_RT_THROW_LAZY, opcount, opnds); #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " 2nd "; tlinst->print(Log::out()); Log::out() << std::endl; } if (Log::isEnabled()) { Log::out() << " to change "; tinst->print(Log::out()); Log::out() << std::endl; } #endif mptinst->insertBefore(tinst); tlinst->insertBefore(tinst); tinst->unlink(); uint16 bcOffset = iinst->getBCOffset(); mptinst->setBCOffset(bcOffset); tlinst->setBCOffset(bcOffset); } } } }
// // traverse dominator tree and rename variables // void SSABuilder::renameNode(RenameStack *renameStack, DominatorNode* dt, const StlVectorSet<VarOpnd *> *whatVars) { if (dt == NULL) return; Node* node = dt->getNode(); Inst* head = (Inst*)node->getFirstInst(); #ifdef DEBUG_SSA std::ostream &cout = Log::out(); if (Log::isEnabled()) { cout << "renameNode "; FlowGraph::printLabel(cout, node); cout << std::endl; } #endif for (Inst* i = head->getNextInst(); i != NULL; i = i->getNextInst()) { if (!i->isPhi()) { // replace src with ssa opnd U_32 nSrcs = i->getNumSrcOperands(); for (U_32 j = 0; j < nSrcs; j++) { Opnd *srcj = i->getSrc(j); VarOpnd *srcjVar = (srcj->isSsaVarOpnd() ? srcj->asSsaVarOpnd()->getVar() : srcj->asVarOpnd()); if (!(srcjVar && !srcjVar->isAddrTaken())) continue; if (whatVars && !whatVars->has(srcjVar)) continue; SsaVarOpnd* ssa = renameStack->lookup(srcjVar); assert(ssa); i->setSrc(j,ssa); } } // for both Phi and non-Phi // we replace any non-ssa dst with a new ssa opnd // and record it in the RenameStack map Opnd* dst = i->getDst(); VarOpnd *theVar = dst->asVarOpnd(); if (theVar && (!theVar->isAddrTaken()) && !(whatVars && !whatVars->has(theVar))) { SsaVarOpnd* ssaDst = opndManager.createSsaVarOpnd((VarOpnd*)dst); #ifdef DEBUG_SSA if (Log::isEnabled()) { cout << "SSA "; ssaDst->print(cout); cout << ::std::endl; } #endif renameStack->insert((VarOpnd*)dst, ssaDst); i->setDst(ssaDst); #ifdef DEBUG_SSA if (Log::isEnabled()) { i->print(cout); cout << ::std::endl; } #endif // record stVar inst } else if (dst->isSsaVarOpnd()) { SsaVarOpnd* ssaDst = dst->asSsaVarOpnd(); theVar = ssaDst->getVar(); if (whatVars && !whatVars->has(theVar)) continue; #ifdef DEBUG_SSA if (Log::isEnabled()) { cout << "SSA "; ssaDst->print(cout); cout << ::std::endl; } #endif renameStack->insert(ssaDst->getVar(), ssaDst); #ifdef DEBUG_SSA if (Log::isEnabled()) { i->print(cout); cout << ::std::endl; } #endif } } // add var sources to following phi instructions const Edges& edges = node->getOutEdges(); Edges::const_iterator eiter = edges.begin(), eend = edges.end(); for(eiter = edges.begin(); eiter != eend; ++eiter) { Edge* e = *eiter; Node* succ = e->getTargetNode(); // Phi insts are inserted to the beginning of the block // if succ does not have phi insts, then we can skip it Inst *phi = (Inst*)succ->getSecondInst(); if (phi==NULL || !phi->isPhi()) continue; // node is jth predecessor for succ // replace jth var of phi insts Inst* nextphi = phi->getNextInst(); for (;phi!=NULL && phi->isPhi(); phi = nextphi) { nextphi = phi->getNextInst(); // get var Opnd *theopnd = phi->getDst(); VarOpnd *thevar = theopnd->asVarOpnd(); if (!thevar) { SsaVarOpnd *theSsaVar = theopnd->asSsaVarOpnd(); assert(theSsaVar); #ifdef DEBUG_SSA if (Log::isEnabled()) { Log::out() << "case 2" << ::std::endl; } #endif thevar = theSsaVar->getVar(); } if (whatVars && !whatVars->has(thevar)) continue; SsaVarOpnd* ssa = renameStack->lookup((VarOpnd*)thevar); if (ssa != NULL) { #ifdef DEBUG_SSA if (Log::isEnabled()) { cout << "redge"; // cout << (I_32)j; cout << " with ssa "; ssa->print(cout); cout << ::std::endl; } #endif addPhiSrc((PhiInst*)phi,ssa); } else { #ifdef DEBUG_SSA if (Log::isEnabled()) { cout << "no source for phi of var "; thevar->print(cout); cout << ::std::endl; } #endif // if ssa is NULL, then the phi must be a dead phi inst // (no more use of var afterwards). it will be removed. } } } }