// -*- C++ -*- (c) 2015 Vladimír Štill DIVINE_RELAX_WARNINGS #include #include #include #include #include #include #include DIVINE_UNRELAX_WARNINGS #include #include #include #ifndef LART_ANALYSIS_BBREACH_H #define LART_ANALYSIS_BBREACH_H namespace lart { namespace analysis { /* Reachablility for basic blocks and instructions in function Internally, this uses transitive closure of SCC collapse of basic block graph, both for forward and backward transition relation */ struct Reachability { using SCC = BasicBlockSCC::SCC; using BB = llvm::BasicBlock; using I = llvm::Instruction; Reachability( llvm::Function &fn, BasicBlockSCC *scc ) : _sccs( scc ) { if ( !fn.empty() ) _mk( fn ); } private: // has to be defined befor use template< typename T > auto _refEqPtr( T *ptr ) { return [ptr]( T &ref ) { return ptr == &ref; }; } public: bool reachable( BB *from, BB *to ) const { return from == to || strictlyReachable( from, to ); } bool strictlyReachable( BB *from, BB *to ) const { return _strictlyReachable( from, to, _forwSccDagClosure ); } bool backwardReachable( BB *from, BB *to ) const { return from == to || strictlyBackwardReachable( from, to ); } bool strictlyBackwardReachable( BB *from, BB *to ) const { return _strictlyReachable( from, to, _backSccDagClosure ); } bool reachable( I *from, I *to ) { return from == to || strictlyReachable( from, to ); } bool strictlyReachable( I *from, I *to ) { // as a special case invoke is considered to be defined at the beginning // of 'normal' patch block, that is it does not reach 'unwind' block, but // it reaches all instructions in 'normal' block (and any block reachable // form the normal block) if ( auto inv = llvm::dyn_cast< llvm::InvokeInst >( from ) ) return reachable( inv->getNormalDest(), to->getParent() ); // this includes case when from is before to in the same bb and there // is cycle going through the bb, and the case of to being // in any reachable bb if ( strictlyReachable( from->getParent(), to->getParent() ) ) return true; // the remaining reachable case is only if from and to are in same bb, // but to occurs later if ( from->getParent() != to->getParent() ) return false; // check if to is in same bb, but later then from auto it = std::next( llvm::BasicBlock::iterator( from ) ); return std::find_if( it, from->getParent()->end(), _refEqPtr( to ) ) != from->getParent()->end(); } bool backwardReachable( I *from, I *to ) { return from == to || strictlyBackwardReachable( from, to ); } bool strictlyBackwardReachable( I *from, I *to ) { auto fromBB = from->getParent(); auto toBB = to->getParent(); // again, invoke is considered to be part of its 'norma' destination // block (see strictlyReachable for more details) if ( auto inv = llvm::dyn_cast< llvm::InvokeInst >( to ) ) return backwardReachable( fromBB, inv->getNormalDest() ); if ( strictlyBackwardReachable( fromBB, toBB ) ) return true; if ( fromBB != toBB ) return false; auto it = std::find_if( fromBB->rbegin(), fromBB->rend(), _refEqPtr( from ) ); return std::find_if( it, fromBB->rend(), _refEqPtr( to ) ) != fromBB->rend(); } private: using Map = std::unordered_map< const SCC *, std::unordered_set< const SCC * > >; bool _strictlyReachable( BB *from, BB *to, const Map &clo ) const { auto fromSCC = _sccs->get( from ); auto toSCC = _sccs->get( to ); return fromSCC->canonical() == toSCC->canonical() // on cycle || clo.find( fromSCC )->second.count( toSCC ); // reachable dag node } void _mk( llvm::Function &fn ) { std::unordered_set< const SCC * > seen; for ( auto &bb : fn ) _closure( _sccs->get( &bb ), seen, _forwSccDagClosure, &SCC::succs ); for ( auto &bb : fn ) _closure( _sccs->get( &bb ), seen, _backSccDagClosure, &SCC::preds ); } template< typename Seen, typename Nx > void _closure( const SCC *scc, Seen &seen, Map &closure, Nx nx ) { if ( seen.insert( scc ).second ) { auto &nxclo = closure[ scc ]; for ( SCC *s : (scc->*nx)() ) { // recursively calculate closure of successor _closure( s, seen, closure, nx ); // then add it to closure of this SCC, together with successor nxclo.insert( s ); auto &sclo = closure[ s ]; nxclo.insert( sclo.begin(), sclo.end() ); } } } BasicBlockSCC *_sccs; Map _forwSccDagClosure; Map _backSccDagClosure; }; } // namespace analysis } // namespace lart #endif // LART_ANALYSIS_BBREACH_H