void SSABuilder::clearPhiSrcs(Node *node, const StlVectorSet<VarOpnd *> *whatVars) { Inst* phi = (Inst*)node->getSecondInst(); if (whatVars) { for (;phi!=NULL && phi->isPhi(); phi = phi->getNextInst()) { Opnd *dstOp = phi->getDst(); VarOpnd *varOpnd = dstOp->asVarOpnd(); if (!varOpnd) { SsaVarOpnd *ssaOpnd = dstOp->asSsaVarOpnd(); assert(ssaOpnd); varOpnd = ssaOpnd->getVar(); } if (whatVars->has(varOpnd)) { PhiInst *phiInst = phi->asPhiInst(); assert(phiInst); phiInst->setNumSrcs(0); } } } else { for (;phi!=NULL && phi->isPhi(); phi = phi->getNextInst()) { PhiInst *phiInst = phi->asPhiInst(); assert(phiInst); phiInst->setNumSrcs(0); } } }
PeepHoleOpt::Changed PeepHoleOpt::handleInst_SSEXor(Inst* inst) { assert(inst->getMnemonic() == Mnemonic_XORPS || inst->getMnemonic() == Mnemonic_XORPD); if (inst->getOpndCount() != 2) { // Expected only XORPS/PD a, b assert(false); return Changed_Nothing; } Opnd* dst = inst->getOpnd(0); Opnd* src = inst->getOpnd(1); if (isReg(dst) && isReg(src, dst->getRegName())) { /*what: XORPS/XORPD regN, regN => PXOR regN, regN why: XORPS/PD used for zero-ing register, but PXOR is faster (2 ticks on PXOR vs 4 ticks for XORPS/XORPD) */ // FIXME: replacing operands on 1 instruction only // will fail liveness verification if their refcount > 1 //dst = convertToXmmReg64(dst); //src = convertToXmmReg64(src); //Inst* ii = irManager->newInst(Mnemonic_PXOR, dst, src); //replaceInst(inst, ii); //return Changed_Inst; } return Changed_Nothing; }
void PrologEpilogGenerator::saveRestorePreservedGr() { opndManager->initSavedBase(); // after this point mem local stack must contain preserved regs only IPF_LOG << " Preserved register saved in memory stack with offset: " << opndManager->savedBase << endl; RegBitSet preservGrMask(string("11110000")); // work with r4-r7 only (not with automatic regs r32-r127) RegBitSet regMask = usedGrMask & preservGrMask; if(regMask.any() == false) return; IPF_LOG << " Preserved grs:"; for(uint16 i=4; i<8; i++) { if(regMask[i] == false) continue; Opnd *storage = newStorage(DATA_U64, SITE_STACK); Opnd *offset = opndManager->newImm(storage->getValue()); Opnd *preserv = opndManager->newRegOpnd(OPND_G_REG, DATA_U64, i); saveGrsInsts.push_back(new(mm) Inst(mm, INST_ADDS, p0, stackAddr, offset, sp)); saveGrsInsts.push_back(new(mm) Inst(mm, INST_ST8_SPILL, p0, stackAddr, preserv)); restGrsInsts.push_back(new(mm) Inst(mm, INST_ADDS, p0, stackAddr, offset, sp)); restGrsInsts.push_back(new(mm) Inst(mm, INST_LD8_FILL, p0, preserv, stackAddr)); IPF_LOG << " " << IrPrinter::toString(preserv); } IPF_LOG << endl; opndManager->savedGrMask = regMask.to_ulong(); }
void PrologEpilogGenerator::saveRestorePreservedBr() { RegBitSet regMask = usedBrMask & opndManager->preservBrMask; if(regMask.any() == false) return; IPF_LOG << " Preserved brs:"; for(uint16 i=1; i<6; i++) { if(regMask[i] == false) continue; Opnd *storage = newStorage(DATA_B, SITE_STACK); Opnd *offset = opndManager->newImm(storage->getValue()); Opnd *scratch = opndManager->newRegOpnd(OPND_G_REG, DATA_B, SPILL_REG2); Opnd *preserv = opndManager->newRegOpnd(OPND_B_REG, DATA_B, i); saveBrsInsts.push_back(new(mm) Inst(mm, INST_MOV, p0, scratch, preserv)); saveBrsInsts.push_back(new(mm) Inst(mm, INST_ADDS, p0, stackAddr, offset, sp)); saveBrsInsts.push_back(new(mm) Inst(mm, INST_ST, CMPLT_SZ_8, p0, stackAddr, scratch)); restBrsInsts.push_back(new(mm) Inst(mm, INST_ADDS, p0, stackAddr, offset, sp)); restBrsInsts.push_back(new(mm) Inst(mm, INST_LD, CMPLT_SZ_8, p0, scratch, stackAddr)); restBrsInsts.push_back(new(mm) Inst(mm, INST_MOV, p0, preserv, scratch)); IPF_LOG << " " << IrPrinter::toString(preserv); } IPF_LOG << endl; opndManager->savedBrMask = regMask.to_ulong(); }
void SSABuilder::deconvertSSA(ControlFlowGraph* fg,OpndManager& opndManager) { const Nodes& nodes = fg->getNodes(); Nodes::const_iterator niter; for(niter = nodes.begin(); niter != nodes.end(); ++niter) { Node* node = *niter; Inst *headInst = (Inst*)node->getFirstInst(); for (Inst *inst = headInst->getNextInst(); inst != NULL; ) { Inst *nextInst = inst->getNextInst(); if (inst->isPhi()) { inst->unlink(); } else { for (U_32 i = 0; i < inst->getNumSrcOperands(); i++) { Opnd *opnd = inst->getSrc(i); if (opnd->isSsaVarOpnd()) { SsaVarOpnd *ssa = (SsaVarOpnd *)opnd; VarOpnd *var = ssa->getVar(); inst->setSrc(i,var); } else if (opnd->isVarOpnd()) { } } Opnd *dst = inst->getDst(); if (dst->isSsaVarOpnd()) { SsaVarOpnd *ssa = (SsaVarOpnd *)dst; inst->setDst(ssa->getVar()); } } inst = nextInst; } } }
/** * 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; }
bool Opnd::isImm(int size) { if (isImm() == false) return false; Opnd* imm = (Opnd*) this; if (Opnd::isFoldableImm(imm->getValue(), size)) return true; return false; }
Opnd* OpndUtils::findImmediateSource(Opnd* opnd) { Opnd* res = opnd; while (!res->isPlacedIn(OpndKind_Imm)) { Inst* defInst = res->getDefiningInst(); if (!defInst || defInst->getMnemonic()!=Mnemonic_MOV) { return NULL; } res = defInst->getOpnd(1); } return res; }
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(); } } }
void Opnd::normalizeMemSubOpnds(void) { if (!isPlacedIn(OpndKind_Mem)) { return; } Opnd* base = getMemOpndSubOpnd(MemOpndSubOpndKind_Base); Opnd* disp = getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); if (base != NULL && base->isPlacedIn(OpndKind_Imm)) { assert(disp == NULL || !disp->isPlacedIn(OpndKind_Imm) || base->getType()->isNullObject()); setMemOpndSubOpnd(MemOpndSubOpndKind_Displacement, base); // can't call setMemOpndSubOpnd() as it fights against zero opnd. memOpndSubOpnds[MemOpndSubOpndKind_Base] = disp; //==setMemOpndSubOpnd(MemOpndSubOpndKind_Base, disp); } }
PeepHoleOpt::Changed PeepHoleOpt::handleInst_Call(Inst* inst) { assert(inst->getMnemonic() == Mnemonic_CALL); CallInst* callInst = (CallInst*)inst; unsigned targetOpndIndex = callInst->getTargetOpndIndex(); Opnd* targetOpnd = callInst->getOpnd(targetOpndIndex); Opnd::RuntimeInfo* ri = targetOpnd->getRuntimeInfo(); Opnd::RuntimeInfo::Kind rt_kind = Opnd::RuntimeInfo::Kind_Null; if (ri != NULL) { rt_kind = ri->getKind(); } if (Opnd::RuntimeInfo::Kind_InternalHelperAddress == rt_kind) { return handleInst_InternalHelperCall(inst, ri); } return Changed_Nothing; }
void IpfCfgCodeSelector::genSwitchEdges(U_32 tailNodeId, U_32 numTargets, U_32 *targets, double *probs, U_32 defaultTarget) { BbNode *tailNode = (BbNode *)nodes[tailNodeId]; InstVector &insts = tailNode->getInsts(); Inst *switchInst = insts.back(); Opnd *defTargetImm = switchInst->getOpnd(POS_SWITCH_DEFAULT); ConstantRef *constantRef = (ConstantRef *) switchInst->getOpnd(POS_SWITCH_TABLE); SwitchConstant *switchConstant = (SwitchConstant *)constantRef->getConstant(); Edge *defedge = NULL; Edge *edge = NULL; bool defadded = false; U_32 i = 0; IPF_LOG << " Generate Switch tailNodeId=" << tailNodeId << "; defaultTarget=" << defaultTarget << endl; defedge = new(mm) Edge(nodes[tailNodeId], nodes[defaultTarget], probs[defaultTarget], EDGE_BRANCH); defedge->insert(); for(i=0; i<numTargets; i++) { if(targets[i] == defaultTarget) { defTargetImm->setValue(i); switchConstant->addEdge(defedge); defadded = true; IPF_LOG << " default: " << i << endl; continue; } IPF_LOG << " case " << i << ": " << targets[i] << endl; edge = new(mm) Edge(nodes[tailNodeId], nodes[targets[i]], probs[i], EDGE_BRANCH); edge->insert(); switchConstant->addEdge(edge); } if (!defadded) { defTargetImm->setValue(i); switchConstant->addEdge(defedge); defadded = true; IPF_LOG << " default: " << i << endl; } }
void PrologEpilogGenerator::saveRestorePreservedFr() { RegBitSet regMask = usedFrMask & opndManager->preservFrMask; if(regMask.any() == false) return; IPF_LOG << " Preserved frs:"; for(uint16 i=2; i<32; i++) { if(regMask[i] == false) continue; Opnd *storage = newStorage(DATA_F, SITE_STACK); Opnd *offset = opndManager->newImm(storage->getValue()); Opnd *preserv = opndManager->newRegOpnd(OPND_F_REG, DATA_F, i); saveFrsInsts.push_back(new(mm) Inst(mm, INST_ADDS, p0, stackAddr, offset, sp)); saveFrsInsts.push_back(new(mm) Inst(mm, INST_STF_SPILL, p0, stackAddr, preserv)); restFrsInsts.push_back(new(mm) Inst(mm, INST_ADDS, p0, stackAddr, offset, sp)); restFrsInsts.push_back(new(mm) Inst(mm, INST_LDF_FILL, p0, preserv, stackAddr)); IPF_LOG << " " << IrPrinter::toString(preserv); } IPF_LOG << endl; opndManager->savedFrMask = regMask.to_ulong(); }
const void* OpndUtils::extractAddrOfConst(const Opnd* op) { if (op->getMemOpndKind() != MemOpndKind_ConstantArea) { return NULL; } // Actually, it's currently only works for IA-32 - I expect // the address of constant completely in the displacement. // On Intel64, the address already get loaded into a register, // so more complicated analysis needed to find the proper constant Opnd* disp = op->getMemOpndSubOpnd(MemOpndSubOpndKind_Displacement); if (disp == NULL) { // Perhaps, it's IA-32? return NULL; } Opnd::RuntimeInfo* rtInfo = disp->getRuntimeInfo(); assert(rtInfo != NULL); assert(rtInfo->getKind() == Opnd::RuntimeInfo::Kind_ConstantAreaItem); ConstantAreaItem* item = (ConstantAreaItem*)rtInfo->getValue(0); // At this point we must have the address... assert(item->getValue()!= NULL); return item->getValue(); }
//All CALL insts except some special helpers that never cause stacktrace printing bool InstUtils::instMustHaveBCMapping(Inst* inst) { if (!inst->hasKind(Inst::Kind_CallInst)) { return false; } CallInst* callInst = (CallInst*)inst; Opnd * targetOpnd=callInst->getOpnd(callInst->getTargetOpndIndex()); Opnd* immOpnd = OpndUtils::findImmediateSource(targetOpnd); Opnd::RuntimeInfo * ri = immOpnd ? immOpnd->getRuntimeInfo() : NULL; if(!ri) { return true; } else if (ri->getKind() == Opnd::RuntimeInfo::Kind_InternalHelperAddress) { return false; } else if (ri->getKind() == Opnd::RuntimeInfo::Kind_HelperAddress) { VM_RT_SUPPORT helperId = (VM_RT_SUPPORT)(POINTER_SIZE_INT)ri->getValue(0); switch (helperId) { case VM_RT_GC_GET_TLS_BASE: case VM_RT_GC_SAFE_POINT: return false; default: break; } } return true; }
void applyToInst(Inst *inst) { if (inst->getOpcode() == Op_Phi) { // we should just delete the whole thing. Opnd *dstOpnd = inst->getDst(); if (dstOpnd->isSsaVarOpnd()) { SsaVarOpnd *ssaOpnd = dstOpnd->asSsaVarOpnd(); VarOpnd *var = ssaOpnd->getVar(); if (usedOutOfSsa.has(var)) { // remove instruction inst->unlink(); return; } } else if (dstOpnd->isVarOpnd()) { VarOpnd *var = dstOpnd->asVarOpnd(); if (usedOutOfSsa.has(var)) { // remove instruction inst->unlink(); return; } } } U_32 numSrcs = inst->getNumSrcOperands(); for (U_32 i=0; i<numSrcs; ++i) { Opnd *thisOpnd = inst->getSrc(i); VarOpnd *varOpnd = needToDeSsaOpnd(thisOpnd); if (varOpnd) { inst->setSrc(i, varOpnd); } } Opnd *dstOpnd = inst->getDst(); VarOpnd *varDstOpnd = needToDeSsaOpnd(dstOpnd); if (varDstOpnd) { inst->setDst(varDstOpnd); } }
PeepHoleOpt::Changed PeepHoleOpt::handleInst(Inst* inst) { PeepHoleOpt::Changed temp; // Local propagation Inst::Opnds opnds(inst, Inst::OpndRole_All); for (Inst::Opnds::iterator it=opnds.begin();it != opnds.end();it = opnds.next(it)) { Opnd * opnd=inst->getOpnd(it); U_32 roles=inst->getOpndRoles(it); if (roles & Inst::OpndRole_Use) { if ((roles & Inst::OpndRole_All & Inst::OpndRole_FromEncoder) && (roles & Inst::OpndRole_All & Inst::OpndRole_ForIterator) && (roles & Inst::OpndRole_Changeable) && ((roles & Inst::OpndRole_Def) == 0) && copyMap->has(opnd)) { if (opnd->getType()->isUnmanagedPtr() && (*copyMap)[opnd]->getType()->isInteger()) (*copyMap)[opnd]->setType(opnd->getType()); inst->setOpnd(it, (*copyMap)[opnd]); } } } for (Inst::Opnds::iterator it = opnds.begin();it != opnds.end();it = opnds.next(it)) { Opnd * opnd=inst->getOpnd(it); U_32 roles=inst->getOpndRoles(it); if (roles & Inst::OpndRole_Def) { if (copyMap->has(opnd)) { if (Log::isEnabled()) Log::out()<<"copy relation DELETED: " << opnd->getFirstId() << "<=" << (*copyMap)[opnd]->getFirstId() <<std::endl; copyMap->erase(opnd); } tempSet->clear(); for(StlHashMap<Opnd*, Opnd*>::iterator iter=copyMap->begin(); iter!=copyMap->end();++iter) if (iter->second == opnd) { if (Log::isEnabled()) Log::out()<<"copy relation DELETED: " << iter->first->getFirstId() << "<=" << iter->second->getFirstId() <<std::endl; tempSet->insert(iter->first); } for(StlSet<Opnd*>::iterator iter=tempSet->begin(); iter!=tempSet->end();++iter) copyMap->erase(*iter); } } if (inst->getMnemonic() == Mnemonic_MOV) { Inst::Opnds opnds(inst, Inst::OpndRole_All); Opnd * dst = NULL; Opnd * src = NULL; U_32 counterDef = 0; U_32 counterUse = 0; for (Inst::Opnds::iterator it=opnds.begin();it!=opnds.end();it=opnds.next(it)) { Opnd * opnd = inst->getOpnd(it); U_32 roles = inst->getOpndRoles(it); if (roles & Inst::OpndRole_Def) { counterDef++; dst = opnd; } else if (roles & Inst::OpndRole_Use) { counterUse++; src = opnd; } } if ((counterDef == 1) && (counterUse == 1) && (!dst->hasAssignedPhysicalLocation())) { bool kindsAreOk = true; if(src->canBePlacedIn(OpndKind_FPReg) || dst->canBePlacedIn(OpndKind_FPReg)) { Constraint srcConstr = src->getConstraint(Opnd::ConstraintKind_Calculated); Constraint dstConstr = dst->getConstraint(Opnd::ConstraintKind_Calculated); kindsAreOk = ! (srcConstr&dstConstr).isNull(); } bool typeConvOk = src->getSize() == dst->getSize() && isTypeConversionAllowed(src, dst); if (typeConvOk && kindsAreOk && ! src->isPlacedIn(OpndKind_Reg)) { if (copyMap->has(src)) { (*copyMap)[dst] = (*copyMap)[src]; if (Log::isEnabled()) Log::out()<<"copy relation INSERTED: " << dst->getFirstId() << "<=" << (*copyMap)[src]->getFirstId() <<std::endl; } else { (*copyMap)[dst] = src; if (Log::isEnabled()) Log::out()<<"copy relation INSERTED: " << dst->getFirstId() << "<=" << src->getFirstId() <<std::endl; } } } } if (inst->hasKind(Inst::Kind_PseudoInst) && inst->getKind() != Inst::Kind_CopyPseudoInst) { return Changed_Nothing; } Mnemonic mnemonic = inst->getMnemonic(); switch(mnemonic) { case Mnemonic_MOV: return handleInst_MOV(inst); case Mnemonic_CALL: return handleInst_Call(inst); case Mnemonic_ADD: case Mnemonic_ADC: case Mnemonic_SUB: case Mnemonic_SBB: case Mnemonic_NOT: case Mnemonic_AND: case Mnemonic_OR: case Mnemonic_XOR: case Mnemonic_TEST: return handleInst_ALU(inst); case Mnemonic_CMP: temp = handleInst_CMP(inst); if ( temp == Changed_Nothing ) { return handleInst_ALU(inst); } else { return temp; } case Mnemonic_SETG: case Mnemonic_SETE: case Mnemonic_SETNE: case Mnemonic_SETL: return handleInst_SETcc(inst); case Mnemonic_IMUL: case Mnemonic_MUL: return handleInst_MUL(inst); case Mnemonic_MOVSS: case Mnemonic_MOVSD: //return handleInst_SSEMov(inst); case Mnemonic_XORPS: case Mnemonic_XORPD: //return handleInst_SSEXor(inst); default: break; } return Changed_Nothing; }
static void doUnroll(MemoryManager& mm, IRManager& irm, const LoopUnrollInfo* info, const UnrollFlags& flags) { //unroll algorithm does the following //before: // loopOrig { // bodyA // check(idxOpnd,limitOpnd) // bodyB // } //after: // unrolledIncOpnd = unrollCount * idx->increment // unrolledLimitOpnd = limitOpnd-unrolledIncOpnd; // bodyA // loopUnrolled { // check(idxOpnd,unrolledLimitOpnd) // bodyB // bodyA // bodyB // ... // bodyA // } // loopEpilogue { // check(idxOpnd,limitOpnd) // bodyB // bodyA // } // //where: // bodyA - all nodes of the same loop accessible from checkNode via incoming edges // bodyB - all nodes except bodyA and checkNode ControlFlowGraph& cfg = irm.getFlowGraph(); LoopTree* lt = cfg.getLoopTree(); InstFactory& instFactory = irm.getInstFactory(); OpndManager& opndManager = irm.getOpndManager(); Type* opType = info->getLimitOpnd()->getType(); // printf("UNROLL\n"); //STEP 0: cache all data needed assert(info->unrollCount >= 1); Node* origHeader = info->header; assert(origHeader->getInDegree() == 2); //loop is normalized OptPass::computeLoops(irm);//recompute loop info if needed LoopNode* loopNode = lt->getLoopNode(origHeader, false); Edge* entryEdge = origHeader->getInEdges().front(); if (lt->isBackEdge(entryEdge)) { entryEdge = origHeader->getInEdges().back(); } Node* origCheckNode = info->branchInst->getNode(); Edge* origLoopExitEdge = info->branchTargetIsExit ? origCheckNode->getTrueEdge() : origCheckNode->getFalseEdge(); U_32 maxNodeId = cfg.getMaxNodeId()+1; //+1 for a split check node StlBitVector nodesInLoop(mm, maxNodeId); { const Nodes& loopNodes = loopNode->getNodesInLoop(); for (Nodes::const_iterator it = loopNodes.begin(), end = loopNodes.end(); it!=end; ++it) { Node* node = *it; nodesInLoop.setBit(node->getId()); } } //STEP 1: calculate bodyA nodes BitSet aFlags(mm, maxNodeId); calculateReachableNodesInLoop(loopNode, origHeader, origCheckNode, aFlags); StlBitVector bodyANodes(mm, maxNodeId); for (U_32 i=0;i<maxNodeId;i++) bodyANodes.setBit(i, aFlags.getBit(i)); //STEP 2: make checkNode a separate node, prepare loop region bodyANodes.setBit(origCheckNode->getId(), true); Node* checkNode = cfg.splitNodeAtInstruction(info->branchInst->prev(), true, false, instFactory.makeLabel()); nodesInLoop.setBit(checkNode->getId(), true); Node* preCheckNode = origCheckNode; bodyANodes.setBit(preCheckNode->getId(), true); //STEP 3: rotate original loop // before: {bodyA1, check , bodyB} // after: bodyA2 {check, bodyB, bodyA1} Edge* bodyA2ToCheckEdge = NULL; Opnd* limitOpndInBodyA2 = NULL; { //WARN: info->limitOpnd and info->indexOpnd can be replaced after code duplication if promoted to vars Opnd* limitOpndBefore = info->getLimitOpnd(); assert(preCheckNode->getOutDegree()==1 && preCheckNode->getUnconditionalEdgeTarget() == checkNode); DefUseBuilder defUses(mm); defUses.initialize(cfg); OpndRenameTable opndRenameTable(mm, maxNodeId); //todo: maxNodeId is overkill estimate here NodeRenameTable nodeRenameTable(mm, maxNodeId); Node* bodyA2 = FlowGraph::duplicateRegion(irm, origHeader, bodyANodes, defUses, nodeRenameTable, opndRenameTable); cfg.replaceEdgeTarget(entryEdge, bodyA2, true); // while duplicating a region new nodes could be created and 'nodesInRegion' bitvector param is updated. // BodyA is part of the loop -> if new nodes were created in the loop we must track them. nodesInLoop.resize(bodyANodes.size()); for (U_32 i=0;i<bodyANodes.size();i++) nodesInLoop.setBit(i, bodyANodes.getBit(i) || nodesInLoop.getBit(i)); Node* bodyA2PreCheckNode = nodeRenameTable.getMapping(preCheckNode); assert(bodyA2PreCheckNode->getOutDegree()==1 && bodyA2PreCheckNode->getUnconditionalEdgeTarget() == checkNode); bodyA2ToCheckEdge = bodyA2PreCheckNode->getUnconditionalEdge(); limitOpndInBodyA2 = limitOpndBefore; if (nodeRenameTable.getMapping(limitOpndBefore->getInst()->getNode())!=NULL) { limitOpndInBodyA2 = opndRenameTable.getMapping(limitOpndBefore); } assert(limitOpndInBodyA2!=NULL); } //STEP 4: prepare epilogue loop: {check, bodyB, bodyA} Node* epilogueLoopHead = NULL; { DefUseBuilder defUses(mm); defUses.initialize(cfg); OpndRenameTable opndRenameTable(mm, maxNodeId); //todo: maxNodeId is overkill estimate here NodeRenameTable nodeRenameTable(mm, maxNodeId); epilogueLoopHead = FlowGraph::duplicateRegion(irm, checkNode, nodesInLoop, defUses, nodeRenameTable, opndRenameTable); cfg.replaceEdgeTarget(origLoopExitEdge, epilogueLoopHead, true); } //STEP 5: prepare unrolledLimitOpnd and replace it in original loop's check { Node* unrolledPreheader = cfg.spliceBlockOnEdge(bodyA2ToCheckEdge, instFactory.makeLabel()); Opnd* unrolledIncOpnd = opndManager.createSsaTmpOpnd(opType); unrolledPreheader->appendInst(instFactory.makeLdConst(unrolledIncOpnd, info->increment * info->unrollCount)); Opnd* unrolledLimitOpnd = opndManager.createSsaTmpOpnd(opType); Modifier mod = Modifier(SignedOp)|Modifier(Strict_No)|Modifier(Overflow_None)|Modifier(Exception_Never); unrolledPreheader->appendInst(instFactory.makeSub(mod, unrolledLimitOpnd, limitOpndInBodyA2, unrolledIncOpnd)); info->branchInst->setSrc(info->branchLimitOpndPos, unrolledLimitOpnd); } DefUseBuilder defUses(mm); defUses.initialize(cfg); //STEP 6: unroll original loop and remove all checks in duplicated bodies { Edge* backedge = preCheckNode->getUnconditionalEdge(); for (int i=1;i<info->unrollCount;i++) { OpndRenameTable opndRenameTable(mm, maxNodeId); NodeRenameTable nodeRenameTable(mm, maxNodeId); Node* unrolledRegionHeader = FlowGraph::duplicateRegion(irm, checkNode, nodesInLoop, defUses, nodeRenameTable, opndRenameTable); cfg.replaceEdgeTarget(backedge, unrolledRegionHeader, true); Node* newTail = nodeRenameTable.getMapping(preCheckNode); assert(newTail->getOutDegree()==1 ); backedge = newTail->getUnconditionalEdge(); cfg.replaceEdgeTarget(backedge, checkNode, true); //remove check from duplicated code Node* duplicateCheckNode = nodeRenameTable.getMapping(checkNode); assert(duplicateCheckNode->getOutDegree()==2); Edge* exitEdge = info->branchTargetIsExit ? duplicateCheckNode->getTrueEdge() : duplicateCheckNode->getFalseEdge(); duplicateCheckNode->getLastInst()->unlink(); cfg.removeEdge(exitEdge); } } //STEP 7: make old loop colder if (cfg.hasEdgeProfile()) { Edge* epilogueExit = info->branchTargetIsExit ? epilogueLoopHead->getTrueEdge() : epilogueLoopHead->getFalseEdge(); epilogueExit->setEdgeProb(epilogueExit->getEdgeProb() * 5); } }
//_________________________________________________________________________________________________ void DCE::runImpl() { bool early = false; getArg("early", early); if (early && !irManager->getCGFlags()->earlyDCEOn) { return; } irManager->updateLivenessInfo(); irManager->calculateOpndStatistics(); BitSet ls(irManager->getMemoryManager(), irManager->getOpndCount()); const Nodes& nodes = irManager->getFlowGraph()->getNodesPostOrder(); #ifdef ORDER MemoryManager mm("dce_parents"); U_32 opndCount = irManager->getOpndCount(); bool * isParentOpnd = new(mm) bool [opndCount]; memset(isParentOpnd, 0, sizeof(bool) * opndCount); for (Nodes::const_iterator it = nodes.begin(),end = nodes.end(); it!=end; ++it) { Node* node = *it; for (Inst * inst=(Inst*)node->getLastInst(); inst!=NULL; inst=inst->getPrevInst()) { Opnd* load_obj = inst->getParentObjectLoad(); if (load_obj) { isParentOpnd[load_obj->getId()] = true; } Opnd* store_obj = inst->getParentObjectStore(); if (store_obj) { isParentOpnd[store_obj->getId()] = true; } } } #endif for (Nodes::const_iterator it = nodes.begin(),end = nodes.end(); it!=end; ++it) { Node* node = *it; if (node->isBlockNode()) { //Here we'll try to remove redundant branches that could appear after //branch translations. All such branches are supposed to be conditional. Inst * inst = (Inst *)node->getLastInst(); if(inst && node->getOutEdges().size() > 1) { Edges edges = node->getOutEdges(); for (Edges::const_iterator ite1 = ++edges.begin(), end = edges.end(); ite1 != end; ++ite1) { for (Edges::const_iterator ite2 = edges.begin(); ite1 != ite2; ++ite2) { Edge *edge1 = *ite1; Edge *edge2 = *ite2; assert(edge1 != edge2); //If this condition is satisfied then there are at least two branches with //the same destination if (edge1->getTargetNode() == edge2->getTargetNode()) { //Check that edges are conditional and the last instruction is branch, //the other situations are not permitted at the moment assert(inst->hasKind(Inst::Kind_BranchInst)); assert(edge1->getKind() == Edge::Kind_True || edge1->getKind() == Edge::Kind_False); assert(edge2->getKind() == Edge::Kind_True || edge2->getKind() == Edge::Kind_False); //Remove last instruction if it is a branch inst->unlink(); irManager->getFlowGraph()->removeEdge(edge2); } } } } irManager->getLiveAtExit(node, ls); for (Inst * inst=(Inst*)node->getLastInst(), * prevInst=NULL; inst!=NULL; inst=prevInst) { prevInst=inst->getPrevInst(); // Prevent debug traps or instructions with side effects // like (MOVS) from being removed. bool deadInst=!inst->hasSideEffect() && (inst->getMnemonic() != Mnemonic_INT3); #ifdef ORDER //yzm for (unsigned int i = 0 ; i < inst->getOpndCount() ; i ++) { Opnd* opnd = inst->getOpnd(i); if (isParentOpnd[opnd->getId()]) deadInst = false; } #endif if (deadInst) { if (inst->hasKind(Inst::Kind_CopyPseudoInst)) { Opnd * opnd=inst->getOpnd(1); if (opnd->getType()->isFP() && opnd->getDefiningInst()!=NULL && opnd->getDefiningInst()->getMnemonic()==Mnemonic_CALL) { deadInst=false; } } if (deadInst) { Inst::Opnds opnds(inst, Inst::OpndRole_All); for (Inst::Opnds::iterator ito = opnds.begin(); ito != opnds.end(); ito = opnds.next(ito)) { Opnd * opnd = inst->getOpnd(ito); if ((ls.getBit(opnd->getId()) && (inst->getOpndRoles(ito) & Inst::OpndRole_Def)) || (((opnd->getMemOpndKind()&(MemOpndKind_Heap|MemOpndKind_StackManualLayout))!=0) && (inst->getMnemonic() != Mnemonic_LEA))) { deadInst=false; break; } } } } if (deadInst) { inst->unlink(); } else { irManager->updateLiveness(inst, ls); } } irManager->getLiveAtEntry(node)->copyFrom(ls); } } irManager->eliminateSameOpndMoves(); irManager->getFlowGraph()->purgeEmptyNodes(); irManager->getFlowGraph()->mergeAdjacentNodes(true, false); irManager->getFlowGraph()->purgeUnreachableNodes(); irManager->packOpnds(); irManager->invalidateLivenessInfo(); }
//___________________________________________________________________________________________________ void EarlyPropagation::runImpl() { irManager->updateLoopInfo(); U_32 opndCount=irManager->getOpndCount(); MemoryManager mm("early_prop"); OpndInfo * opndInfos = new(mm) OpndInfo[opndCount]; Node * currentLoopHeader = NULL; bool anyInstHandled=false; LoopTree* lt = irManager->getFlowGraph()->getLoopTree(); const Nodes& postOrdered = irManager->getFlowGraph()->getNodesPostOrder(); for (Nodes::const_reverse_iterator it = postOrdered.rbegin(), end = postOrdered.rend(); it!=end; ++it) { Node * node=*it; if (!node->isBlockNode()) { continue; } Node * loopHeader = lt->getLoopHeader(node, false); if (currentLoopHeader != loopHeader){ currentLoopHeader = loopHeader; for (U_32 i = 0; i < opndCount; ++i) if (opndInfos[i].sourceOpndId != EmptyUint32) opndInfos[i].defCount++; } for (Inst * inst = (Inst*)node->getFirstInst(); inst != NULL; inst=inst->getNextInst()){ bool assignedOpndPropagated = false; Inst::Opnds opnds(inst, Inst::OpndRole_All); for (Inst::Opnds::iterator it = opnds.begin(); it != opnds.end(); it = opnds.next(it)){ Opnd * opnd=inst->getOpnd(it); U_32 roles=inst->getOpndRoles(it); U_32 opndId = opnd->getId(); OpndInfo& opndInfo = opndInfos[opndId]; U_32 mask = 0; if (roles & Inst::OpndRole_Def){ ++opndInfo.defCount; }else if (roles & Inst::OpndRole_Use){ if (opndInfo.sourceOpndId != EmptyUint32){ if (opndInfo.sourceOpndDefCountAtCopy < opndInfos[opndInfo.sourceOpndId].defCount) opndInfo.sourceOpndId = EmptyUint32; else{ Opnd * srcOpnd = irManager->getOpnd(opndInfo.sourceOpndId); Constraint co = srcOpnd->getConstraint(Opnd::ConstraintKind_Location); if (co.getKind() == OpndKind_Mem){ mask = (1<<it)-1; if ((roles & Inst::OpndRole_Explicit) == 0 || inst->hasKind(Inst::Kind_PseudoInst) || irManager->isGCSafePoint(inst) || opndInfo.sourceInst != inst->getPrevInst() || assignedOpndPropagated || (inst->getConstraint(it, mask, co.getSize())&co).isNull() ) opndInfo.sourceOpndId = EmptyUint32; assignedOpndPropagated = true; } } } } if (opndInfo.defCount > 1){ opndInfo.sourceOpndId = EmptyUint32; } } /* Here is the previous version to test whether the inst is copy or not. bool isCopy = inst->getMnemonic() == Mnemonic_MOV ||( (inst->getMnemonic() == Mnemonic_ADD || inst->getMnemonic() == Mnemonic_SUB) && inst->getOpnd(3)->isPlacedIn(OpndKind_Imm) && inst->getOpnd(3)->getImmValue()==0 && inst->getOpnd(3)->getRuntimeInfo()==NULL ); It considered special case of 'dst = src +/- 0' as copy. In fact there are more similar cases like 'IMUL src, 1 ; shift src, 0' etc. Such checks are obsolete now, Should as peephole takes care about such copies. Anyway, the code above had a bug: 'inst->getOpnd(3)' crashes in instructions in native form (like ADD def_use, use). */ const bool isCopy = inst->getMnemonic() == Mnemonic_MOV; if (isCopy){ // CopyPseudoInst or mov Opnd * defOpnd = inst->getOpnd(0); Opnd * srcOpnd = inst->getOpnd(1); U_32 defOpndId = defOpnd->getId(); OpndInfo * opndInfo = opndInfos + defOpndId; bool instHandled=false; bool typeConvOk = isTypeConversionAllowed(srcOpnd, defOpnd); if (typeConvOk && opndInfo->defCount == 1 && ! srcOpnd->isPlacedIn(OpndKind_Reg)){ if (!defOpnd->hasAssignedPhysicalLocation()){ opndInfo->sourceInst = inst; opndInfo->sourceOpndId = srcOpnd->getId(); instHandled=true; } } if (instHandled){ if (opndInfos[opndInfo->sourceOpndId].sourceOpndId != EmptyUint32) opndInfo->sourceOpndId = opndInfos[opndInfo->sourceOpndId].sourceOpndId; opndInfo->sourceOpndDefCountAtCopy = opndInfos[opndInfo->sourceOpndId].defCount; anyInstHandled=true; } } } } if (anyInstHandled){ Opnd ** replacements = new(mm) Opnd* [opndCount]; memset(replacements, 0, sizeof(Opnd*) * opndCount); bool hasReplacements = false; for (U_32 i = 0; i < opndCount; ++i){ if (opndInfos[i].sourceOpndId != EmptyUint32){ Inst * inst = opndInfos[i].sourceInst; if (inst !=NULL){ inst->unlink(); } if (opndInfos[i].sourceOpndId != i){ Opnd* origOpnd= irManager->getOpnd(i); Opnd* replacementOpnd = irManager->getOpnd(opndInfos[i].sourceOpndId); assert(isTypeConversionAllowed(replacementOpnd, origOpnd)); if (origOpnd->getType()->isUnmanagedPtr() && replacementOpnd->getType()->isInteger()) { replacementOpnd->setType(origOpnd->getType()); }/* else if (origOpnd->getType()->isObject() && replacementOpnd->getType()->isUnmanagedPtr()) { replacementOpnd->setType(origOpnd->getType()); }*/ replacements[i] = replacementOpnd; hasReplacements = true; } } } if (hasReplacements){ const Nodes& postOrdered = irManager->getFlowGraph()->getNodesPostOrder(); for (Nodes::const_reverse_iterator it = postOrdered.rbegin(), end = postOrdered.rend(); it!=end; ++it) { Node * node=*it; if (!node->isBlockNode()) { continue; } for (Inst * inst = (Inst*)node->getFirstInst(); inst != NULL; inst=inst->getNextInst()){ inst->replaceOpnds(replacements); } } } } }
// rename vars to make un-overlapping live ranges of a variable into // different variables. void SSABuilder::splitSsaWebs(ControlFlowGraph* fg,OpndManager& opndManager) { U_32 numSsaOpnds = opndManager.getNumSsaOpnds(); MemoryManager localMM("SSABuilder::splitSsaWebs::memManager"); SsaVarClique *cliques = new (localMM) SsaVarClique[numSsaOpnds]; const Nodes& nodes = fg->getNodes(); Nodes::const_iterator niter; for(niter = nodes.begin(); niter != nodes.end(); ++niter) { Node* node = *niter; Inst *headInst = (Inst*)node->getFirstInst(); for (Inst *inst = headInst->getNextInst(); inst != NULL; ) { Inst *nextInst = inst->getNextInst(); if (inst->isPhi()) { // do something VarOpnd *var0 = 0; SsaVarClique *clique = 0; for (U_32 i = 0; i < inst->getNumSrcOperands(); i++) { Opnd *opnd = inst->getSrc(i); if (opnd->isSsaVarOpnd()) { SsaVarOpnd *ssa = (SsaVarOpnd *)opnd; U_32 id = ssa->getId(); if (var0) { assert(ssa->getVar()==var0); cliques[id].link(clique); } else { var0 = ssa->getVar(); clique = &cliques[id]; } } } Opnd *dst = inst->getDst(); if (dst->isSsaVarOpnd()) { SsaVarOpnd *ssa = (SsaVarOpnd *)dst; ssa->getVar(); U_32 id = ssa->getId(); if (var0) { assert(ssa->getVar()==var0); cliques[id].link(clique); } else { var0 = ssa->getVar(); clique = &cliques[id]; } } } inst = nextInst; } } U_32 numvars = opndManager.getNumVarOpnds(); bool *used = new (localMM) bool[numvars]; for (U_32 i=0; i<numvars; i++) { used[i] = false; } for(niter = nodes.begin(); niter != nodes.end(); ++niter) { Node* node = *niter; Inst *headInst = (Inst*)node->getFirstInst(); for (Inst *inst = headInst->getNextInst(); inst != NULL; ) { Inst *nextInst = inst->getNextInst(); for (U_32 i = 0; i < inst->getNumSrcOperands(); i++) { Opnd *opnd = inst->getSrc(i); if (opnd->isSsaVarOpnd()) { SsaVarOpnd *ssa = (SsaVarOpnd *)opnd; VarOpnd *var = ssa->getVar(); U_32 id=ssa->getId(); SsaVarClique *clique = &cliques[id]; clique = clique->getRoot(); VarOpnd *cvar = clique->var; if (cvar == 0) { U_32 varId = var->getId(); if (used[varId]) { cvar = opndManager.createVarOpnd(var->getType(), var->isPinned()); } else { cvar = var; used[varId] = true; } clique->var = cvar; } if (cvar != var) { ssa->setVar(cvar); } } } Opnd *dst = inst->getDst(); if (dst->isSsaVarOpnd()) { SsaVarOpnd *ssa = (SsaVarOpnd *)dst; VarOpnd *var = ssa->getVar(); U_32 id=ssa->getId(); SsaVarClique *clique = &cliques[id]; clique = clique->getRoot(); VarOpnd *cvar = clique->var; if (cvar == 0) { U_32 varId = var->getId(); if (used[varId]) { cvar = opndManager.createVarOpnd(var->getType(), var->isPinned()); } else { cvar = var; used[varId] = true; } clique->var = cvar; } if (cvar != var) { ssa->setVar(cvar); } } inst = nextInst; } } }
// // 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. } } } }
void SSABuilder::clearPhiSrcs2(Node *node, const StlVectorSet<VarOpnd *> *whatVars, StlVector<VarOpnd *> *changedVars, const StlVectorSet<Opnd *> *removedVars, StlVector<Node *> &scratchNodeList) { bool needPreds = true; StlVector<Node *> &preds = scratchNodeList; Inst* inst = (Inst*)node->getSecondInst(); for (;inst!=NULL && inst->isPhi(); inst = inst->getNextInst()) { Opnd *dstOp =inst->getDst(); VarOpnd *varOpnd = 0; if (whatVars) { varOpnd = dstOp->asVarOpnd(); if (!varOpnd) { SsaVarOpnd *ssaOpnd = dstOp->asSsaVarOpnd(); assert(ssaOpnd); varOpnd = ssaOpnd->getVar(); } if (!whatVars->has(varOpnd)) continue; } bool changed=false; U_32 numSrcs = inst->getNumSrcOperands(); for (U_32 i=0; i<numSrcs; ++i) { Opnd *thisOpnd = inst->getSrc(i); if (!(removedVars && removedVars->has(thisOpnd))) { // need to test whether need to remove if (needPreds) { needPreds = false; const Edges& edges2 = node->getInEdges(); preds.clear(); preds.reserve(edges2.size()); Edges::const_iterator eiter2; for(eiter2 = edges2.begin(); eiter2 != edges2.end(); ++eiter2){ preds.push_back((*eiter2)->getSourceNode()); } } DominatorTree &domTree = frontier.getDominator(); Inst *thisOpndInst = thisOpnd->getInst(); Node *thisOpndInstNode = thisOpndInst->getNode(); if (thisOpndInstNode) { // the operand's source instruction was not already dead. StlVector<Node *>::const_iterator predIter = preds.begin(), predEnd = preds.end(); bool foundDom = false; for ( ; predIter != predEnd; ++predIter) { Node *predNode = *predIter; if (domTree.dominates(thisOpndInstNode, predNode)) { // we found it, leave this operand alone. foundDom = true; break; } } if (foundDom) continue; // leave operand alone. } } // remove this operand; if (i < numSrcs-1) { inst->setSrc(i, inst->getSrc(numSrcs-1)); --i; // re-examine this operand, which is now the last } --numSrcs; // we deleted one operand PhiInst *phiInst = inst->asPhiInst(); assert(phiInst); phiInst->setNumSrcs(numSrcs); changed = true; } if (changed) { // note the changed var; if (!varOpnd) { varOpnd = dstOp->asVarOpnd(); if (!varOpnd) { SsaVarOpnd *ssaOpnd = dstOp->asSsaVarOpnd(); assert(ssaOpnd); varOpnd = ssaOpnd->getVar(); } } changedVars->push_back(varOpnd); } } }
PeepHoleOpt::Changed PeepHoleOpt::handleInst_ALU(Inst* inst) { // The normal form is 'OPERATION left opnd, right operand' // except for NOT operation. const Mnemonic mnemonic = inst->getMnemonic(); if (mnemonic == Mnemonic_NOT) { // No optimizations this time return Changed_Nothing; } // Only these mnemonics have the majestic name of ALUs. assert(mnemonic == Mnemonic_ADD || mnemonic == Mnemonic_SUB || mnemonic == Mnemonic_ADC || mnemonic == Mnemonic_SBB || mnemonic == Mnemonic_OR || mnemonic == Mnemonic_XOR || mnemonic == Mnemonic_AND || mnemonic == Mnemonic_CMP || mnemonic == Mnemonic_TEST); if (mnemonic == Mnemonic_AND) { Inst::Opnds defs(inst, Inst::OpndRole_Explicit|Inst::OpndRole_Def); Opnd* dst = inst->getOpnd(defs.begin()); Inst::Opnds uses(inst, Inst::OpndRole_Explicit|Inst::OpndRole_Use); Opnd* src1= inst->getOpnd(uses.begin()); Opnd* src2= inst->getOpnd(uses.next(uses.begin())); Opnd *newopnd2; // test can work only with operands having equal sizes if (isImm(src2) && src2->getSize() != src1->getSize()) newopnd2 = irManager->newImmOpnd(src1->getType(), src2->getImmValue()); else newopnd2 = src2; if (!isMem(dst) && !isMem(src1) && !isMem(src2)) { BitSet ls(irManager->getMemoryManager(), irManager->getOpndCount()); irManager->updateLivenessInfo(); irManager->getLiveAtExit(inst->getNode(), ls); for (Inst* i = (Inst*)inst->getNode()->getLastInst(); i!=inst; i = i->getPrevInst()) { irManager->updateLiveness(i, ls); } bool dstNotUsed = !ls.getBit(dst->getId()); if (dstNotUsed) { // what: AND opnd1, opnd2 => TEST opnd1, opnd2 // nb: applicable if opnd1 will not be used further if (inst->getForm() == Inst::Form_Extended) irManager->newInstEx(Mnemonic_TEST, 0, src1, newopnd2)->insertAfter(inst); else irManager->newInst(Mnemonic_TEST, src1, newopnd2)->insertAfter(inst); inst->unlink(); return Changed_Inst; } } } else if (mnemonic == Mnemonic_ADD) { /* Change "dst=src+0" to "MOV dst, src" if there is another ADD inst followed in the same BB. */ Inst::Opnds defs(inst, Inst::OpndRole_Explicit|Inst::OpndRole_Def); Opnd* dst = inst->getOpnd(defs.begin()); Inst::Opnds uses(inst, Inst::OpndRole_Explicit|Inst::OpndRole_Use); Opnd* src1= inst->getOpnd(uses.begin()); Opnd* src2= inst->getOpnd(uses.next(uses.begin())); bool src1IsZero = false; bool src2IsZero = false; if (src1->isPlacedIn(OpndKind_Imm) && (src1->getImmValue() == 0)) src1IsZero = true; if (src2->isPlacedIn(OpndKind_Imm) && (src2->getImmValue() == 0)) src2IsZero = true; bool anotherADD = false; Inst *iter = inst->getNextInst(); while (iter != NULL) { if (iter->getMnemonic() == Mnemonic_ADC) break; if (iter->getMnemonic() == Mnemonic_ADD) { anotherADD = true; break; } iter = iter->getNextInst();; } if (anotherADD) { if (src1IsZero) { irManager->newCopyPseudoInst(Mnemonic_MOV, dst, src2)->insertAfter(inst); inst->unlink(); return Changed_Inst; } else if (src2IsZero) { irManager->newCopyPseudoInst(Mnemonic_MOV, dst, src1)->insertAfter(inst); inst->unlink(); return Changed_Inst; } } } return Changed_Nothing; }
PeepHoleOpt::Changed PeepHoleOpt::handleInst_Convert_F2I_D2I(Inst* inst) { // // Inline 'int_value = (int)(float_value or double_value)' // Opnd* dst = inst->getOpnd(0); Opnd* src = inst->getOpnd(2); Type* srcType = src->getType(); assert(srcType->isSingle() || srcType->isDouble()); assert(dst->getType()->isInt4()); const bool is_dbl = srcType->isDouble(); // Here, we might have to deal with 3 cases with src (_value): // 1. Unassigned operand - act as if were operating with XMM // 2. Assigned to FPU - convert to FPU operations, to // avoid long FPU->mem->XMM chain // 3. Assigned to XMM - see #1 const bool xmm_way = !(src->hasAssignedPhysicalLocation() && src->isPlacedIn(OpndKind_FPReg)); if (!xmm_way) { //TODO: will add FPU later if measurements show it worths trying return Changed_Nothing; } // // /* movss xmm0, val // presuming the corner cases (NaN, overflow) // normally happen rare, do conversion first, // and check for falls later -- convertNode cvttss2si eax, xmm0 -- ovfTestNode // did overflow happen ? cmp eax, 0x80000000 jne _done // no - go return result -- testAgainstZeroNode // test SRC against zero comiss xmm0, [fp_zero] // isNaN ? jp _nan // yes - go load 0 -- testIfBelowNode // xmm < 0 ? jb _done // yes - go load MIN_INT. EAX already has it - simply return. -- loadMaxIntNode // ok. at this point, XMM is positive and > MAX_INT // must load MAX_INT which is 0x7fffffff. // As EAX has 0x80000000, then simply substract 1 sub eax, 1 jmp _done -- loadZeroNode _nan: xor eax, eax -- nodeNode _done: mov result, eax } */ Opnd* fpZeroOpnd = getZeroConst(srcType); Type* int32type = irManager->getTypeManager().getInt32Type(); Opnd* oneOpnd = irManager->newImmOpnd(int32type, 1); Opnd* intZeroOpnd = getIntZeroConst(); // 0x8..0 here is not the INT_MIN, but comes from the COMISS // opcode description instead. Opnd* minIntOpnd = irManager->newImmOpnd(int32type, 0x80000000); newSubGFG(); Node* entryNode = getSubCfgEntryNode(); Node* convertNode = newBB(); Node* ovfTestNode = newBB(); Node* testAgainstZeroNode = newBB(); Node* testIfBelowNode = newBB(); Node* loadMaxIntNode = newBB(); Node* loadZeroNode = newBB(); Node* doneNode = newBB(); // // presuming the corner cases (NaN, overflow) // normally happen rare, do conversion first, // and check for falls later // connectNodes(entryNode, convertNode); // // convert // setCurrentNode(convertNode) ; Mnemonic mn_cvt = is_dbl ? Mnemonic_CVTTSD2SI : Mnemonic_CVTTSS2SI; /*cvttss2si r32, xmm*/ newInst(mn_cvt, 1, dst, src); connectNodeTo(ovfTestNode); setCurrentNode(NULL); // // check whether overflow happened // setCurrentNode(ovfTestNode); /*cmp r32, MIN_INT*/ newInst(Mnemonic_CMP, dst, minIntOpnd); /*jne _done */ newBranch(Mnemonic_JNE, doneNode, testAgainstZeroNode, 0.9, 0.1); // setCurrentNode(NULL); // test SRC against zero // setCurrentNode(testAgainstZeroNode); Mnemonic mn_cmp = is_dbl ? Mnemonic_UCOMISD : Mnemonic_UCOMISS; /*comiss src, 0. */ newInst(mn_cmp, src, fpZeroOpnd); /*jp _nan:result=0*/ newBranch(Mnemonic_JP, loadZeroNode, testIfBelowNode); setCurrentNode(NULL); // // // setCurrentNode(loadZeroNode); /*mov r32, 0*/ newInst(Mnemonic_MOV, dst, intZeroOpnd); /*jmp _done*/ connectNodeTo(doneNode); setCurrentNode(NULL); // // test if we have a huge negative in SRC // setCurrentNode(testIfBelowNode); /*jb _done:*/ newBranch(Mnemonic_JB, doneNode, loadMaxIntNode); setCurrentNode(NULL); // // // setCurrentNode(loadMaxIntNode); /* sub dst, 1*/ newInst(Mnemonic_SUB, dst, oneOpnd); connectNodeTo(doneNode); setCurrentNode(NULL); // connectNodes(doneNode, getSubCfgReturnNode()); // propagateSubCFG(inst); return Changed_Node; }
void Compiler::gen_switch(const JInst & jinst) { assert(jinst.opcode == OPCODE_LOOKUPSWITCH || jinst.opcode == OPCODE_TABLESWITCH); Opnd val = vstack(0, true).as_opnd(); vpop(); rlock(val); gen_bb_leave(NOTHING); if (jinst.opcode == OPCODE_LOOKUPSWITCH) { unsigned n = jinst.get_num_targets(); for (unsigned i = 0; i < n; i++) { Opnd key(jinst.key(i)); unsigned pc = jinst.get_target(i); alu(alu_cmp, val, key); br(eq, pc, m_bbinfo->start); } runlock(val); br(cond_none, jinst.get_def_target(), m_bbinfo->start); return; } // // TABLESWITCH // alu(alu_cmp, val, jinst.high()); br(gt, jinst.get_def_target(), m_bbinfo->start); alu(alu_cmp, val, jinst.low()); br(lt, jinst.get_def_target(), m_bbinfo->start); AR gr_tabl = valloc(jobj); movp(gr_tabl, DATA_SWITCH_TABLE | m_curr_inst->pc, m_bbinfo->start); #ifdef _EM64T_ // On EM64T, we operate with I_32 value in a register, but the // register will be used as 64 bit in address form - have to extend sx(Opnd(i64, val.reg()), Opnd(i32, val.reg())); #endif // Here, we need to extract 'index-=low()' - can pack this into // complex address form: // [table + index*sizeof(void*) - low()*sizeof(void*)], // but only if low()*sizeof(void*) does fit into displacement ... int tmp = -jinst.low(); const int LO_BOUND = INT_MIN/(int)sizeof(void*); const int UP_BOUND = INT_MAX/(int)sizeof(void*); if (LO_BOUND<=tmp && tmp<=UP_BOUND) { ld(jobj, gr_tabl, gr_tabl, -jinst.low()*sizeof(void*), val.reg(), sizeof(void*)); } else { // ... otherwise subtract explicitly, but only if the register // is not used anywhere else if (rrefs(val.reg()) !=0) { Opnd vtmp(i32, valloc(i32)); mov(vtmp, val); // make a copy of val runlock(val); val = vtmp; rlock(val); } alu(alu_sub, val, jinst.low()); ld(jobj, gr_tabl, gr_tabl, 0, val.reg(), sizeof(void*)); } runlock(val); br(gr_tabl); }
/** * Executes lazy exception optimization pass. */ void LazyExceptionOpt::doLazyExceptionOpt() { MethodDesc &md = irManager.getMethodDesc(); BitSet excOpnds(leMemManager,irManager.getOpndManager().getNumSsaOpnds()); StlDeque<Inst*> candidateSet(leMemManager); optCandidates = new (leMemManager) OptCandidates(leMemManager); Method_Side_Effects m_sideEff = md.getSideEffect(); const Nodes& nodes = irManager.getFlowGraph().getNodes(); Nodes::const_iterator niter; #ifdef _DEBUG mtdDesc=&md; #endif #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << std::endl; for (int i=0; i<level; i++) Log::out() << " "; Log::out() << "doLE "; md.printFullName(Log::out()); Log::out() << " SideEff " << (int)m_sideEff << std::endl; } #endif level++; U_32 opndId = 0; isArgCheckNull = false; isExceptionInit = md.isInstanceInitializer() && md.getParentType()->isLikelyExceptionType(); // core api exception init if (m_sideEff == MSE_Unknown && isExceptionInit && strncmp(md.getParentType()->getName(),"java/lang/",10) == 0) { m_sideEff = MSE_False; md.setSideEffect(m_sideEff); #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " core api exc "; md.printFullName(Log::out()); Log::out() << " SideEff " << (int)m_sideEff << std::endl; } #endif } for(niter = nodes.begin(); niter != nodes.end(); ++niter) { Node* node = *niter; Inst *headInst = (Inst*)node->getFirstInst(); for (Inst* inst=headInst->getNextInst(); inst!=NULL; inst=inst->getNextInst()) { #ifdef _DEBUG if (inst->getOpcode()==Op_DefArg && isExceptionInit) { if (Log::isEnabled()) { Log::out() << " defarg: "; inst->print(Log::out()); Log::out() << std::endl; Log::out() << " "; Log::out() << (int)(inst->getDefArgModifier()) << " " << (inst->getDefArgModifier()==DefArgNoModifier) << " " << (inst->getDefArgModifier()==NonNullThisArg) << " " << (inst->getDefArgModifier()==SpecializedToExactType) << " " << (inst->getDefArgModifier()==DefArgBothModifiers) << std::endl; } } #endif if (inst->getOpcode()==Op_Throw) { if (inst->getSrc(0)->getInst()->getOpcode()==Op_NewObj) { excOpnds.setBit(opndId=inst->getSrc(0)->getId(),true); if (!addOptCandidates(opndId,inst)) excOpnds.setBit(opndId,false); // different exc. edges #ifdef _DEBUG if (excOpnds.getBit(opndId)==1) { if (Log::isEnabled()) { Log::out() << " add opnd: "; inst->print(Log::out()); Log::out() << std::endl; Log::out() << " add obj: "; inst->getSrc(0)->getInst()->print(Log::out()); Log::out() << std::endl; } } #endif } } if (m_sideEff == MSE_Unknown) if (instHasSideEffect(inst)) { m_sideEff = MSE_True; #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << "~~~~~~inst sideEff "; inst->print(Log::out()); Log::out() << std::endl; } #endif } } } if (md.getSideEffect() == MSE_Unknown) { if (m_sideEff == MSE_Unknown) { if (isExceptionInit && isArgCheckNull) { #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << "~~~~~~init sideEff reset: " << m_sideEff << " 3 "; md.printFullName(Log::out()); Log::out() << std::endl; } #endif m_sideEff = MSE_True_Null_Param; } else m_sideEff = MSE_False; } md.setSideEffect(m_sideEff); } for(niter = nodes.begin(); niter != nodes.end(); ++niter) { Node* node = *niter; Inst *headInst = (Inst*)node->getFirstInst(); Opnd* opnd; for (Inst* inst=headInst->getNextInst(); inst!=NULL; inst=inst->getNextInst()) { U_32 nsrc = inst->getNumSrcOperands(); for (U_32 i=0; i<nsrc; i++) { if (!(opnd=inst->getSrc(i))->isSsaOpnd()) // check ssa operands continue; if (excOpnds.getBit(opndId=opnd->getId())==0) continue; if (inst->getOpcode()==Op_DirectCall) { MethodDesc* md = inst->asMethodInst()->getMethodDesc(); if (md->isInstanceInitializer() && md->getParentType()->isLikelyExceptionType()) { if (!addOptCandidates(opndId,inst)) { excOpnds.setBit(opndId,false); #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " - rem opnd " << opnd->getId() << " "; inst->print(Log::out()); Log::out() << std::endl; } #endif } } else { excOpnds.setBit(opndId,false); #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " -- rem opnd " << opnd->getId() << " "; inst->print(Log::out()); Log::out() << std::endl; } #endif } } else { if (inst->getOpcode()!=Op_Throw) { excOpnds.setBit(opndId,false); #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << " rem opnd " << opnd->getId() << " "; inst->print(Log::out()); Log::out() << std::endl; } #endif } } } } } if (!excOpnds.isEmpty()) { #ifdef _DEBUG if (Log::isEnabled()) { Log::out() << "------LE: "; md.printFullName(Log::out()); Log::out() << std::endl; } #endif fixOptCandidates(&excOpnds); } level--; #ifdef _DEBUG if (Log::isEnabled()) { for (int i=0; i<level; i++) Log::out() << " "; Log::out() << "done "; md.printFullName(Log::out()); Log::out() << " SideEff " << (int)m_sideEff << std::endl; } #endif };