This patch by Chris Manghane changes the Go frontend to use the backend interface for binary expressions. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline.
Ian 2014-01-16 Chris Manghane <cm...@google.com> * go-gcc.cc (Gcc_backend::conditional_expression): Add btype parameter. (operator_to_tree_code): New static function. (Gcc_backend::binary_expression): New function.
Index: gcc/go/gofrontend/expressions.cc =================================================================== --- gcc/go/gofrontend/expressions.cc (revision 206615) +++ gcc/go/gofrontend/expressions.cc (working copy) @@ -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); Index: gcc/go/gofrontend/expressions.h =================================================================== --- gcc/go/gofrontend/expressions.h (revision 206615) +++ gcc/go/gofrontend/expressions.h (working copy) @@ -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(); } Index: gcc/go/gofrontend/backend.h =================================================================== --- gcc/go/gofrontend/backend.h (revision 206615) +++ gcc/go/gofrontend/backend.h (working copy) @@ -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. Index: gcc/go/go-gcc.cc =================================================================== --- gcc/go/go-gcc.cc (revision 206615) +++ gcc/go/go-gcc.cc (working copy) @@ -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*