===================================================================
@@ -5536,6 +5536,61 @@ Binary_expression::lower_compare_to_memc
return Expression::make_binary(this->op_, call, zero, loc);
}
+Expression*
+Binary_expression::do_flatten(Gogo*, Named_object*,
+ Statement_inserter* inserter)
+{
+ Location loc = this->location();
+ Temporary_statement* temp;
+ if (this->left_->type()->is_string_type()
+ && this->op_ == OPERATOR_PLUS)
+ {
+ if (!this->left_->is_variable())
+ {
+ temp = Statement::make_temporary(NULL, this->left_, loc);
+ inserter->insert(temp);
+ this->left_ = Expression::make_temporary_reference(temp, loc);
+ }
+ if (!this->right_->is_variable())
+ {
+ temp =
+ Statement::make_temporary(this->left_->type(), this->right_, loc);
+ this->right_ = Expression::make_temporary_reference(temp, loc);
+ inserter->insert(temp);
+ }
+ }
+
+ Type* left_type = this->left_->type();
+ bool is_shift_op = (this->op_ == OPERATOR_LSHIFT
+ || this->op_ == OPERATOR_RSHIFT);
+ bool is_idiv_op = ((this->op_ == OPERATOR_DIV &&
+ left_type->integer_type() != NULL)
+ || this->op_ == OPERATOR_MOD);
+
+ // FIXME: go_check_divide_zero and go_check_divide_overflow are globals
+ // defined in gcc/go/lang.opt. These should be defined in go_create_gogo
+ // and accessed from the Gogo* passed to do_flatten.
+ if (is_shift_op
+ || (is_idiv_op && (go_check_divide_zero || go_check_divide_overflow)))
+ {
+ if (!this->left_->is_variable())
+ {
+ temp = Statement::make_temporary(NULL, this->left_, loc);
+ inserter->insert(temp);
+ this->left_ = Expression::make_temporary_reference(temp, loc);
+ }
+ if (!this->right_->is_variable())
+ {
+ temp =
+ Statement::make_temporary(NULL, this->right_, loc);
+ this->right_ = Expression::make_temporary_reference(temp, loc);
+ inserter->insert(temp);
+ }
+ }
+ return this;
+}
+
+
// Return the address of EXPR, cast to unsafe.Pointer.
Expression*
@@ -5956,14 +6011,10 @@ tree
Binary_expression::do_get_tree(Translate_context* context)
{
Gogo* gogo = context->gogo();
+ Location loc = this->location();
+ Type* left_type = this->left_->type();
+ Type* right_type = this->right_->type();
- tree left = this->left_->get_tree(context);
- tree right = this->right_->get_tree(context);
-
- if (left == error_mark_node || right == error_mark_node)
- return error_mark_node;
-
- enum tree_code code;
bool use_left_type = true;
bool is_shift_op = false;
bool is_idiv_op = false;
@@ -5975,198 +6026,126 @@ Binary_expression::do_get_tree(Translate
case OPERATOR_LE:
case OPERATOR_GT:
case OPERATOR_GE:
- return Expression::comparison_tree(context, this->type_, this->op_,
- this->left_, this->right_,
- this->location());
+ {
+ Bexpression* ret =
+ Expression::comparison(context, this->type_, this->op_,
+ this->left_, this->right_, loc);
+ return expr_to_tree(ret);
+ }
case OPERATOR_OROR:
- code = TRUTH_ORIF_EXPR;
- use_left_type = false;
- break;
case OPERATOR_ANDAND:
- code = TRUTH_ANDIF_EXPR;
use_left_type = false;
break;
case OPERATOR_PLUS:
- code = PLUS_EXPR;
- break;
case OPERATOR_MINUS:
- code = MINUS_EXPR;
- break;
case OPERATOR_OR:
- code = BIT_IOR_EXPR;
- break;
case OPERATOR_XOR:
- code = BIT_XOR_EXPR;
- break;
case OPERATOR_MULT:
- code = MULT_EXPR;
break;
case OPERATOR_DIV:
- {
- Type *t = this->left_->type();
- if (t->float_type() != NULL || t->complex_type() != NULL)
- code = RDIV_EXPR;
- else
- {
- code = TRUNC_DIV_EXPR;
- is_idiv_op = true;
- }
- }
- break;
+ if (left_type->float_type() != NULL || left_type->complex_type() != NULL)
+ break;
case OPERATOR_MOD:
- code = TRUNC_MOD_EXPR;
is_idiv_op = true;
break;
case OPERATOR_LSHIFT:
- code = LSHIFT_EXPR;
- is_shift_op = true;
- break;
case OPERATOR_RSHIFT:
- code = RSHIFT_EXPR;
is_shift_op = true;
break;
- case OPERATOR_AND:
- code = BIT_AND_EXPR;
- break;
case OPERATOR_BITCLEAR:
- right = fold_build1(BIT_NOT_EXPR, TREE_TYPE(right), right);
- code = BIT_AND_EXPR;
+ this->right_ = Expression::make_unary(OPERATOR_XOR, this->right_, loc);
+ case OPERATOR_AND:
break;
default:
go_unreachable();
}
- location_t gccloc = this->location().gcc_location();
- tree type = use_left_type ? TREE_TYPE(left) : TREE_TYPE(right);
-
- if (this->left_->type()->is_string_type())
+ if (left_type->is_string_type())
{
go_assert(this->op_ == OPERATOR_PLUS);
- Type* st = Type::make_string_type();
- tree string_type = type_to_tree(st->get_backend(gogo));
- static tree string_plus_decl;
- return Gogo::call_builtin(&string_plus_decl,
- this->location(),
- "__go_string_plus",
- 2,
- string_type,
- string_type,
- left,
- string_type,
- right);
+ Expression* string_plus =
+ Runtime::make_call(Runtime::STRING_PLUS, loc, 2,
+ this->left_, this->right_);
+ return string_plus->get_tree(context);
}
- // For complex division Go wants slightly different results than the
- // GCC library provides, so we have our own runtime routine.
+ // For complex division Go might want slightly different results than the
+ // backend implementation provides, so we have our own runtime routine.
if (this->op_ == OPERATOR_DIV && this->left_->type()->complex_type() != NULL)
{
- const char *name;
- tree *pdecl;
- Type* ctype;
- static tree complex64_div_decl;
- static tree complex128_div_decl;
+ Runtime::Function complex_code;
switch (this->left_->type()->complex_type()->bits())
{
case 64:
- name = "__go_complex64_div";
- pdecl = &complex64_div_decl;
- ctype = Type::lookup_complex_type("complex64");
+ complex_code = Runtime::COMPLEX64_DIV;
break;
case 128:
- name = "__go_complex128_div";
- pdecl = &complex128_div_decl;
- ctype = Type::lookup_complex_type("complex128");
+ complex_code = Runtime::COMPLEX128_DIV;
break;
default:
go_unreachable();
}
- Btype* cbtype = ctype->get_backend(gogo);
- tree ctype_tree = type_to_tree(cbtype);
- return Gogo::call_builtin(pdecl,
- this->location(),
- name,
- 2,
- ctype_tree,
- ctype_tree,
- fold_convert_loc(gccloc, ctype_tree, left),
- type,
- fold_convert_loc(gccloc, ctype_tree, right));
+ Expression* complex_div =
+ Runtime::make_call(complex_code, loc, 2, this->left_, this->right_);
+ return complex_div->get_tree(context);
}
- tree compute_type = excess_precision_type(type);
- if (compute_type != NULL_TREE)
- {
- left = ::convert(compute_type, left);
- right = ::convert(compute_type, right);
- }
+ Bexpression* left = tree_to_expr(this->left_->get_tree(context));
+ Bexpression* right = tree_to_expr(this->right_->get_tree(context));
- tree eval_saved = NULL_TREE;
- if (is_shift_op
- || (is_idiv_op && (go_check_divide_zero || go_check_divide_overflow)))
- {
- // Make sure the values are evaluated.
- if (!DECL_P(left))
- {
- left = save_expr(left);
- eval_saved = left;
- }
- if (!DECL_P(right))
- {
- right = save_expr(right);
- if (eval_saved == NULL_TREE)
- eval_saved = right;
- else
- eval_saved = fold_build2_loc(gccloc, COMPOUND_EXPR,
- void_type_node, eval_saved, right);
- }
- }
+ Type* type = use_left_type ? left_type : right_type;
+ Btype* btype = type->get_backend(gogo);
+
+ Bexpression* ret =
+ gogo->backend()->binary_expression(this->op_, left, right, loc);
+ ret = gogo->backend()->convert_expression(btype, ret, loc);
- tree ret = fold_build2_loc(gccloc, code,
- compute_type != NULL_TREE ? compute_type : type,
- left, right);
+ // Initialize overflow constants.
+ Bexpression* overflow;
+ mpz_t zero;
+ mpz_init_set_ui(zero, 0UL);
+ mpz_t one;
+ mpz_init_set_ui(one, 1UL);
+ mpz_t neg_one;
+ mpz_init_set_si(neg_one, -1);
- if (compute_type != NULL_TREE)
- ret = ::convert(type, ret);
+ Btype* left_btype = left_type->get_backend(gogo);
+ Btype* right_btype = right_type->get_backend(gogo);
// In Go, a shift larger than the size of the type is well-defined.
- // This is not true in GENERIC, so we need to insert a conditional.
+ // This is not true in C, so we need to insert a conditional.
if (is_shift_op)
{
- go_assert(INTEGRAL_TYPE_P(TREE_TYPE(left)));
- go_assert(this->left_->type()->integer_type() != NULL);
- int bits = TYPE_PRECISION(TREE_TYPE(left));
+ go_assert(left_type->integer_type() != NULL);
- tree compare = fold_build2(LT_EXPR, boolean_type_node, right,
- build_int_cst_type(TREE_TYPE(right), bits));
-
- tree overflow_result = fold_convert_loc(gccloc, TREE_TYPE(left),
- integer_zero_node);
+ mpz_t bitsval;
+ int bits = left_type->integer_type()->bits();
+ mpz_init_set_ui(bitsval, bits);
+ Bexpression* bits_expr =
+ gogo->backend()->integer_constant_expression(right_btype, bitsval);
+ Bexpression* compare =
+ gogo->backend()->binary_expression(OPERATOR_LT,
+ right, bits_expr, loc);
+
+ Bexpression* zero_expr =
+ gogo->backend()->integer_constant_expression(left_btype, zero);
+ overflow = zero_expr;
if (this->op_ == OPERATOR_RSHIFT
- && !this->left_->type()->integer_type()->is_unsigned())
+ && !left_type->integer_type()->is_unsigned())
{
- tree neg =
- fold_build2_loc(gccloc, LT_EXPR, boolean_type_node,
- left,
- fold_convert_loc(gccloc, TREE_TYPE(left),
- integer_zero_node));
- tree neg_one =
- fold_build2_loc(gccloc, MINUS_EXPR, TREE_TYPE(left),
- fold_convert_loc(gccloc, TREE_TYPE(left),
- integer_zero_node),
- fold_convert_loc(gccloc, TREE_TYPE(left),
- integer_one_node));
- overflow_result =
- fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(left),
- neg, neg_one, overflow_result);
- }
-
- ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(left),
- compare, ret, overflow_result);
-
- if (eval_saved != NULL_TREE)
- ret = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret),
- eval_saved, ret);
+ Bexpression* neg_expr =
+ gogo->backend()->binary_expression(OPERATOR_LT, left,
+ zero_expr, loc);
+ Bexpression* neg_one_expr =
+ gogo->backend()->integer_constant_expression(left_btype, neg_one);
+ overflow = gogo->backend()->conditional_expression(btype, neg_expr,
+ neg_one_expr,
+ zero_expr, loc);
+ }
+ ret = gogo->backend()->conditional_expression(btype, compare, ret,
+ overflow, loc);
+ mpz_clear(bitsval);
}
// Add checks for division by zero and division overflow as needed.
@@ -6175,23 +6154,20 @@ Binary_expression::do_get_tree(Translate
if (go_check_divide_zero)
{
// right == 0
- tree check = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node,
- right,
- fold_convert_loc(gccloc,
- TREE_TYPE(right),
- integer_zero_node));
+ Bexpression* zero_expr =
+ gogo->backend()->integer_constant_expression(right_btype, zero);
+ Bexpression* check =
+ gogo->backend()->binary_expression(OPERATOR_EQEQ,
+ right, zero_expr, loc);
- // __go_runtime_error(RUNTIME_ERROR_DIVISION_BY_ZERO), 0
+ // __go_runtime_error(RUNTIME_ERROR_DIVISION_BY_ZERO)
int errcode = RUNTIME_ERROR_DIVISION_BY_ZERO;
- Expression* crash = gogo->runtime_error(errcode, this->location());
- tree panic = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret),
- crash->get_tree(context),
- fold_convert_loc(gccloc, TREE_TYPE(ret),
- integer_zero_node));
+ Expression* crash = gogo->runtime_error(errcode, loc);
+ Bexpression* crash_expr = tree_to_expr(crash->get_tree(context));
// right == 0 ? (__go_runtime_error(...), 0) : ret
- ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
- check, panic, ret);
+ ret = gogo->backend()->conditional_expression(btype, check,
+ crash_expr, ret, loc);
}
if (go_check_divide_overflow)
@@ -6199,60 +6175,62 @@ Binary_expression::do_get_tree(Translate
// right == -1
// FIXME: It would be nice to say that this test is expected
// to return false.
- tree m1 = integer_minus_one_node;
- tree check = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node,
- right,
- fold_convert_loc(gccloc,
- TREE_TYPE(right),
- m1));
- tree overflow;
- if (TYPE_UNSIGNED(TREE_TYPE(ret)))
+ Bexpression* neg_one_expr =
+ gogo->backend()->integer_constant_expression(right_btype, neg_one);
+ Bexpression* check =
+ gogo->backend()->binary_expression(OPERATOR_EQEQ,
+ right, neg_one_expr, loc);
+
+ Bexpression* zero_expr =
+ gogo->backend()->integer_constant_expression(btype, zero);
+ Bexpression* one_expr =
+ gogo->backend()->integer_constant_expression(btype, one);
+
+ if (type->integer_type()->is_unsigned())
{
// An unsigned -1 is the largest possible number, so
// dividing is always 1 or 0.
- tree cmp = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node,
- left, right);
+
+ Bexpression* cmp =
+ gogo->backend()->binary_expression(OPERATOR_EQEQ,
+ left, right, loc);
if (this->op_ == OPERATOR_DIV)
- overflow = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
- cmp,
- fold_convert_loc(gccloc,
- TREE_TYPE(ret),
- integer_one_node),
- fold_convert_loc(gccloc,
- TREE_TYPE(ret),
- integer_zero_node));
+ overflow =
+ gogo->backend()->conditional_expression(btype, cmp,
+ one_expr, zero_expr,
+ loc);
else
- overflow = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
- cmp,
- fold_convert_loc(gccloc,
- TREE_TYPE(ret),
- integer_zero_node),
- left);
+ overflow =
+ gogo->backend()->conditional_expression(btype, cmp,
+ zero_expr, left,
+ loc);
}
else
{
// Computing left / -1 is the same as computing - left,
// which does not overflow since Go sets -fwrapv.
if (this->op_ == OPERATOR_DIV)
- overflow = fold_build1_loc(gccloc, NEGATE_EXPR, TREE_TYPE(left),
- left);
+ {
+ Expression* negate_expr =
+ Expression::make_unary(OPERATOR_MINUS, this->left_, loc);
+ overflow = tree_to_expr(negate_expr->get_tree(context));
+ }
else
- overflow = integer_zero_node;
+ overflow = zero_expr;
}
- overflow = fold_convert_loc(gccloc, TREE_TYPE(ret), overflow);
+ overflow = gogo->backend()->convert_expression(btype, overflow, loc);
// right == -1 ? - left : ret
- ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
- check, overflow, ret);
+ ret = gogo->backend()->conditional_expression(btype, check, overflow,
+ ret, loc);
}
-
- if (eval_saved != NULL_TREE)
- ret = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret),
- eval_saved, ret);
}
- return ret;
+ mpz_clear(zero);
+ mpz_clear(one);
+ mpz_clear(neg_one);
+ return expr_to_tree(ret);
}
// Export a binary expression.
@@ -6471,10 +6449,10 @@ Expression::make_binary(Operator op, Exp
// Implement a comparison.
-tree
-Expression::comparison_tree(Translate_context* context, Type* result_type,
- Operator op, Expression* left, Expression* right,
- Location location)
+Bexpression*
+Expression::comparison(Translate_context* context, Type* result_type,
+ Operator op, Expression* left, Expression* right,
+ Location location)
{
Type* left_type = left->type();
Type* right_type = right->type();
@@ -6484,31 +6462,6 @@ Expression::comparison_tree(Translate_co
Expression* zexpr = Expression::make_integer(&zval, NULL, location);
mpz_clear(zval);
- enum tree_code code;
- switch (op)
- {
- case OPERATOR_EQEQ:
- code = EQ_EXPR;
- break;
- case OPERATOR_NOTEQ:
- code = NE_EXPR;
- break;
- case OPERATOR_LT:
- code = LT_EXPR;
- break;
- case OPERATOR_LE:
- code = LE_EXPR;
- break;
- case OPERATOR_GT:
- code = GT_EXPR;
- break;
- case OPERATOR_GE:
- code = GE_EXPR;
- break;
- default:
- go_unreachable();
- }
-
if (left_type->is_string_type() && right_type->is_string_type())
{
left = Runtime::make_call(Runtime::STRCMP, location, 2,
@@ -6601,20 +6554,15 @@ Expression::comparison_tree(Translate_co
}
}
- tree left_tree = left->get_tree(context);
- tree right_tree = right->get_tree(context);
- if (left_tree == error_mark_node || right_tree == error_mark_node)
- return error_mark_node;
+ Bexpression* left_bexpr = tree_to_expr(left->get_tree(context));
+ Bexpression* right_bexpr = tree_to_expr(right->get_tree(context));
- tree result_type_tree;
- if (result_type == NULL)
- result_type_tree = boolean_type_node;
- else
- result_type_tree = type_to_tree(result_type->get_backend(context->gogo()));
-
- tree ret = fold_build2(code, result_type_tree, left_tree, right_tree);
- if (CAN_HAVE_LOCATION_P(ret))
- SET_EXPR_LOCATION(ret, location.gcc_location());
+ Gogo* gogo = context->gogo();
+ Bexpression* ret = gogo->backend()->binary_expression(op, left_bexpr,
+ right_bexpr, location);
+ if (result_type != NULL)
+ ret = gogo->backend()->convert_expression(result_type->get_backend(gogo),
+ ret, location);
return ret;
}
@@ -6830,6 +6778,7 @@ Bound_method_expression::create_thunk(Go
Block* b = gogo->finish_block(loc);
gogo->add_block(b, loc);
gogo->lower_block(new_no, b);
+ gogo->flatten_block(new_no, b);
gogo->finish_function(loc);
ins.first->second = new_no;
@@ -11827,6 +11776,7 @@ Interface_field_reference_expression::cr
Block* b = gogo->finish_block(loc);
gogo->add_block(b, loc);
gogo->lower_block(new_no, b);
+ gogo->flatten_block(new_no, b);
gogo->finish_function(loc);
ins.first->second->push_back(std::make_pair(name, new_no));
@@ -11888,7 +11838,7 @@ Interface_field_reference_expression::do
Bexpression* bcrash = tree_to_expr(crash->get_tree(context));
Bexpression* bcond =
- gogo->backend()->conditional_expression(bnil_check, bcrash, NULL, loc);
+ gogo->backend()->conditional_expression(NULL, bnil_check, bcrash, NULL, loc);
Bstatement* cond_statement = gogo->backend()->expression_statement(bcond);
Bexpression* ret =
gogo->backend()->compound_expression(cond_statement, bclosure, loc);
@@ -12157,6 +12107,7 @@ Selector_expression::lower_method_expres
// Lower the call in case there are multiple results.
gogo->lower_block(no, b);
+ gogo->flatten_block(no, b);
gogo->finish_function(location);
===================================================================
@@ -704,11 +704,11 @@ class Expression
Type* rhs_type, tree rhs_tree,
bool for_type_guard, Location);
- // Return a tree implementing the comparison LHS_EXPR OP RHS_EXPR.
+ // Return a backend expression implementing the comparison LEFT OP RIGHT.
// TYPE is the type of both sides.
- static tree
- comparison_tree(Translate_context*, Type* result_type, Operator op,
- Expression* left_expr, Expression* right_expr, Location);
+ static Bexpression*
+ comparison(Translate_context*, Type* result_type, Operator op,
+ Expression* left, Expression* right, Location);
// Return the backend expression for the numeric constant VAL.
static Bexpression*
@@ -1289,6 +1289,9 @@ class Binary_expression : public Express
Expression*
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
+ Expression*
+ do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
bool
do_is_constant() const
{ return this->left_->is_constant() && this->right_->is_constant(); }
===================================================================
@@ -10,6 +10,8 @@
#include <gmp.h>
#include <mpfr.h>
+#include "operator.h"
+
// Pointers to these types are created by the backend, passed to the
// frontend, and passed back to the backend. The types must be
// defined by the backend using these names.
@@ -289,10 +291,20 @@ class Backend
compound_expression(Bstatement* bstat, Bexpression* bexpr, Location) = 0;
// Return an expression that executes THEN_EXPR if CONDITION is true, or
- // ELSE_EXPR otherwise. ELSE_EXPR may be NULL.
+ // ELSE_EXPR otherwise and returns the result as type BTYPE. ELSE_EXPR
+ // may be NULL. BTYPE may be NULL.
+ virtual Bexpression*
+ conditional_expression(Btype* btype, Bexpression* condition,
+ Bexpression* then_expr, Bexpression* else_expr,
+ Location) = 0;
+
+ // Return an expression for the binary operation LEFT OP RIGHT.
+ // Supported values of OP are (from operators.h):
+ // EQEQ, NOTEQ, LT, LE, GT, GE, PLUS, MINUS, OR, XOR, MULT, DIV, MOD,
+ // LSHIFT, RSHIFT, AND, NOT.
virtual Bexpression*
- conditional_expression(Bexpression* condition, Bexpression* then_expr,
- Bexpression* else_expr, Location) = 0;
+ binary_expression(Operator op, Bexpression* left, Bexpression* right,
+ Location) = 0;
// Statements.
===================================================================
@@ -250,7 +250,11 @@ class Gcc_backend : public Backend
compound_expression(Bstatement*, Bexpression*, Location);
Bexpression*
- conditional_expression(Bexpression*, Bexpression*, Bexpression*, Location);
+ conditional_expression(Btype*, Bexpression*, Bexpression*, Bexpression*,
+ Location);
+
+ Bexpression*
+ binary_expression(Operator, Bexpression*, Bexpression*, Location);
// Statements.
@@ -1059,22 +1063,142 @@ Gcc_backend::compound_expression(Bstatem
// ELSE_EXPR otherwise.
Bexpression*
-Gcc_backend::conditional_expression(Bexpression* condition,
+Gcc_backend::conditional_expression(Btype* btype, Bexpression* condition,
Bexpression* then_expr,
Bexpression* else_expr, Location location)
{
+ tree type_tree = btype == NULL ? void_type_node : btype->get_tree();
tree cond_tree = condition->get_tree();
tree then_tree = then_expr->get_tree();
tree else_tree = else_expr == NULL ? NULL_TREE : else_expr->get_tree();
- if (cond_tree == error_mark_node
+ if (type_tree == error_mark_node
+ || cond_tree == error_mark_node
|| then_tree == error_mark_node
|| else_tree == error_mark_node)
return this->error_expression();
- tree ret = build3_loc(location.gcc_location(), COND_EXPR, void_type_node,
+ tree ret = build3_loc(location.gcc_location(), COND_EXPR, type_tree,
cond_tree, then_tree, else_tree);
return this->make_expression(ret);
}
+// Convert a gofrontend operator to an equivalent tree_code.
+
+enum tree_code
+operator_to_tree_code(Operator op, tree type)
+{
+ enum tree_code code;
+ switch (op)
+ {
+ case OPERATOR_EQEQ:
+ code = EQ_EXPR;
+ break;
+ case OPERATOR_NOTEQ:
+ code = NE_EXPR;
+ break;
+ case OPERATOR_LT:
+ code = LT_EXPR;
+ break;
+ case OPERATOR_LE:
+ code = LE_EXPR;
+ break;
+ case OPERATOR_GT:
+ code = GT_EXPR;
+ break;
+ case OPERATOR_GE:
+ code = GE_EXPR;
+ break;
+ case OPERATOR_OROR:
+ code = TRUTH_ORIF_EXPR;
+ break;
+ case OPERATOR_ANDAND:
+ code = TRUTH_ANDIF_EXPR;
+ break;
+ case OPERATOR_PLUS:
+ code = PLUS_EXPR;
+ break;
+ case OPERATOR_MINUS:
+ code = MINUS_EXPR;
+ break;
+ case OPERATOR_OR:
+ code = BIT_IOR_EXPR;
+ break;
+ case OPERATOR_XOR:
+ code = BIT_XOR_EXPR;
+ break;
+ case OPERATOR_MULT:
+ code = MULT_EXPR;
+ break;
+ case OPERATOR_DIV:
+ if (TREE_CODE(type) == REAL_TYPE || TREE_CODE(type) == COMPLEX_TYPE)
+ code = RDIV_EXPR;
+ else
+ code = TRUNC_DIV_EXPR;
+ break;
+ case OPERATOR_MOD:
+ code = TRUNC_MOD_EXPR;
+ break;
+ case OPERATOR_LSHIFT:
+ code = LSHIFT_EXPR;
+ break;
+ case OPERATOR_RSHIFT:
+ code = RSHIFT_EXPR;
+ break;
+ case OPERATOR_AND:
+ code = BIT_AND_EXPR;
+ break;
+ case OPERATOR_BITCLEAR:
+ code = BIT_AND_EXPR;
+ break;
+ default:
+ gcc_unreachable();
+ }
+
+ return code;
+}
+
+// Return an expression for the binary operation LEFT OP RIGHT.
+
+Bexpression*
+Gcc_backend::binary_expression(Operator op, Bexpression* left,
+ Bexpression* right, Location location)
+{
+ tree left_tree = left->get_tree();
+ tree right_tree = right->get_tree();
+ if (left_tree == error_mark_node
+ || right_tree == error_mark_node)
+ return this->error_expression();
+ enum tree_code code = operator_to_tree_code(op, TREE_TYPE(left_tree));
+
+ bool use_left_type = op != OPERATOR_OROR && op != OPERATOR_ANDAND;
+ tree type_tree = use_left_type ? TREE_TYPE(left_tree) : TREE_TYPE(right_tree);
+ tree computed_type = excess_precision_type(type_tree);
+ if (computed_type != NULL_TREE)
+ {
+ left_tree = convert(computed_type, left_tree);
+ right_tree = convert(computed_type, right_tree);
+ type_tree = computed_type;
+ }
+
+ // For comparison operators, the resulting type should be boolean.
+ switch (op)
+ {
+ case OPERATOR_EQEQ:
+ case OPERATOR_NOTEQ:
+ case OPERATOR_LT:
+ case OPERATOR_LE:
+ case OPERATOR_GT:
+ case OPERATOR_GE:
+ type_tree = boolean_type_node;
+ break;
+ default:
+ break;
+ }
+
+ tree ret = fold_build2_loc(location.gcc_location(), code, type_tree,
+ left_tree, right_tree);
+ return this->make_expression(ret);
+}
+
// An expression as a statement.
Bstatement*