diff options
author | Josh Stone <jistone@redhat.com> | 2010-02-24 18:51:51 -0800 |
---|---|---|
committer | Josh Stone <jistone@redhat.com> | 2010-02-24 19:44:27 -0800 |
commit | e7227e90cd1414b2d02884617da0346134892526 (patch) | |
tree | d8a0cf8331ab30cd67971da5a0c10738ee03cc8b /elaborate.cxx | |
parent | 1cb79a7245a86f563a8e54a0b47937f253636bde (diff) | |
download | systemtap-steved-e7227e90cd1414b2d02884617da0346134892526.tar.gz systemtap-steved-e7227e90cd1414b2d02884617da0346134892526.tar.xz systemtap-steved-e7227e90cd1414b2d02884617da0346134892526.zip |
PR10719 cont'd: const-fold binary expressions
We can compute results between two literals, we can reduce identity
elements, and reduce constants if the non-literal side has no side
effects.
* elaborate.cxx (const_folder::visit_binary_expression): Implement.
Diffstat (limited to 'elaborate.cxx')
-rw-r--r-- | elaborate.cxx | 99 |
1 files changed, 97 insertions, 2 deletions
diff --git a/elaborate.cxx b/elaborate.cxx index d74051a9..5f3cc8ae 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -3123,8 +3123,103 @@ const_folder::visit_foreach_loop (foreach_loop* s) void const_folder::visit_binary_expression (binary_expression* e) { - // TODO - update_visitor::visit_binary_expression (e); + int64_t value; + literal_number* left = get_number (e->left); + literal_number* right = get_number (e->right); + + if (right && !right->value && (e->op == "/" || e->op == "%")) + { + // Give divide-by-zero a chance to be optimized out elsewhere, + // and if not it will be a runtime error anyway... + provide (e); + return; + } + + if (left && right) + { + if (e->op == "+") + value = left->value + right->value; + else if (e->op == "-") + value = left->value - right->value; + else if (e->op == "*") + value = left->value * right->value; + else if (e->op == "&") + value = left->value & right->value; + else if (e->op == "|") + value = left->value | right->value; + else if (e->op == "^") + value = left->value ^ right->value; + else if (e->op == ">>") + value = left->value >> max(min(right->value, (int64_t)64), (int64_t)0); + else if (e->op == "<<") + value = left->value << max(min(right->value, (int64_t)64), (int64_t)0); + else if (e->op == "/") + value = (left->value == LLONG_MIN && right->value == -1) ? LLONG_MIN : + left->value / right->value; + else if (e->op == "%") + value = (left->value == LLONG_MIN && right->value == -1) ? 0 : + left->value % right->value; + else + throw semantic_error ("unsupported binary operator " + e->op); + } + + else if ((left && ((left->value == 0 && (e->op == "*" || e->op == "&" || + e->op == ">>" || e->op == "<<" )) || + (left->value ==-1 && (e->op == "|" || e->op == ">>")))) + || + (right && ((right->value == 0 && (e->op == "*" || e->op == "&")) || + (right->value == 1 && (e->op == "%")) || + (right->value ==-1 && (e->op == "%" || e->op == "|"))))) + { + expression* other = left ? e->right : e->left; + varuse_collecting_visitor vu(session); + other->visit(&vu); + if (!vu.side_effect_free()) + { + provide (e); + return; + } + + if (left) + value = left->value; + else if (e->op == "%") + value = 0; + else + value = right->value; + } + + else if ((left && ((left->value == 0 && (e->op == "+" || e->op == "|" || + e->op == "^")) || + (left->value == 1 && (e->op == "*")) || + (left->value ==-1 && (e->op == "&")))) + || + (right && ((right->value == 0 && (e->op == "+" || e->op == "-" || + e->op == "|" || e->op == "^")) || + (right->value == 1 && (e->op == "*" || e->op == "/")) || + (right->value ==-1 && (e->op == "&")) || + (right->value <= 0 && (e->op == ">>" || e->op == "<<"))))) + { + if (session.verbose>2) + clog << "Collapsing constant-identity binary operator " << *e->tok << endl; + relaxed_p = false; + + provide (left ? e->right : e->left); + return; + } + + else + { + provide (e); + return; + } + + if (session.verbose>2) + clog << "Collapsing constant binary operator " << *e->tok << endl; + relaxed_p = false; + + literal_number* n = new literal_number(value); + n->tok = e->tok; + n->visit (this); } void |