Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Protoベースの実行時コンパイル

 Protoベースの実行時コンパイル

Boost.Protoを使って構築した構文木をLLVMで実行時にコンパイルするライブラリについて解説します

Fadis

May 09, 2015
Tweet

More Decks by Fadis

Other Decks in Programming

Transcript

  1. if( x >= 5 ) x *= 2;! else x

    += 5; ! cmpl! $4, -4(%rbp)! ! jle! .L2! ! sall! -4(%rbp)! ! jmp! .L3! .L2:! ! addl! $5, -4(%rbp)! .L3:
  2. if( true ) x *= 2;! else x += 5;

    ! sall! -4(%rbp) ίϯύΠϧ࣌ʹ৚݅ࣜͷ஋͕ఆ·͍ͬͯͨΒ ෼ذΛແ͔ͬͨ͜ͱʹग़དྷΔ
  3. ࣮ྫύέοτϑΟϧλ ৚݅ʹ߹கͨ͠ύέοτΛऽΔ ৚݅ if( ௨৴ݩͷΞυϨε͕΄͛΄͛ )...! if( ௨৴ઌͷϙʔτ͕΄͛΄͛ )...! if(

    ύέοτͷ௕͕͞΄͛΄͛ )... ࣮ࡍʹ͸ϙʔτ੍ݶ͚ͩ ৚݅͸࣮ߦ࣌ʹ มߋ͞ΕΔ͔΋ ৚݅ࣜͷத਎͕͔ΘΔස౓ʹରͯ͠ ॲཧ͢Δσʔλͷྔ͕ۃ୺ʹଟ͍ͱ ແବͳ෼ذ͕ແࢹग़དྷͳ͍
  4. llvm::Value *x = ir_builder.CreateLoad( arg1 );! llvm::Value *y = ir_builder.CreateLoad(

    arg2 );! llvm::Value *a = llvm::ConstantFP::get(! llvm::Type::getFloatTy( context ), 0.8f! );! llvm::Value *b = llvm::ConstantFP::get(! llvm::Type::getFloatTy( context ), 0.2f! );! llvm::Value *t0 = ir_builder.CreateMul( x, a );! llvm::Value *t1 = ir_builder.CreateMul( y, b );! llvm::Value *result = ir_builder.CreateAdd( t0, t1 ); arg1 * 0.8f + arg2 * 0.2f; Λॻ͘୅ΘΓʹ ઈରݏͩʂ $ Ͱ
  5. llvm::Value *x = ir_builder.CreateLoad( arg1 );! llvm::Value *y = ir_builder.CreateLoad(

    arg2 );! llvm::Value *a = llvm::ConstantFP::get(! llvm::Type::getFloatTy( context ), 0.8f! );! llvm::Value *b = llvm::ConstantFP::get(! llvm::Type::getFloatTy( context ), 0.2f! );! llvm::Value *t0 = ir_builder.CreateMul( x, a );! llvm::Value *t1 = ir_builder.CreateMul( y, b );! llvm::Value *result = ir_builder.CreateAdd( t0, t1 ); ͬͯॻ͍ͨͷͱ౳ՁʹͳΔ ຐ๏ͷϥΠϒϥϦ࡞Εͳ͍͔ͳʔ arg1 * 0.8f + arg2 * 0.2f; ͬͯॻ͍ͨΒ $ Ͱ
  6. struct woo {! typedef int function_type(! softdsp::data_layout::array< int, 2 >,!

    softdsp::data_layout::tuple<! int, double, int, int! >,! softdsp::data_layout::array<! softdsp::data_layout::array< int, 2 >, 2! >! );! };! sd_module.create_function< woo >()[! softdsp::_1[ 0 ] <<= 20,! softdsp::_1[ 1 ] = (! softdsp::static_cast_< int32_t >(! softdsp::static_cast_< float >(! softdsp::_1[ 0 ]! ) * 3 + ++--softdsp::at_c< 2 >( softdsp::_2 ) / 3! ) + (! ~softdsp::_3[ 1 ][ 1 ] << 1 )! ) % 6! ];
  7. TEXPP HFUFMFNFOUQUSJOCPVOET<Y<YJ>>  J J HFUFMFNFOUQUSJOCPVOET<YJ>  J J MPBEJ

     YPSJ  TIMJ  HFUFMFNFOUQUSJOCPVOET  J J MPBEJ  TVCJ  TUPSFJ J  MPBEJ  BEEJ  TUPSFJ J  MPBEJ  TEJWJ  HFUFMFNFOUQUSJOCPVOET<YJ>  J J MPBEJ  TJUPGQJUPqPBU GNVMqPBU F  TJUPGQJUPqPBU GBEEqPBU  GQUPTJqPBUUPJ BEEJ  TSFNJ  HFUFMFNFOUQUSJOCPVOET<YJ>  J J TUPSFJ J  HFUFMFNFOUQUSJOCPVOET<YJ>  J J MPBEJ  TIMJ  TUPSFJ J  MPBEJ  SFUJ
  8. &YQSFTTJPO5FNQMBUFT QSPUPMJU      JOU JOU JOUͷఆ਺ܕ

    JOUͷఆ਺ʹJOUͷఆ਺Λ଍͢ܕ JOUͷఆ਺ʹJOUͷఆ਺Λ଍ͨ͠΍ͭʹJOUͷఆ਺Λֻ͚Δܕ JOU ͜ͷࣜͷ݁Ռͷܕ͸ JOUͷఆ਺ʹJOUͷఆ਺Λ଍ͨ͠΍ͭʹJOUͷఆ਺Λֻ͚ͨ΍ͭʹ ུ JOU JOUͷఆ਺ʹJOUͷఆ਺Λ଍ͨ͠΍ͭʹJOUͷఆ਺Λֻ͚ͨ΍ͭʹ ུ ςϯϓϨʔτΛ࢖ͬͯܕͰߏจ໦Λදݱ͢Δ
  9. &YQSFTTJPO5FNQMBUFT ͖ͬ͞ͷTPGUETQͷࣜͷ৔߹ boost::proto::exprns_::expr<boost::proto::tagns_::tag::comma, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_left_assign, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::subscript, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<softdsp::placeholder<mpl_::int_<0> > >, 0l>

    const&, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<int const&>, 0l> >, 2l> const&, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<int const&>, 0l> >, 2l> const&, boost::proto::exprns_::expr<boost::proto::tagns_::tag::assign, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::subscript, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<softdsp::placeholder<mpl_::int_<0> > >, 0l> const&, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<int const&>, 0l> >, 2l> const&, boost::proto::exprns_::expr<boost::proto::tagns_::tag::modulus, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::plus, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::function, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<softdsp::keywords::static_cast_<int> >, 0l>&, boost::proto::exprns_::expr<boost::proto::tagns_::tag::plus, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::multiplies, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::function, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<softdsp::keywords::static_cast_<float> >, 0l>&, boost::proto::exprns_::expr<boost::proto::tagns_::tag::subscript, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<softdsp::placeholder<mpl_::int_<0> > >, 0l> const&, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<int const&>, 0l> >, 2l> const&>, 2l> const&, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<int const&>, 0l> >, 2l> const&, boost::proto::exprns_::expr<boost::proto::tagns_::tag::divides, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::pre_inc, boost::proto::argsns_::list1<boost::proto::exprns_::expr<boost::proto::tagns_::tag::pre_dec, boost::proto::argsns_::list1<boost::proto::exprns_::expr<boost::proto::tagns_::tag::function, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<softdsp::keywords::at<mpl_::size_t<2ul> > >, 0l>&, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<softdsp::placeholder<mpl_::int_<1> > >, 0l> const&>, 2l> const&>, 1l> const&>, 1l> const&, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<int const&>, 0l> >, 2l> const&>, 2l> const&>, 2l> const&, boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_left, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::complement, boost::proto::argsns_::list1<boost::proto::exprns_::expr<boost::proto::tagns_::tag::subscript, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::subscript, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<softdsp::placeholder<mpl_::int_<2> > >, 0l> const&, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<int const&>, 0l> >, 2l> const&, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<int const&>, 0l> >, 2l> const&>, 1l> const&, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<int const&>, 0l> >, 2l> const&>, 2l> const&, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<int const&>, 0l> >, 2l> const&>, 2l> const&>, 2l>
  10. #PPTU1SPUP ग़དྷ্໊͕ͬͨঢ়͕͍ͨ͠ܕͷ஋Λ CPPTUQSPUPFWBM ໊ঢ় ུ ஋ DPOUFYU  struct context

    {! template< typename Expr, typename Enable = void > struct eval{};! template< typename Expr > struct eval< Expr,! typename boost::enable_if< proto::matches< Expr,! proto::plus< proto::_, proto::_ >! > >::type > {! typedef int result_type;! result_type operator()( Expr &expr, context_type &context ){! (ҎԼུ) Ͱॲཧ͢Δ ߏจ໦Λ୧Δ࣌ʹߦ͏ॲཧΛఆٛͨ͠΋ͷ
  11. template< typename Expr > struct eval< Expr,! typename boost::enable_if<! proto::matches<

    Expr,! proto::plus< proto::_, proto::_ >! >! >::type! > {! typedef llvm::Value* result_type;! result_type operator()(! Expr &expr,! context_type &context! ) {! return ir_builder.CreateAdd(! proto::eval( boost::proto::left( expr ), context ),! proto::eval( boost::proto::right( expr ), context )! );! }! }; Ճࢉ
  12. template< typename Expr > struct eval< Expr,! typename boost::enable_if<! proto::matches<

    Expr,! proto::terminal< proto::_ >! >! >::type! > {! typedef llvm::Value* result_type;! result_type operator()(! Expr &expr,! context_type &context,! typename boost::enable_if< boost::is_same< int32_t,! decltype( boost::proto::value( expr ) )! > >::type* = 0! ) {! return llvm::ConstantInt::get(! llvm::Type::getInt32Ty( context ),! boost::proto::value( expr )! );! }! }; ߏจ໦ͷऴ୺
  13. --7.ͷ੔਺ܕ J J JJJJ $ ͷ੔਺ܕ CPPM DIBS TIPSU JOU

    MPOH MPOHMPOH TJHOFE ූ߸෇͖ VOTJHOFE ූ߸ແ͠ ූ߸Ͳ͍ͬͨ͜ʂ
  14. add i8 %0, %1 div i8 %0, %1 ූ߸ແͩͬͨ͠৔߹Y& YY#

    ූ߸෇͖ͩͬͨ৔߹Y& YY# ූ߸ແͩͬͨ͠৔߹Y&YY ූ߸෇͖ͩͬͨ৔߹Y&YY'$ udiv i8 %0, %1 sdiv i8 %0, %1 ผͷ໋ྩ ූ߸ͷ༗ແͷ৘ใ͕ඞཁ
  15. template< typename Expr > struct eval< Expr,! typename boost::enable_if<! proto::matches<

    Expr,! proto::plus< proto::_, proto::_ >! >! >::type! > {! typedef llvm::Value* result_type;! result_type operator()(! Expr &expr,! context_type &context! ) {! return ir_builder.CreateAdd(! proto::eval( boost::proto::left( expr ), context ),! proto::eval( boost::proto::right( expr ), context )! );! }! }; $ Ͱͷܕͷ৘ใ͕ ্Ґͷϊʔυʹ ఻ΘΒͳ͍
  16. template< typename Expr > struct eval< Expr,! typename boost::enable_if<! proto::matches<

    Expr,! proto::divides< proto::_, proto::_ >! >! >::type! > {! typedef llvm::Value* result_type;! result_type operator()(! Expr &expr,! context_type &context! ) {! return ir_builder.Create???(! proto::eval( boost::proto::left( expr ), context ),! proto::eval( boost::proto::right( expr ), context )! );! }! }; llvm::Value* ූ߸ͷ༗ແͷ৘ใ͕ࣦΘΕ͍ͯͯ ໋ྩΛܾఆͰ͖ͳ͍
  17. struct return_value_ {};! template< typename T >! struct return_value :

    public return_value_ {! return_value( llvm::Value *value_ )! : value( value_ ) {}! llvm::Value * const value;! }; return_value< signed int >(! llvm::ConstantInt::get(! llvm::Type::getInt32Ty( context ),! boost::proto::value( expr )! )! ); $ ͰԿܕͩͬͨͷ͔Λ෇Ճͯ͠ฦ͢
  18. template< typename Expr > struct eval< Expr,! typename boost::enable_if<! proto::matches<

    Expr,! proto::plus< proto::_, proto::_ >! >! >::type! > {! typedef (ུ) raw_result_type; // left + rightͷ݁Ռͷܕ! typedef return_value< raw_result_type > result_type;! result_type operator()(! Expr &expr,! context_type &context! ) {! return return_value< raw_result_type >(! ir_builder.CreateAdd(! proto::eval( boost::proto::left( expr ), context ),! proto::eval( boost::proto::right( expr ), context )! )! );! }! }; ฦΓ஋ʹ$ Ͱͷܕ͕ ؚ·ΕΔ
  19. template< typename Expr > struct eval< Expr,! typename boost::enable_if<! proto::matches<

    Expr,! proto::divides< proto::_, proto::_ >! >! >::type! > {! typedef (ུ) raw_result_type; // left / rightͷ݁Ռͷܕ! typedef return_value< raw_result_type > result_type;! result_type operator()(! Expr &expr, context_type &context,! typename boost::enable_if<! boost::is_signed< raw_result_type >! >::type* = 0! ) {! return return_value< raw_result_type >(! ir_builder.CreateSDiv(! proto::eval( boost::proto::left( expr ),! context ).value,! proto::eval( boost::proto::right( expr ),! context ).value! ));! }! }; ූ߸෇͖Ͱ͋Δ͜ͱΛ ֬ೝ ූ߸෇͖༻ͷ໋ྩʹ֬ఆͰ͖Δ
  20. B C  D E BΛϩʔυ a / b +

    c * d Ϩδελʹϩʔυ ͞ΕͨBͱCͰআࢉ আࢉͷ݁ՌΛ ʹฦ͢ CΛϩʔυ
  21. B C  D E e = a / b

    + c * d  F FΛϩʔυ ͕ೖͬͯͨ 3 = a / b + c * d ͑
  22. int a;! int b = 1;! int c = 2;

    a = b + c; ࢀর ࢀর ࢀর ࣜͷதʹ໊લΛ෇͚ͨม਺Λஔ͍ͨஈ֊Ͱ͸ɺ ͦΕ͸ม਺΁ͷࢀরͱͯ͠ѻΘΕΔ ՃࢉΛ͢Δ࣌ʹॳΊͯ ϩʔυ͢Δ
  23. a = b + c; ม਺BͷΞυϨε ໌ࣔతʹ໊લΛ༩͑ΒΕͨྖҬΛࢦ͍ͯ͠Δ ࠨล஋ࢀর ʹɺC Dͷ݁ՌΛ୅ೖ

    ୅ೖޙʹഁغ͞ΕΔҰ࣌ྖҬΛࢦ͍ͯ͠Δ ӈล஋ࢀর ࠨล஋ࢀরʹ͸୅ೖͰ͖Δ ӈล஋ࢀরʹ͸୅ೖͰ͖ͳ͍
  24. template< typename Index >! return_value< typename boost::mpl::at<! boost::function_types::parameter_types<! function_type! >,!

    Index! >::type& > as_value( const placeholder< Index > & ) {! llvm::Value *value = &*std::next(! llvm_function->getArgumentList().begin(),! Index::value! );! return return_value< typename boost::mpl::at<! boost::function_types::parameter_types<! function_type! >,! Index! >::type& >( value );! } ϩʔυ͠ͳ͍ͰΞυϨεΛฦ͢
  25. template< typename Expr > struct eval< Expr,! typename boost::enable_if<! proto::matches<

    Expr,! proto::plus< proto::_, proto::_ >! >! >::type! > {! typedef (ུ) raw_result_type; // left + rightͷ݁Ռͷܕ! typedef return_value< raw_result_type > result_type;! result_type operator()(! Expr &expr,! context_type &context! ) {! const auto left =! tools->load( proto::eval( boost::proto::left( expr ) );! const auto right =! tools->load( proto::eval( boost::proto::right( expr ) );! return return_value< raw_result_type >(! ir_builder.CreateAdd( left.value, right.value )! );! }! }; ܭࢉͷ௚લͰϩʔυ
  26. template< typename value_type >! return_value< typename boost::remove_reference<! typename get_return_type< value_type

    >::type! >::type >! load( value_type value,! typename boost::enable_if<! boost::mpl::and_<! boost::is_convertible< value_type, return_value_ >,! boost::is_reference< typename get_return_type< value_type >::type >! >! >::type* = 0! ) {! return return_value< typename boost::remove_reference<! typename get_return_type< value_type >::type! >::type >( ir_builder.CreateLoad( value.value ) );! }! template< typename value_type >! value_type! load( value_type value,! typename boost::enable_if< boost::mpl::not_< boost::mpl::and_<! boost::is_convertible< value_type, return_value_ >,! boost::mpl::not_<! boost::is_reference< typename get_return_type< value_type >::type > ! >! > > >::type* = 0 ) { return value; } ࠨล஋ࢀরͩͬͨΒ ϩʔυͯ͠ࢀরΛ֎͢ ͦΕҎ֎ͩͬͨΒ ͦͷ··ฦ͢
  27. template< typename LeftType, typename RightType >! return_value<(ུ)> operator()( LeftType left_,

    RightType right_,! typename boost::enable_if<(ུ)>::type* = 0! ) {! const auto left = tools->as_llvm_value( tools->load( left_ ) );! std::vector< int > args =! { static_cast< int >( right_ ) };! llvm::ArrayRef< int > args_ref( args );! return return_value<! typename hermit::range_value<! typename boost::remove_reference<! typename get_return_type< LeftType >::type! >::type! >::type! >( ! tools->ir_builder.CreateExtractValue( left.value, args_ref )! );! } Ϩδελ্ʹ͋Δ഑ྻͷཁૉΛऔΓग़ͯ͠ฦ͢ ఴࣈԋࢉࢠ ӈล஋ࢀর൛
  28. template< typename LeftType, typename RightType >! return_value<(ུ)> operator()( LeftType left_,

    RightType right_,! typename boost::enable_if<(ུ)>::type* = 0! ) {! typename static_cast_< int >::template eval< Context > cast( tools );! llvm::Value *indices[] = {! cast( tools->as_llvm_value( 0u ) ).value,! cast( tools->as_llvm_value( tools->load( right_ ) ) ).value! };! return return_value<! typename hermit::range_value<! typename boost::remove_reference<! typename get_return_type< LeftType >::type! >::type! >::type&! >(! tools->ir_builder.CreateInBoundsGEP( left_.value, indices )! );! } ഑ྻͷઌ಄ΞυϨε͔ΒཁૉͷΞυϨεΛٻΊͯฦ͢ ఴࣈԋࢉࢠ ࠨล஋ࢀর൛
  29. template< typename From, typename To_ >! llvm::Value *cast( llvm::Value *src,!

    typename boost::enable_if<! boost::mpl::and_<! boost::is_integral< From >,! boost::is_signed< From >,! boost::is_float< To_ >! >! >::type* = 0! ) {! return tools->ir_builder.CreateSIToFP(! src,! tools->type_generator_( tag< To_ >() )! );! } ූ߸෇͖੔਺͔Βුಈখ਺΁ͷΩϟετ
  30. template< typename Expr > struct eval< Expr,! typename boost::enable_if<! proto::matches<

    Expr,! proto::plus< proto::_, proto::_ >! >! >::type! > {! typedef (ུ) raw_result_type; // left + rightͷ݁Ռͷܕ! typedef return_value< raw_result_type > result_type;! result_type operator()(! Expr &expr,! context_type &context! ) {! typename static_cast_< result_type >::template eval< Context >! cast( tools );! const auto left =! cast( tools->load( proto::eval( boost::proto::left( expr ) ) );! const auto right =! cast( tools->load( proto::eval( boost::proto::right( expr ) ) );! return return_value< raw_result_type >(! ir_builder.CreateAdd( left.value, right.value )! );! }! }; ྆ลͷ஋Λ݁ՌͷܕʹΩϟετ
  31. "#*ͷนΛӽ͑Δ data_layout::array< int32_t, 3 > foo; ಉ༷ʹ഑ྻ΋ 3BOEPN"DDFTT5SBWFSTBM3BOHF <JY> foo.get()

    --7.͕ཁٻ͢Δσʔλͷ഑ஔΛ γϦΞϥΠθʔγϣϯϑΥʔϚοτͱݟͳͯ͠ σʔλߏ଄ΛγϦΞϥΠζ͢Δ
  32. "#*ͷนΛӽ͑Δ value_generator vg(! context, data_layout! );! auto value = vg(!

    tag< softdsp::data_layout::tuple<! int, double, int, int! > >()! );! boost::fusion::at_c< 0 >( value ) = 4;! boost::fusion::at_c< 1 >( value ) = 5.0;! boost::fusion::at_c< 2 >( value ) = 8;! boost::fusion::at_c< 3 >( value ) = 20;