// -*- C++ -*- (c) 2019 Vladimír Štill DIVINE_RELAX_WARNINGS #include #include #include #include #include #include #include #include #include #include #include DIVINE_UNRELAX_WARNINGS #include #include #include #include #include #include #include namespace lart::nontermination { struct Termsec { static PassMeta meta() { return passMetaC( "termsec", "Instrument detection of terminating blocks.", []( PassVector &ps, std::string opt ) { ps.emplace_back< Termsec >( opt ); } ); } explicit Termsec( std::string mode ) : _mode( read_nonterm( mode ) ) { } void run( llvm::Module &m ) { auto hook_begin = m.getFunction( "__lart_termsec_begin" ); auto hook_end = m.getFunction( "__lart_termsec_end" ); auto impl_begin = m.getFunction( "__lart_termsec_begin_impl" ); ASSERT( impl_begin ); auto impl_end = m.getFunction( "__lart_termsec_end_impl" ); ASSERT( impl_end ); auto resched_cond_hook = m.getFunction( "__lart_termsec_reschedule_cond_acc_hook" ); auto resched_hook = m.getFunction( "__lart_termsec_reschedule_acc_hook" ); auto resched = m.getFunction( "__dios_reschedule" ); auto suspend = m.getFunction( "__dios_suspend" ); if ( _mode != NonterminationMode::Global ) { using FP = std::pair< llvm::Function *, llvm::Function * >; for ( auto [ hook, impl ] : { FP{ hook_begin, impl_begin }, FP{ hook_end, impl_end } } ) { std::vector< llvm::User * > users( hook->user_begin(), hook->user_end() ); for ( auto usr : users ) { llvm::CallSite call( usr ); if ( call ) { auto kind_c = llvm::dyn_cast< llvm::ConstantInt >( call.getArgument( 0 ) ); if ( !kind_c ) UNREACHABLE( "Unexpected non-constant termsec kind value in ", usr ); NonterminationMode kind = NonterminationMode( kind_c->getZExtValue() ); if ( _mode & kind ) call.setCalledFunction( impl ); } } } } for ( auto dios_end : { resched, suspend } ) { if ( dios_end ) { llvm::IRBuilder<> irb( &*dios_end->begin(), dios_end->begin()->getFirstInsertionPt() ); llvm::CallSite cs = irb.CreateCall( _mode == NonterminationMode::Global ? resched_hook : resched_cond_hook, { } ); llvm::InlineFunctionInfo ifi; llvm::InlineFunction( cs, ifi ); } } } NonterminationMode _mode; }; PassMeta termsecPass() { return Termsec::meta(); } } // namespace lart::nontermination