// -*- C++ -*- (c) 2020 Henrich Lauko #pragma once DIVINE_RELAX_WARNINGS #include #include #include DIVINE_UNRELAX_WARNINGS #include #include #include namespace lart::tag { using ctag_t = llvm::StringLiteral; using tag_t = llvm::StringRef; using meta_t = llvm::StringRef; using maybe_meta = std::optional< std::string >; namespace noalias { constexpr ctag_t prefix = "lart.noalias"; constexpr ctag_t arg = "lart.noalias.arg"; constexpr ctag_t ret = "lart.noalias.ret"; } namespace function { constexpr ctag_t arguments = "lart.function.argument.tags"; } namespace transform { constexpr ctag_t prefix = "lart.transform"; namespace ignore { constexpr ctag_t ret = "lart.transform.ignore.ret"; constexpr ctag_t arg = "lart.transform.ignore.arg"; } constexpr ctag_t forbidden = "lart.transform.forbidden"; } /* creates metadata node from given string */ llvm::MDNode * create( llvm::LLVMContext & ctx, meta_t str ); /* Gets stored metadata string from position 'idx' from metadata node */ maybe_meta value( llvm::MDNode * node, unsigned idx = 0 ); /* Metadata are stored as map, where tag points to metadata tuple */ /* gets metadata string from value for given meta tag */ maybe_meta get( llvm::Value * val, tag_t tag ); /* gets metadata for given operand */ template< typename value_t > maybe_meta operand( value_t v, unsigned idx ) { if ( auto node = v->getMetadata( function::arguments ) ) return ::lart::tag::value( node, idx ); return std::nullopt; } llvm::Value * get_value_from_meta( llvm::Instruction * inst, tag_t tag ); /* checks whether values has metadata for given tag */ bool has( llvm::Value * val, tag_t tag ); /* sets metadata with tag to value */ void set( llvm::Value * val, tag_t tag ); void set( llvm::Value * val, tag_t tag, meta_t meta ); void set_value_as_meta( llvm::Instruction * inst, tag_t tag, llvm::Value * val ); namespace tuple { inline llvm::MDTuple * create( llvm::LLVMContext & ctx, const llvm::ArrayRef< llvm::Metadata * > vals ) { assert( !vals.empty() ); return llvm::MDTuple::getDistinct( ctx, vals ); } template< typename Init > inline llvm::MDTuple * create( llvm::LLVMContext & ctx, unsigned size, Init init ) { std::vector< llvm::Metadata* > values( size ); std::generate( values.begin(), values.end(), init ); return llvm::MDTuple::getDistinct( ctx, values ); } inline llvm::MDTuple * empty( llvm::LLVMContext &ctx ) { return llvm::MDTuple::getDistinct( ctx, {} ); } } namespace function { inline auto ignore_call = [] ( llvm::Function * fn ) -> bool { return has( fn, transform::ignore::arg ); }; inline auto ignore_return = [] ( llvm::Function * fn ) -> bool { return has( fn, transform::ignore::ret ); }; inline auto is_forbidden = [] ( llvm::Function * fn ) -> bool { return has( fn, transform::forbidden ); }; } namespace argument { void set( llvm::Argument * arg, meta_t meta ); void set( llvm::Argument * arg, llvm::Metadata * node ); maybe_meta get( llvm::Argument * arg ); bool has( llvm::Argument * arg ); } inline auto tag_filter( tag_t t ) { return [t] ( auto v ) { return lart::tag::has( v, t ); }; } template< typename LLVM > auto enumerate_range( LLVM & ll, tag_t t ) { return util::inst_range( ll ).filter( tag_filter( t ) ); } template< typename LLVM > auto enumerate( LLVM & ll, tag_t t ) { return enumerate_range( ll, t ).freeze(); } template< typename I, typename LLVM > auto enumerate_range( LLVM & ll, tag_t t ) { return util::filter_range< I >( enumerate_range( ll, t ) ); } template< typename I, typename LLVM > auto enumerate( LLVM & ll, tag_t t ) { return enumerate_range< I >( ll, t ).freeze(); } inline auto calls_with_tag( llvm::Module & m, tag_t t ) { return util::callsites( enumerate_range( m, t ) ); } inline auto functions_with_tag( llvm::Module & m, tag_t t ) { return util::functions_range( m ).filter( tag_filter( t ) ).freeze(); } }