Commit b5407ad1 by Chris Manghane Committed by Ian Lance Taylor

compiler: Use backend interface for binary expressions.

	* go-gcc.cc (Gcc_backend::conditional_expression): Add btype
	parameter.
	(operator_to_tree_code): New static function.
	(Gcc_backend::binary_expression): New function.

From-SVN: r206696
parent f910753d
2014-01-16 Chris Manghane <cmang@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.
2014-01-14 Chris Manghane <cmang@google.com> 2014-01-14 Chris Manghane <cmang@google.com>
* go-gcc.cc (Gcc_backend::compound_expression): New function. * go-gcc.cc (Gcc_backend::compound_expression): New function.
......
...@@ -250,7 +250,11 @@ class Gcc_backend : public Backend ...@@ -250,7 +250,11 @@ class Gcc_backend : public Backend
compound_expression(Bstatement*, Bexpression*, Location); compound_expression(Bstatement*, Bexpression*, Location);
Bexpression* Bexpression*
conditional_expression(Bexpression*, Bexpression*, Bexpression*, Location); conditional_expression(Btype*, Bexpression*, Bexpression*, Bexpression*,
Location);
Bexpression*
binary_expression(Operator, Bexpression*, Bexpression*, Location);
// Statements. // Statements.
...@@ -1059,22 +1063,142 @@ Gcc_backend::compound_expression(Bstatement* bstat, Bexpression* bexpr, ...@@ -1059,22 +1063,142 @@ Gcc_backend::compound_expression(Bstatement* bstat, Bexpression* bexpr,
// ELSE_EXPR otherwise. // ELSE_EXPR otherwise.
Bexpression* Bexpression*
Gcc_backend::conditional_expression(Bexpression* condition, Gcc_backend::conditional_expression(Btype* btype, Bexpression* condition,
Bexpression* then_expr, Bexpression* then_expr,
Bexpression* else_expr, Location location) Bexpression* else_expr, Location location)
{ {
tree type_tree = btype == NULL ? void_type_node : btype->get_tree();
tree cond_tree = condition->get_tree(); tree cond_tree = condition->get_tree();
tree then_tree = then_expr->get_tree(); tree then_tree = then_expr->get_tree();
tree else_tree = else_expr == NULL ? NULL_TREE : else_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 || then_tree == error_mark_node
|| else_tree == error_mark_node) || else_tree == error_mark_node)
return this->error_expression(); 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); cond_tree, then_tree, else_tree);
return this->make_expression(ret); return this->make_expression(ret);
} }
// Convert a gofrontend operator to an equivalent tree_code.
static 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. // An expression as a statement.
Bstatement* Bstatement*
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include <gmp.h> #include <gmp.h>
#include <mpfr.h> #include <mpfr.h>
#include "operator.h"
// Pointers to these types are created by the backend, passed to the // Pointers to these types are created by the backend, passed to the
// frontend, and passed back to the backend. The types must be // frontend, and passed back to the backend. The types must be
// defined by the backend using these names. // defined by the backend using these names.
...@@ -289,10 +291,20 @@ class Backend ...@@ -289,10 +291,20 @@ class Backend
compound_expression(Bstatement* bstat, Bexpression* bexpr, Location) = 0; compound_expression(Bstatement* bstat, Bexpression* bexpr, Location) = 0;
// Return an expression that executes THEN_EXPR if CONDITION is true, or // 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* virtual Bexpression*
conditional_expression(Bexpression* condition, Bexpression* then_expr, conditional_expression(Btype* btype, Bexpression* condition,
Bexpression* else_expr, Location) = 0; 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*
binary_expression(Operator op, Bexpression* left, Bexpression* right,
Location) = 0;
// Statements. // Statements.
......
...@@ -5536,6 +5536,61 @@ Binary_expression::lower_compare_to_memcmp(Gogo*, Statement_inserter* inserter) ...@@ -5536,6 +5536,61 @@ Binary_expression::lower_compare_to_memcmp(Gogo*, Statement_inserter* inserter)
return Expression::make_binary(this->op_, call, zero, loc); 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. // Return the address of EXPR, cast to unsafe.Pointer.
Expression* Expression*
...@@ -5956,14 +6011,10 @@ tree ...@@ -5956,14 +6011,10 @@ tree
Binary_expression::do_get_tree(Translate_context* context) Binary_expression::do_get_tree(Translate_context* context)
{ {
Gogo* gogo = context->gogo(); 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 use_left_type = true;
bool is_shift_op = false; bool is_shift_op = false;
bool is_idiv_op = false; bool is_idiv_op = false;
...@@ -5975,198 +6026,126 @@ Binary_expression::do_get_tree(Translate_context* context) ...@@ -5975,198 +6026,126 @@ Binary_expression::do_get_tree(Translate_context* context)
case OPERATOR_LE: case OPERATOR_LE:
case OPERATOR_GT: case OPERATOR_GT:
case OPERATOR_GE: case OPERATOR_GE:
return Expression::comparison_tree(context, this->type_, this->op_, {
this->left_, this->right_, Bexpression* ret =
this->location()); Expression::comparison(context, this->type_, this->op_,
this->left_, this->right_, loc);
return expr_to_tree(ret);
}
case OPERATOR_OROR: case OPERATOR_OROR:
code = TRUTH_ORIF_EXPR;
use_left_type = false;
break;
case OPERATOR_ANDAND: case OPERATOR_ANDAND:
code = TRUTH_ANDIF_EXPR;
use_left_type = false; use_left_type = false;
break; break;
case OPERATOR_PLUS: case OPERATOR_PLUS:
code = PLUS_EXPR;
break;
case OPERATOR_MINUS: case OPERATOR_MINUS:
code = MINUS_EXPR;
break;
case OPERATOR_OR: case OPERATOR_OR:
code = BIT_IOR_EXPR;
break;
case OPERATOR_XOR: case OPERATOR_XOR:
code = BIT_XOR_EXPR;
break;
case OPERATOR_MULT: case OPERATOR_MULT:
code = MULT_EXPR;
break; break;
case OPERATOR_DIV: case OPERATOR_DIV:
{ if (left_type->float_type() != NULL || left_type->complex_type() != NULL)
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; break;
case OPERATOR_MOD: case OPERATOR_MOD:
code = TRUNC_MOD_EXPR;
is_idiv_op = true; is_idiv_op = true;
break; break;
case OPERATOR_LSHIFT: case OPERATOR_LSHIFT:
code = LSHIFT_EXPR;
is_shift_op = true;
break;
case OPERATOR_RSHIFT: case OPERATOR_RSHIFT:
code = RSHIFT_EXPR;
is_shift_op = true; is_shift_op = true;
break; break;
case OPERATOR_AND:
code = BIT_AND_EXPR;
break;
case OPERATOR_BITCLEAR: case OPERATOR_BITCLEAR:
right = fold_build1(BIT_NOT_EXPR, TREE_TYPE(right), right); this->right_ = Expression::make_unary(OPERATOR_XOR, this->right_, loc);
code = BIT_AND_EXPR; case OPERATOR_AND:
break; break;
default: default:
go_unreachable(); go_unreachable();
} }
location_t gccloc = this->location().gcc_location(); if (left_type->is_string_type())
tree type = use_left_type ? TREE_TYPE(left) : TREE_TYPE(right);
if (this->left_->type()->is_string_type())
{ {
go_assert(this->op_ == OPERATOR_PLUS); go_assert(this->op_ == OPERATOR_PLUS);
Type* st = Type::make_string_type(); Expression* string_plus =
tree string_type = type_to_tree(st->get_backend(gogo)); Runtime::make_call(Runtime::STRING_PLUS, loc, 2,
static tree string_plus_decl; this->left_, this->right_);
return Gogo::call_builtin(&string_plus_decl, return string_plus->get_tree(context);
this->location(),
"__go_string_plus",
2,
string_type,
string_type,
left,
string_type,
right);
} }
// For complex division Go wants slightly different results than the // For complex division Go might want slightly different results than the
// GCC library provides, so we have our own runtime routine. // backend implementation provides, so we have our own runtime routine.
if (this->op_ == OPERATOR_DIV && this->left_->type()->complex_type() != NULL) if (this->op_ == OPERATOR_DIV && this->left_->type()->complex_type() != NULL)
{ {
const char *name; Runtime::Function complex_code;
tree *pdecl;
Type* ctype;
static tree complex64_div_decl;
static tree complex128_div_decl;
switch (this->left_->type()->complex_type()->bits()) switch (this->left_->type()->complex_type()->bits())
{ {
case 64: case 64:
name = "__go_complex64_div"; complex_code = Runtime::COMPLEX64_DIV;
pdecl = &complex64_div_decl;
ctype = Type::lookup_complex_type("complex64");
break; break;
case 128: case 128:
name = "__go_complex128_div"; complex_code = Runtime::COMPLEX128_DIV;
pdecl = &complex128_div_decl;
ctype = Type::lookup_complex_type("complex128");
break; break;
default: default:
go_unreachable(); go_unreachable();
} }
Btype* cbtype = ctype->get_backend(gogo); Expression* complex_div =
tree ctype_tree = type_to_tree(cbtype); Runtime::make_call(complex_code, loc, 2, this->left_, this->right_);
return Gogo::call_builtin(pdecl, return complex_div->get_tree(context);
this->location(),
name,
2,
ctype_tree,
ctype_tree,
fold_convert_loc(gccloc, ctype_tree, left),
type,
fold_convert_loc(gccloc, ctype_tree, right));
} }
tree compute_type = excess_precision_type(type); Bexpression* left = tree_to_expr(this->left_->get_tree(context));
if (compute_type != NULL_TREE) Bexpression* right = tree_to_expr(this->right_->get_tree(context));
{
left = ::convert(compute_type, left);
right = ::convert(compute_type, right);
}
tree eval_saved = NULL_TREE; Type* type = use_left_type ? left_type : right_type;
if (is_shift_op Btype* btype = type->get_backend(gogo);
|| (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);
}
}
tree ret = fold_build2_loc(gccloc, code, Bexpression* ret =
compute_type != NULL_TREE ? compute_type : type, gogo->backend()->binary_expression(this->op_, left, right, loc);
left, right); ret = gogo->backend()->convert_expression(btype, ret, loc);
if (compute_type != NULL_TREE) // Initialize overflow constants.
ret = ::convert(type, ret); 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);
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. // 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) if (is_shift_op)
{ {
go_assert(INTEGRAL_TYPE_P(TREE_TYPE(left))); go_assert(left_type->integer_type() != NULL);
go_assert(this->left_->type()->integer_type() != NULL);
int bits = TYPE_PRECISION(TREE_TYPE(left));
tree compare = fold_build2(LT_EXPR, boolean_type_node, right, mpz_t bitsval;
build_int_cst_type(TREE_TYPE(right), bits)); 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);
tree overflow_result = fold_convert_loc(gccloc, TREE_TYPE(left), Bexpression* zero_expr =
integer_zero_node); gogo->backend()->integer_constant_expression(left_btype, zero);
overflow = zero_expr;
if (this->op_ == OPERATOR_RSHIFT if (this->op_ == OPERATOR_RSHIFT
&& !this->left_->type()->integer_type()->is_unsigned()) && !left_type->integer_type()->is_unsigned())
{ {
tree neg = Bexpression* neg_expr =
fold_build2_loc(gccloc, LT_EXPR, boolean_type_node, gogo->backend()->binary_expression(OPERATOR_LT, left,
left, zero_expr, loc);
fold_convert_loc(gccloc, TREE_TYPE(left), Bexpression* neg_one_expr =
integer_zero_node)); gogo->backend()->integer_constant_expression(left_btype, neg_one);
tree neg_one = overflow = gogo->backend()->conditional_expression(btype, neg_expr,
fold_build2_loc(gccloc, MINUS_EXPR, TREE_TYPE(left), neg_one_expr,
fold_convert_loc(gccloc, TREE_TYPE(left), zero_expr, loc);
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 = gogo->backend()->conditional_expression(btype, compare, ret,
ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(left), overflow, loc);
compare, ret, overflow_result); mpz_clear(bitsval);
if (eval_saved != NULL_TREE)
ret = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret),
eval_saved, ret);
} }
// Add checks for division by zero and division overflow as needed. // Add checks for division by zero and division overflow as needed.
...@@ -6175,23 +6154,20 @@ Binary_expression::do_get_tree(Translate_context* context) ...@@ -6175,23 +6154,20 @@ Binary_expression::do_get_tree(Translate_context* context)
if (go_check_divide_zero) if (go_check_divide_zero)
{ {
// right == 0 // right == 0
tree check = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node, Bexpression* zero_expr =
right, gogo->backend()->integer_constant_expression(right_btype, zero);
fold_convert_loc(gccloc, Bexpression* check =
TREE_TYPE(right), gogo->backend()->binary_expression(OPERATOR_EQEQ,
integer_zero_node)); 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; int errcode = RUNTIME_ERROR_DIVISION_BY_ZERO;
Expression* crash = gogo->runtime_error(errcode, this->location()); Expression* crash = gogo->runtime_error(errcode, loc);
tree panic = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret), Bexpression* crash_expr = tree_to_expr(crash->get_tree(context));
crash->get_tree(context),
fold_convert_loc(gccloc, TREE_TYPE(ret),
integer_zero_node));
// right == 0 ? (__go_runtime_error(...), 0) : ret // right == 0 ? (__go_runtime_error(...), 0) : ret
ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret), ret = gogo->backend()->conditional_expression(btype, check,
check, panic, ret); crash_expr, ret, loc);
} }
if (go_check_divide_overflow) if (go_check_divide_overflow)
...@@ -6199,60 +6175,62 @@ Binary_expression::do_get_tree(Translate_context* context) ...@@ -6199,60 +6175,62 @@ Binary_expression::do_get_tree(Translate_context* context)
// right == -1 // right == -1
// FIXME: It would be nice to say that this test is expected // FIXME: It would be nice to say that this test is expected
// to return false. // 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; Bexpression* neg_one_expr =
if (TYPE_UNSIGNED(TREE_TYPE(ret))) 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 // An unsigned -1 is the largest possible number, so
// dividing is always 1 or 0. // 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) if (this->op_ == OPERATOR_DIV)
overflow = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret), overflow =
cmp, gogo->backend()->conditional_expression(btype, cmp,
fold_convert_loc(gccloc, one_expr, zero_expr,
TREE_TYPE(ret), loc);
integer_one_node),
fold_convert_loc(gccloc,
TREE_TYPE(ret),
integer_zero_node));
else else
overflow = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret), overflow =
cmp, gogo->backend()->conditional_expression(btype, cmp,
fold_convert_loc(gccloc, zero_expr, left,
TREE_TYPE(ret), loc);
integer_zero_node),
left);
} }
else else
{ {
// Computing left / -1 is the same as computing - left, // Computing left / -1 is the same as computing - left,
// which does not overflow since Go sets -fwrapv. // which does not overflow since Go sets -fwrapv.
if (this->op_ == OPERATOR_DIV) 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 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 // right == -1 ? - left : ret
ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret), ret = gogo->backend()->conditional_expression(btype, check, overflow,
check, overflow, ret); 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. // Export a binary expression.
...@@ -6471,8 +6449,8 @@ Expression::make_binary(Operator op, Expression* left, Expression* right, ...@@ -6471,8 +6449,8 @@ Expression::make_binary(Operator op, Expression* left, Expression* right,
// Implement a comparison. // Implement a comparison.
tree Bexpression*
Expression::comparison_tree(Translate_context* context, Type* result_type, Expression::comparison(Translate_context* context, Type* result_type,
Operator op, Expression* left, Expression* right, Operator op, Expression* left, Expression* right,
Location location) Location location)
{ {
...@@ -6484,31 +6462,6 @@ Expression::comparison_tree(Translate_context* context, Type* result_type, ...@@ -6484,31 +6462,6 @@ Expression::comparison_tree(Translate_context* context, Type* result_type,
Expression* zexpr = Expression::make_integer(&zval, NULL, location); Expression* zexpr = Expression::make_integer(&zval, NULL, location);
mpz_clear(zval); 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()) if (left_type->is_string_type() && right_type->is_string_type())
{ {
left = Runtime::make_call(Runtime::STRCMP, location, 2, left = Runtime::make_call(Runtime::STRCMP, location, 2,
...@@ -6601,20 +6554,15 @@ Expression::comparison_tree(Translate_context* context, Type* result_type, ...@@ -6601,20 +6554,15 @@ Expression::comparison_tree(Translate_context* context, Type* result_type,
} }
} }
tree left_tree = left->get_tree(context); Bexpression* left_bexpr = tree_to_expr(left->get_tree(context));
tree right_tree = right->get_tree(context); Bexpression* right_bexpr = tree_to_expr(right->get_tree(context));
if (left_tree == error_mark_node || right_tree == error_mark_node)
return error_mark_node;
tree result_type_tree; Gogo* gogo = context->gogo();
if (result_type == NULL) Bexpression* ret = gogo->backend()->binary_expression(op, left_bexpr,
result_type_tree = boolean_type_node; right_bexpr, location);
else if (result_type != NULL)
result_type_tree = type_to_tree(result_type->get_backend(context->gogo())); ret = gogo->backend()->convert_expression(result_type->get_backend(gogo),
ret, location);
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());
return ret; return ret;
} }
...@@ -6830,6 +6778,7 @@ Bound_method_expression::create_thunk(Gogo* gogo, const Method* method, ...@@ -6830,6 +6778,7 @@ Bound_method_expression::create_thunk(Gogo* gogo, const Method* method,
Block* b = gogo->finish_block(loc); Block* b = gogo->finish_block(loc);
gogo->add_block(b, loc); gogo->add_block(b, loc);
gogo->lower_block(new_no, b); gogo->lower_block(new_no, b);
gogo->flatten_block(new_no, b);
gogo->finish_function(loc); gogo->finish_function(loc);
ins.first->second = new_no; ins.first->second = new_no;
...@@ -11827,6 +11776,7 @@ Interface_field_reference_expression::create_thunk(Gogo* gogo, ...@@ -11827,6 +11776,7 @@ Interface_field_reference_expression::create_thunk(Gogo* gogo,
Block* b = gogo->finish_block(loc); Block* b = gogo->finish_block(loc);
gogo->add_block(b, loc); gogo->add_block(b, loc);
gogo->lower_block(new_no, b); gogo->lower_block(new_no, b);
gogo->flatten_block(new_no, b);
gogo->finish_function(loc); gogo->finish_function(loc);
ins.first->second->push_back(std::make_pair(name, new_no)); ins.first->second->push_back(std::make_pair(name, new_no));
...@@ -11888,7 +11838,7 @@ Interface_field_reference_expression::do_get_tree(Translate_context* context) ...@@ -11888,7 +11838,7 @@ Interface_field_reference_expression::do_get_tree(Translate_context* context)
Bexpression* bcrash = tree_to_expr(crash->get_tree(context)); Bexpression* bcrash = tree_to_expr(crash->get_tree(context));
Bexpression* bcond = 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); Bstatement* cond_statement = gogo->backend()->expression_statement(bcond);
Bexpression* ret = Bexpression* ret =
gogo->backend()->compound_expression(cond_statement, bclosure, loc); gogo->backend()->compound_expression(cond_statement, bclosure, loc);
...@@ -12157,6 +12107,7 @@ Selector_expression::lower_method_expression(Gogo* gogo) ...@@ -12157,6 +12107,7 @@ Selector_expression::lower_method_expression(Gogo* gogo)
// Lower the call in case there are multiple results. // Lower the call in case there are multiple results.
gogo->lower_block(no, b); gogo->lower_block(no, b);
gogo->flatten_block(no, b);
gogo->finish_function(location); gogo->finish_function(location);
......
...@@ -704,11 +704,11 @@ class Expression ...@@ -704,11 +704,11 @@ class Expression
Type* rhs_type, tree rhs_tree, Type* rhs_type, tree rhs_tree,
bool for_type_guard, Location); 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. // TYPE is the type of both sides.
static tree static Bexpression*
comparison_tree(Translate_context*, Type* result_type, Operator op, comparison(Translate_context*, Type* result_type, Operator op,
Expression* left_expr, Expression* right_expr, Location); Expression* left, Expression* right, Location);
// Return the backend expression for the numeric constant VAL. // Return the backend expression for the numeric constant VAL.
static Bexpression* static Bexpression*
...@@ -1289,6 +1289,9 @@ class Binary_expression : public Expression ...@@ -1289,6 +1289,9 @@ class Binary_expression : public Expression
Expression* Expression*
do_lower(Gogo*, Named_object*, Statement_inserter*, int); do_lower(Gogo*, Named_object*, Statement_inserter*, int);
Expression*
do_flatten(Gogo*, Named_object*, Statement_inserter*);
bool bool
do_is_constant() const do_is_constant() const
{ return this->left_->is_constant() && this->right_->is_constant(); } { return this->left_->is_constant() && this->right_->is_constant(); }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment