From 5805e55f8df26ada302e58bfda6701cde0e42600 Mon Sep 17 00:00:00 2001 From: Zach Laine Date: Tue, 15 Nov 2016 20:07:32 -0600 Subject: [PATCH] Add a code-gen sample, useful for getting the assembly generated for proto17 vs. straight c++ expressions. --- CMakeLists.txt | 2 +- test/CMakeLists.txt | 2 + test/code_gen_samples.cpp | 132 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 test/code_gen_samples.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2dbad5b..5f1a7b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.6) -add_definitions(-std=c++1z -stdlib=libc++) +add_definitions(-std=c++1z -stdlib=libc++ -g) add_subdirectory(googletest-release-1.8.0) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0d21ec6..fc95bbc 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -41,3 +41,5 @@ add_executable( compile_term_plus_x_this_ref_overloads.cpp compile_const_term.cpp ) + +add_executable(code_gen_samples code_gen_samples.cpp) diff --git a/test/code_gen_samples.cpp b/test/code_gen_samples.cpp new file mode 100644 index 0000000..856b96d --- /dev/null +++ b/test/code_gen_samples.cpp @@ -0,0 +1,132 @@ +#define BOOST_PROTO17_CONVERSION_OPERATOR_TEMPLATE +#include "expression.hpp" + + +template +using term = boost::proto17::terminal; + +namespace bp17 = boost::proto17; + + +namespace user { + + struct number + { + double value; + + friend number operator+ (number lhs, number rhs) + { return number{lhs.value + rhs.value}; } + + friend number operator* (number lhs, number rhs) + { return number{lhs.value * rhs.value}; } + }; + + number naxpy (number a, number x, number y) + { return number{a.value * x.value + y.value + 10.0}; } + + template + decltype(auto) transform_expression ( + bp17::expression< + bp17::expr_kind::plus, + bp17::expression< + bp17::expr_kind::multiplies, + Expr1, + Expr2 + >, + Expr3 + > const & expr + ) { + return naxpy( + evaluate(expr.left().left()), + evaluate(expr.left().right()), + evaluate(expr.right()) + ); + } + +} + +term a{{1.0}}; +term x{{42.0}}; +term y{{3.0}}; + +#define HANDLE_COMMON_SUBEXPRESSION 1 +#if HANDLE_COMMON_SUBEXPRESSION + +user::number eval_as_proto_expr ( + decltype((a * x + y) * (a * x + y) + (a * x + y)) & expr +) { + auto const tmp = evaluate(expr.right()); + return tmp * tmp + tmp; +} + +/* LLVM produces this for eval_as_proto_expr under -O3: +Dump of assembler code for function eval_as_proto_expr(boost::proto17::expression<(boost::proto17::expr_kind)17, boost::proto17::expression<(boost::proto17::expr_kind)14, boost::proto17::expression<(boost::proto17::expr_kind)17, boost::proto17::expression<(boost::proto17::expr_kind)14, boost::proto17::expression<(boost::proto17::expr_kind)0, user::number>, boost::proto17::expression<(boost::proto17::expr_kind)0, user::number> >, boost::proto17::expression<(boost::proto17::expr_kind)0, user::number> >, boost::proto17::expression<(boost::proto17::expr_kind)17, boost::proto17::expression<(boost::proto17::expr_kind)14, boost::proto17::expression<(boost::proto17::expr_kind)0, user::number>, boost::proto17::expression<(boost::proto17::expr_kind)0, user::number> >, boost::proto17::expression<(boost::proto17::expr_kind)0, user::number> > >, boost::proto17::expression<(boost::proto17::expr_kind)17, boost::proto17::expression<(boost::proto17::expr_kind)14, boost::proto17::expression<(boost::proto17::expr_kind)0, user::number>, boost::proto17::expression<(boost::proto17::expr_kind)0, user::number> >, boost::proto17::expression<(boost::proto17::expr_kind)0, user::number> > >&): + 0x00000000004005e0 <+0>: movsd 0x30(%rdi),%xmm1 + 0x00000000004005e5 <+5>: mulsd 0x38(%rdi),%xmm1 + 0x00000000004005ea <+10>: addsd 0x40(%rdi),%xmm1 + 0x00000000004005ef <+15>: addsd 0xd1(%rip),%xmm1 # 0x4006c8 + 0x00000000004005f7 <+23>: movapd %xmm1,%xmm0 + 0x00000000004005fb <+27>: mulsd %xmm0,%xmm0 + 0x00000000004005ff <+31>: addsd %xmm1,%xmm0 + 0x0000000000400603 <+35>: retq +End of assembler dump. +*/ + +#else + +user::number eval_as_proto_expr ( + decltype((a * x + y) * (a * x + y) + (a * x + y)) & expr +) { + return expr; +} + +/* LLVM produces this for eval_as_proto_expr under -O3: +Dump of assembler code for function eval_as_proto_expr(boost::proto17::expression<(boost::proto17::expr_kind)17, boost::proto17::expression<(boost::proto17::expr_kind)14, boost::proto17::expression<(boost::proto17::expr_kind)17, boost::proto17::expression<(boost::proto17::expr_kind)14, boost::proto17::expression<(boost::proto17::expr_kind)0, user::number>, boost::proto17::expression<(boost::proto17::expr_kind)0, user::number> >, boost::proto17::expression<(boost::proto17::expr_kind)0, user::number> >, boost::proto17::expression<(boost::proto17::expr_kind)17, boost::proto17::expression<(boost::proto17::expr_kind)14, boost::proto17::expression<(boost::proto17::expr_kind)0, user::number>, boost::proto17::expression<(boost::proto17::expr_kind)0, user::number> >, boost::proto17::expression<(boost::proto17::expr_kind)0, user::number> > >, boost::proto17::expression<(boost::proto17::expr_kind)17, boost::proto17::expression<(boost::proto17::expr_kind)14, boost::proto17::expression<(boost::proto17::expr_kind)0, user::number>, boost::proto17::expression<(boost::proto17::expr_kind)0, user::number> >, boost::proto17::expression<(boost::proto17::expr_kind)0, user::number> > >&): + 0x00000000004005e0 <+0>: movsd (%rdi),%xmm1 + 0x00000000004005e4 <+4>: movsd 0x18(%rdi),%xmm0 + 0x00000000004005e9 <+9>: mulsd 0x8(%rdi),%xmm1 + 0x00000000004005ee <+14>: addsd 0x10(%rdi),%xmm1 + 0x00000000004005f3 <+19>: movsd 0xed(%rip),%xmm2 # 0x4006e8 + 0x00000000004005fb <+27>: addsd %xmm2,%xmm1 + 0x00000000004005ff <+31>: mulsd 0x20(%rdi),%xmm0 + 0x0000000000400604 <+36>: addsd 0x28(%rdi),%xmm0 + 0x0000000000400609 <+41>: addsd %xmm2,%xmm0 + 0x000000000040060d <+45>: movsd 0x30(%rdi),%xmm3 + 0x0000000000400612 <+50>: mulsd 0x38(%rdi),%xmm3 + 0x0000000000400617 <+55>: addsd 0x40(%rdi),%xmm3 + 0x000000000040061c <+60>: addsd %xmm2,%xmm3 + 0x0000000000400620 <+64>: mulsd %xmm1,%xmm0 + 0x0000000000400624 <+68>: addsd %xmm3,%xmm0 + 0x0000000000400628 <+72>: addsd %xmm2,%xmm0 + 0x000000000040062c <+76>: retq +End of assembler dump. +*/ + +#endif + +user::number eval_as_cpp_expr (user::number a, user::number x, user::number y) +{ + return (a * x + y) * (a * x + y) + (a * x + y); +} + +/* LLVM produces this for eval_as_cpp_expr under -O3: +Dump of assembler code for function eval_as_cpp_expr(user::number, user::number, user::number): + 0x0000000000400630 <+0>: mulsd %xmm1,%xmm0 + 0x0000000000400634 <+4>: addsd %xmm2,%xmm0 + 0x0000000000400638 <+8>: movapd %xmm0,%xmm1 + 0x000000000040063c <+12>: mulsd %xmm1,%xmm1 + 0x0000000000400640 <+16>: addsd %xmm0,%xmm1 + 0x0000000000400644 <+20>: movapd %xmm1,%xmm0 + 0x0000000000400648 <+24>: retq +End of assembler dump. +*/ + + +int main () +{ + auto expr = (a * x + y) * (a * x + y) + (a * x + y); + user::number result_1 = eval_as_proto_expr(expr); + user::number result_2 = eval_as_cpp_expr(a, x, y); + + return 0; +}