| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * @author Intel, Pavel A. Ozhdikhin |
| * @version $Revision: 1.20.24.4 $ |
| * |
| */ |
| |
| #include "irmanager.h" |
| #include "Dominator.h" |
| #include "constantfolder.h" |
| #include "abcd.h" |
| #include "abcdbounds.h" |
| #include "abcdsolver.h" |
| #include "opndmap.h" |
| |
| #include "Stl.h" |
| #include "Log.h" |
| #include "open/types.h" |
| #include "Inst.h" |
| #include "walkers.h" |
| #include "PMFAction.h" |
| |
| #include <assert.h> |
| #include <iostream> |
| #include <algorithm> |
| |
| namespace Jitrino { |
| |
| //Array Bounds Check Elimination |
| DEFINE_SESSION_ACTION(ABCDPass, abcd, "ABCD: eliminating Array Bounds Check on Demand"); |
| |
| void |
| ABCDPass::_run(IRManager &irm) { |
| OptPass::splitCriticalEdges(irm); |
| OptPass::computeDominators(irm); |
| Abcd abcd(irm, irm.getNestedMemoryManager(), *irm.getDominatorTree()); |
| abcd.runPass(); |
| } |
| |
| void |
| Abcd::readFlags(Action* argSource, AbcdFlags* flags ) { |
| IAction::HPipeline p = NULL; //default pipeline for argSource |
| flags->partial = argSource->getBoolArg(p, "abcd.partial", false); |
| flags->dryRun = argSource->getBoolArg(p, "abcd.dry_run", false); |
| flags->useAliases = argSource->getBoolArg(p, "abcd.use_aliases", true); |
| flags->useConv = argSource->getBoolArg(p, "abcd.use_conv", true); |
| flags->remConv = argSource->getBoolArg(p, "abcd.rem_conv", false); |
| flags->useShr = argSource->getBoolArg(p, "abcd.use_shr", true); |
| flags->unmaskShifts = argSource->getBoolArg(p, "abcd.unmask_shifts", true); |
| flags->remBr = argSource->getBoolArg(p, "abcd.rem_br", true); |
| flags->remCmp = argSource->getBoolArg(p, "abcd.rem_cmp", true); |
| flags->remOneBound = argSource->getBoolArg(p, "abcd.rem_one_bound", true); |
| flags->remOverflow = argSource->getBoolArg(p, "abcd.rem_overflow", false); |
| flags->checkOverflow = argSource->getBoolArg(p, "abcd.check_overflow", false); |
| flags->useReasons = argSource->getBoolArg(p, "abcd.use_reasons", false); |
| } |
| |
| void Abcd::showFlags(std::ostream& os) { |
| os << " abcd flags:"<<std::endl; |
| os << " abcd.partial[={on|OFF}] - try to eliminate partial ABCs" << std::endl; |
| os << " abcd.dry_run[={ON|off}] - don't really eliminate checks" << std::endl; |
| os << " abcd.use_aliases[={ON|off}] - try to use ld/stvar induced aliases" << std::endl; |
| os << " abcd.use_conv[={ON|off}] - make use of conv info" << std::endl; |
| os << " abcd.rem_conv[={ON|off}] - remove conv ops in abcd" << std::endl; |
| os << " abcd.use_shr={ON|off}] - use shr info" << std::endl; |
| os << " abcd.unmask_shifts={ON|off}] - try to unmask shifts" << std::endl; |
| os << " abcd.rem_br[={ON|off}] - try to remove branches in abcd" << std::endl; |
| os << " abcd.rem_cmp[={ON|off}] - try to fold cmps in abcd" << std::endl; |
| os << " abcd.rem_one_bound[={ON|off}] - eliminate even just upper or lower bound check" << std::endl; |
| os << " abcd.rem_overflow[={on|OFF}] - try to mark overflow impossible in 32-bit int add/sub"; |
| os << " abcd.check_overflow[={on|OFF}] - try to mark overflow impossible in checkbounds"; |
| os << " abcd.use_reasons[={ON|off}] - build more precise taus for eliminated instructions"; |
| } |
| |
| Abcd::Abcd(IRManager &irManager0, MemoryManager& memManager, DominatorTree& dom0) : |
| irManager(irManager0), |
| mm(memManager), |
| dominators(dom0), |
| solver(0), |
| canEliminate(memManager), |
| canEliminateUB(memManager), |
| canEliminateLB(memManager), |
| tauUnsafe(0), |
| tauSafe(0), |
| flags(*irManager.getOptimizerFlags().abcdFlags), |
| insertPi(memManager, dom0, irManager0, flags.useAliases), |
| blockTauPoint(0), |
| lastTauPointBlock(0) |
| {} |
| |
| void Abcd::runPass() |
| { |
| if ( Log::isEnabled() ) { |
| Log::out() << "IR before ABCD pass" << std::endl; |
| FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), irManager.getMethodDesc()); |
| FlowGraph::printDotFile(irManager.getFlowGraph(), irManager.getMethodDesc(), "beforeabcd"); |
| dominators.printDotFile(irManager.getMethodDesc(), "beforeabcd.dom"); |
| } |
| |
| insertPi.insertPi(); |
| |
| removeRedundantBoundsChecks(); |
| if ( Log::isEnabled() ) { |
| Log::out() << "IR after removeRedundantBoundsChecks" << std::endl; |
| FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), irManager.getMethodDesc()); |
| } |
| |
| removePiEliminateChecks(); |
| if ( Log::isEnabled() ) { |
| Log::out() << "IR after ABCD pass" << std::endl; |
| FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), irManager.getMethodDesc()); |
| } |
| } |
| |
| SsaTmpOpnd* Abcd::getTauUnsafe() { |
| if (!tauUnsafe) { |
| Node *head = irManager.getFlowGraph().getEntryNode(); |
| Inst *entryLabel = (Inst*)head->getFirstInst(); |
| // first search for one already there |
| Inst *inst = entryLabel->getNextInst(); |
| while (inst != NULL) { |
| if (inst->getOpcode() == Op_TauUnsafe) { |
| tauUnsafe = inst->getDst()->asSsaTmpOpnd(); |
| assert(tauUnsafe); |
| return tauUnsafe; |
| } |
| inst = inst->getNextInst(); |
| } |
| // need to insert one |
| TypeManager &tm = irManager.getTypeManager(); |
| SsaTmpOpnd *tauOpnd = irManager.getOpndManager().createSsaTmpOpnd(tm.getTauType()); |
| Inst *tauUnsafeInst = irManager.getInstFactory().makeTauUnsafe(tauOpnd); |
| // place after label and Phi instructions |
| inst = entryLabel->getNextInst(); |
| while (inst != NULL) { |
| Opcode opc = inst->getOpcode(); |
| if ((opc != Op_Phi) && (opc != Op_TauPi) && (opc != Op_TauPoint)) { |
| break; |
| } |
| inst = inst->getNextInst(); |
| } |
| if(Log::isEnabled()) { |
| Log::out() << "Inserting tauUnsafe inst "; |
| tauUnsafeInst->print(Log::out()); |
| if (inst!=NULL) { |
| Log::out() << " before inst "; |
| inst->print(Log::out()); |
| } |
| Log::out() << std::endl; |
| } |
| if (inst!=NULL) { |
| tauUnsafeInst->insertBefore(inst); |
| } else { |
| head->appendInst(tauUnsafeInst); |
| } |
| tauUnsafe = tauOpnd; |
| } |
| return tauUnsafe; |
| }; |
| |
| SsaTmpOpnd* Abcd::getTauSafe() { |
| if (!tauSafe) { |
| Node *head = irManager.getFlowGraph().getEntryNode(); |
| Inst *entryLabel = (Inst*)head->getFirstInst(); |
| // first search for one already there |
| Inst *inst = entryLabel->getNextInst(); |
| while (inst != NULL) { |
| if (inst->getOpcode() == Op_TauSafe) { |
| tauSafe = inst->getDst()->asSsaTmpOpnd(); |
| assert(tauSafe); |
| return tauSafe; |
| } |
| inst = inst->getNextInst(); |
| } |
| // need to insert one |
| TypeManager &tm = irManager.getTypeManager(); |
| SsaTmpOpnd *tauOpnd = irManager.getOpndManager().createSsaTmpOpnd(tm.getTauType()); |
| Inst *tauSafeInst = irManager.getInstFactory().makeTauSafe(tauOpnd); |
| // place after label and Phi instructions |
| inst = entryLabel->getNextInst(); |
| while (inst != NULL) { |
| Opcode opc = inst->getOpcode(); |
| if ((opc != Op_Phi) && (opc != Op_TauPi) && (opc != Op_TauPoint)) { |
| break; |
| } |
| inst = inst->getNextInst(); |
| } |
| if(Log::isEnabled()) { |
| Log::out() << "Inserting tauSafe inst "; |
| tauSafeInst->print(Log::out()); |
| if (inst!=NULL) { |
| Log::out() << " before inst "; |
| inst->print(Log::out()); |
| } |
| Log::out() << std::endl; |
| } |
| if (inst!=NULL) { |
| tauSafeInst->insertBefore(inst); |
| } else { |
| head->appendInst(tauSafeInst); |
| } |
| tauSafe = tauOpnd; |
| } |
| return tauSafe; |
| }; |
| |
| // an InstWalker |
| class AbcdSolverWalker { |
| AbcdSolver *theSolver; |
| public: |
| AbcdSolverWalker(AbcdSolver *solver) : theSolver(solver) {}; |
| void applyToInst(Inst *i) { |
| theSolver->tryToEliminate(i); |
| } |
| }; |
| |
| void Abcd::removeRedundantBoundsChecks() |
| { |
| assert(!solver); |
| solver = new (mm) AbcdSolver(this); |
| AbcdSolverWalker solveInst(solver); // to apply to each |
| typedef Inst2NodeWalker<true, AbcdSolverWalker> AbcdSolverNodeWalker; |
| AbcdSolverNodeWalker solveNode(solveInst); |
| NodeWalk<AbcdSolverNodeWalker>(irManager.getFlowGraph(), solveNode); |
| |
| solver = 0; |
| } |
| |
| |
| void Abcd::markInstToEliminate(Inst *i) |
| { |
| if (Log::isEnabled()) { |
| Log::out() << "Can eliminate instruction "; i->print(Log::out()); |
| Log::out() << std::endl; |
| } |
| typedef StlVector<InstReasonPair>::iterator itertype; |
| itertype start = canEliminate.begin(); |
| itertype finish = canEliminate.end(); |
| itertype lb = ::std::lower_bound(start, finish, InstReasonPair(i, 0)); |
| if ((lb == finish) || (lb->first != i)) { |
| canEliminate.insert(lb, InstReasonPair(i, 0)); |
| } |
| } |
| |
| void Abcd::markInstToEliminateAndWhy(Inst *i, AbcdReasons *why) |
| { |
| if (Log::isEnabled()) { |
| Log::out() << "Can eliminate instruction "; i->print(Log::out()); |
| Log::out() << std::endl; |
| } |
| typedef StlVector<InstReasonPair>::iterator itertype; |
| itertype start = canEliminate.begin(); |
| itertype finish = canEliminate.end(); |
| itertype lb = ::std::lower_bound(start, finish, InstReasonPair(i, 0)); |
| if ((lb == finish) || (lb->first != i)) { |
| canEliminate.insert(lb, InstReasonPair(i, why)); |
| } |
| AbcdReasons *why2; |
| bool ism2e = isMarkedToEliminate(i, why2); |
| if( !(ism2e && (why == why2)) ) assert(0); |
| } |
| |
| void Abcd::markCheckToEliminate(Inst *i) |
| { |
| markInstToEliminate(i); |
| } |
| |
| void Abcd::markCheckToEliminateAndWhy(Inst *i, AbcdReasons *why) |
| { |
| markInstToEliminateAndWhy(i, why); |
| } |
| |
| bool Abcd::isMarkedToEliminate(Inst *i, AbcdReasons *&why) |
| { |
| typedef StlVector<InstReasonPair>::iterator itertype; |
| itertype start = canEliminate.begin(); |
| itertype finish = canEliminate.end(); |
| |
| itertype lb = ::std::lower_bound(start, finish, InstReasonPair(i, 0)); |
| if ((lb == finish) || (lb->first != i)) { |
| return false; |
| } |
| why = lb->second; |
| return true; |
| } |
| |
| void Abcd::markInstToEliminateLB(Inst *i) |
| { |
| if (Log::isEnabled()) { |
| Log::out() << "Can eliminate LB check in instruction "; i->print(Log::out()); |
| Log::out() << std::endl; |
| } |
| typedef StlVector<InstReasonPair>::iterator itertype; |
| itertype start = canEliminateLB.begin(); |
| itertype finish = canEliminateLB.end(); |
| itertype lb = ::std::lower_bound(start, finish, InstReasonPair(i, 0)); |
| if ((lb == finish) || (lb->first != i)) { |
| canEliminateLB.insert(lb, InstReasonPair(i, 0)); |
| } |
| } |
| |
| void Abcd::markInstToEliminateLBAndWhy(Inst *i, AbcdReasons *why) |
| { |
| if (Log::isEnabled()) { |
| Log::out() << "Can eliminate LB check in instruction "; i->print(Log::out()); |
| Log::out() << " for why=" << ::std::hex << (void *) why << ::std::dec << "="; |
| why->print(Log::out()); |
| Log::out() << std::endl; |
| } |
| typedef StlVector<InstReasonPair>::iterator itertype; |
| itertype start = canEliminateLB.begin(); |
| itertype finish = canEliminateLB.end(); |
| itertype lb = ::std::lower_bound(start, finish, InstReasonPair(i, 0)); |
| if ((lb == finish) || (lb->first != i)) { |
| canEliminateLB.insert(lb, InstReasonPair(i, why)); |
| } |
| AbcdReasons *why2; |
| bool ism2eLB = isMarkedToEliminateLB(i, why2); |
| if( !(ism2eLB && (why == why2)) ) assert(0); |
| } |
| |
| void Abcd::markCheckToEliminateLB(Inst *i) |
| { |
| markInstToEliminateLB(i); |
| } |
| |
| void Abcd::markCheckToEliminateLBAndWhy(Inst *i, AbcdReasons *why) |
| { |
| markInstToEliminateLBAndWhy(i, why); |
| } |
| |
| bool Abcd::isMarkedToEliminateLB(Inst *i, AbcdReasons *&why) |
| { |
| typedef StlVector<InstReasonPair>::iterator itertype; |
| itertype start = canEliminateLB.begin(); |
| itertype finish = canEliminateLB.end(); |
| |
| itertype lb = ::std::lower_bound(start, finish, InstReasonPair(i, 0)); |
| if ((lb == finish) || (lb->first != i)) { |
| return false; |
| } |
| why = lb->second; |
| return true; |
| } |
| |
| void Abcd::markInstToEliminateUB(Inst *i) |
| { |
| if (Log::isEnabled()) { |
| Log::out() << "Can eliminate UB of instruction "; i->print(Log::out()); |
| Log::out() << std::endl; |
| } |
| typedef StlVector<InstReasonPair>::iterator itertype; |
| itertype start = canEliminateUB.begin(); |
| itertype finish = canEliminateUB.end(); |
| itertype lb = ::std::lower_bound(start, finish, InstReasonPair(i, 0)); |
| if ((lb == finish) || (lb->first != i)) { |
| canEliminateUB.insert(lb, InstReasonPair(i, 0)); |
| } |
| } |
| |
| void Abcd::markInstToEliminateUBAndWhy(Inst *i, AbcdReasons *why) |
| { |
| if (Log::isEnabled()) { |
| Log::out() << "Can eliminate UB of instruction "; i->print(Log::out()); |
| Log::out() << std::endl; |
| } |
| typedef StlVector<InstReasonPair>::iterator itertype; |
| itertype start = canEliminateUB.begin(); |
| itertype finish = canEliminateUB.end(); |
| itertype lb = ::std::lower_bound(start, finish, InstReasonPair(i, 0)); |
| if ((lb == finish) || (lb->first != i)) { |
| canEliminateUB.insert(lb, InstReasonPair(i, why)); |
| } |
| AbcdReasons *why2; |
| bool ism2eUB = isMarkedToEliminateUB(i, why2); |
| if( !(ism2eUB && (why == why2)) ) assert(0); |
| } |
| |
| void Abcd::markCheckToEliminateUB(Inst *i) |
| { |
| markInstToEliminateUB(i); |
| } |
| |
| void Abcd::markCheckToEliminateUBAndWhy(Inst *i, AbcdReasons *why) |
| { |
| markInstToEliminateUBAndWhy(i, why); |
| } |
| |
| bool Abcd::isMarkedToEliminateUB(Inst *i, AbcdReasons *&why) |
| { |
| typedef StlVector<InstReasonPair>::iterator itertype; |
| itertype start = canEliminateUB.begin(); |
| itertype finish = canEliminateUB.end(); |
| |
| itertype lb = ::std::lower_bound(start, finish, InstReasonPair(i, 0)); |
| if ((lb == finish) || (lb->first != i)) { |
| return false; |
| } |
| why = lb->second; |
| return true; |
| } |
| |
| template <class inst_fun_type> |
| struct NodeInst2NodeFun : ::std::unary_function<Node *, void> |
| { |
| inst_fun_type underlying_fun; |
| NodeInst2NodeFun(const inst_fun_type &theFun) : underlying_fun(theFun) {}; |
| void operator()(Node *theNode) { |
| Inst *thisinst = (Inst*)theNode->getFirstInst(); |
| assert(thisinst); |
| do { |
| underlying_fun(theNode, thisinst); |
| thisinst = thisinst->getNextInst(); |
| } while (thisinst != NULL); |
| } |
| }; |
| |
| struct SsaCheckingFun : public ::std::binary_function<Node *, Inst *, void> { |
| void operator()(Node *node, Inst *i) { |
| if (i->getOpcode() == Op_Phi) { |
| const Edges& edges2 = node->getInEdges(); |
| U_32 numEdges = (U_32) edges2.size(); |
| U_32 numOps = i->getNumSrcOperands(); |
| if( !(numOps == numEdges) ) assert(0); |
| } |
| } |
| }; |
| |
| void checkSSA(ControlFlowGraph* flowgraph) |
| { |
| SsaCheckingFun checkInst; |
| NodeInst2NodeFun<SsaCheckingFun> checkNode(checkInst); |
| Node2FlowgraphFun<NodeInst2NodeFun<SsaCheckingFun> > |
| checkFlowGraph(checkNode); |
| |
| checkFlowGraph(*flowgraph); |
| } |
| |
| bool |
| Abcd::isConvOpnd(const Opnd *opnd) { |
| Inst *defInst = opnd ? opnd->getInst() : 0; |
| return (defInst && (defInst->getOpcode() == Op_Conv)); |
| } |
| |
| bool |
| Abcd::convPassesSource(const Opnd *opnd) { |
| assert(isConvOpnd(opnd)); |
| Inst *instr = opnd->getInst(); |
| Opnd *srci = instr->getSrc(0); // the source operand |
| Type::Tag srcType = srci->getType()->tag; |
| Type::Tag dstType = opnd->getType()->tag; |
| Type::Tag instrType = instr->getType(); |
| if (typeIncludes(dstType, instrType) && |
| typeIncludes(instrType, srcType)) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| Opnd *Abcd::getConvSource(const Opnd *opnd) { |
| assert(isConvOpnd(opnd)); |
| Inst *defInst = opnd->getInst(); |
| return defInst->getSrc(0); |
| } |
| |
| // true if type1 includes all values from type2 |
| bool Abcd::typeIncludes(Type::Tag type1, Type::Tag type2) |
| { |
| if (type1 == type2) return true; |
| int64 lb1, lb2, ub1, ub2; |
| bool hasBounds1, hasBounds2; |
| hasBounds1 = Abcd::hasTypeBounds(type1, lb1, ub1); |
| hasBounds2 = Abcd::hasTypeBounds(type2, lb2, ub2); |
| if ((!hasBounds1) || (!hasBounds2)) { |
| return false; |
| } else { |
| if ((lb1 <= lb2) && (ub2 <= ub1)) { |
| return true; |
| } else { |
| return false; |
| } |
| } |
| } |
| |
| bool |
| Abcd::hasTypeBounds(Type::Tag srcTag, int64 &lb, int64 &ub) |
| { |
| switch (srcTag) { |
| case Type::Int8: lb = -int64(0x80); ub = 0x7f; return true; |
| case Type::Int16: lb = -int64(0x8000); ub = 0x7fff; return true; |
| case Type::Int32: lb = -int64(0x80000000); ub = 0x7fffffff; return true; |
| case Type::Int64: |
| lb = __INT64_C(0x8000000000000000); |
| ub = __INT64_C(0x7fffffffffffffff); return true; |
| case Type::UInt8: lb = 0; ub = 0x100; return true; |
| case Type::UInt16: lb = 0; ub = 0x10000; return true; |
| case Type::UInt32: lb = 0; ub = __INT64_C(0x100000000); return true; |
| default: |
| return false; |
| } |
| } |
| |
| bool |
| Abcd::isCheckableType(Type::Tag typetag) { |
| if (Type::isInteger(typetag) && |
| (typetag != Type::IntPtr) && |
| (typetag != Type::UIntPtr)) |
| return true; |
| else |
| return false; |
| } |
| |
| bool |
| Abcd::hasCheckableType(const Opnd *opnd) { |
| Type::Tag typetag = opnd->getType()->tag; |
| return Abcd::isCheckableType(typetag); |
| } |
| |
| // phi reasons together |
| // derefVar definition site is a Phi which should be used for placement |
| SsaTmpOpnd *Abcd::makeReasonPhi(Opnd *derefVar, StlVector<AbcdReasons *> &reasons, |
| StlVector<Opnd *> &derefVarVersions) |
| { |
| InstFactory &instFactory = irManager.getInstFactory(); |
| OpndManager &opndManager = irManager.getOpndManager(); |
| TypeManager &typeManager = irManager.getTypeManager(); |
| |
| U_32 n = (U_32) reasons.size(); |
| assert(derefVarVersions.size() == n); |
| Opnd **newPhiOpnds = new (mm) Opnd*[n]; |
| |
| Type *tauType = typeManager.getTauType(); |
| VarOpnd *tauBaseVar = opndManager.createVarOpnd(tauType, false); |
| |
| SsaVarOpnd *tauPhiDstOpnd = opndManager.createSsaVarOpnd(tauBaseVar); |
| SsaTmpOpnd *tauResOpnd = opndManager.createSsaTmpOpnd(typeManager.getTauType()); |
| |
| for (U_32 i=0; i<n; ++i) { |
| AbcdReasons *reason = reasons[i]; |
| Opnd *derefVarVersion = derefVarVersions[i]; |
| Inst *derefVarInst = derefVarVersion->getInst(); |
| |
| Inst *stVarLoc = derefVarInst; // inst to insert stvar before |
| if (stVarLoc->getOpcode() != Op_StVar) { |
| assert(stVarLoc->getOpcode() == Op_Phi); |
| // make sure we place stvar in a legal location |
| Inst *nextInst = stVarLoc->getNextInst(); |
| while ((nextInst->getOpcode() == Op_Phi) && (nextInst->getOpcode() == Op_TauPi)) { |
| nextInst = nextInst->getNextInst(); |
| } |
| stVarLoc = nextInst; |
| } |
| |
| newPhiOpnds[i] = opndManager.createSsaVarOpnd(tauBaseVar); |
| SsaTmpOpnd *tauToStVar = getReasonTau(reason, stVarLoc); |
| SsaVarOpnd *varToStTo = newPhiOpnds[i]->asSsaVarOpnd(); |
| assert(varToStTo); |
| Inst *tauStVarInst = instFactory.makeStVar(varToStTo, tauToStVar); |
| |
| if (Log::isEnabled()) { |
| Log::out() << "Inserting tauStVarInst=("; |
| tauStVarInst->print(Log::out()); |
| Log::out() << ") after stVarLoc= "; |
| stVarLoc->print(Log::out()); |
| Log::out() << ")" << std::endl; |
| } |
| tauStVarInst->insertAfter(stVarLoc); |
| } |
| |
| Inst *tauPhiInst = instFactory.makePhi(tauPhiDstOpnd, n, newPhiOpnds); |
| Inst *derefVarInst = derefVar->getInst(); |
| assert(derefVarInst->getOpcode() == Op_Phi); |
| |
| if (Log::isEnabled()) { |
| Log::out() << "Inserting tauPhiInst=("; |
| tauPhiInst->print(Log::out()); |
| Log::out() << ") before derefVarInst= "; |
| derefVarInst->print(Log::out()); |
| Log::out() << ")" << std::endl; |
| } |
| |
| tauPhiInst->insertBefore(derefVarInst); |
| Inst *tauLdVarInst = instFactory.makeLdVar(tauResOpnd, tauPhiDstOpnd); |
| Inst *ldVarLoc = tauPhiInst->getNextInst(); |
| while ( (ldVarLoc!=NULL && (ldVarLoc->getOpcode() == Op_Phi)) || |
| (ldVarLoc->getOpcode() == Op_TauPi) ) { |
| ldVarLoc = ldVarLoc->getNextInst(); |
| } |
| if (Log::isEnabled()) { |
| Log::out() << "Inserting tauLdVarInst=("; |
| tauLdVarInst->print(Log::out()); |
| Log::out() << ") before ldVarLoc= "; |
| ldVarLoc->print(Log::out()); |
| Log::out() << ")" << std::endl; |
| } |
| tauLdVarInst->insertBefore(ldVarLoc); |
| return tauResOpnd; |
| } |
| |
| // return an opnd to be used just before useSite, possibly building |
| // a tauAnd instruction to use. |
| SsaTmpOpnd* Abcd::getReasonTau(AbcdReasons *reason, Inst *useSite) |
| { |
| InstFactory &instFactory = irManager.getInstFactory(); |
| OpndManager &opndManager = irManager.getOpndManager(); |
| TypeManager &typeManager = irManager.getTypeManager(); |
| |
| U_32 numReasons = (U_32) reason->facts.size(); |
| assert(numReasons < 100); |
| if (numReasons == 1) { |
| SsaTmpOpnd *reasonOpnd = *(reason->facts.begin()); |
| return reasonOpnd; |
| } else if (numReasons == 0) { |
| SsaTmpOpnd *reasonOpnd = getTauSafe(); |
| return reasonOpnd; |
| } else { |
| // need to build a tauAnd |
| Opnd **newAndOpnds = new (mm) Opnd*[numReasons]; |
| StlSet<SsaTmpOpnd*>::iterator iter = reason->facts.begin(); |
| for (U_32 i = 0; i < numReasons; ++i, ++iter) { |
| newAndOpnds[i] = *iter; |
| } |
| SsaTmpOpnd *tauDst = opndManager.createSsaTmpOpnd(typeManager.getTauType()); |
| Inst *tauAndInst = instFactory.makeTauAnd(tauDst, numReasons, newAndOpnds); |
| |
| if (Log::isEnabled()) { |
| Log::out() << "Inserting tauAndInst=("; |
| tauAndInst->print(Log::out()); |
| Log::out() << ") before useSite= "; |
| useSite->print(Log::out()); |
| Log::out() << ")" << std::endl; |
| } |
| |
| tauAndInst->insertBefore(useSite); |
| return tauDst; |
| } |
| } |
| |
| // a ScopedDomNodeInstWalker, forward/preorder |
| class RemovePiEliminateChecksWalker { |
| public: |
| RemovePiEliminateChecksWalker(Abcd* abcd) : _abcd(abcd), block(0) // forward |
| {} |
| |
| void startNode(DominatorNode *domNode) { block = domNode->getNode(); }; |
| void applyToInst(Inst *i) { _abcd->removePiEliminateChecksOnInst(block, i); }; |
| void finishNode(DominatorNode *domNode) {} |
| |
| void enterScope() {} |
| void exitScope() {} |
| private: |
| Abcd* _abcd; |
| Node* block; |
| }; |
| //------------------------------------------------------------------------------ |
| |
| void Abcd::removePiEliminateChecks() |
| { |
| RemovePiEliminateChecksWalker removePiWalker(this); |
| typedef ScopedDomNodeInst2DomWalker<true, RemovePiEliminateChecksWalker> |
| RemovePiDomWalker; |
| RemovePiDomWalker removePiDomWalker(removePiWalker); |
| |
| DomTreeWalk<true, RemovePiDomWalker>(dominators, removePiDomWalker, mm); |
| } |
| |
| void Abcd::removePiEliminateChecksOnInst(Node *block, Inst *inst) |
| { |
| AbcdReasons *why; |
| if (inst->getOpcode() == Op_TauPi) { |
| inst->unlink(); |
| } else if ((!flags.dryRun) && |
| (inst->getOpcode() == Op_TauCheckBounds) && |
| isMarkedToEliminate(inst, why)) { |
| Opnd* srcOpnd = (flags.useReasons |
| ? getReasonTau(why, inst) |
| : getBlockTauPoint(block)); |
| Opnd* dstOpnd = inst->getDst(); |
| inst->setDst(OpndManager::getNullOpnd()); |
| Inst* copy = irManager.getInstFactory().makeCopy(dstOpnd,srcOpnd); |
| copy->insertBefore(inst); |
| FlowGraph::eliminateCheck(irManager.getFlowGraph(),block, inst, false); |
| } else { |
| U_32 numOpnds = inst->getNumSrcOperands(); |
| for (U_32 i=0; i<numOpnds; i++) { |
| Opnd *opnd0 = inst->getSrc(i); |
| Opnd *opnd = opnd0; |
| Opnd *newOpnd = opnd0; |
| while (newOpnd) { |
| opnd = newOpnd; |
| newOpnd = 0; |
| if (opnd->isPiOpnd()) { |
| // it's a Pi operand, dereference directly |
| PiOpnd *piOpnd = opnd->asPiOpnd(); |
| newOpnd = piOpnd->getOrg(); |
| } |
| } |
| if (flags.remConv && |
| (!flags.dryRun) && |
| (opnd->getInst()->getOpcode() == Op_Conv)) { |
| Opnd *srcOpnd = opnd->getInst()->getSrc(0); |
| bool deref = isMarkedToEliminate(opnd->getInst(), why); |
| while (deref) { |
| deref = false; |
| if (srcOpnd->getType()->tag == |
| opnd->getType()->tag) { |
| opnd = srcOpnd; |
| Inst *newInst = opnd->getInst(); |
| if ((newInst->getOpcode() == Op_Conv) && |
| isMarkedToEliminate(newInst, why)) { |
| |
| deref = true; |
| } |
| } |
| } |
| } |
| if (flags.unmaskShifts && |
| (!flags.dryRun) && |
| ((opnd->getInst()->getOpcode() == Op_Shr) || |
| (opnd->getInst()->getOpcode() == Op_Shl))) { |
| Inst *the_inst = opnd->getInst(); |
| |
| if (isMarkedToEliminate(the_inst, why)) { |
| // don't eliminate, just clear shift-mask |
| |
| the_inst->setShiftMaskModifier(ShiftMask_None); |
| } |
| } |
| |
| if (opnd0 != opnd) { |
| inst->setSrc(i,opnd); |
| } |
| } |
| |
| if (flags.remOneBound && |
| (inst->getOpcode() == Op_TauCheckBounds)) { |
| if (isMarkedToEliminateLB(inst, why)) { |
| Opnd *dstTau = inst->getDst(); |
| inst->setDst(OpndManager::getNullOpnd()); |
| Opnd *a = inst->getSrc(1); // index |
| Opnd *b = inst->getSrc(0); // array length |
| // don't bother with tauAnd, chkbound is immobile |
| Inst *new_check |
| = irManager.getInstFactory().makeTauCheckUpperBound(dstTau, a, b); |
| if (inst->getOverflowModifier() == Overflow_None) { |
| new_check->setOverflowModifier(Overflow_None); |
| } |
| if (Log::isEnabled()) { |
| Log::out() << " inserting "; |
| new_check->print(Log::out()); |
| Log::out() << " in place of "; |
| inst->print(Log::out()); |
| Log::out() << std::endl; |
| } |
| new_check->insertBefore(inst); |
| inst->unlink(); |
| |
| } else if (isMarkedToEliminateUB(inst, why)) { |
| Opnd *dstTau = inst->getDst(); |
| inst->setDst(OpndManager::getNullOpnd()); |
| Opnd *b = inst->getSrc(1); // index |
| |
| // build a constant 0 operand a |
| Type *idxType = b->getType(); |
| ConstInst::ConstValue constZero; |
| constZero.i8 = 0; |
| OpndManager &opndManager = irManager.getOpndManager(); |
| SsaTmpOpnd *a = opndManager.createSsaTmpOpnd(idxType); |
| InstFactory &instFactory = irManager.getInstFactory(); |
| Inst *ldcInst = instFactory.makeLdConst(a, constZero); |
| // don't bother with tauAnd, chk is immobile |
| Inst *new_check |
| = instFactory.makeTauCheckLowerBound(dstTau, a, b); |
| if (inst->getOverflowModifier() == Overflow_None) { |
| new_check->setOverflowModifier(Overflow_None); |
| } |
| if (Log::isEnabled()) { |
| Log::out() << " inserting "; |
| ldcInst->print(Log::out()); |
| Log::out() << ";"; |
| new_check->print(Log::out()); |
| Log::out() << "; in place of "; |
| inst->print(Log::out()); |
| Log::out() << std::endl; |
| } |
| new_check->insertBefore(inst); |
| ldcInst->insertBefore(new_check); |
| inst->unlink(); |
| } |
| } |
| } |
| } |
| |
| SsaTmpOpnd* Abcd::getBlockTauPoint(Node *block) |
| { |
| if ((lastTauPointBlock == block) && blockTauPoint) return blockTauPoint; |
| Inst *firstInst = (Inst*)block->getFirstInst(); |
| Inst *inst = (Inst*)firstInst->getNextInst(); |
| for (; inst != NULL; inst = inst->getNextInst()) { |
| if (inst->getOpcode() == Op_TauPoint) { |
| blockTauPoint = inst->getDst()->asSsaTmpOpnd(); |
| assert(blockTauPoint); |
| lastTauPointBlock = block; |
| return blockTauPoint; |
| } |
| } |
| for (inst = firstInst->getNextInst(); inst != NULL; inst = inst->getNextInst()) { |
| if (inst->getOpcode() != Op_Phi) { |
| break; // insert before inst. |
| } |
| } |
| // no non-phis, insert before inst; |
| TypeManager &tm = irManager.getTypeManager(); |
| SsaTmpOpnd *tauOpnd = irManager.getOpndManager().createSsaTmpOpnd(tm.getTauType()); |
| Inst* tauPoint = irManager.getInstFactory().makeTauPoint(tauOpnd); |
| if(Log::isEnabled()) { |
| Log::out() << "Inserting tauPoint inst "; |
| tauPoint->print(Log::out()); |
| if (inst!=NULL) { |
| Log::out() << " before inst "; |
| inst->print(Log::out()); |
| } |
| Log::out() << std::endl; |
| } |
| if (inst!=NULL) { |
| tauPoint->insertBefore(inst); |
| } else { |
| block->appendInst(tauPoint); |
| } |
| blockTauPoint = tauOpnd; |
| lastTauPointBlock = block; |
| return tauOpnd; |
| } |
| |
| } //namespace Jitrino |