2
0
mirror of https://github.com/boostorg/yap.git synced 2026-01-31 08:42:26 +00:00
Files
yap/perf/code_gen_samples.cpp
2016-12-07 20:01:18 -06:00

177 lines
5.0 KiB
C++

#define BOOST_PROTO17_CONVERSION_OPERATOR_TEMPLATE
#include "expression.hpp"
template <typename T>
using term = boost::proto17::terminal<T>;
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 <typename Expr1, typename Expr2, typename Expr3>
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<user::number> a{{1.0}};
term<user::number> x{{42.0}};
term<user::number> y{{3.0}};
#define HANDLE_COMMON_SUBEXPRESSION 0
#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:
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
*/
user::number eval_as_proto_expr_4x (
decltype(
(a * x + y) * (a * x + y) + (a * x + y) +
(a * x + y) * (a * x + y) + (a * x + y) +
(a * x + y) * (a * x + y) + (a * x + y) +
(a * x + y) * (a * x + y) + (a * x + y)
) & expr
) {
auto const tmp = evaluate(expr.right());
return user::number{4} * (tmp * tmp + tmp);
}
/* LLVM produces this for eval_as_proto_expr under -O3:
*/
#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:
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
*/
user::number eval_as_proto_expr_4x (
decltype(
#if 0
// TODO: Somewhere between 36 and 45 terminals, LLVM gives up on
// inlining this function. Document this.
(a * x + y) * (a * x + y) + (a * x + y) +
#endif
(a * x + y) * (a * x + y) + (a * x + y) +
(a * x + y) * (a * x + y) + (a * x + y) +
(a * x + y) * (a * x + y) + (a * x + y) +
(a * x + y) * (a * x + y) + (a * x + y)
) & expr
) {
return expr;
}
/* LLVM produces this for eval_as_proto_expr under -O3:
*/
#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:
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
*/
user::number eval_as_cpp_expr_4x (user::number a, user::number x, user::number y)
{
return
(a * x + y) * (a * x + y) + (a * x + y) +
(a * x + y) * (a * x + y) + (a * x + y) +
(a * x + y) * (a * x + y) + (a * x + y) +
(a * x + y) * (a * x + y) + (a * x + y);
}
/* LLVM produces this for eval_as_cpp_expr under -O3:
*/
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);
(void)result_1;
(void)result_2;
return 0;
}