Index: build/custom/msvc_2003/jitrino/jitrino.vcproj =================================================================== --- build/custom/msvc_2003/jitrino/jitrino.vcproj (revision 532324) +++ build/custom/msvc_2003/jitrino/jitrino.vcproj (working copy) @@ -368,11 +368,32 @@ RelativePath="..\..\..\..\vm\jitrino\src\optimizer\abcd\abcdbounds.h"> + + + + + + + + + + + + + + InstReasonPair; inline bool operator <(const InstReasonPair &pair1, const InstReasonPair &pair2) { return (pair1.first < pair2.first); } -struct AbcdFlags { - bool partial; - bool dryRun; - bool useAliases; - bool useConv; - bool remConv; - bool useShr; - bool unmaskShifts; - bool remBr; - bool remCmp; - bool remOneBound; - bool remOverflow; - bool checkOverflow; - bool useReasons; -}; - class Abcd { - IRManager& irManager; - MemoryManager &mm; - InequalityGraph *ineqGraph; - DominatorTree& dominators; - SparseOpndMap *piMap; - uint32 nextPiOpndId; - AbcdSolver *solver; - StlVector canEliminate; // sorted by Inst - StlVector canEliminateUB; // keep sorted - StlVector canEliminateLB; // keep sorted - - SsaTmpOpnd *tauUnsafe; - SsaTmpOpnd *tauSafe; - SsaTmpOpnd *blockTauPoint; - Node *lastTauPointBlock; - SsaTmpOpnd *blockTauEdge; - Node *lastTauEdgeBlock; - - AbcdFlags& flags; public: static void readFlags(Action* argSource, AbcdFlags* flags); static void showFlags(std::ostream& os); Abcd(IRManager &irManager0, MemoryManager& memManager, DominatorTree& dom0); - ~Abcd() { - }; + ~Abcd() {} void runPass(); -private: - void insertPiNodes(); // insert and rename over whole tree; - void insertPiNodes(DominatorNode *domBlock); // for each dominator - void insertPiNodes(Node *block); // for each dominator - void insertPiNodesForUnexceptionalPEI(Node *block, Inst *pei); - void insertPiNodesForBranch(Node *block, BranchInst *branchi, - Edge::Kind kind); - void insertPiNodesForComparison(Node *block, - ComparisonModifier mod, - const PiCondition &bounds, - Opnd *op, - bool swap_operands, - bool negate_comparison); - void insertPiNodeForOpnd(Node *block, Opnd *org, - const PiCondition &cond, - Opnd *tauOpnd = 0); - // checks for aliases of opnd, inserts them. - void insertPiNodeForOpndAndAliases(Node *block, Opnd *org, - const PiCondition &cond, - Opnd *tauOpnd = 0); - PiOpnd *getNewDestOpnd(Node *block, Opnd *org); + bool getAliases(Opnd *theOpnd, AbcdAliases *, + int64 addend); // adds them to aliases list, adding addend + + static bool isConvOpnd(const Opnd *opnd); + static bool convPassesSource(const Opnd *opnd); + static Opnd *getConvSource(const Opnd *opnd); + static bool typeIncludes(Type::Tag type1, Type::Tag type2); + static bool hasTypeBounds(Type::Tag srcTag, int64 &lb, int64 &ub); + static bool isCheckableType(Type::Tag type1); + static bool hasCheckableType(const Opnd *opnd); +private: Opnd *getConstantOpnd(Opnd *opnd); // dereferencing through Pis, 0 if not constant. - void renamePiVariables(); - void renamePiVariables(Node *block); - void renamePiVariables(DominatorNode *block); - void removePiNodes(); - void removePiNodes(Node *block, Inst *i); - - void updateSsaForm(); - void buildInequalityGraph(); void removeRedundantBoundsChecks(); + void removePiEliminateChecksOnInst(Node *block, Inst *inst); void markCheckToEliminate(Inst *); // used by solver to mark eliminable branches void markInstToEliminate(Inst *); // used by solver to mark other eliminable instructions @@ -152,31 +100,33 @@ bool isMarkedToEliminateUB(Inst *, AbcdReasons *&why); SsaTmpOpnd *getBlockTauPoint(Node *block); - SsaTmpOpnd *getBlockTauEdge(Node *block); SsaTmpOpnd *getTauUnsafe(); SsaTmpOpnd *getTauSafe(); - SsaTmpOpnd *getReasonTau(AbcdReasons *reason, - Inst *useSite); SsaTmpOpnd *makeReasonPhi(Opnd *derefVar, StlVector &reasons, StlVector &derefVarVersions); + SsaTmpOpnd* getReasonTau(AbcdReasons *reason, Inst *useSite); - friend class AbcdSolver; - friend class InsertPiWalker; - friend class RenamePiWalker; - friend class RemovePiWalker; - friend struct AliasCheckingFun; - void checkForAliases(); -public: - bool getAliases(Opnd *theOpnd, AbcdAliases *, - int64 addend); // adds them to aliases list, adding addend + void removePiEliminateChecks(); - static bool isConvOpnd(const Opnd *opnd); - static bool convPassesSource(const Opnd *opnd); - static Opnd *getConvSource(const Opnd *opnd); - static bool typeIncludes(Type::Tag type1, Type::Tag type2); - static bool hasTypeBounds(Type::Tag srcTag, int64 &lb, int64 &ub); - static bool isCheckableType(Type::Tag type1); - static bool hasCheckableType(const Opnd *opnd); + IRManager& irManager; + MemoryManager &mm; + DominatorTree& dominators; + AbcdSolver *solver; + StlVector canEliminate; // sorted by Inst + StlVector canEliminateUB; // keep sorted + StlVector canEliminateLB; // keep sorted + + SsaTmpOpnd *tauUnsafe; + SsaTmpOpnd *tauSafe; + + AbcdFlags& flags; + InsertPi insertPi; + + SsaTmpOpnd* blockTauPoint; + Node* lastTauPointBlock; + + friend class AbcdSolver; + friend class RemovePiEliminateChecksWalker; }; } //namespace Jitrino Index: vm/jitrino/src/optimizer/abcd/classic_abcd.h =================================================================== --- vm/jitrino/src/optimizer/abcd/classic_abcd.h (revision 0) +++ vm/jitrino/src/optimizer/abcd/classic_abcd.h (revision 0) @@ -0,0 +1,58 @@ +/* + * 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. + */ + +#ifndef _CLASSIC_ABCD_H +#define _CLASSIC_ABCD_H + +#include +#include "open/types.h" +#include "Opcode.h" +#include "FlowGraph.h" +#include "optpass.h" +#include "classic_abcd_solver.h" +#include "insertpi.h" + +namespace Jitrino { + +class ClassicAbcd { +public: + ClassicAbcd(SessionAction* arg_source, IRManager &ir_manager, + MemoryManager& mem_manager, DominatorTree& dom0) + : + _irManager(ir_manager), + _mm(mem_manager), + _domTree(dom0) + { + _runTests = arg_source->getBoolArg("run_tests", false); + _useAliases = arg_source->getBoolArg("use_aliases", true); + } + + void runPass(); +private: + friend class BuildInequalityGraphWalker; + + IRManager& _irManager; + MemoryManager& _mm; + DominatorTree& _domTree; + + bool _runTests; + bool _useAliases; +}; + +} //namespace Jitrino + +#endif /* _CLASSIC_ABCD_H */ Index: vm/jitrino/src/optimizer/abcd/insertpi.h =================================================================== --- vm/jitrino/src/optimizer/abcd/insertpi.h (revision 0) +++ vm/jitrino/src/optimizer/abcd/insertpi.h (revision 0) @@ -0,0 +1,120 @@ +/* + * 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. + */ + +#ifndef _INSERTPI_H +#define _INSERTPI_H + +#include +#include "open/types.h" +#include "Opcode.h" +#include "FlowGraph.h" +#include "abcd/AbcdFlags.h" +#include "abcdbounds.h" +#include "opndmap.h" + +namespace Jitrino { + +class InsertPi { +public: + enum ProblemType { + Upper = 2, + Lower = 1, + Both = 0 + }; + + InsertPi(MemoryManager& mm, DominatorTree& dom_tree, IRManager& irm, + bool use_aliases, ProblemType type = Both) : + _mm(mm), + _domTree(dom_tree), + _useAliases(use_aliases), + _problemType(type), + _irManager(irm), + _blockTauEdge(0), + _lastTauEdgeBlock(0), + _piMap(0) + {} + + // Add a Pi node in the node if it is after each test + // which tells something about a variable + void insertPi(); + + void removePi(); + + void setUseAliases(bool use = true) { _useAliases = use; } + bool useAliases() const { return _useAliases; } +private: + friend class InsertPiWalker; + friend class RenamePiWalker; + friend class RemovePiWalker; + + // add Pi in the node iff after a test which tells something about the var + void insertPiToNode(Node* block); + + // definition: PEI=Potentially Excepting Instruction + void insertPiForUnexceptionalPEI(Node *block, Inst *lasti); + + SsaTmpOpnd* getBlockTauEdge(Node *block); + + void insertPiForBranch(Node* block, + BranchInst* branchi, + Edge::Kind kind); + + void insertPiForComparison(Node* block, + ComparisonModifier mod, + const PiCondition& bounds, + Opnd* op, + bool swap_operands, + bool negate_comparison); + + void insertPiForOpnd(Node* block, + Opnd* org, + const PiCondition &cond, + Opnd* tauOpnd); + + // checks for aliases of opnd, inserts them. + void insertPiForOpndAndAliases(Node* block, + Opnd* org, + const PiCondition& cond, + Opnd* tauOpnd); + + bool getAliases(Opnd *opnd, AbcdAliases *aliases, int64 addend); + + Opnd* getConstantOpnd(Opnd *opnd); + + // Renames variables for which we have Pi nodes. + void renamePiVariables(); + + void renamePiVariablesInNode(Node *block); + + void renamePiVariablesInDomNode(DominatorNode *block); + + void removePiOnInst(Node* block, Inst *inst); + + MemoryManager& _mm; + DominatorTree& _domTree; + bool _useAliases; + ProblemType _problemType; + IRManager& _irManager; + + SsaTmpOpnd* _blockTauEdge; + Node* _lastTauEdgeBlock; + SparseOpndMap *_piMap; +}; + +} //namespace Jitrino + +#endif /* _INSERTPI_H */ Index: vm/jitrino/src/optimizer/abcd/classic_abcd_solver.cpp =================================================================== --- vm/jitrino/src/optimizer/abcd/classic_abcd_solver.cpp (revision 0) +++ vm/jitrino/src/optimizer/abcd/classic_abcd_solver.cpp (revision 0) @@ -0,0 +1,1083 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed 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. + */ + +#include +#include "classic_abcd_solver.h" +#include "Log.h" + +namespace Jitrino { + +void IOpnd::printName(std::ostream& os) const +{ + os << "o" << getID(); +} + +void IOpnd::printFullName(std::ostream& os) const +{ + printName(os); + assert((!isPhi()) || (!isConstant())); + if ( isPhi() ) { + os << "(phi)"; + } + if ( isConstant() ) { + os << "(const=" << getConstant() << ")"; + } +} + +//------------------------------------------------------------------------------ + +bool InequalityGraph::has_other_opnd_with_same_id(IdToOpndMap& map, IOpnd* opnd) +{ + IdToOpndMap::iterator it = map.find(opnd->getID()); + if ( it != map.end() && it->second != opnd ) { + return true; + } + return false; +} + +//------------------------------------------------------------------------------ + +const InequalityGraph::EdgeList& InequalityGraph::getInEdges(IOpnd* opnd) const +{ + OpndEdgeMap::const_iterator it = _opnd_to_inedges_map.find(opnd->getID()); + + if ( it == _opnd_to_inedges_map.end() ) { + return _emptyList; + } + return it->second; +} + +const InequalityGraph::EdgeList& InequalityGraph::getOutEdges(IOpnd* opnd) const +{ + OpndEdgeMap::const_iterator it = _opnd_to_outedges_map.find(opnd->getID()); + if ( it == _opnd_to_outedges_map.end() ) { + return _emptyList; + } + return it->second; +} + +void InequalityGraph::addEdgeToIdMap + (OpndEdgeMap& mp, uint32 id, IneqEdge* edge) +{ + OpndEdgeMap::iterator it = mp.find(id); + if ( it == mp.end() ) { + StlList * new_list = new (_mem_mgr) StlList(_mem_mgr); + new_list->push_back(edge); + mp.insert(std::make_pair(id, *new_list)); + }else{ + it->second.push_back(edge); + } +} + +void InequalityGraph::addEdge(IOpnd* from, IOpnd* to, int32 distance) +{ + assert(!has_other_opnd_with_same_id(_id_to_opnd_map, from)); + assert(!has_other_opnd_with_same_id(_id_to_opnd_map, to)); + + _id_to_opnd_map[from->getID()] = from; + _id_to_opnd_map[to->getID()] = to; + + IneqEdge* p_edge = new (_mem_mgr) IneqEdge(from, to, distance); + _edges.push_back(p_edge); + + addEdgeToIdMap(_opnd_to_outedges_map, from->getID(), p_edge); + addEdgeToIdMap(_opnd_to_inedges_map, to->getID(), p_edge); +} + +void InequalityGraph::addEdge(uint32 id_from, uint32 id_to, int32 distance) +{ + IOpnd *from, *to; + IdToOpndMap::iterator it; + + it = _id_to_opnd_map.find(id_from); + assert(it != _id_to_opnd_map.end()); + from = it->second; + it = _id_to_opnd_map.find(id_to); + assert(it != _id_to_opnd_map.end()); + to = it->second; + + addEdge(from, to, distance); +} + +void InequalityGraph::addOpnd(IOpnd* opnd) +{ + assert(!has_other_opnd_with_same_id(_id_to_opnd_map, opnd)); + _id_to_opnd_map[opnd->getID()] = opnd; +} + +void InequalityGraph::printDotHeader(std::ostream& os) const +{ + os << "digraph dotgraph {" << std::endl; + os << "node [shape=record,fontname=\"Courier\",fontsize=9];" << std::endl; + os << "label=\"Inequality Graph\";" << std::endl; +} + +/* + * example: + * + * digraph dotgraph { + * node [shape=record,fontname="Courier",fontsize=9]; + * label="Label"; + * ENTRY [label="{ENTRY}"] + * L1 [label="{L1}"] + * L2 [label="{L2}"] + * ENTRY -> L1 [label="55"]; + * L1 -> L2; + * L2 -> ENTRY; + * } + */ +void InequalityGraph::printDotFile(std::ostream& os) const +{ + printDotHeader(os); + printDotBody(os); + printDotEnd(os); +} + +void InequalityGraph::printDotEnd(std::ostream& os) const +{ + os << "}" << std::endl; +} + +void InequalityGraph::printDotBody(std::ostream& os) const +{ + IdToOpndMap::const_iterator it = _id_to_opnd_map.begin(), + last = _id_to_opnd_map.end(); + for (; it != last; it++ ) { + IOpnd* opnd = it->second; + os << "\""; opnd->printName(os); os << "\""; + os << " [label=\"{"; + opnd->printFullName(os); + os << "}\"];" << std::endl; + } + for (it = _id_to_opnd_map.begin(); it != last; it++ ) { + IOpnd* from_opnd = it->second; + const EdgeList& out_edges_list = getOutEdges(from_opnd); + EdgeList::const_iterator out_iter = out_edges_list.begin(), + out_last = out_edges_list.end(); + for (; out_iter != out_last; out_iter++) { + IOpnd* to_opnd = (*out_iter)->getDst(); + os << "\""; from_opnd->printName(os); os << "\""; + os << " -> "; + os << "\""; to_opnd->printName(os); os << "\""; + os << " [label=\"" << (*out_iter)->getLength() << "\"];" + << std::endl; + } + } +} + +IOpnd* InequalityGraph::findOpnd(uint32 id) const +{ + IdToOpndMap::const_iterator it = _id_to_opnd_map.find(id); + if ( it == _id_to_opnd_map.end() ) { + return NULL; + } + return it->second; +} +//------------------------------------------------------------------------------ + +TrueReducedFalseChart* BoundAllocator::create_empty_TRFChart() +{ + return new (_mem_mgr) TrueReducedFalseChart(this); +} + +Bound* BoundAllocator::newBound(int32 val, const BoundState& bs) +{ + return new (_mem_mgr) Bound(val, bs); +} + +Bound* BoundAllocator::create_inc1(Bound* bound) +{ + return newBound(bound->isUpper() ? bound->_bound + 1 : bound->_bound - 1, + bound->getBoundState()); +} + +Bound* BoundAllocator::create_dec1(Bound* bound) +{ + return newBound(bound->isUpper() ? bound->_bound - 1 : bound->_bound + 1, + bound->getBoundState()); +} + +Bound* BoundAllocator::create_dec_const(Bound* bound, int32 cnst) +{ + return newBound(bound->_bound - cnst, bound->getBoundState()); +} + +//------------------------------------------------------------------------------ + +void Bound::printFullName(std::ostream& os) +{ + os << "Bound("; + if ( isUpper() ) { + os << "upper"; + }else{ + os << "lower"; + } + os << ", " << _bound << ")"; +} + +bool Bound::leq(Bound* bound1, Bound* bound2) +{ + assert(bound1 && bound2); + assert(bound1->isUpper() == bound2->isUpper()); + return Bound::int32_leq(bound1->_bound, bound2); +} + +bool Bound::eq(Bound* bound1, Bound* bound2) +{ + assert(!bound1 || !bound2 || bound1->isUpper() == bound2->isUpper()); + return bound1 && bound2 && + Bound::leq(bound1, bound2) && Bound::leq(bound2, bound1); +} + +bool Bound::leq_int32(Bound* bound1, int32 value) +{ + assert(bound1); + return bound1->isUpper() ? + bound1->_bound <= value : + bound1->_bound >= value; +} + +bool Bound::int32_leq(int32 value, Bound* bound1) +{ + assert(bound1); + return bound1->isUpper() ? + value <= bound1->_bound : + value >= bound1->_bound; +} + +// returns (dst_val - src_val <= bound) +bool Bound::const_distance_leq(int32 src_val, int32 dst_val, Bound* bound) +{ + assert(bound); + int32 distance = dst_val - src_val; + assert(distance + src_val == dst_val); + return Bound::int32_leq(distance, bound); +} + +//------------------------------------------------------------------------------ + +ProveResult meetBest(ProveResult res1, ProveResult res2) +{ + return (ProveResult) std::max(res1, res2); +} + +ProveResult meetWorst(ProveResult res1, ProveResult res2) +{ + return (ProveResult) std::min(res1, res2); +} + +void print_result(ProveResult r, std::ostream& os) +{ + switch (r) { + case True : os << "True"; break; + case Reduced : os << "Reduced"; break; + case False : os << "False"; break; + } +} + +//------------------------------------------------------------------------------ + +void TrueReducedFalseChart::addFalse(Bound* f_bound) +{ + if ( !_max_false || Bound::leq(_max_false, f_bound) ) { + _max_false = f_bound; + } + + /* make none of 3 bounds equal */ + if ( Bound::eq(_max_false, _min_reduced) ) { + _min_reduced = _bound_alloc->create_inc1(_min_reduced); + } + if ( Bound::eq(_max_false, _min_true) ) { + _min_true = _bound_alloc->create_inc1(_min_true); + } + if ( Bound::eq(_min_reduced, _min_true) ) { + _min_reduced = NULL; + } + + clearRedundantReduced(); + assert(!_min_true || Bound::leq(_max_false, _min_true)); + assert(!_min_reduced || Bound::leq(_max_false, _min_reduced)); +} + +void TrueReducedFalseChart::addReduced(Bound* r_bound) +{ + if ( !_min_reduced || Bound::leq(r_bound, _min_reduced) ) { + _min_reduced = r_bound; + } + + /* make none of 3 bounds equal */ + if ( Bound::eq(_min_reduced, _min_true) ) { + _min_true = _bound_alloc->create_inc1(_min_true); + } + if ( Bound::eq(_min_reduced, _max_false) ) { + _max_false = _bound_alloc->create_dec1(_max_false); + } + + assert(!_min_true || Bound::leq(_min_reduced, _min_true)); + assert(!_max_false || Bound::leq(_max_false, _min_reduced)); +} + +void TrueReducedFalseChart::addTrue(Bound* t_bound) +{ + if ( !_min_true || Bound::leq(t_bound, _min_true) ) { + _min_true = t_bound; + } + + /* make none of 3 bounds equal */ + if ( Bound::eq(_min_true, _min_reduced) ) { + _min_reduced = _bound_alloc->create_dec1(_min_reduced); + } + if ( Bound::eq(_min_true, _max_false) ) { + _max_false = _bound_alloc->create_dec1(_max_false); + } + if ( Bound::eq(_max_false, _min_reduced) ) { + _min_reduced = NULL; + } + + clearRedundantReduced(); + assert(!_min_reduced || Bound::leq(_min_reduced, _min_true)); + assert(!_max_false || !_min_reduced || + Bound::leq(_max_false, _min_reduced)); +} + +bool TrueReducedFalseChart::hasBoundResult(Bound* bound) const +{ + assert(!Bound::eq(_min_true, _max_false)); + assert(!Bound::eq(_min_true, _min_reduced)); + assert(!Bound::eq(_max_false, _min_reduced)); + + if ( (_max_false && Bound::leq(bound, _max_false)) || + (_min_reduced && Bound::leq(_min_reduced, bound)) || + (_min_true && Bound::leq(_min_true, bound)) ) { + return true; + } + return false; +} + +ProveResult TrueReducedFalseChart::getBoundResult(Bound* bound) const +{ + assert(hasBoundResult(bound)); + if ( (_max_false && Bound::leq(bound, _max_false)) ) { + return False; + } + if ( _min_true && Bound::leq(_min_true, bound) ) { + return True; + } + if ( _min_reduced && Bound::leq(_min_reduced, bound) ) { + return Reduced; + } + assert(0); + return False; +} + +void TrueReducedFalseChart::print(std::ostream& os) const +{ + os << "maxF="; + printBound(_max_false, os); + os << ", minR="; + printBound(_min_reduced, os); + os << ", minT="; + printBound(_min_true, os); +} + +void TrueReducedFalseChart::printBound(Bound* b, std::ostream& os) const +{ + if ( !b ) { + os << "NULL"; + }else{ + b->printFullName(os); + } +} + +void TrueReducedFalseChart::clearRedundantReduced() +{ + if ( _min_true && _min_reduced && Bound::leq(_min_true, _min_reduced) && + !Bound::eq(_min_true, _min_reduced) ) { + _min_reduced = NULL; + } + if ( _max_false && _min_reduced && Bound::leq(_min_reduced, _max_false) && + !Bound::eq(_min_reduced, _max_false) ) { + _min_reduced = NULL; + } +} + +//------------------------------------------------------------------------------ + +void MemoizedDistances::makeEmpty() +{ + _map.clear(); +} + +void MemoizedDistances::initOpnd(IOpnd* op) +{ + OpndToTRFChart::const_iterator it = _map.find(op); + if ( it == _map.end() ) { + _map.insert(std::make_pair(op, *_bound_alloc.create_empty_TRFChart())); + } +} + +void MemoizedDistances::updateLeqBound(IOpnd* dest, Bound* bound, ProveResult res) +{ + initOpnd(dest); + if ( res == False ) { + _map[dest].addFalse(bound); + }else if ( res == True ) { + _map[dest].addTrue(bound); + }else{ + _map[dest].addReduced(bound); + } +} + +bool MemoizedDistances::hasLeqBoundResult(IOpnd* dest, Bound* bound) const +{ + OpndToTRFChart::const_iterator it = _map.find(dest); + if ( it == _map.end() ) { + return false; + } + return (it->second).hasBoundResult(bound); +} + +ProveResult MemoizedDistances::getLeqBoundResult(IOpnd* dest, Bound* bound) const +{ + assert(hasLeqBoundResult(dest, bound)); + return (_map.find(dest)->second).getBoundResult(bound); +} + +// true iff: (there is a distance to 'dest') && (distance <= bound) +bool MemoizedDistances::minTrueDistanceLeqBound(IOpnd* dest, Bound* bound) +{ + initOpnd(dest); + Bound* stored_bound = _map[dest].getMinTrueBound(); + return stored_bound && Bound::leq(stored_bound, bound); +} + +bool MemoizedDistances::maxFalseDistanceGeqBound(IOpnd* dest, Bound* bound) +{ + initOpnd(dest); + Bound* stored_bound = _map[dest].getMaxFalseBound(); + return stored_bound && Bound::leq(bound, stored_bound); +} + +bool MemoizedDistances::minReducedDistanceLeqBound(IOpnd* dest, Bound* bound) +{ + initOpnd(dest); + Bound* stored_bound = _map[dest].getMinReducedBound(); + return stored_bound && Bound::leq(stored_bound, bound); +} + +void MemoizedDistances::print(std::ostream& os) const +{ + OpndToTRFChart::const_iterator it = _map.begin(), last = _map.end(); + os << "--- begin MemoizedDistances dump ---" << std::endl; + for (; it != last; it++) { + it->first->printFullName(os); + os << " --> "; + (it->second).print(os); + os << std::endl; + } + os << "--- end MemoizedDistances dump ---" << std::endl; +} + +//------------------------------------------------------------------------------ + +Bound* ActiveOpnds::getBound(IOpnd* opnd) const +{ + assert(hasOpnd(opnd)); + + return _map.find(opnd)->second; +} + +void ActiveOpnds::print(std::ostream& os) const +{ + os << "--- begin ActiveOpnds dump ---" << std::endl; + for (iter_t it = _map.begin(), last = _map.end(); it != last; it++) { + it->first->printFullName(os); + os << " --> "; + it->second->printFullName(os); + os << std::endl; + } + os << "--- end ActiveOpnds dump ---" << std::endl; +} + +//------------------------------------------------------------------------------ + +bool ClassicAbcdSolver::demandProve + (IOpnd* source, IOpnd* dest, int32 bound_int, bool prove_upper_bound) +{ + assert(source && dest); + _source_opnd = source; + BoundState bs(prove_upper_bound); + Bound bound(bound_int, bs); + + _active.makeEmpty(); + _mem_distance.makeEmpty(); + + if (Log::isEnabled() ) { + Log::out() << "demandProve("; + _source_opnd->printFullName(Log::out()); + Log::out() << ", "; + dest->printFullName(Log::out()); + Log::out() << ", "; + bound.printFullName(Log::out()); + Log::out() << std::endl; + } + + if ( prove(dest, &bound, 0) == False ) { + if (Log::isEnabled() ) { + Log::out() << "demandProve: cannot eliminate check" << std::endl; + } + return false; + } + if (Log::isEnabled() ) { + Log::out() << "demandProve: !!!CAN!!! eliminate check" << std::endl; + } + return true; +} + +void ClassicAbcdSolver::updateMemDistanceWithPredecessors (IOpnd* dest, + Bound* bound, + uint32 prn_level, + meet_func_t meet_f) +{ + const InequalityGraph::EdgeList& in_edges = _igraph.getInEdges(dest); + assert(!in_edges.empty()); + InequalityGraph::EdgeList::const_iterator in_iter = in_edges.begin(); + InequalityGraph::EdgeList::const_iterator in_last = in_edges.end(); + IneqEdge* in_edge = (*in_iter); + assert(in_edge->getDst() == dest); + ProveResult res; + assert(!_mem_distance.hasLeqBoundResult(dest, bound)); + res = prove(in_edge->getSrc(), + _bound_alloc.create_dec_const(bound, + in_edge->getLength()), + prn_level + 1); + in_iter++; + for (; in_iter != in_last; in_iter++) { + if(((res >= Reduced) && (meet_f == meetBest)) || + ((res == False) && (meet_f == meetWorst))) { + // For any x, meetBest(True, x) == True + // meetBest(Reduced, x) >= Reduced + // and meetWorst(False, x) == False + if (Log::isEnabled() ) { + Printer prn(prn_level, Log::out()); + prn.prnStr("skipping remaining preds, proven: "); + print_result(res, Log::out()); + Log::out() << std::endl; + } + break; + } + in_edge = (*in_iter); + assert(in_edge->getDst() == dest); + IOpnd* pred = in_edge->getSrc(); + res = meet_f(res, + prove(pred, + _bound_alloc.create_dec_const(bound, + in_edge->getLength()), + prn_level + 1)); + } + _mem_distance.updateLeqBound(dest, bound, res); +} + +// +// prove that distance between '_source_opnd' and 'dest' is <= bound +// +ProveResult ClassicAbcdSolver::prove(IOpnd* dest, Bound* bound, + uint32 prn_level) +{ + Printer prn(prn_level, Log::out()); + if ( Log::isEnabled() ) { + prn.prnStr("prove("); + dest->printFullName(Log::out()); + Log::out() << ", "; + bound->printFullName(Log::out()); Log::out() << ")" << std::endl; + } + + // if ( C[dest - _source_opnd <= e] == True for some e<=bound ) + // return True + if ( _mem_distance.minTrueDistanceLeqBound(dest, bound) ) { + prn.prnStrLn("case 3: => True"); + return True; + } + + // if ( C[dest - _source_opnd <= e] == False for some e>=bound ) + // return False + if ( _mem_distance.maxFalseDistanceGeqBound(dest, bound) ) { + prn.prnStrLn("case 4: => False"); + return False; + } + + // if ( C[dest - _source_opnd <= e] == Reduced for some e<=bound ) + // return Reduced + if ( _mem_distance.minReducedDistanceLeqBound(dest, bound) ) { + prn.prnStrLn("case 5: => Reduced"); + return Reduced; + } + + // traversal reached the _source_opnd vertex + if ( (dest->getID() == _source_opnd->getID()) && + Bound::int32_leq(0, bound) ) { + prn.prnStrLn("reached source vertex => True"); + return True; + } + + // all constant operands are implicitly connected + if ( dest->isConstant() && _source_opnd->isConstant() ) { + if ( Bound::const_distance_leq(_source_opnd->getConstant(), + dest->getConstant(), + bound) ) { + prn.prnStrLn("reached source vertex (const) => True"); + return True; + }else { + prn.prnStrLn("reached source vertex (bad const) => False"); + return False; + } + } + + // if dest has no predecessor then fail + if ( _igraph.getInEdges(dest).empty() ) { + prn.prnStrLn("no predecessors => False"); + return False; + } + + // a cycle was encountered + if ( _active.hasOpnd(dest) ) { + if ( Bound::leq(_active.getBound(dest), bound) ) { + prn.prnStrLn("harmless cycle => Reduced"); + return Reduced; // a harmless cycle + }else{ + prn.prnStrLn("amplifying cycle => False"); + return False; // an amplifying cycle + } + } + + _active.setBound(dest, bound); + if ( dest->isPhi() ) { + prn.prnStrLn("phi => worst"); + updateMemDistanceWithPredecessors(dest, bound, prn_level, meetWorst); + }else{ + prn.prnStrLn("non_phi => best"); + updateMemDistanceWithPredecessors(dest, bound, prn_level, meetBest); + } + _active.clearOpnd(dest); + + ProveResult res = _mem_distance.getLeqBoundResult(dest, bound); + if (Log::isEnabled() ) { + prn.prnStr("proven: "); print_result(res, Log::out()); Log::out() << std::endl; + } + return res; +} + +void ClassicAbcdSolver::Printer::prnLevel() +{ + if (Log::isEnabled()) { + for (uint32 i = 0; i < _level; i++) { + _os << " "; + } + } +} + +void ClassicAbcdSolver::Printer::prnStr(char* str) +{ + prnLevel(); + if (Log::isEnabled()) { + _os << str; + } +} + +void ClassicAbcdSolver::Printer::prnStrLn(char* str) +{ + if (Log::isEnabled()) { + prnStr(str); + _os << std::endl; + } +} + +//------------------------------------------------------------------------------ + +/* + * for(i = 5; i < A.length; i++) { + * check(-1 < i); + * check(i < A.length); + * ... + * } + * + * i0 = 5 + * for: + * i1 = phi(i0, i2) + * if (i1 < A.length) { + * i3 = pi(i1) + * __check(i3 > -1); + * __check(i3 < A.length); + * ... + * i2 = i3 + 1; + * goto for + * } + * + * 0 -(0)-> i0 -(0)-> i1(phi) + * i1(phi) -(0)-> i3 -(1)-> i2 -(0)-> i1(phi) + * A.length -(-1)-> i3 + * + * upper: prove(i3 - A.length <= -1) // trivial :) + * lower: prove(i3 - (-1) >= 1) // not so trivial + */ +void testSimpleIGraph() +{ + MemoryManager mm(1024, "testSimpleIGraph.MemoryManager"); + InequalityGraph g(mm); + ClassicAbcdSolver solver(g, mm); + assert(g.isEmpty()); + + IOpnd op0(0), op1(1, true /*phi*/), op2(2), op3(3); + g.addOpnd(&op0); + g.addOpnd(&op1); + g.addOpnd(&op2); + g.addOpnd(&op3); + + IOpnd op_const_5(4, false, true); + op_const_5.setConstant(5); + g.addOpnd(&op_const_5); + + IOpnd length(5); + + g.addOpnd(&length); + g.addEdge(0, 1, 0); + g.addEdge(1, 3, 0); + g.addEdge(3, 2, 1); + g.addEdge(2, 1, 0); + g.addEdge(5, 3, -1); + g.addEdge(4, 0, 0); + + assert(solver.demandProve(g.findOpnd(5), g.findOpnd(3), -1, true)); + //logfile << " testSimpleIGraph: OK" << std::endl; + + IOpnd op_m1(6, false /* phi */, true /* constant */); + op_m1.setConstant(-1); + g.addOpnd(&op_m1); + + assert(solver.demandProve(&op_m1, g.findOpnd(3), 1, false)); + op_const_5.setConstant(-5); + assert(!solver.demandProve(&op_m1, g.findOpnd(3), 1, false)); + op_const_5.setConstant(0); + assert(solver.demandProve(&op_m1, g.findOpnd(3), 1, false)); + op_const_5.setConstant(-1); + assert(!solver.demandProve(&op_m1, g.findOpnd(3), 1, false)); + op_const_5.setConstant(5); + + //logfile << " lower_testSimpleIGraph: OK" << std::endl; + //g.printDotFile(std::cout); +} + +/* + * for(i = 0; i < A.length; i++) { + * for (j = 0; j < i; j++) { + * check(j < A.length); + * } + * } + * i0 = 0 + * for1: + * i1 = phi(i0, i3) + * if (i1 < A.length) { + * i2 = pi(i1) + * j0 = 0 + * for2: + * j1 = phi(j0, j3) + * if (j1 < i2) { + * j2 = pi(j1) + * __check(j2 < A.length) + * j3 = j2 + 1 + * goto for2 + * } + * i3 = i2 + 1 + * goto for1 + * } + * 0 -(0)-> i0 -(0)-> i1(phi) -(0)-> i2 -(1)-> i3 -(0)-> i1 (phi) + * A.length -(-1)-> i2 + * 0 -(0)-> j0 -(0)-> j1(phi) -(0)-> j2 -(1)-> j3 -(0)-> j1 (phi) + * i2 -(-1)-> j2 + * + * upper: prove(j2 - A.length <= -1) + * lower: prove(j2 - (-1) >= 1) + */ +void testDoubleCycleGraph() +{ + MemoryManager mm(1024, "testDoubleCycleGraph.MemoryManager"); + InequalityGraph g(mm); + ClassicAbcdSolver solver(g, mm); + + IOpnd i0(0), i1(1, true /*phi*/), i2(2), i3(3), + j0(10), j1(11, true /*phi*/), j2(12), j3(13), length(20); + assert(g.isEmpty()); + g.addOpnd(&i0); + g.addOpnd(&i1); + g.addOpnd(&i2); + g.addOpnd(&i3); + g.addOpnd(&j0); + g.addOpnd(&j1); + g.addOpnd(&j2); + g.addOpnd(&j3); + g.addOpnd(&length); + + IOpnd op_const_0(21, false, true /*constant*/); + op_const_0.setConstant(0); + g.addOpnd(&op_const_0); + + g.addEdge(21, 0, 0); + + g.addEdge(0, 1, 0); + g.addEdge(1, 2, 0); + g.addEdge(2, 3, 1); + g.addEdge(3, 1, 0); + g.addEdge(20, 2, -1); + g.addEdge(21, 10, 0); + g.addEdge(10, 11, 0); + g.addEdge(11, 12, 0); + g.addEdge(12, 13, 1); + g.addEdge(13, 11, 0); + g.addEdge(2, 12, -1); + + assert(solver.demandProve(g.findOpnd(20), g.findOpnd(12), -1, true)); + //logfile << " testDoubleCycleGraph: OK" << std::endl; + + IOpnd op_m1(6, false /* phi */, true /* constant */); + op_m1.setConstant(-1); + g.addOpnd(&op_m1); + + assert(solver.demandProve(&op_m1, g.findOpnd(12), 1, false)); + //logfile << " lower_testDoubleCycleGraph: OK" << std::endl; + //g.printDotFile(std::cout); +} + +/* + * limit = A.length + * st = -1 + * while ( st < limit ) { + * st++ + * limit-- + * for (j = st; j < limit; j++) { + * check(limit >= 0) // should *not* be removable (amplifying) + * check(limit - j >= 0) + * check(j < A.length) + * t = j + 1; + * check(t < A.length) + * } + * } + * + * limit0 = A.length // 00 + * st0 = -1 // 10 + * while: + * limit1 = phi(limit0, limit3) // 01 + * st1 = phi(st0, st3) // 11 + * if ( st1 < limit1 ) { + * st2 = pi(st1) // 12 + * limit2 = pi(limit1) // 02 + * st3 = st2 + 1 // 13 + * limit3 = limit2 - 1 // 03 + * j0 = st3 // 20 + * for: + * j1 = phi(j0, j4) // 21 + * if ( j1 < limit3 ) { + * j2 = pi(j1) // 22 + * limit4 = pi(limit3) // 04 + * __check(j2 < A.length) //(22 < 55) + * __check(limit4 >= 0) + * j3 = pi(j2) // 23 + * __check(limit2 - j3 >= 0) + * t0 = j3 + 1 // 30 + * __check(t0 < A.length) //(30 < 55) + * t1 = pi(t0) // 31 + * j4 = j3 + 1 // 24 + * goto for + * } + * goto while + * } + */ +void testPaperIGraph() +{ + MemoryManager mm(1024, "testPaperIGraph.MemoryManager"); + InequalityGraph g(mm); + ClassicAbcdSolver solver(g, mm); + + assert(g.isEmpty()); + IOpnd minus_1(66, false /* phi */, true /*constant*/); + minus_1.setConstant(-1); + IOpnd length(55); // A.length + + IOpnd limit0(00), st0(10), limit1(01, true /*phi*/), st1(11, true /*phi*/), + st2(12), limit2(02), st3(13), limit3(03), j0(20), + j1(21, true /*phi*/), j2(22), limit4(04), j3(23), t0(30), t1(31), + j4(24); + + g.addOpnd(&limit0); g.addOpnd(&limit1); g.addOpnd(&limit2); + g.addOpnd(&limit3); g.addOpnd(&limit4); + g.addOpnd(&st0); g.addOpnd(&st1); g.addOpnd(&st2); g.addOpnd(&st3); + g.addOpnd(&j0); g.addOpnd(&j1); g.addOpnd(&j2); g.addOpnd(&j3); + g.addOpnd(&j4); + g.addOpnd(&t0); g.addOpnd(&t1); + + g.addEdge(&minus_1, &st0, 0); + g.addEdge(&st0, &st1, 0); + g.addEdge(&st1, &st2, 0); + g.addEdge(&st2, &st3, 1); + g.addEdge(&st3, &st1, 0); + g.addEdge(&st3, &j0, 0); + g.addEdge(&limit2, &st2, -1); + g.addEdge(&length, &limit0, 0); + g.addEdge(&limit0, &limit1, 0); + g.addEdge(&limit1, &limit2, 0); + g.addEdge(&limit2, &limit3, -1); + g.addEdge(&limit3, &limit1, 0); + g.addEdge(&limit3, &limit4, 0); + g.addEdge(&limit4, &j2, -1); + g.addEdge(&j0, &j1, 0); + g.addEdge(&j1, &j2, 0); + g.addEdge(&j2, &j3, 0); + g.addEdge(&j3, &j4, 1); + g.addEdge(&j4, &j1, 0); + g.addEdge(&j3, &t0, 1); + g.addEdge(&length, &j3, -1); + g.addEdge(&t0, &t1, 0); + + assert(solver.demandProve(&length, &j2, -1, true)); + assert(solver.demandProve(&length, &t0, -1, true)); + //logfile << " testPaperIGraph: OK" << std::endl; + + assert(!solver.demandProve(&minus_1, &limit4, 1, false)); + + assert(solver.demandProve(&limit2, &j3, 0, false)); + //logfile << " lower_testPaperIGraph: OK" << std::endl; + //g.printDotFile(std::cout); +} + +void printExampleGraph() +{ + uint32 opnd_id = 0; + IOpnd op0(opnd_id++), op1(opnd_id++, true), op2(opnd_id++, true, true); + + op2.setConstant(25); + MemoryManager mm(1024, "printExampleGraph.MemoryManager"); + InequalityGraph graph(mm); + graph.addOpnd(&op0); + graph.addOpnd(&op1); + graph.addOpnd(&op2); + graph.addEdge(0, 1, 3); + graph.addEdge(1, 2, -3); + graph.addEdge(2, 0, 1); + graph.printDotFile(std::cout); +} + +void testMemoizedDistances() +{ + MemoryManager mm(1024, "testMemoizedDistances.MemoryManager"); + BoundState bs(true); + InequalityGraph graph(mm); + BoundAllocator b_alloc(mm); + MemoizedDistances mem_distances(b_alloc); + IOpnd op0(0), op1(1), op2(2); + Bound bnd1(-1, bs), bnd2(5, bs), bnd3(10, bs), bndXX(5, bs); + + assert(!mem_distances.hasLeqBoundResult(&op0, &bnd1)); + mem_distances.updateLeqBound(&op0, &bnd2, Reduced); + mem_distances.updateLeqBound(&op0, &bnd2, False); + mem_distances.updateLeqBound(&op0, &bnd2, True); + assert(mem_distances.getLeqBoundResult(&op0, &bnd2) == True); +} + +/* + * for(i = INT_MAX; i < A.length; i+= 25) { + * check(-1 < i); + * } + * + * i0 = INT_MAX + * for: + * i1 = phi(i0, i2) + * if (i1 < A.length) { + * i2 = pi(i1) + * __check(i2 > -1); + * ... + * i3 = i2 + 1; + * goto for + * } + * + * INT_MAX -(0)-> i0 -(0)-> i1(phi) + * i1(phi) -(0)-> i2 -(1)-> i3 -(0)-> i1(phi) + * A.length -(-1)-> i2 + * + * lower: prove(i2 - (0) >= 0) + * + * ----------------------------------------- + * for(i = 25; i < A.length; i+= INT_MAX) { + * check(0 <= i); + * } + */ +void testOverflow() +{ + MemoryManager mm(1024, "testOverflow.MemoryManager"); + InequalityGraph g(mm); + ClassicAbcdSolver solver(g, mm); + + assert(g.isEmpty()); + IOpnd i0(00), i1(01, true /*phi */), i2(02), i3(03), + intmax(20, false /* phi */, true /* constant */), + zero(22, false /* phi */, true /* constant */), + length(21); + + intmax.setConstant(INT_MAX); + zero.setConstant(0); + g.addOpnd(&zero); + g.addOpnd(&i0); + g.addOpnd(&i1); + g.addOpnd(&i2); + g.addOpnd(&i3); + g.addOpnd(&intmax); + g.addOpnd(&length); + + g.addEdge(&intmax, &i0, 0); + g.addEdge(&i0, &i1, 0); + g.addEdge(&i1, &i2, 0); + g.addEdge(&i2, &i3, 1); + g.addEdge(&i3, &i1, 0); + g.addEdge(&length, &i2, -1); + + assert(!solver.demandProve(&zero, &i2, 0, false)); + // well, array size is too big + //g.printDotFile(std::cout); + + intmax.setConstant(25); + (*g.getOutEdges(&i2).begin())->setLength(INT_MAX - 5); + //g.printDotFile(std::cout); + assert(!solver.demandProve(&zero, &i2, 0, false)); + //logfile << " testOverflow: OK" << std::endl; +} + +//------------------------------------------------------------------------------ + +int classic_abcd_test_main() +{ + std::cout << "running ABCD self-tests" << std::endl; + testMemoizedDistances(); + testSimpleIGraph(); + testDoubleCycleGraph(); + testPaperIGraph(); + + // OK, testOverflow should fail + //testOverflow(); + std::cout << "ABCD self-tests PASSED" << std::endl; + + return 0; +} + +} //namespace Jitrino + Index: vm/jitrino/src/optimizer/abcd/abcd.cpp =================================================================== --- vm/jitrino/src/optimizer/abcd/abcd.cpp (revision 532324) +++ vm/jitrino/src/optimizer/abcd/abcd.cpp (working copy) @@ -43,16 +43,10 @@ namespace Jitrino { //Array Bounds Check Elimination -class ABCDPass: public SessionAction { -public: - void run(); -}; +DEFINE_SESSION_ACTION(ABCDPass, abcd, "ABCD: eliminating Array Bounds Check on Demand"); -ActionFactory _abcd("abcd"); - void -ABCDPass::run() { - IRManager& irm = *getCompilationContext()->getHIRManager(); +ABCDPass::_run(IRManager &irm) { OptPass::splitCriticalEdges(irm); OptPass::computeDominators(irm); Abcd abcd(irm, irm.getNestedMemoryManager(), *irm.getDominatorTree()); @@ -94,688 +88,46 @@ 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), -ineqGraph(0), -dominators(dom0), -piMap(0), -nextPiOpndId(0), -solver(0), -canEliminate(memManager), -canEliminateUB(memManager), -canEliminateLB(memManager), -tauUnsafe(0), -tauSafe(0), -blockTauPoint(0), -lastTauPointBlock(0), -blockTauEdge(0), -lastTauEdgeBlock(0), -flags(*irManager.getOptimizerFlags().abcdFlags) -{ -}; +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::isEnabled()) { + 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"); } - insertPiNodes(); // add a pi node after each test on a variable - renamePiVariables(); // rename all uses to use the inserted Pi variables + insertPi.insertPi(); - // WARNING: Pi var live ranges may overlap the original - // var live ranges here - - if (Log::isEnabled()) { - Log::out() << "IR after Pi insertion" << std::endl; - FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), irManager.getMethodDesc()); - FlowGraph::printDotFile(irManager.getFlowGraph(), irManager.getMethodDesc(), "withpi"); - } - removeRedundantBoundsChecks(); - if (Log::isEnabled() || Log::isEnabled()) { + if ( Log::isEnabled() ) { Log::out() << "IR after removeRedundantBoundsChecks" << std::endl; FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), irManager.getMethodDesc()); } - removePiNodes(); - if (Log::isEnabled()) { + removePiEliminateChecks(); + if ( Log::isEnabled() ) { Log::out() << "IR after ABCD pass" << std::endl; FlowGraph::printHIR(Log::out(), irManager.getFlowGraph(), irManager.getMethodDesc()); } } -// a DomWalker, to be applied pre-order -class InsertPiWalker { - Abcd *thePass; -public: - void applyToDominatorNode(DominatorNode *domNode) { thePass->insertPiNodes(domNode->getNode()); }; - void enterScope() {}; // is called before a node and its children are processed - void exitScope() {}; // is called after node and children are processed - InsertPiWalker(Abcd *thePass0) : thePass(thePass0) {}; -}; - - -// Inserts Pi nodes. -// WARNING: Pi var live ranges may overlap the original var live ranges -// since we don't bother to add Phi nodes and rename subsequent uses of var. -void Abcd::insertPiNodes() -{ - // Add a Pi node on each branch after - // a test which tells something about a variable. - // For now, don't bother with Exception edges. - - InsertPiWalker insertPiWalker(this); - DomTreeWalk(dominators, insertPiWalker, mm); // pre-order -} - -PiOpnd *Abcd::getNewDestOpnd(Node *block, - Opnd *org) -{ - PiOpnd *tmpOp = irManager.getOpndManager().createPiOpnd(org); - return tmpOp; -} - -// a DomWalker, to be applied forwards/preorder -class RenamePiWalker { - Abcd *thePass; - MemoryManager &localMemManager; - SparseOpndMap* &piMap; - int sizeEstimate; -public: - void applyToDominatorNode(DominatorNode *domNode) { thePass->renamePiVariables(domNode->getNode()); }; - - void enterScope() { - if (!piMap) piMap = new (localMemManager) SparseOpndMap(sizeEstimate, - localMemManager, 1, 4, 7); - piMap->enter_scope(); }; - void exitScope() { piMap->exit_scope(); }; - RenamePiWalker(Abcd *thePass0, - MemoryManager &localMM, - SparseOpndMap* &piMap0, - int sizeEstimate0) - : thePass(thePass0), localMemManager(localMM), piMap(piMap0), - sizeEstimate(sizeEstimate0) - { - }; -}; - -// Renames variables for which we have Pi nodes. -void Abcd::renamePiVariables() -{ - MethodDesc &methodDesc= irManager.getMethodDesc(); - uint32 byteCodeSize = methodDesc.getByteCodeSize(); - MemoryManager localMemManager(byteCodeSize*16, - "Abcd::renamePiNodes"); - - RenamePiWalker theWalker(this, localMemManager, piMap, byteCodeSize); - DomTreeWalk(dominators, theWalker, - localMemManager); -} - - -void Abcd::insertPiNodeForOpnd(Node *block, - Opnd *org, - const PiCondition &cond, - Opnd *tauOpnd) -{ - if (ConstantFolder::isConstant(org)) { - if (Log::isEnabled()) { - Log::out() << "Skipping Pi Node for opnd "; - org->print(Log::out()); - Log::out() << " under condition "; - cond.print(Log::out()); - Log::out() << " since it is constant" << std::endl; - } - } else { - - PiOpnd *piOpnd = irManager.getOpndManager().createPiOpnd(org); - Inst *headInst = (Inst*)block->getFirstInst(); - PiCondition *condPtr = new (irManager.getMemoryManager()) PiCondition(cond); - if (tauOpnd == 0) - tauOpnd = getBlockTauEdge(block); - Inst *newInst = irManager.getInstFactory().makeTauPi(piOpnd, org, tauOpnd, condPtr); - Inst *place = headInst->getNextInst(); - while (place != NULL) { - Opcode opc = place->getOpcode(); - if ((opc != Op_Phi) && (opc != Op_TauPoint) && (opc != Op_TauEdge)) - break; - place = place->getNextInst(); - } - if (Log::isEnabled()) { - Log::out() << "Inserting Pi Node for opnd "; - org->print(Log::out()); - Log::out() << " under condition "; - cond.print(Log::out()); - if (place!=NULL) { - Log::out() << " just before inst "; - place->print(Log::out()); - } - Log::out() << std::endl; - } - if (place != NULL) { - newInst->insertBefore(place); - } else { - block->appendInst(newInst); - } - } -} - -void Abcd::insertPiNodeForOpndAndAliases(Node *block, - Opnd *org, - const PiCondition &cond, - Opnd *tauOpnd) -{ - if (flags.useAliases) { - if (Log::isEnabled()) { - Log::out() << "Inserting Pi Node for opnd "; - org->print(Log::out()); - Log::out() << " and its aliases"; - Log::out() << " under condition "; - cond.print(Log::out()); - Log::out() << std::endl; - } - AbcdAliases aliases(mm); - // check for aliases - insertPiNodeForOpnd(block, org, cond, tauOpnd); - if (getAliases(org, &aliases, 0)) { - if (Log::isEnabled()) { - Log::out() << "Has aliases "; - AbcdAliasesSet::iterator iter = aliases.theSet.begin(); - AbcdAliasesSet::iterator end = aliases.theSet.end(); - for ( ; iter != end; iter++) { - PiBound alias = *iter; - alias.print(Log::out()); - Log::out() << " "; - } - Log::out() << std::endl; - } - AbcdAliasesSet::iterator iter = aliases.theSet.begin(); - AbcdAliasesSet::iterator end = aliases.theSet.end(); - const PiBound &lb = cond.getLb(); - const PiBound &ub = cond.getUb(); - for ( ; iter != end; iter++) { - PiBound alias = *iter; - PiBound inverted = alias.invert(org); // org - c - // plug-in lb and ub into inverted, yields bounds: - // [ lb - c, ub - c ] - PiCondition renamedCondition(PiBound(inverted, org, lb), - PiBound(inverted, org, ub)); - insertPiNodeForOpnd(block, alias.getVar().the_var, - renamedCondition, tauOpnd); - } - } - } else { - insertPiNodeForOpnd(block, org, cond, tauOpnd); - } -} - -static ComparisonModifier -negateComparison(ComparisonModifier mod) -{ - switch (mod) { - case Cmp_GT: return Cmp_GTE; - case Cmp_GT_Un: return Cmp_GTE_Un; - case Cmp_GTE: return Cmp_GT; - case Cmp_GTE_Un: return Cmp_GT_Un; - case Cmp_EQ: return Cmp_EQ; - case Cmp_NE_Un: return Cmp_NE_Un; - default: - assert(0); return mod; - } -} - -static const char * -printableComparison(ComparisonModifier mod) -{ - switch (mod) { - case Cmp_GT: return "Cmp_GT"; - case Cmp_GT_Un: return "Cmp_GT_Un"; - case Cmp_GTE: return "Cmp_GTE"; - case Cmp_GTE_Un: return "Cmp_GTE_Un"; - case Cmp_EQ: return "Cmp_EQ"; - case Cmp_NE_Un: return "Cmp_NE_Un"; - default: - assert(0); return ""; - } -} - -static Type::Tag -unsignType(Type::Tag typetag) -{ - switch (typetag) { - case Type::IntPtr: return Type::UIntPtr; - case Type::Int8: return Type::UInt8; - case Type::Int16: return Type::UInt16; - case Type::Int32: return Type::UInt32; - case Type::Int64: return Type::UInt64; - default: - assert(0); return typetag; - } -} - -void Abcd::insertPiNodesForComparison(Node *block, - ComparisonModifier mod, - const PiCondition &bounds, - Opnd *op, - bool swap_operands, - bool negate_comparison) -{ - if (Log::isEnabled()) { - Log::out() << "insertPiNodesForComparison(..., "; - Log::out() << printableComparison(mod); - Log::out() << ", "; - bounds.print(Log::out()); - Log::out() << ", "; - op->print(Log::out()); - Log::out() << ", "; - Log::out() << (swap_operands ? "true" : "false"); - Log::out() << (negate_comparison ? "true" : "false"); - Log::out() << std::endl; - } - - PiCondition bounds0 = bounds; - // add a Pi node for immediate value. - if (negate_comparison) { - mod = negateComparison(mod); - swap_operands = !swap_operands; - if (Log::isEnabled()) { - Log::out() << "insertPiNodesForComparison: negating comparison to " ; - Log::out() << printableComparison(mod); - Log::out() << std::endl; - } - } - switch (mod) { - case Cmp_EQ: - if (negate_comparison) - insertPiNodeForOpndAndAliases(block, op, bounds0); - else { - if (Log::isEnabled()) { - Log::out() << "insertPiNodesForComparison: cannot represent ! Cmp_EQ" << std::endl; - } - } - // we can't represent the other case - break; - case Cmp_NE_Un: - if (!negate_comparison) - insertPiNodeForOpndAndAliases(block, op, bounds0); - else { - if (Log::isEnabled()) { - Log::out() << "insertPiNodesForComparison: cannot represent Cmp_NE_Un" << std::endl; - } - } - // we can't represent the other case - break; - case Cmp_GT_Un: - if (swap_operands) { // op > bounds, only a lower bound on op - Type::Tag optag = op->getType()->tag; - if (!Type::isUnsignedInteger(optag)) { - // 1 is a lower bound on int op - PiCondition oneBounds(PiBound(optag, (int64)1), - PiBound(optag, (int64)1)); - PiCondition oneLowerBound(oneBounds.only_lower_bound()); - insertPiNodeForOpndAndAliases(block, op, oneLowerBound); - } else { - // we can be more precise for an unsigned op - bounds0 = bounds0.cast(unsignType(bounds0.getType())); - PiCondition bounds1a(bounds0.only_lower_bound()); - PiCondition bounds1(bounds1a.add((int64)1)); - if (! bounds1.getLb().isUnknown()) - insertPiNodeForOpndAndAliases(block, op, bounds1); - else { - if (Log::isEnabled()) { - Log::out() << "insertPiNodesForComparison(1): bounds1 LB is Unknown;\n\tbounds is "; - bounds.print(Log::out()); - Log::out() << "\n\tbounds0 is "; - bounds0.print(Log::out()); - Log::out() << "\n\tbounds1a is "; - bounds1a.print(Log::out()); - Log::out() << "\n\tbounds1 is "; - bounds1.print(Log::out()); - Log::out() << std::endl; - } - } - } - } else { // bounds > op, only an upper bound on op - Type::Tag optag = op->getType()->tag; - if (Type::isUnsignedInteger(optag)) { - // for an unsigned upper bound, we're ok - bounds0 = bounds0.cast(unsignType(bounds0.getType())); - PiCondition bounds1(bounds0.only_upper_bound().add((int64)-1)); - if (! bounds1.getUb().isUnknown()) - insertPiNodeForOpndAndAliases(block, op, bounds1); - else { - if (Log::isEnabled()) { - Log::out() << "insertPiNodesForComparison(2): bounds1 LB is Unknown;\n\tbounds is "; - bounds.print(Log::out()); - Log::out() << "\n\tbounds0 is "; - bounds0.print(Log::out()); - Log::out() << "\n\tbounds1 is "; - bounds1.print(Log::out()); - Log::out() << std::endl; - } - } - } else { - // otherwise, we know nothing unless bound is a small constant - PiCondition bounds1(bounds0.only_upper_bound().add((int64)-1)); - if (bounds0.getUb().isConstant()) { - int64 ubConst = bounds1.getUb().getConst(); - if (((optag == Type::Int32) && - ((ubConst&0xffffffff) <= 0x7ffffff) && - ((ubConst&0xffffffff) >= 0)) || - ((optag == Type::Int64) && - ((ubConst <= 0x7ffffff) && - (ubConst >= 0)))) { - insertPiNodeForOpndAndAliases(block, op, bounds1); - } else { - if (Log::isEnabled()) { - Log::out() << "insertPiNodesForComparison(2): bounds1 LB is Unknown;\n\tbounds is "; - bounds.print(Log::out()); - Log::out() << "\n\tbounds0 is "; - bounds0.print(Log::out()); - Log::out() << "\n\tbounds1 is "; - bounds1.print(Log::out()); - Log::out() << std::endl; - } - } - } - } - } - break; - case Cmp_GT: - if (swap_operands) { // op > bounds, only a lower bound on op - PiCondition bounds1a(bounds0.only_lower_bound()); - PiCondition bounds1(bounds1a.add((int64)1)); - if (! bounds1.getLb().isUnknown()) - insertPiNodeForOpndAndAliases(block, op, bounds1); - else { - if (Log::isEnabled()) { - Log::out() << "insertPiNodesForComparison(1): bounds1 LB is Unknown;\n\tbounds is "; - bounds.print(Log::out()); - Log::out() << "\n\tbounds0 is "; - bounds0.print(Log::out()); - Log::out() << "\n\tbounds1a is "; - bounds1a.print(Log::out()); - Log::out() << "\n\tbounds1 is "; - bounds1.print(Log::out()); - Log::out() << std::endl; - } - } - } else { // bounds > op, only an upper bound on op - PiCondition bounds1(bounds0.only_upper_bound().add((int64)-1)); - if (! bounds1.getUb().isUnknown()) - insertPiNodeForOpndAndAliases(block, op, bounds1); - else { - if (Log::isEnabled()) { - Log::out() << "insertPiNodesForComparison(2): bounds1 LB is Unknown;\n\tbounds is "; - bounds.print(Log::out()); - Log::out() << "\n\tbounds0 is "; - bounds0.print(Log::out()); - Log::out() << "\n\tbounds1 is "; - bounds1.print(Log::out()); - Log::out() << std::endl; - } - } - } - break; - case Cmp_GTE_Un: - if (swap_operands) { // op >= bounds, only lower bound on op - Type::Tag optag = op->getType()->tag; - if (!Type::isUnsignedInteger(optag)) { - // 0 is a lower bound on an int op - PiCondition zeroBounds(PiBound(optag, (int64)0), - PiBound(optag, (int64)0)); - PiCondition zeroLowerBound(zeroBounds.only_lower_bound()); - insertPiNodeForOpndAndAliases(block, op, zeroLowerBound); - } else { - // we can be more precise for an unsigned op lb - bounds0 = bounds0.cast(unsignType(bounds0.getType())); - if (! bounds0.getLb().isUnknown()) { - insertPiNodeForOpndAndAliases(block, op, - bounds0.only_lower_bound()); - } else { - if (Log::isEnabled()) { - Log::out() << "insertPiNodesForComparison(3): bounds0 LB is Unknown;\n\tbounds is "; - bounds.print(Log::out()); - Log::out() << "\n\tbounds0 is "; - bounds0.print(Log::out()); - Log::out() << std::endl; - } - } - } - } else { // bounds >= op, only upper bound on op - Type::Tag optag = op->getType()->tag; - if (Type::isUnsignedInteger(optag)) { - // unsigned ub on unsigned op - bounds0 = bounds0.cast(unsignType(bounds0.getType())); - if (! bounds0.getUb().isUnknown()) - insertPiNodeForOpndAndAliases(block, op, - bounds0.only_upper_bound()); - else { - if (Log::isEnabled()) { - Log::out() << "insertPiNodesForComparison(4): bounds0 UB is Unknown;\n\tbounds is "; - bounds.print(Log::out()); - Log::out() << "\n\tbounds0 is "; - bounds0.print(Log::out()); - Log::out() << std::endl; - } - } - } else { - // otherwise, we know nothing unless bound is a small constant - if (bounds0.getUb().isConstant()) { - int64 ubConst = bounds0.getUb().getConst(); - if (((optag == Type::Int32) && - ((ubConst&0xffffffff) <= 0x7ffffff) && - ((ubConst&0xffffffff) >= 0)) || - ((optag == Type::Int64) && - ((ubConst <= 0x7ffffff) && - (ubConst >= 0)))) { - insertPiNodeForOpndAndAliases(block, op, bounds0); - } else { - if (Log::isEnabled()) { - Log::out() << "insertPiNodesForComparison(2): bounds0 LB is Unknown;\n\tbounds is "; - bounds.print(Log::out()); - Log::out() << "\n\tbounds0 is "; - bounds0.print(Log::out()); - Log::out() << std::endl; - } - } - } - } - } - break; - case Cmp_GTE: - if (swap_operands) { // op >= bounds, only lower bound on op - if (! bounds0.getLb().isUnknown()) { - insertPiNodeForOpndAndAliases(block, op, - bounds0.only_lower_bound()); - } else { - if (Log::isEnabled()) { - Log::out() << "insertPiNodesForComparison(3): bounds0 LB is Unknown;\n\tbounds is "; - bounds.print(Log::out()); - Log::out() << "\n\tbounds0 is "; - bounds0.print(Log::out()); - Log::out() << std::endl; - } - } - } else { // bounds >= op, only upper bound on op - if (! bounds0.getUb().isUnknown()) - insertPiNodeForOpndAndAliases(block, op, - bounds0.only_upper_bound()); - else { - if (Log::isEnabled()) { - Log::out() << "insertPiNodesForComparison(4): bounds0 UB is Unknown;\n\tbounds is "; - bounds.print(Log::out()); - Log::out() << "\n\tbounds0 is "; - bounds0.print(Log::out()); - Log::out() << std::endl; - } - } - } - break; - case Cmp_Zero: - case Cmp_NonZero: - case Cmp_Mask: - assert(0); - break; - default: - assert(false); - break; - } -} - -// Insert Pi Nodes for any variables occurring in the branch test -// -// Since we're examining the test anyway, let's figure out the conditions -// here, too, so we don't have to duplicate any code. Note that this -// condition may already be in terms of Pi variables from the predecessor -// block, since -// -- predecessor dominates this block -// -- we are traversing blocks in a dominator-tree preorder -// so we must have already visited the predecessor. -// -// We also must add the new Pi variable to our map. -// -void Abcd::insertPiNodesForBranch(Node *block, BranchInst *branchi, - Edge::Kind kind) // True or False only -{ - Type::Tag instTypeTag = branchi->getType(); - if (!Type::isInteger(instTypeTag)) - return; - ComparisonModifier mod = branchi->getComparisonModifier(); - if (branchi->getNumSrcOperands() == 1) { - Opnd *op0 = branchi->getSrc(0); - PiCondition zeroBounds(PiBound(instTypeTag, (int64)0), - PiBound(instTypeTag, (int64)0)); - switch (mod) { - case Cmp_Zero: - insertPiNodesForComparison(block, - Cmp_EQ, - zeroBounds, - op0, - false, - (kind == Edge::Kind_False)); // negate if false edge - break; - case Cmp_NonZero: - insertPiNodesForComparison(block, - Cmp_EQ, // use EQ - zeroBounds, - op0, - false, - (kind == Edge::Kind_True)); // but negate if true edge - break; - default: - break; - } - } else { - Opnd *op0 = branchi->getSrc(0); - Opnd *op1 = branchi->getSrc(1); - assert(branchi->getNumSrcOperands() == 2); - PiCondition bounds0(op0->getType()->tag, op0); - PiCondition bounds1(op1->getType()->tag, op1); - if (!bounds0.isUnknown()) { - insertPiNodesForComparison(block, - mod, - bounds0, - op1, - false, - (kind == Edge::Kind_False)); // negate for false edge - } - if (!bounds1.isUnknown()) { - insertPiNodesForComparison(block, - mod, - bounds1, - op0, - true, - (kind == Edge::Kind_False)); // negate for false edge - } - } -} - -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; -} - -SsaTmpOpnd* Abcd::getBlockTauEdge(Node *block) { - if ((lastTauEdgeBlock == block) && blockTauEdge) return blockTauEdge; - Inst *firstInst = (Inst*)block->getFirstInst(); - Inst *inst = firstInst->getNextInst(); - for (; inst != NULL; inst = inst->getNextInst()) { - if (inst->getOpcode() == Op_TauEdge) { - blockTauEdge = inst->getDst()->asSsaTmpOpnd(); - assert(blockTauEdge); - lastTauEdgeBlock = block; - return blockTauEdge; - } - } - for (inst = firstInst->getNextInst(); inst != NULL; inst = inst->getNextInst()) { - if ((inst->getOpcode() != Op_Phi) && (inst->getOpcode() != Op_TauPoint)) { - break; // insert before inst. - } - } - // no non-phis, insert before inst; - TypeManager &tm = irManager.getTypeManager(); - SsaTmpOpnd *tauOpnd = irManager.getOpndManager().createSsaTmpOpnd(tm.getTauType()); - Inst* tauEdge = irManager.getInstFactory().makeTauEdge(tauOpnd); - if(Log::isEnabled()) { - Log::out() << "Inserting tauEdge inst "; - tauEdge->print(Log::out()); - if (inst!=NULL) { - Log::out() << " before inst "; - inst->print(Log::out()); - } - Log::out() << std::endl; - } - if (inst != NULL) { - tauEdge->insertBefore(inst); - } else { - block->appendInst(tauEdge); - } - blockTauEdge = tauOpnd; - lastTauEdgeBlock = block; - return tauOpnd; -} - SsaTmpOpnd* Abcd::getTauUnsafe() { if (!tauUnsafe) { Node *head = irManager.getFlowGraph().getEntryNode(); @@ -868,326 +220,6 @@ return tauSafe; }; -void Abcd::insertPiNodesForUnexceptionalPEI(Node *block, Inst *lasti) -{ - switch (lasti->getOpcode()) { - case Op_TauCheckBounds: - { - // the number of newarray elements must be >= 0. - assert(lasti->getNumSrcOperands() == 2); - Opnd *idxOp = lasti->getSrc(1); - Opnd *boundsOp = lasti->getSrc(0); - - if (Log::isEnabled()) { - Log::out() << "Adding info about CheckBounds instruction "; - lasti->print(Log::out()); - Log::out() << std::endl; - } - Type::Tag typetag = idxOp->getType()->tag; - PiBound lb(typetag, int64(0)); - PiBound ub(typetag, 1, VarBound(boundsOp),int64(-1)); - PiCondition bounds0(lb, ub); - Opnd *tauOpnd = lasti->getDst(); // use the checkbounds tau - insertPiNodeForOpndAndAliases(block, idxOp, bounds0, tauOpnd); - - PiBound idxBound(typetag, 1, VarBound(idxOp), int64(1)); - PiCondition bounds1(idxBound, PiBound(typetag, false)); - insertPiNodeForOpndAndAliases(block, boundsOp, bounds1, tauOpnd); - } - break; - case Op_NewArray: - { - // the number of newarray elements must be in [0, MAXINT32] - assert(lasti->getNumSrcOperands() == 1); - Opnd *numElemOpnd = lasti->getSrc(0); - if (Log::isEnabled()) { - Log::out() << "Adding info about NewArray instruction "; - lasti->print(Log::out()); - Log::out() << std::endl; - } - Opnd *tauOpnd = getBlockTauEdge(block); // need to use a TauEdge - PiCondition bounds0(PiBound(numElemOpnd->getType()->tag, int64(0)), - PiBound(numElemOpnd->getType()->tag, int64(0x7fffffff))); - insertPiNodeForOpndAndAliases(block, numElemOpnd, bounds0, tauOpnd); - } - break; - case Op_NewMultiArray: - { - // the number of newarray dimensions must be >= 1. - uint32 numOpnds = lasti->getNumSrcOperands(); - assert(numOpnds >= 1); - StlSet done(mm); - if (Log::isEnabled()) { - Log::out() << "Adding info about NewMultiArray instruction "; - lasti->print(Log::out()); - Log::out() << std::endl; - } - Opnd *tauOpnd = 0; - // the number of newarray elements must be in [0, MAXINT32] - for (uint32 opndNum = 0; opndNum < numOpnds; opndNum++) { - Opnd *thisOpnd = lasti->getSrc(opndNum); - if (!done.has(thisOpnd)) { - done.insert(thisOpnd); - PiCondition bounds0(PiBound(thisOpnd->getType()->tag, int64(0)), - PiBound(thisOpnd->getType()->tag, int64(0x7fffffff))); - if (!tauOpnd) tauOpnd = getBlockTauEdge(block); // must use a tauEdge - insertPiNodeForOpndAndAliases(block, thisOpnd, bounds0, tauOpnd); - } - } - } - break; - default: - break; - } -} - -// Add a Pi node in the node if it is after -// a test which tells something about a variable. -// For now, don't bother with Exception edges. -void Abcd::insertPiNodes(Node *block) -{ - Edge *domEdge = 0; - - // see if there is a predecessor block idom such that - // (1) idom dominates this one - // (2) this block dominates all other predecessors - // (3) idom has multiple out-edges - // (4) idom has only 1 edge to this node - - // (1a) if a predecessor dominates it must be idom - Node *idom = dominators.getIdom(block); - - // (3) must exist and have multiple out-edges - if ((idom == NULL) || (idom->hasOnlyOneSuccEdge())) { - return; - } - - if (Log::isEnabled()) { - Log::out() << "Checking block " << (int)block->getId() << " with idom " - << (int) idom->getId() << std::endl; - } - - if (block->hasOnlyOnePredEdge()) { - // must be from idom -- (1b) - // satisfies (2) trivially - domEdge = *(block->getInEdges().begin()); - } else { - // check (1b) and (2) - const Edges &inedges = block->getInEdges(); - typedef Edges::const_iterator EdgeIter; - EdgeIter eLast = inedges.end(); - for (EdgeIter eIter = inedges.begin(); eIter != eLast; eIter++) { - Edge *inEdge = *eIter; - Node *predBlock = inEdge->getSourceNode(); - if (predBlock == idom) { - // (1b) found idom - if (domEdge) { - // failed (4): idom found on more than one incoming edge - return; - } - domEdge = inEdge; - } else if (! dominators.dominates(block, predBlock)) { - // failed (2) - return; - } - } - } - - if (domEdge) { - Edge *inEdge = domEdge; - Node *predBlock = idom; - if (Log::isEnabled()) { - Log::out() << "Checking branch for " << (int)block->getId() << " with idom " - << (int) idom->getId() << std::endl; - } - if (!predBlock->hasOnlyOneSuccEdge()) { - Edge::Kind kind = inEdge->getKind(); - switch (kind) { - case Edge::Kind_True: - case Edge::Kind_False: - { - Inst* branchi1 = (Inst*)predBlock->getLastInst(); - assert(branchi1 != NULL); - BranchInst* branchi = branchi1->asBranchInst(); - if (branchi && branchi->isConditionalBranch()) { - insertPiNodesForBranch(block, branchi, kind); - } else { - return; - } - } - break; - - case Edge::Kind_Dispatch: - return; - - case Edge::Kind_Unconditional: - // Previous block must have a PEI - // since it had multiple out-edges. - // This is the unexceptional condition. - { - Inst* lasti = (Inst*)predBlock->getLastInst(); - assert(lasti != NULL); - insertPiNodesForUnexceptionalPEI(block, lasti); - } - // We could look for a bounds check in predecessor. - - // But: since now all useful PEIs have explicit results, - // they imply a Pi-like action. - break; - - case Edge::Kind_Catch: - break; - default: - break; - }; - } - } -} - -void Abcd::renamePiVariables(Node *block) -{ - // For each variable use in the block, check for a Pi version in - // the piTable. Since we are visiting in preorder over dominator - // tree dominator order, any found version will dominate this node. - - // we defer adding any new mappings for the Pi instructions here until - // we are past the Pi instructions - - // first process any pi nodes, just the RHSs - Inst* headInst = (Inst*)block->getFirstInst(); - for (int phase=0; phase < 2; ++phase) { - // phase 0: remap just Pi node source operands - // phase 1: add Pi remappings, remap source operands of other instructions - - for (Inst* inst = headInst->getNextInst(); inst != NULL; inst = inst->getNextInst()) { - - if (inst->getOpcode() == Op_TauPi) { - if (phase == 1) { - // add any Pi node destination to the map. - - Opnd *dstOpnd = inst->getDst(); - assert(dstOpnd->isPiOpnd()); - Opnd *orgOpnd = dstOpnd->asPiOpnd()->getOrg(); - if (flags.useAliases) { - if (orgOpnd->isSsaVarOpnd()) { - orgOpnd = orgOpnd->asSsaVarOpnd()->getVar(); - } - } - piMap->insert(orgOpnd, dstOpnd); - if (Log::isEnabled()) { - Log::out() << "adding remap for Pi of "; - orgOpnd->print(Log::out()); - Log::out() << " to "; - inst->getDst()->print(Log::out()); - Log::out() << std::endl; - } - - continue; // don't remap Pi sources; - } - } else { - if (phase == 0) { - // no more Pi instructions, we're done with phase 0. - break; - } - } - - // now process source operands - uint32 numOpnds = inst->getNumSrcOperands(); - for (uint32 i=0; igetSrc(i); - if (opnd->isPiOpnd()) - opnd = opnd->asPiOpnd()->getOrg(); - Opnd *foundOpnd = piMap->lookup(opnd); - if (foundOpnd) { - inst->setSrc(i,foundOpnd); - } - } - - if (inst->getOpcode() == Op_TauPi) { - // for a Pi, remap variables appearing in the condition as well - if (Log::isEnabled()) { - Log::out() << "remapping condition in "; - inst->print(Log::out()); - Log::out() << std::endl; - } - TauPiInst *thePiInst = inst->asTauPiInst(); - assert(thePiInst); - PiCondition *cond = thePiInst->cond; - if (Log::isEnabled()) { - Log::out() << " original condition is "; - cond->print(Log::out()); - Log::out() << std::endl; - } - Opnd *lbRemap = cond->getLb().getVar().the_var; - if (lbRemap) { - if (Log::isEnabled()) { - Log::out() << " has lbRemap="; - lbRemap->print(Log::out()); - Log::out() << std::endl; - } - if (lbRemap->isPiOpnd()) - lbRemap = lbRemap->asPiOpnd()->getOrg(); - Opnd *lbRemapTo = piMap->lookup(lbRemap); - if (lbRemapTo) { - if (Log::isEnabled()) { - Log::out() << "adding remap of lbRemap="; - lbRemap->print(Log::out()); - Log::out() << " to lbRemapTo="; - lbRemapTo->print(Log::out()); - Log::out() << " to condition "; - cond->print(Log::out()); - } - PiCondition remapped(*cond, lbRemap, lbRemapTo); - if (Log::isEnabled()) { - Log::out() << " YIELDS1 "; - remapped.print(Log::out()); - } - *cond = remapped; - if (Log::isEnabled()) { - Log::out() << " YIELDS "; - cond->print(Log::out()); - Log::out() << std::endl; - } - } - } - Opnd *ubRemap = cond->getUb().getVar().the_var; - if (ubRemap && (lbRemap != ubRemap)) { - if (Log::isEnabled()) { - Log::out() << " has ubRemap="; - ubRemap->print(Log::out()); - Log::out() << std::endl; - } - if (ubRemap->isPiOpnd()) - ubRemap = ubRemap->asPiOpnd()->getOrg(); - Opnd *ubRemapTo = piMap->lookup(ubRemap); - if (ubRemapTo) { - if (Log::isEnabled()) { - Log::out() << "adding remap of ubRemap="; - ubRemap->print(Log::out()); - Log::out() << " to ubRemapTo="; - ubRemapTo->print(Log::out()); - Log::out() << " to condition "; - cond->print(Log::out()); - } - PiCondition remapped(*cond, ubRemap, ubRemapTo); - if (Log::isEnabled()) { - Log::out() << " YIELDS1 "; - remapped.print(Log::out()); - } - *cond = remapped; - if (Log::isEnabled()) { - Log::out() << " YIELDS "; - cond->print(Log::out()); - Log::out() << std::endl; - } - } - } - } - } - - } -} - // an InstWalker class AbcdSolverWalker { AbcdSolver *theSolver; @@ -1200,7 +232,6 @@ void Abcd::removeRedundantBoundsChecks() { - assert(!solver); solver = new (mm) AbcdSolver(this); AbcdSolverWalker solveInst(solver); // to apply to each @@ -1211,163 +242,7 @@ solver = 0; } -// a ScopedDomNodeInstWalker, forward/preorder -class RemovePiWalker { - Abcd *thePass; - Node *block; -public: - void startNode(DominatorNode *domNode) { block = domNode->getNode(); }; - void applyToInst(Inst *i) { thePass->removePiNodes(block, i); }; - void finishNode(DominatorNode *domNode) { }; - void enterScope() { }; - void exitScope() { }; - RemovePiWalker(Abcd *thePass0) - : thePass(thePass0), block(0) // forward - { - }; -}; - - -void Abcd::removePiNodes() -{ - RemovePiWalker removePiWalker(this); - - typedef ScopedDomNodeInst2DomWalker - RemovePiDomWalker; - RemovePiDomWalker removePiDomWalker(removePiWalker); - - DomTreeWalk(dominators, removePiDomWalker, - mm); -} - -void Abcd::removePiNodes(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 { - uint32 numOpnds = inst->getNumSrcOperands(); - for (uint32 i=0; igetSrc(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(); - } - } - } -} - void Abcd::markInstToEliminate(Inst *i) { if (Log::isEnabled()) { @@ -1541,99 +416,6 @@ return true; } -Opnd *Abcd::getConstantOpnd(Opnd *opnd) -{ - if (ConstantFolder::isConstant(opnd)) { - return opnd; - } else { - return 0; - } -} - -bool Abcd::getAliases(Opnd *opnd, AbcdAliases *aliases, int64 addend) -{ - Inst *inst = opnd->getInst(); - switch (inst->getOpcode()) { - case Op_TauPi: - return getAliases(inst->getSrc(0), aliases, addend); - - case Op_Add: - { - Opnd *op0 = inst->getSrc(0); - Opnd *op1 = inst->getSrc(1); - Opnd *constOpnd0 = getConstantOpnd(op0); - Opnd *constOpnd1 = getConstantOpnd(op1); - if ((constOpnd0 || constOpnd1) && - (inst->getType() == Type::Int32)) { - // I assume we've done folding first - assert(!(constOpnd0 && constOpnd1)); - if (constOpnd1) { - // swap the operands; - constOpnd0 = constOpnd1; - op1 = op0; - } - // now constOpnd0 should be constant - // op1 is the non-constant operand - - Inst *inst0 = constOpnd0->getInst(); - assert(inst0); - ConstInst *cinst0 = inst0->asConstInst(); - assert(cinst0); - ConstInst::ConstValue cv = cinst0->getValue(); - int32 c = cv.i4; - int64 sumc = c + addend; - if (add_overflowed(sumc, c, addend)) { - return false; - } else { - VarBound vb(op1); - aliases->theSet.insert(PiBound(inst->getType(), 1, vb, sumc)); - getAliases(op1, aliases, sumc); - return true; - } - } - } - break; - case Op_Sub: - { - Opnd *constOpnd = getConstantOpnd(inst->getSrc(1)); - if (constOpnd && (inst->getType() == Type::Int32)) { - Opnd *op0 = inst->getSrc(0); - Opnd *op1 = constOpnd; - // now op1 should be constant - // I assume we've done folding first - if( !(!getConstantOpnd(op0)) ) assert(0); - - Inst *inst1 = op1->getInst(); - assert(inst1); - ConstInst *cinst1 = inst1->asConstInst(); - assert(cinst1); - ConstInst::ConstValue cv = cinst1->getValue(); - int64 c = cv.i4; - int64 negc = -c; - int64 subres = addend + negc; - if (neg_overflowed(negc, c) || - add_overflowed(subres, addend, negc)) { - return false; - } else { - VarBound vb(op1); - aliases->theSet.insert(PiBound(inst->getType(), 1, vb, subres)); - getAliases(op1, aliases, subres); - return true; - } - } - } - break; - case Op_Copy: - assert(0); // do copy propagation first - break; - case Op_TauCheckZero: - return false; - default: - break; - } - return false; -} - template struct NodeInst2NodeFun : ::std::unary_function { @@ -1751,46 +533,6 @@ return Abcd::isCheckableType(typetag); } -// 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(); - - uint32 numReasons = (uint32) 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::iterator iter = reason->facts.begin(); - for (uint32 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; - } -} - // phi reasons together // derefVar definition site is a Phi which should be used for placement SsaTmpOpnd *Abcd::makeReasonPhi(Opnd *derefVar, StlVector &reasons, @@ -1871,4 +613,239 @@ 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(); + + uint32 numReasons = (uint32) 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::iterator iter = reason->facts.begin(); + for (uint32 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 + RemovePiDomWalker; + RemovePiDomWalker removePiDomWalker(removePiWalker); + + DomTreeWalk(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 { + uint32 numOpnds = inst->getNumSrcOperands(); + for (uint32 i=0; igetSrc(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 Index: vm/jitrino/src/optimizer/abcd/classic_abcd_solver.h =================================================================== --- vm/jitrino/src/optimizer/abcd/classic_abcd_solver.h (revision 0) +++ vm/jitrino/src/optimizer/abcd/classic_abcd_solver.h (revision 0) @@ -0,0 +1,350 @@ +/* + * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable. + * + * Licensed 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. + */ + +#ifndef _CLASSIC_ABCD_SOLVER_H +#define _CLASSIC_ABCD_SOLVER_H + +#include +#include +#include + +#include "open/types.h" +#include "Stl.h" + +namespace Jitrino { + +class IOpnd { +public: + IOpnd(uint32 id, bool is_phi = false, bool is_constant = false) : + _id(id), _phi(is_phi), _const(is_constant), + _unconstrained(false), _value(0) + {} + + IOpnd() { assert(0); } + virtual ~IOpnd() {}; + + void setPhi(bool s = true) { _phi = s; } + bool isPhi() const { return _phi; } + + void setIsConstant(bool s = true) { _const = s; } + bool isConstant() const { return _const; } + + void setConstant(int32 val) { setIsConstant(true); _value = val; } + int32 getConstant() const { assert(isConstant()); return _value; } + + void setUnconstrained(bool unc) { _unconstrained = unc; } + bool isUnconstrained() { return _unconstrained; } + + void setID(uint32 id) { _id = id; } + uint32 getID() const { return _id; } + + virtual void printName(std::ostream& os) const; + void printFullName(std::ostream& os) const; +private: + uint32 _id; + bool _phi, _const, _unconstrained; + int32 _value; +}; + +class BoundState { +public: + BoundState() : _upper(true) {} + BoundState(bool upper) : _upper(upper) {} + + void setUpper(bool upper = true) { _upper = upper; } + + bool isUpper() const { return _upper; } +private: + + bool _upper; +}; + +class HasBoundState { +public: + HasBoundState(const BoundState& bs) : _bound_state(bs) {} + + const BoundState& getBoundState() { return _bound_state; } + + bool isUpper() const { return _bound_state.isUpper(); } +private: + const BoundState& _bound_state; +}; + +class IneqEdge { +public: + IneqEdge(IOpnd* src, IOpnd* dst, int32 len) : + _src(src), _dst(dst), _length(len) + {} + IOpnd* getSrc() const { return _src; } + IOpnd* getDst() const { return _dst; } + int32 getLength() const { return _length; } + void setLength(int32 len) { _length = len; } +private: + IOpnd *_src, *_dst; + int32 _length; +}; + +class InequalityGraph { + typedef StlMap > OpndEdgeMap; +public: + typedef StlList EdgeList; + InequalityGraph(MemoryManager& mem_mgr) : + _mem_mgr(mem_mgr), + _id_to_opnd_map(mem_mgr), + _edges(mem_mgr), + _opnd_to_inedges_map(mem_mgr), + _opnd_to_outedges_map(mem_mgr), + _emptyList(mem_mgr) + {} + + void addEdge(IOpnd* from, IOpnd* to, int32 distance); + + void addEdge(uint32 id_from, uint32 id_to, int32 distance); + + void addOpnd(IOpnd* opnd); + + const EdgeList& getInEdges(IOpnd* opnd) const; + + const EdgeList& getOutEdges(IOpnd* opnd) const; + + void printDotFile(std::ostream& os) const; + + bool isEmpty() const { return _id_to_opnd_map.empty(); } + + IOpnd* findOpnd(uint32 id) const; + + MemoryManager& getMemoryManager() { return _mem_mgr; } +private: + friend class InequalityOpndIterator; + friend class InequalityGraphPrinter; + typedef StlMap IdToOpndMap; + + static bool has_other_opnd_with_same_id(IdToOpndMap& map, IOpnd* opnd); + + void printDotHeader(std::ostream& os) const; + void printDotBody(std::ostream& os) const; + void printDotEnd(std::ostream& os) const; + + void addEdgeToIdMap (OpndEdgeMap& mp, uint32 id, IneqEdge* edge); + + MemoryManager& _mem_mgr; + IdToOpndMap _id_to_opnd_map; + EdgeList _edges; + + OpndEdgeMap _opnd_to_inedges_map, _opnd_to_outedges_map; + EdgeList _emptyList; +}; + +class Bound : public HasBoundState { +public: + Bound(int32 bnd, const BoundState& bs) : HasBoundState(bs), _bound(bnd) {} + + // bound - int32 -> Bound + Bound(Bound* bound, int32 val, const BoundState& bs); + + void printFullName(std::ostream& os); + + static bool leq(Bound* bound1, Bound* bound2); + + static bool eq(Bound* bound1, Bound* bound2); + + static bool leq_int32(Bound* bound1, int32 value); + + static bool int32_leq(int32 value, Bound* bound1); + + // returns (dst_val - src_val <= bound) + static bool const_distance_leq(int32 src_val, int32 dst_val, Bound* bound); + +private: + friend class BoundAllocator; + int32 _bound; +}; + +class TrueReducedFalseChart; + +class BoundAllocator { +public: + BoundAllocator(MemoryManager& mem_mgr) : _mem_mgr(mem_mgr) {} + + Bound* create_inc1(Bound* bound); + + Bound* create_dec1(Bound* bound); + + Bound* create_dec_const(Bound* bound, int32 cnst); + + TrueReducedFalseChart* create_empty_TRFChart(); + +private: + friend class MemoizedDistances; + + MemoryManager& getMemoryManager() { return _mem_mgr; } + + Bound* newBound(int32 val, const BoundState& bs); + MemoryManager& _mem_mgr; +}; + +enum ProveResult { + True = 2, + Reduced = 1, + False = 0 +}; + +typedef ProveResult (*meet_func_t)(ProveResult, ProveResult); + +class TrueReducedFalseChart { +public: + TrueReducedFalseChart() : + _max_false(NULL), + _min_true(NULL), + _min_reduced(NULL), + _bound_alloc(NULL) + {assert(0);} + + TrueReducedFalseChart(BoundAllocator* alloc) : + _max_false(NULL), + _min_true(NULL), + _min_reduced(NULL), + _bound_alloc(alloc) + {} + + void addFalse(Bound* f_bound); + + void addReduced(Bound* r_bound); + + void addTrue(Bound* t_bound); + + bool hasBoundResult(Bound* bound) const; + + ProveResult getBoundResult(Bound* bound) const; + + Bound* getMaxFalseBound() { return _max_false; } + + Bound* getMinTrueBound() { return _min_true; } + + Bound* getMinReducedBound() { return _min_reduced; } + + void print(std::ostream& os) const; + +private: + void printBound(Bound* b, std::ostream& os) const; + + void clearRedundantReduced(); + + Bound *_max_false, *_min_true, *_min_reduced; + BoundAllocator* _bound_alloc; +}; + +class MemoizedDistances { +public: + MemoizedDistances(BoundAllocator& alloc) : + _bound_alloc(alloc), + _map(_bound_alloc.getMemoryManager()) + {} + + void makeEmpty(); + + // set [dest - source <= bound] + void updateLeqBound(IOpnd* dest, Bound* bound, ProveResult res); + + bool hasLeqBoundResult(IOpnd* dest, Bound* bound) const; + + // returns [dest - source <= bound] + // that is True, Reduced or False + ProveResult getLeqBoundResult(IOpnd* dest, Bound* bound) const; + + bool minTrueDistanceLeqBound(IOpnd* dest, Bound* bound); + + bool maxFalseDistanceGeqBound(IOpnd* dest, Bound* bound); + + bool minReducedDistanceLeqBound(IOpnd* dest, Bound* bound); + + void print(std::ostream& os) const; + +private: + void initOpnd(IOpnd* op); + + typedef StlMap OpndToTRFChart; + BoundAllocator& _bound_alloc; + OpndToTRFChart _map; +}; + +class ActiveOpnds { +typedef StlMap::const_iterator iter_t; +public: + ActiveOpnds(MemoryManager& mem_mgr) : _map(mem_mgr) {} + + void makeEmpty() { _map.clear(); } + + bool hasOpnd(IOpnd* opnd) const { return _map.find(opnd) != _map.end(); } + + Bound* getBound(IOpnd* opnd) const; + + void setBound(IOpnd* opnd, Bound* bound) { _map[opnd] = bound; } + + void clearOpnd(IOpnd* opnd) { _map.erase(_map.find(opnd)); } + + void print(std::ostream& os) const; + +private: + StlMap _map; +}; + +class ClassicAbcdSolver { +public: + ClassicAbcdSolver(InequalityGraph& i, MemoryManager& solver_mem_mgr) : + _igraph(i), + _source_opnd(NULL), + _bound_alloc(solver_mem_mgr), + _mem_distance(_bound_alloc), + _active(solver_mem_mgr) + {} + + bool demandProve + (IOpnd* source, IOpnd* dest, int32 bound_int, bool prove_upper_bound); + +private: + ProveResult prove(IOpnd* dest, Bound* bound, uint32 prn_level); + + void updateMemDistanceWithPredecessors + (IOpnd* dest, Bound* bound, uint32 prn_level, meet_func_t meet_f); + + class Printer { + public: + Printer(uint32 level, std::ostream& os) : _level(level), _os(os) {} + + void prnLevel(); + + void prnStr(char* str); + + void prnStrLn(char* str); + + private: + uint32 _level; + std::ostream& _os; + }; + + InequalityGraph& _igraph; + IOpnd* _source_opnd; + BoundAllocator _bound_alloc; + MemoizedDistances _mem_distance; + ActiveOpnds _active; +}; + +int classic_abcd_test_main(); + +} //namespace Jitrino + +#endif /* _CLASSIC_ABCD_SOLVER_H */ Index: vm/jitrino/src/optimizer/abcd/classic_abcd.cpp =================================================================== --- vm/jitrino/src/optimizer/abcd/classic_abcd.cpp (revision 0) +++ vm/jitrino/src/optimizer/abcd/classic_abcd.cpp (revision 0) @@ -0,0 +1,582 @@ +/* + * 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. + */ + +#include "irmanager.h" +#include "Dominator.h" +#include "classic_abcd.h" +#include "classic_abcd_solver.h" +#include "opndmap.h" + +#include "Stl.h" +#include "Log.h" +#include "open/types.h" +#include "Inst.h" +#include "walkers.h" +#include "PMFAction.h" +#include "constantfolder.h" + +#include +#include +#include + +namespace Jitrino { + +// eliminating Array Bounds Check on Demand +DEFINE_SESSION_ACTION(CLASSIC_ABCDPass, classic_abcd, "Classic ABCD: eliminating Array Bounds Check on Demand"); + +void +CLASSIC_ABCDPass::_run(IRManager &irm) { + OptPass::splitCriticalEdges(irm); + OptPass::computeDominators(irm); + ClassicAbcd classic_abcd(this, irm, irm.getNestedMemoryManager(), + *irm.getDominatorTree()); + classic_abcd.runPass(); +} +//------------------------------------------------------------------------------ + +class IOpndProxy : public IOpnd +{ +public: + IOpndProxy(Opnd* opnd); + + IOpndProxy(int32 c, uint32 id); + + virtual void printName(std::ostream& os) const + { + if ( _opnd ) { + _opnd->print(os); + }else{ + os << "_c" << getID() << "(const=" << getConstant() << ")"; + } + } + + Opnd* getOrg() const { assert(_opnd); return _opnd; } + + static uint32 getProxyIdByOpnd(Opnd* opnd); +private: + Opnd* _opnd; + + /* ids of PiOpnd, SsaOpnd, VarOpnd may alias their IDs, + * encoding all in one ID with unaliasing + */ + static const uint64 min_var_opnd = 0; + static const uint64 min_ssa_opnd = MAX_UINT32 / 4; + static const uint64 min_pi_opnd = (min_ssa_opnd) * 2; + static const uint64 min_const_opnd = (min_ssa_opnd) * 3; +}; +//------------------------------------------------------------------------------ + +bool inInt32(int64 c) { + return (int64)(int32)c == c; +} + +bool inInt32Type(Type t) { + return (t.tag == Type::Int8) || + (t.tag == Type::Int16) || + (t.tag == Type::Int32); +} + +IOpndProxy::IOpndProxy(Opnd* opnd) : + IOpnd(0/* id */, + opnd->getInst()->isPhi() /* is_phi */, + ConstantFolder::isConstant(opnd) /* is_constant */), + _opnd(opnd) +{ + setID(getProxyIdByOpnd(_opnd)); + if ( isConstant() ) { + ConstInst* c_inst = _opnd->getInst()->asConstInst(); + assert(c_inst); + int64 value = c_inst->getValue().i8; + if ( inInt32Type(c_inst->getType()) ) { + value = c_inst->getValue().i4; + }else if ( c_inst->getType() != Type::Int64 ) { + setUnconstrained(true); + return; + } + if ( inInt32(value) ) { + setConstant((int32)value); + }else{ + setUnconstrained(true); + } + } +} +//------------------------------------------------------------------------------ + +IOpndProxy::IOpndProxy(int32 c, uint32 id) : + IOpnd(0, false /* is_phi */, true /* is_constant */), + _opnd(NULL) +{ + setID(min_const_opnd + id); + setConstant(c); +} + +uint32 IOpndProxy::getProxyIdByOpnd(Opnd* opnd) +{ + uint32 id = opnd->getId(); + if ( opnd->isVarOpnd() ) { + id += min_var_opnd; + }else if ( opnd->isPiOpnd() ) { + // note: PiOpnd inherits from SsaOpnd, check PiOpnd first + id += min_pi_opnd; + }else if ( opnd->isSsaOpnd() ) { + id += min_ssa_opnd; + }else { + assert(0); + } + return id; +} +//------------------------------------------------------------------------------ + +class BuildInequalityGraphWalker { +public: + BuildInequalityGraphWalker(InequalityGraph* igraph, bool isLower) : + _igraph(igraph), _isLower(isLower), _const_id_counter(1 /*reserve 0 for solver*/) + {} + + void startNode(DominatorNode *domNode) {} + void applyToInst(Inst* i); + void finishNode(DominatorNode *domNode) {} + + void enterScope() {} + void exitScope() {} +private: + void updateDstForInst(Inst* inst); + + // returns true if an edge to const opnd is actually added + bool addEdgeIfConstOpnd(IOpndProxy* dst, Opnd* const_src, Opnd* src, + bool negate_src); + + void addAllSrcOpndsForPhi(Inst* inst); + + // returns true if the edge is actually added + bool addDistance(IOpndProxy* dst, IOpndProxy* src, int64 constant, + bool negate); + + // same as addDistance, but swap 'from' and 'to' if 'negate' + void addDistanceSwapNegate(IOpndProxy* to, IOpndProxy* from, int64 c, + bool negate); + + // add edges to (or from) 'dst' induced by given bounds + void addPiEdgesForBounds(IOpndProxy* dst, + const PiBound& lb, const PiBound& ub); + + void addPiEdgesWithOneBoundInf + (IOpndProxy* dst, bool lb_is_inf, const PiBound& non_inf_bound); + + IOpndProxy* findProxy(Opnd* opnd); + + IOpndProxy* addOldOrCreateOpnd(Opnd* opnd); + + InequalityGraph* _igraph; + bool _isLower; + uint32 _const_id_counter; +}; +//------------------------------------------------------------------------------ + +IOpndProxy* BuildInequalityGraphWalker::findProxy(Opnd* opnd) +{ + assert(_igraph); + return (IOpndProxy*) _igraph->findOpnd(IOpndProxy::getProxyIdByOpnd(opnd)); +} +//------------------------------------------------------------------------------ + +void BuildInequalityGraphWalker::addAllSrcOpndsForPhi(Inst* inst) +{ + assert(inst->getOpcode() == Op_Phi); + for (uint32 j = 0; j < inst->getNumSrcOperands(); j++) { + IOpndProxy* proxy_src = addOldOrCreateOpnd(inst->getSrc(j)); + addDistance(findProxy(inst->getDst()), proxy_src, 0, false /*negate*/); + } +} +//------------------------------------------------------------------------------ + +void BuildInequalityGraphWalker::applyToInst(Inst* inst) +{ + assert(inst); + + Type::Tag inst_type = inst->getType(); + if ( !Type::isInteger(inst_type) && inst_type != Type::Boolean && + inst_type != Type::Char ) { + // note: some operations of unsupported type can produce operands of + // supported (int) types, for example, + // inst-compare-two-unmanaged-pointers, we need these operands as + // unconstrained in the graph + Opnd* dst = inst->getDst(); + if ( dst && !dst->isNull() && + (dst->getType()->isInteger() || + dst->getType()->isBoolean() ) ) { + addOldOrCreateOpnd(dst)->setUnconstrained(true); + } + return; + } + if ( inst->isUnconditionalBranch() || inst->isConditionalBranch() || + inst->isReturn() ) { + return; + } + IOpndProxy* proxy_dst; + Opcode opc = inst->getOpcode(); + switch ( opc ) { + case Op_Phi: + { + proxy_dst = addOldOrCreateOpnd(inst->getDst()); + addAllSrcOpndsForPhi(inst); + } + break; + case Op_Copy: + case Op_LdVar: + case Op_StVar: + { + proxy_dst = addOldOrCreateOpnd(inst->getDst()); + addDistance(proxy_dst, findProxy(inst->getSrc(0)), 0, + false /* negate */); + } + break; + case Op_Add: + { + proxy_dst = addOldOrCreateOpnd(inst->getDst()); + Opnd* src0 = inst->getSrc(0); + Opnd* src1 = inst->getSrc(1); + addEdgeIfConstOpnd(proxy_dst, src0, src1, false /* negate */) + || addEdgeIfConstOpnd(proxy_dst, src1, src0, false /* negate */); + } + break; + case Op_Sub: + { + proxy_dst = addOldOrCreateOpnd(inst->getDst()); + addEdgeIfConstOpnd(proxy_dst, inst->getSrc(1), inst->getSrc(0), + true /* negate */ ); + } + break; + case Op_TauPi: + { + proxy_dst = addOldOrCreateOpnd(inst->getDst()); + IOpndProxy* src0 = findProxy(inst->getSrc(0)); + addDistance(proxy_dst, src0, 0, false /* negate */); + const PiCondition* condition = inst->asTauPiInst()->getCond(); + addPiEdgesForBounds(proxy_dst, + condition->getLb(), + condition->getUb()); + } + break; + case Op_TauArrayLen: + case Op_LdConstant: + addOldOrCreateOpnd(inst->getDst()); + break; + case Op_TauStInd: case Op_TauStElem: case Op_TauStField: + case Op_TauStRef: case Op_TauStStatic: + break; + default: + addOldOrCreateOpnd(inst->getDst())->setUnconstrained(true); + break; + } +} +//------------------------------------------------------------------------------ + +// returns true if the edge is actually added +bool BuildInequalityGraphWalker::addDistance + (IOpndProxy* dst, IOpndProxy* src, int64 constant, bool negate) +{ + assert(dst && src); + // Note: is this an optimization? It prevents adding a link from + // unconstrained operands. This is always safe, and it shouldn't lose + // opportunity, but maybe we should discuss it to be sure? + if ( !src->isUnconstrained() ) { + if ( !inInt32(constant) ) { + return false; + } + if ( negate ) { + constant = (-1) * constant; + } + _igraph->addEdge(src->getID(), dst->getID(), constant); + return true; + } + return false; +} +//------------------------------------------------------------------------------ + +void BuildInequalityGraphWalker::addDistanceSwapNegate + (IOpndProxy* to, IOpndProxy* from, int64 c, bool negate) +{ + addDistance(!negate ? to : from, !negate ? from : to, c, negate); +} +//------------------------------------------------------------------------------ + +// returns true if an edge to const opnd is actually added +bool BuildInequalityGraphWalker::addEdgeIfConstOpnd + (IOpndProxy* dst, Opnd* const_src, Opnd* src, bool negate_src) +{ + if ( ConstantFolder::isConstant(const_src) ) { + IOpnd* from = findProxy(const_src); + assert(from); + if ( !from->isUnconstrained() ) { + return addDistance(dst, findProxy(src), from->getConstant(), + negate_src); + } + } + return false; +} +//------------------------------------------------------------------------------ + +/* + * pi (src0 \in [undef,A + c] -) dst + * dst <= A + c <-> (dst - A) <= c + * edge(from:A, to:dst, c) + * + * pi (src0 \in [A + c,undef] -) dst + * (A + c) <= dst <-> (A - dst) <= -c + * edge(from:dst, to:A, -c) + */ +void BuildInequalityGraphWalker::addPiEdgesForBounds + (IOpndProxy* dst, const PiBound& lb, const PiBound& ub) +{ + if ( _isLower && !lb.isUndefined() ) { + addPiEdgesWithOneBoundInf(dst, false, lb); + } + else if ( !_isLower && !ub.isUndefined() ) { + addPiEdgesWithOneBoundInf(dst, true, ub); + } +} +//------------------------------------------------------------------------------ + +void BuildInequalityGraphWalker::addPiEdgesWithOneBoundInf + (IOpndProxy* dst, bool lb_is_inf, const PiBound& non_inf_bound) +{ + if ( non_inf_bound.isVarPlusConst() ) { + Opnd* var = non_inf_bound.getVar().the_var; + addDistanceSwapNegate(dst /* to */, + findProxy(var) /* from */, + non_inf_bound.getConst(), + false /* negate */); + } else if ( non_inf_bound.isConst() ) { + MemoryManager& mm = _igraph->getMemoryManager(); + IOpndProxy* c_opnd = new (mm) + IOpndProxy(non_inf_bound.getConst(), _const_id_counter++); + _igraph->addOpnd(c_opnd); + addDistanceSwapNegate(c_opnd /* to */, dst, 0, false /* negate */); + } +} +//------------------------------------------------------------------------------ + +IOpndProxy* BuildInequalityGraphWalker::addOldOrCreateOpnd(Opnd* opnd) +{ + IOpndProxy* proxy = findProxy(opnd); + if ( !proxy ) { + MemoryManager& mm = _igraph->getMemoryManager(); + proxy = new (mm) IOpndProxy(opnd); + _igraph->addOpnd(proxy); + if ( Log::isEnabled() ) { + Log::out() << "added opnd: "; + proxy->printFullName(Log::out()); + Log::out() << std::endl; + } + } + return proxy; +} + +class InequalityGraphPrinter : public PrintDotFile { +public: + InequalityGraphPrinter(InequalityGraph& graph) : _graph(graph) {} + void printDotBody() + { + _graph.printDotBody(*os); + } +private: + InequalityGraph& _graph; +}; +//------------------------------------------------------------------------------ + +void ClassicAbcd::runPass() +{ + static bool run_once = true; + if ( run_once && _runTests ) { + classic_abcd_test_main(); + _runTests = false; + run_once = false; + } + + MethodDesc& method_desc = _irManager.getMethodDesc(); + ControlFlowGraph& cfg = _irManager.getFlowGraph(); + TypeManager& typeManager = _irManager.getTypeManager(); + OpndManager& opndManager = _irManager.getOpndManager(); + InstFactory& instFactory = _irManager.getInstFactory(); + + if ( Log::isEnabled() ) { + FlowGraph::printDotFile(cfg, method_desc, "before_classic_abcd"); + _domTree.printDotFile(method_desc, "before_classic_abcd.dom"); + Log::out() << "ClassicAbcd pass started" << std::endl; + } + + StlMap redundantChecks(_mm); + + { + uint32 ineq_sz = method_desc.getByteCodeSize() * 32; + MemoryManager ineq_mm(ineq_sz, "ClassicAbcd::InequalityGraph"); + + InsertPi insertPi(ineq_mm, _domTree, _irManager, _useAliases, InsertPi::Upper); + insertPi.insertPi(); + + InequalityGraph igraph(ineq_mm); + + BuildInequalityGraphWalker igraph_walker(&igraph, false /*lower*/); + typedef ScopedDomNodeInst2DomWalker + IneqBuildDomWalker; + IneqBuildDomWalker dom_walker(igraph_walker); + DomTreeWalk(_domTree, dom_walker, ineq_mm); + + if ( Log::isEnabled() ) { + InequalityGraphPrinter printer(igraph); + printer.printDotFile(method_desc, "inequality.graph"); + } + + ClassicAbcdSolver solver(igraph, ineq_mm); + + for (Nodes::const_iterator i = cfg.getNodes().begin(); i != cfg.getNodes().end(); ++i) { + Node *curr_node = *i; + + for (Inst *curr_inst = (Inst*)curr_node->getFirstInst(); + curr_inst != NULL; curr_inst = curr_inst->getNextInst()) { + + if (curr_inst->getOpcode() == Op_TauCheckBounds) { + assert(curr_inst->getNumSrcOperands() == 2); + Opnd *idxOp = curr_inst->getSrc(1); + Opnd *boundsOp = curr_inst->getSrc(0); + + if (Log::isEnabled()) { + Log::out() << "Trying to eliminate CheckBounds instruction "; + curr_inst->print(Log::out()); + Log::out() << std::endl; + } + + IOpnd *idxIOp = igraph.findOpnd(IOpndProxy::getProxyIdByOpnd(idxOp)); + IOpnd *boundsIOp = igraph.findOpnd(IOpndProxy::getProxyIdByOpnd(boundsOp)); + + bool upper_res = solver.demandProve(boundsIOp, idxIOp, -1, true /*upper*/); + if (upper_res) { + redundantChecks[curr_inst] = 0x1 /*upper redundant*/; + if (Log::isEnabled()) { + Log::out() << "can eliminate upper bound check!\n"; + } + } + } + } + } + insertPi.removePi(); + } + + + { + uint32 ineq_sz = method_desc.getByteCodeSize() * 32; + MemoryManager ineq_mm(ineq_sz, "ClassicAbcd::InequalityGraph"); + + InsertPi insertPi(ineq_mm, _domTree, _irManager, _useAliases, InsertPi::Lower); + insertPi.insertPi(); + + InequalityGraph igraph(ineq_mm); + + BuildInequalityGraphWalker igraph_walker(&igraph, true /*lower*/); + typedef ScopedDomNodeInst2DomWalker + IneqBuildDomWalker; + IneqBuildDomWalker dom_walker(igraph_walker); + DomTreeWalk(_domTree, dom_walker, ineq_mm); + + IOpndProxy *zeroIOp = new (ineq_mm) IOpndProxy(0, 0 /*using reserved ID*/); + igraph.addOpnd(zeroIOp); + if ( Log::isEnabled() ) { + Log::out() << "added zero opnd for solving lower bound problem: "; + zeroIOp->printFullName(Log::out()); + Log::out() << std::endl; + } + + if ( Log::isEnabled() ) { + InequalityGraphPrinter printer(igraph); + printer.printDotFile(method_desc, "inequality.graph.inverted"); + } + + ClassicAbcdSolver solver(igraph, ineq_mm); + + for (Nodes::const_iterator i = cfg.getNodes().begin(); i != cfg.getNodes().end(); ++i) { + Node *curr_node = *i; + + for (Inst *curr_inst = (Inst*)curr_node->getFirstInst(); + curr_inst != NULL; curr_inst = curr_inst->getNextInst()) { + + if (curr_inst->getOpcode() == Op_TauCheckBounds) { + assert(curr_inst->getNumSrcOperands() == 2); + Opnd *idxOp = curr_inst->getSrc(1); + + if (Log::isEnabled()) { + Log::out() << "Trying to eliminate CheckBounds instruction "; + curr_inst->print(Log::out()); + Log::out() << std::endl; + } + + IOpnd *idxIOp = igraph.findOpnd(IOpndProxy::getProxyIdByOpnd(idxOp)); + + bool lower_res = solver.demandProve(zeroIOp, idxIOp, 0, false /*lower*/); + if (lower_res) { + redundantChecks[curr_inst] |= 0x2 /*lower redundant*/; + if (Log::isEnabled()) { + Log::out() << "can eliminate lower bound check!\n"; + } + } + } + } + } + insertPi.removePi(); + } + + for(StlMap::const_iterator i = redundantChecks.begin(); + i != redundantChecks.end(); ++i) { + Inst *redundant_inst = i->first; + bool fully_redundant = i->second == 0x3; + + if (fully_redundant) { + // should we check if another tau has already been placed in + // this block, and if so reuse it? Also, should we be using + // taupoint or tauedge? + Opnd *tauOp = opndManager.createSsaTmpOpnd(typeManager.getTauType()); + Inst* tau_point = instFactory.makeTauPoint(tauOp); + tau_point->insertBefore(redundant_inst); + + if (Log::isEnabled()) { + Log::out() << "Inserted taupoint inst "; + tau_point->print(Log::out()); + Log::out() << " before inst "; + redundant_inst->print(Log::out()); + Log::out() << std::endl; + } + + Opnd* dstOp = redundant_inst->getDst(); + redundant_inst->setDst(OpndManager::getNullOpnd()); + Inst* copy = instFactory.makeCopy(dstOp, tauOp); + copy->insertBefore(redundant_inst); + FlowGraph::eliminateCheck(cfg, redundant_inst->getNode(), redundant_inst, false); + + if (Log::isEnabled()) { + Log::out() << "Replaced bound check with inst "; + copy->print(Log::out()); + Log::out() << std::endl; + } + } + } + + Log::out() << "ClassicAbcd pass finished" << std::endl; +} +//------------------------------------------------------------------------------ + +} //namespace Jitrino + Index: vm/jitrino/src/optimizer/abcd/AbcdFlags.h =================================================================== --- vm/jitrino/src/optimizer/abcd/AbcdFlags.h (revision 0) +++ vm/jitrino/src/optimizer/abcd/AbcdFlags.h (revision 0) @@ -0,0 +1,41 @@ +/* + * 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. + */ + +#ifndef _ABCD_FLAGS_H +#define _ABCD_FLAGS_H + +namespace Jitrino { + +struct AbcdFlags { + bool partial; + bool dryRun; + bool useAliases; + bool useConv; + bool remConv; + bool useShr; + bool unmaskShifts; + bool remBr; + bool remCmp; + bool remOneBound; + bool remOverflow; + bool checkOverflow; + bool useReasons; +}; + +} + +#endif /* _ABCD_FLAGS_H */ Index: vm/jitrino/src/optimizer/abcd/insertpi.cpp =================================================================== --- vm/jitrino/src/optimizer/abcd/insertpi.cpp (revision 0) +++ vm/jitrino/src/optimizer/abcd/insertpi.cpp (revision 0) @@ -0,0 +1,1117 @@ +/* + * 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. + */ + +#include "insertpi.h" +#include "walkers.h" +#include "abcdbounds.h" +#include "constantfolder.h" + +namespace Jitrino { + +static ComparisonModifier +negateComparison(ComparisonModifier mod) +{ + switch (mod) { + case Cmp_GT: return Cmp_GTE; + case Cmp_GT_Un: return Cmp_GTE_Un; + case Cmp_GTE: return Cmp_GT; + case Cmp_GTE_Un: return Cmp_GT_Un; + case Cmp_EQ: return Cmp_EQ; + case Cmp_NE_Un: return Cmp_NE_Un; + default: + assert(0); return mod; + } +} + +static const char * +printableComparison(ComparisonModifier mod) +{ + switch (mod) { + case Cmp_GT: return "Cmp_GT"; + case Cmp_GT_Un: return "Cmp_GT_Un"; + case Cmp_GTE: return "Cmp_GTE"; + case Cmp_GTE_Un: return "Cmp_GTE_Un"; + case Cmp_EQ: return "Cmp_EQ"; + case Cmp_NE_Un: return "Cmp_NE_Un"; + default: + assert(0); return ""; + } +} + +static Type::Tag +unsignType(Type::Tag typetag) +{ + switch (typetag) { + case Type::IntPtr: return Type::UIntPtr; + case Type::Int8: return Type::UInt8; + case Type::Int16: return Type::UInt16; + case Type::Int32: return Type::UInt32; + case Type::Int64: return Type::UInt64; + default: + assert(0); return typetag; + } +} + +// a DomWalker, to be applied in pre-order +class InsertPiWalker { +public: + InsertPiWalker(InsertPi* insert_pi) : _insertPi(insert_pi) {}; + + void applyToDominatorNode(DominatorNode *domNode) + { + _insertPi->insertPiToNode(domNode->getNode()); + } + + // is called before a node and its children are processed + void enterScope() {}; + + // is called after node and children are processed + void exitScope() {}; + +private: + InsertPi* _insertPi; +}; +//------------------------------------------------------------------------------ + +// Add a Pi node in the node if it is after each test +// which tells something about a variable +// +// WARNING: Pi var live ranges may overlap the original var live ranges +// since we don't bother to add Phi nodes and rename subsequent uses of var. +void InsertPi::insertPi() +{ + InsertPiWalker insert_pi_walker(this); + + // dom-pre-order traversal + DomTreeWalk(_domTree, insert_pi_walker, _mm); + renamePiVariables(); + + if (Log::isEnabled()) { + Log::out() << "IR after Pi insertion" << std::endl; + FlowGraph::printHIR(Log::out(), _irManager.getFlowGraph(), + _irManager.getMethodDesc()); + FlowGraph::printDotFile(_irManager.getFlowGraph(), + _irManager.getMethodDesc(), "withpi"); + } +} +//------------------------------------------------------------------------------ + +// add Pi in the node iff after a test which tells something about the var +void InsertPi::insertPiToNode(Node* block) +{ + Edge *dom_edge = 0; + + // see if there is a predecessor block idom such that + // (1) idom dominates this one + // (2) this block dominates all other predecessors + // (3) idom has multiple out-edges + // (4) idom has only 1 edge to this node + + // (1a) if a predecessor dominates it must be idom + Node *idom = _domTree.getIdom(block); + + // (3) must exist and have multiple out-edges + if ((idom == NULL) || (idom->hasOnlyOneSuccEdge())) { + return; + } + + if (Log::isEnabled()) { + Log::out() << "Checking block " << (int)block->getId() << " with idom " + << (int) idom->getId() << std::endl; + } + + if (block->hasOnlyOnePredEdge()) { + // must be from idom -- (1b) + // satisfies (2) trivially + dom_edge = *(block->getInEdges().begin()); + } else { + // check (1b) and (2) + const Edges &inedges = block->getInEdges(); + typedef Edges::const_iterator EdgeIter; + EdgeIter e_last = inedges.end(); + for (EdgeIter e_iter = inedges.begin(); e_iter != e_last; e_iter++) { + Edge *in_edge = *e_iter; + Node *pred_block = in_edge->getSourceNode(); + if (pred_block == idom) { + // (1b) found idom + if (dom_edge) { + // failed (4): idom found on more than one incoming edge + return; + } + dom_edge = in_edge; + } else if (! _domTree.dominates(block, pred_block)) { + // failed (2) + return; + } + } + } + + if (dom_edge) { + Edge *in_edge = dom_edge; + Node *pred_block = idom; + if (Log::isEnabled()) { + Log::out() << "Checking branch for " << (int)block->getId() + << " with idom " + << (int) idom->getId() << std::endl; + } + if (!pred_block->hasOnlyOneSuccEdge()) { + Edge::Kind kind = in_edge->getKind(); + switch (kind) { + case Edge::Kind_True: + case Edge::Kind_False: + { + Inst* branchi1 = (Inst*)pred_block->getLastInst(); + assert(branchi1 != NULL); + BranchInst* branchi = branchi1->asBranchInst(); + if (branchi && branchi->isConditionalBranch()) { + insertPiForBranch(block, branchi, kind); + } else { + return; + } + } + break; + + case Edge::Kind_Dispatch: + return; + + case Edge::Kind_Unconditional: + // Previous block must have a PEI + // since it had multiple out-edges. + // This is the unexceptional condition. + { + Inst* lasti = (Inst*)pred_block->getLastInst(); + assert(lasti != NULL); + insertPiForUnexceptionalPEI(block, lasti); + } + // We could look for a bounds check in predecessor. + + // But: since now all useful PEIs have explicit results, + // they imply a Pi-like action. + break; + + case Edge::Kind_Catch: + break; + default: + break; + } + } + } +} +//------------------------------------------------------------------------------ + +void InsertPi::insertPiForUnexceptionalPEI(Node *block, Inst *lasti) +{ + switch (lasti->getOpcode()) { + case Op_TauCheckBounds: + { + // the number of newarray elements must be >= 0. + assert(lasti->getNumSrcOperands() == 2); + Opnd *idxOp = lasti->getSrc(1); + Opnd *boundsOp = lasti->getSrc(0); + + if (Log::isEnabled()) { + Log::out() << "Adding info about CheckBounds instruction "; + lasti->print(Log::out()); + Log::out() << std::endl; + } + Type::Tag typetag = idxOp->getType()->tag; + PiBound lb(typetag, int64(0)); + PiBound ub(typetag, 1, VarBound(boundsOp),int64(-1)); + PiCondition bounds0(lb, ub); + Opnd *tauOpnd = lasti->getDst(); // use the checkbounds tau + insertPiForOpndAndAliases(block, idxOp, bounds0, tauOpnd); + + PiBound idxBound(typetag, 1, VarBound(idxOp), int64(1)); + PiCondition bounds1(idxBound, PiBound(typetag, false)); + insertPiForOpndAndAliases(block, boundsOp, bounds1, tauOpnd); + } + break; + case Op_NewArray: + { + // the number of newarray elements must be in [0, MAXINT32] + assert(lasti->getNumSrcOperands() == 1); + Opnd *numElemOpnd = lasti->getSrc(0); + if (Log::isEnabled()) { + Log::out() << "Adding info about NewArray instruction "; + lasti->print(Log::out()); + Log::out() << std::endl; + } + Opnd *tauOpnd = getBlockTauEdge(block); // need to use a TauEdge + PiCondition bounds0(PiBound(numElemOpnd->getType()->tag, + int64(0)), + PiBound(numElemOpnd->getType()->tag, + int64(0x7fffffff))); + insertPiForOpndAndAliases(block, numElemOpnd, bounds0, tauOpnd); + } + break; + case Op_NewMultiArray: + { + // the number of newarray dimensions must be >= 1. + uint32 numOpnds = lasti->getNumSrcOperands(); + assert(numOpnds >= 1); + StlSet done(_mm); + if (Log::isEnabled()) { + Log::out() << "Adding info about NewMultiArray instruction "; + lasti->print(Log::out()); + Log::out() << std::endl; + } + Opnd *tauOpnd = 0; + // the number of newarray elements must be in [0, MAXINT32] + for (uint32 opndNum = 0; opndNum < numOpnds; opndNum++) { + Opnd *thisOpnd = lasti->getSrc(opndNum); + if (!done.has(thisOpnd)) { + done.insert(thisOpnd); + PiCondition bounds0(PiBound(thisOpnd->getType()->tag, + int64(0)), + PiBound(thisOpnd->getType()->tag, + int64(0x7fffffff))); + if ( !tauOpnd ) { + tauOpnd = getBlockTauEdge(block); // must use a tauEdge + } + insertPiForOpndAndAliases(block, thisOpnd, bounds0, tauOpnd); + } + } + } + break; + default: + break; + } +} +//------------------------------------------------------------------------------ + +SsaTmpOpnd* InsertPi::getBlockTauEdge(Node *block) { + if ((_lastTauEdgeBlock == block) && _blockTauEdge) return _blockTauEdge; + Inst *firstInst = (Inst*)block->getFirstInst(); + Inst *inst = firstInst->getNextInst(); + for (; inst != NULL; inst = inst->getNextInst()) { + if (inst->getOpcode() == Op_TauEdge) { + _blockTauEdge = inst->getDst()->asSsaTmpOpnd(); + assert(_blockTauEdge); + _lastTauEdgeBlock = block; + return _blockTauEdge; + } + } + for (inst = firstInst->getNextInst(); inst != NULL; inst = inst->getNextInst()) { + if ((inst->getOpcode() != Op_Phi) && (inst->getOpcode() != Op_TauPoint)) { + break; // insert before inst. + } + } + // no non-phis, insert before inst; + TypeManager &tm = _irManager.getTypeManager(); + SsaTmpOpnd *tauOpnd = _irManager.getOpndManager().createSsaTmpOpnd(tm.getTauType()); + Inst* tauEdge = _irManager.getInstFactory().makeTauEdge(tauOpnd); + if(Log::isEnabled()) { + Log::out() << "Inserting tauEdge inst "; + tauEdge->print(Log::out()); + if (inst!=NULL) { + Log::out() << " before inst "; + inst->print(Log::out()); + } + Log::out() << std::endl; + } + if (inst != NULL) { + tauEdge->insertBefore(inst); + } else { + block->appendInst(tauEdge); + } + _blockTauEdge = tauOpnd; + _lastTauEdgeBlock = block; + return tauOpnd; +} +//------------------------------------------------------------------------------ + +// Insert Pi Nodes for any variables occurring in the branch test +// +// Since we're examining the test anyway, let's figure out the conditions +// here, too, so we don't have to duplicate any code. Note that this +// condition may already be in terms of Pi variables from the predecessor +// block, since +// -- predecessor dominates this block +// -- we are traversing blocks in a dominator-tree preorder +// so we must have already visited the predecessor. +// +// We also must add the new Pi variable to our map. +// +void InsertPi::insertPiForBranch(Node* block, + BranchInst* branchi, + Edge::Kind kind) // True or False only +{ + Type::Tag instTypeTag = branchi->getType(); + if (!Type::isInteger(instTypeTag)) + return; + ComparisonModifier mod = branchi->getComparisonModifier(); + if (branchi->getNumSrcOperands() == 1) { + Opnd *op0 = branchi->getSrc(0); + PiCondition zeroBounds(PiBound(instTypeTag, (int64)0), + PiBound(instTypeTag, (int64)0)); + switch (mod) { + case Cmp_Zero: + insertPiForComparison(block, + Cmp_EQ, + zeroBounds, + op0, + false, + // negate if false edge + (kind == Edge::Kind_False)); + break; + case Cmp_NonZero: + insertPiForComparison(block, + Cmp_EQ, // use EQ + zeroBounds, + op0, + false, + // but negate if true edge + (kind == Edge::Kind_True)); + break; + default: + break; + } + } else { + Opnd *op0 = branchi->getSrc(0); + Opnd *op1 = branchi->getSrc(1); + assert(branchi->getNumSrcOperands() == 2); + PiCondition bounds0(op0->getType()->tag, op0); + PiCondition bounds1(op1->getType()->tag, op1); + if (!bounds0.isUnknown()) { + insertPiForComparison(block, + mod, + bounds0, + op1, + false, + // negate for false edge + (kind == Edge::Kind_False)); + } + if (!bounds1.isUnknown()) { + insertPiForComparison(block, + mod, + bounds1, + op0, + true, + // negate for false edge + (kind == Edge::Kind_False)); + } + } +} +//------------------------------------------------------------------------------ + +void InsertPi::insertPiForComparison(Node* block, + ComparisonModifier mod, + const PiCondition &bounds, + Opnd* op, + bool swap_operands, + bool negate_comparison) +{ + if (Log::isEnabled()) { + Log::out() << "insertPiForComparison(..., "; + Log::out() << printableComparison(mod); + Log::out() << ", "; + bounds.print(Log::out()); + Log::out() << ", "; + op->print(Log::out()); + Log::out() << ", "; + Log::out() << (swap_operands ? "true" : "false"); + Log::out() << (negate_comparison ? "true" : "false"); + Log::out() << std::endl; + } + + PiCondition bounds0 = bounds; + // add a Pi node for immediate value. + if (negate_comparison) { + mod = negateComparison(mod); + swap_operands = !swap_operands; + if (Log::isEnabled()) { + Log::out() << "insertPiForComparison: negating comparison to " ; + Log::out() << printableComparison(mod); + Log::out() << std::endl; + } + } + switch (mod) { + case Cmp_EQ: + if (!negate_comparison) + insertPiForOpndAndAliases(block, op, bounds0, NULL); + else { + if (Log::isEnabled()) { + Log::out() << "insertPiForComparison: cannot represent ! Cmp_EQ" << std::endl; + } + } + // we can't represent the other case + break; + case Cmp_NE_Un: + if (negate_comparison) + insertPiForOpndAndAliases(block, op, bounds0, NULL); + else { + if (Log::isEnabled()) { + Log::out() << "insertPiForComparison: cannot represent Cmp_NE_Un" << std::endl; + } + } + // we can't represent the other case + break; + case Cmp_GT_Un: + if (swap_operands) { // op > bounds, only a lower bound on op + Type::Tag optag = op->getType()->tag; + if (!Type::isUnsignedInteger(optag)) { + // 1 is a lower bound on int op + PiCondition oneBounds(PiBound(optag, (int64)1), + PiBound(optag, (int64)1)); + PiCondition oneLowerBound(oneBounds.only_lower_bound()); + insertPiForOpndAndAliases(block, op, oneLowerBound, NULL); + } else { + // we can be more precise for an unsigned op + bounds0 = bounds0.cast(unsignType(bounds0.getType())); + PiCondition bounds1a(bounds0.only_lower_bound()); + PiCondition bounds1(bounds1a.add((int64)1)); + if (! bounds1.getLb().isUnknown()) + insertPiForOpndAndAliases(block, op, bounds1, NULL); + else { + if (Log::isEnabled()) { + Log::out() << "insertPiForComparison(1): bounds1 LB is Unknown;\n\tbounds is "; + bounds.print(Log::out()); + Log::out() << "\n\tbounds0 is "; + bounds0.print(Log::out()); + Log::out() << "\n\tbounds1a is "; + bounds1a.print(Log::out()); + Log::out() << "\n\tbounds1 is "; + bounds1.print(Log::out()); + Log::out() << std::endl; + } + } + } + } else { // bounds > op, only an upper bound on op + Type::Tag optag = op->getType()->tag; + if (Type::isUnsignedInteger(optag)) { + // for an unsigned upper bound, we're ok + bounds0 = bounds0.cast(unsignType(bounds0.getType())); + PiCondition bounds1(bounds0.only_upper_bound().add((int64)-1)); + if (! bounds1.getUb().isUnknown()) + insertPiForOpndAndAliases(block, op, bounds1, NULL); + else { + if (Log::isEnabled()) { + Log::out() << "insertPiForComparison(2): bounds1 LB is Unknown;\n\tbounds is "; + bounds.print(Log::out()); + Log::out() << "\n\tbounds0 is "; + bounds0.print(Log::out()); + Log::out() << "\n\tbounds1 is "; + bounds1.print(Log::out()); + Log::out() << std::endl; + } + } + } else { + // otherwise, we know nothing unless bound is a small constant + PiCondition bounds1(bounds0.only_upper_bound().add((int64)-1)); + if (bounds0.getUb().isConstant()) { + int64 ubConst = bounds1.getUb().getConst(); + if (((optag == Type::Int32) && + ((ubConst&0xffffffff) <= 0x7ffffff) && + ((ubConst&0xffffffff) >= 0)) || + ((optag == Type::Int64) && + ((ubConst <= 0x7ffffff) && + (ubConst >= 0)))) { + insertPiForOpndAndAliases(block, op, bounds1, NULL); + } else { + if (Log::isEnabled()) { + Log::out() << "insertPiForComparison(2): bounds1 LB is Unknown;\n\tbounds is "; + bounds.print(Log::out()); + Log::out() << "\n\tbounds0 is "; + bounds0.print(Log::out()); + Log::out() << "\n\tbounds1 is "; + bounds1.print(Log::out()); + Log::out() << std::endl; + } + } + } + } + } + break; + case Cmp_GT: + if (swap_operands) { // op > bounds, only a lower bound on op + PiCondition bounds1a(bounds0.only_lower_bound()); + PiCondition bounds1(bounds1a.add((int64)1)); + if (! bounds1.getLb().isUnknown()) + insertPiForOpndAndAliases(block, op, bounds1, NULL); + else { + if (Log::isEnabled()) { + Log::out() << "insertPiForComparison(1): bounds1 LB is Unknown;\n\tbounds is "; + bounds.print(Log::out()); + Log::out() << "\n\tbounds0 is "; + bounds0.print(Log::out()); + Log::out() << "\n\tbounds1a is "; + bounds1a.print(Log::out()); + Log::out() << "\n\tbounds1 is "; + bounds1.print(Log::out()); + Log::out() << std::endl; + } + } + } else { // bounds > op, only an upper bound on op + PiCondition bounds1(bounds0.only_upper_bound().add((int64)-1)); + if (! bounds1.getUb().isUnknown()) + insertPiForOpndAndAliases(block, op, bounds1, NULL); + else { + if (Log::isEnabled()) { + Log::out() << "insertPiForComparison(2): bounds1 LB is Unknown;\n\tbounds is "; + bounds.print(Log::out()); + Log::out() << "\n\tbounds0 is "; + bounds0.print(Log::out()); + Log::out() << "\n\tbounds1 is "; + bounds1.print(Log::out()); + Log::out() << std::endl; + } + } + } + break; + case Cmp_GTE_Un: + if (swap_operands) { // op >= bounds, only lower bound on op + Type::Tag optag = op->getType()->tag; + if (!Type::isUnsignedInteger(optag)) { + // 0 is a lower bound on an int op + PiCondition zeroBounds(PiBound(optag, (int64)0), + PiBound(optag, (int64)0)); + PiCondition zeroLowerBound(zeroBounds.only_lower_bound()); + insertPiForOpndAndAliases(block, op, zeroLowerBound, NULL); + } else { + // we can be more precise for an unsigned op lb + bounds0 = bounds0.cast(unsignType(bounds0.getType())); + if (! bounds0.getLb().isUnknown()) { + insertPiForOpndAndAliases(block, op, + bounds0.only_lower_bound(), NULL); + } else { + if (Log::isEnabled()) { + Log::out() << "insertPiForComparison(3): bounds0 LB is Unknown;\n\tbounds is "; + bounds.print(Log::out()); + Log::out() << "\n\tbounds0 is "; + bounds0.print(Log::out()); + Log::out() << std::endl; + } + } + } + } else { // bounds >= op, only upper bound on op + Type::Tag optag = op->getType()->tag; + if (Type::isUnsignedInteger(optag)) { + // unsigned ub on unsigned op + bounds0 = bounds0.cast(unsignType(bounds0.getType())); + if (! bounds0.getUb().isUnknown()) + insertPiForOpndAndAliases(block, op, + bounds0.only_upper_bound(), NULL); + else { + if (Log::isEnabled()) { + Log::out() << "insertPiForComparison(4): bounds0 UB is Unknown;\n\tbounds is "; + bounds.print(Log::out()); + Log::out() << "\n\tbounds0 is "; + bounds0.print(Log::out()); + Log::out() << std::endl; + } + } + } else { + // otherwise, we know nothing unless bound is a small constant + if (bounds0.getUb().isConstant()) { + int64 ubConst = bounds0.getUb().getConst(); + if (((optag == Type::Int32) && + ((ubConst&0xffffffff) <= 0x7ffffff) && + ((ubConst&0xffffffff) >= 0)) || + ((optag == Type::Int64) && + ((ubConst <= 0x7ffffff) && + (ubConst >= 0)))) { + insertPiForOpndAndAliases(block, op, bounds0, NULL); + } else { + if (Log::isEnabled()) { + Log::out() << "insertPiForComparison(2): bounds0 LB is Unknown;\n\tbounds is "; + bounds.print(Log::out()); + Log::out() << "\n\tbounds0 is "; + bounds0.print(Log::out()); + Log::out() << std::endl; + } + } + } + } + } + break; + case Cmp_GTE: + if (swap_operands) { // op >= bounds, only lower bound on op + if (! bounds0.getLb().isUnknown()) { + insertPiForOpndAndAliases(block, op, + bounds0.only_lower_bound(), NULL); + } else { + if (Log::isEnabled()) { + Log::out() << "insertPiForComparison(3): bounds0 LB is Unknown;\n\tbounds is "; + bounds.print(Log::out()); + Log::out() << "\n\tbounds0 is "; + bounds0.print(Log::out()); + Log::out() << std::endl; + } + } + } else { // bounds >= op, only upper bound on op + if (! bounds0.getUb().isUnknown()) + insertPiForOpndAndAliases(block, op, + bounds0.only_upper_bound(), NULL); + else { + if (Log::isEnabled()) { + Log::out() << "insertPiForComparison(4): bounds0 UB is Unknown;\n\tbounds is "; + bounds.print(Log::out()); + Log::out() << "\n\tbounds0 is "; + bounds0.print(Log::out()); + Log::out() << std::endl; + } + } + } + break; + case Cmp_Zero: + case Cmp_NonZero: + case Cmp_Mask: + assert(0); + break; + default: + assert(false); + break; + } +} +//------------------------------------------------------------------------------ + +void InsertPi::insertPiForOpnd(Node *block, + Opnd *org, + const PiCondition &cond, + Opnd *tauOpnd) +{ + if (ConstantFolder::isConstant(org)) { + if (Log::isEnabled()) { + Log::out() << "Skipping Pi Node for opnd "; + org->print(Log::out()); + Log::out() << " under condition "; + cond.print(Log::out()); + Log::out() << " since it is constant" << std::endl; + } + } else { + PiOpnd *piOpnd = _irManager.getOpndManager().createPiOpnd(org); + Inst *headInst = (Inst*)block->getFirstInst(); + PiCondition *condPtr = new (_irManager.getMemoryManager()) PiCondition(cond); + if (tauOpnd == 0) + tauOpnd = getBlockTauEdge(block); + Inst *newInst = _irManager.getInstFactory().makeTauPi(piOpnd, org, tauOpnd, condPtr); + Inst *place = headInst->getNextInst(); + while (place != NULL) { + Opcode opc = place->getOpcode(); + if ((opc != Op_Phi) && (opc != Op_TauPoint) && (opc != Op_TauEdge)) + break; + place = place->getNextInst(); + } + if (Log::isEnabled()) { + Log::out() << "Inserting Pi Node for opnd "; + org->print(Log::out()); + Log::out() << " under condition "; + cond.print(Log::out()); + if (place!=NULL) { + Log::out() << " just before inst "; + place->print(Log::out()); + } + Log::out() << std::endl; + } + if (place != NULL) { + newInst->insertBefore(place); + } else { + block->appendInst(newInst); + } + } +} +//------------------------------------------------------------------------------ + +// dereferencing through Pis, 0 if not constant. +Opnd* InsertPi::getConstantOpnd(Opnd *opnd) +{ + return ConstantFolder::isConstant(opnd) ? opnd : NULL; +} +//------------------------------------------------------------------------------ + +bool InsertPi::getAliases(Opnd *opnd, AbcdAliases *aliases, int64 addend) +{ + Inst *inst = opnd->getInst(); + switch (inst->getOpcode()) { + case Op_TauPi: + return getAliases(inst->getSrc(0), aliases, addend); + + case Op_Add: + { + Opnd *op0 = inst->getSrc(0); + Opnd *op1 = inst->getSrc(1); + Opnd *constOpnd0 = getConstantOpnd(op0); + Opnd *constOpnd1 = getConstantOpnd(op1); + if ((constOpnd0 || constOpnd1) && + (inst->getType() == Type::Int32)) { + // I assume we've done folding first + assert(!(constOpnd0 && constOpnd1)); + if (constOpnd1) { + // swap the operands; + constOpnd0 = constOpnd1; + op1 = op0; + } + // now constOpnd0 should be constant + // op1 is the non-constant operand + + Inst *inst0 = constOpnd0->getInst(); + assert(inst0); + ConstInst *cinst0 = inst0->asConstInst(); + assert(cinst0); + ConstInst::ConstValue cv = cinst0->getValue(); + int32 c = cv.i4; + int64 sumc = c + addend; + if (add_overflowed(sumc, c, addend)) { + return false; + } else { + VarBound vb(op1); + aliases->theSet.insert(PiBound(inst->getType(), 1, vb, sumc)); + getAliases(op1, aliases, sumc); + return true; + } + } + } + break; + case Op_Sub: + { + Opnd *constOpnd = getConstantOpnd(inst->getSrc(1)); + if (constOpnd && (inst->getType() == Type::Int32)) { + Opnd *op0 = inst->getSrc(0); + Opnd *op1 = constOpnd; + // now op1 should be constant + // I assume we've done folding first + if( !(!getConstantOpnd(op0)) ) assert(0); + + Inst *inst1 = op1->getInst(); + assert(inst1); + ConstInst *cinst1 = inst1->asConstInst(); + assert(cinst1); + ConstInst::ConstValue cv = cinst1->getValue(); + int64 c = cv.i4; + int64 negc = -c; + int64 subres = addend + negc; + if (neg_overflowed(negc, c) || + add_overflowed(subres, addend, negc)) { + return false; + } else { + VarBound vb(op1); + aliases->theSet.insert(PiBound(inst->getType(), 1, vb, subres)); + getAliases(op1, aliases, subres); + return true; + } + } + } + break; + case Op_Copy: + assert(0); // do copy propagation first + break; + case Op_TauCheckZero: + return false; + default: + break; + } + return false; +} +//------------------------------------------------------------------------------ + +// checks for aliases of opnd, inserts them. +void InsertPi::insertPiForOpndAndAliases(Node *block, + Opnd *org, + const PiCondition &cond, + Opnd *tauOpnd) +{ + const PiBound &lb = cond.getLb(); + const PiBound &ub = cond.getUb(); + + if((_problemType == Lower) && lb.isUndefined()) return; + else if((_problemType == Upper) && ub.isUndefined()) return; + + if (_useAliases) { + if (Log::isEnabled()) { + Log::out() << "Inserting Pi Node for opnd "; + org->print(Log::out()); + Log::out() << " and its aliases"; + Log::out() << " under condition "; + cond.print(Log::out()); + Log::out() << std::endl; + } + AbcdAliases aliases(_mm); + // check for aliases + insertPiForOpnd(block, org, cond, tauOpnd); + if (getAliases(org, &aliases, 0)) { + if (Log::isEnabled()) { + Log::out() << "Has aliases "; + AbcdAliasesSet::iterator iter = aliases.theSet.begin(); + AbcdAliasesSet::iterator end = aliases.theSet.end(); + for ( ; iter != end; iter++) { + PiBound alias = *iter; + alias.print(Log::out()); + Log::out() << " "; + } + Log::out() << std::endl; + } + AbcdAliasesSet::iterator iter = aliases.theSet.begin(); + AbcdAliasesSet::iterator end = aliases.theSet.end(); + for ( ; iter != end; iter++) { + PiBound alias = *iter; + PiBound inverted = alias.invert(org); // org - c + // plug-in lb and ub into inverted, yields bounds: + // [ lb - c, ub - c ] + PiCondition renamedCondition(PiBound(inverted, org, lb), + PiBound(inverted, org, ub)); + insertPiForOpnd(block, alias.getVar().the_var, + renamedCondition, tauOpnd); + } + } + } else { + insertPiForOpnd(block, org, cond, tauOpnd); + } +} +//------------------------------------------------------------------------------ + +// a DomWalker, to be applied forwards/preorder +class RenamePiWalker { +public: + + RenamePiWalker(InsertPi *insert_pi, + MemoryManager &localMM, + SparseOpndMap* &piMap0, + int sizeEstimate0) : + _insertPi(insert_pi), + localMemManager(localMM), + _piMap(piMap0), + sizeEstimate(sizeEstimate0) + {} + + void applyToDominatorNode(DominatorNode *domNode) + { + _insertPi->renamePiVariablesInNode(domNode->getNode()); + } + + void enterScope() + { + if (!_piMap) _piMap = + new (localMemManager) SparseOpndMap(sizeEstimate, + localMemManager, 1, 4, 7); + _piMap->enter_scope(); + } + + void exitScope() + { + _piMap->exit_scope(); + } +private: + InsertPi* _insertPi; + MemoryManager &localMemManager; + SparseOpndMap* &_piMap; + int sizeEstimate; +}; +//------------------------------------------------------------------------------ + +void InsertPi::renamePiVariables() +{ + MethodDesc &methodDesc= _irManager.getMethodDesc(); + uint32 byteCodeSize = methodDesc.getByteCodeSize(); + MemoryManager localMemManager(byteCodeSize*16, "Abcd::renamePiNodes"); + + RenamePiWalker theWalker(this, localMemManager, _piMap, byteCodeSize); + DomTreeWalk(_domTree, theWalker, localMemManager); +} +//------------------------------------------------------------------------------ + +void InsertPi::renamePiVariablesInNode(Node *block) +{ + // For each variable use in the block, check for a Pi version in + // the piTable. Since we are visiting in preorder over dominator + // tree dominator order, any found version will dominate this node. + + // we defer adding any new mappings for the Pi instructions here until + // we are past the Pi instructions + + // first process any pi nodes, just the RHSs + Inst* headInst = (Inst*)block->getFirstInst(); + for (int phase=0; phase < 2; ++phase) { + // phase 0: remap just Pi node source operands + // phase 1: add Pi remappings, remap source operands of other instructions + + for (Inst* inst = headInst->getNextInst(); inst != NULL; inst = inst->getNextInst()) { + + if (inst->getOpcode() == Op_TauPi) { + if (phase == 1) { + // add any Pi node destination to the map. + + Opnd *dstOpnd = inst->getDst(); + assert(dstOpnd->isPiOpnd()); + Opnd *orgOpnd = dstOpnd->asPiOpnd()->getOrg(); + if (_useAliases) { + if (orgOpnd->isSsaVarOpnd()) { + orgOpnd = orgOpnd->asSsaVarOpnd()->getVar(); + } + } + _piMap->insert(orgOpnd, dstOpnd); + if (Log::isEnabled()) { + Log::out() << "adding remap for Pi of "; + orgOpnd->print(Log::out()); + Log::out() << " to "; + inst->getDst()->print(Log::out()); + Log::out() << std::endl; + } + + continue; // don't remap Pi sources; + } + } else { + if (phase == 0) { + // no more Pi instructions, we're done with phase 0. + break; + } + } + + // now process source operands + uint32 numOpnds = inst->getNumSrcOperands(); + for (uint32 i=0; igetSrc(i); + if (opnd->isPiOpnd()) + opnd = opnd->asPiOpnd()->getOrg(); + Opnd *foundOpnd = _piMap->lookup(opnd); + if (foundOpnd) { + inst->setSrc(i,foundOpnd); + } + } + + if (inst->getOpcode() == Op_TauPi) { + // for a Pi, remap variables appearing in the condition as well + if (Log::isEnabled()) { + Log::out() << "remapping condition in "; + inst->print(Log::out()); + Log::out() << std::endl; + } + TauPiInst *thePiInst = inst->asTauPiInst(); + assert(thePiInst); + PiCondition *cond = thePiInst->cond; + if (Log::isEnabled()) { + Log::out() << " original condition is "; + cond->print(Log::out()); + Log::out() << std::endl; + } + Opnd *lbRemap = cond->getLb().getVar().the_var; + if (lbRemap) { + if (Log::isEnabled()) { + Log::out() << " has lbRemap="; + lbRemap->print(Log::out()); + Log::out() << std::endl; + } + if (lbRemap->isPiOpnd()) + lbRemap = lbRemap->asPiOpnd()->getOrg(); + Opnd *lbRemapTo = _piMap->lookup(lbRemap); + if (lbRemapTo) { + if (Log::isEnabled()) { + Log::out() << "adding remap of lbRemap="; + lbRemap->print(Log::out()); + Log::out() << " to lbRemapTo="; + lbRemapTo->print(Log::out()); + Log::out() << " to condition "; + cond->print(Log::out()); + } + PiCondition remapped(*cond, lbRemap, lbRemapTo); + if (Log::isEnabled()) { + Log::out() << " YIELDS1 "; + remapped.print(Log::out()); + } + *cond = remapped; + if (Log::isEnabled()) { + Log::out() << " YIELDS "; + cond->print(Log::out()); + Log::out() << std::endl; + } + } + } + Opnd *ubRemap = cond->getUb().getVar().the_var; + if (ubRemap && (lbRemap != ubRemap)) { + if (Log::isEnabled()) { + Log::out() << " has ubRemap="; + ubRemap->print(Log::out()); + Log::out() << std::endl; + } + if (ubRemap->isPiOpnd()) + ubRemap = ubRemap->asPiOpnd()->getOrg(); + Opnd *ubRemapTo = _piMap->lookup(ubRemap); + if (ubRemapTo) { + if (Log::isEnabled()) { + Log::out() << "adding remap of ubRemap="; + ubRemap->print(Log::out()); + Log::out() << " to ubRemapTo="; + ubRemapTo->print(Log::out()); + Log::out() << " to condition "; + cond->print(Log::out()); + } + PiCondition remapped(*cond, ubRemap, ubRemapTo); + if (Log::isEnabled()) { + Log::out() << " YIELDS1 "; + remapped.print(Log::out()); + } + *cond = remapped; + if (Log::isEnabled()) { + Log::out() << " YIELDS "; + cond->print(Log::out()); + Log::out() << std::endl; + } + } + } + } + } + } +} +//------------------------------------------------------------------------------ + +// a ScopedDomNodeInstWalker, forward/preorder +class RemovePiWalker { +public: + RemovePiWalker(InsertPi* ins) : _insertPi(ins), block(0) // forward + {} + + void startNode(DominatorNode *domNode) { block = domNode->getNode(); }; + void applyToInst(Inst *i) { _insertPi->removePiOnInst(block, i); } + void finishNode(DominatorNode *domNode) {} + + void enterScope() {} + void exitScope() {} +private: + InsertPi* _insertPi; + Node* block; +}; +//------------------------------------------------------------------------------ + +void InsertPi::removePi() +{ + RemovePiWalker removePiWalker(this); + typedef ScopedDomNodeInst2DomWalker + RemovePiDomWalker; + RemovePiDomWalker removePiDomWalker(removePiWalker); + DomTreeWalk(_domTree, removePiDomWalker, _mm); +} +//------------------------------------------------------------------------------ + +void InsertPi::removePiOnInst(Node* block, Inst *inst) +{ + if ( inst->getOpcode() == Op_TauPi ) { + inst->unlink(); + }else{ + // replace Pi operands with original ones + uint32 num_opnds = inst->getNumSrcOperands(); + for (uint32 i = 0; i < num_opnds; i++) { + Opnd* pi_opnd = inst->getSrc(i); + while ( pi_opnd->isPiOpnd() ) { + pi_opnd = pi_opnd->asPiOpnd()->getOrg(); + } + inst->setSrc(i, pi_opnd); + } + } +} +//------------------------------------------------------------------------------ + +} //namespace Jitrino +