summaryrefslogtreecommitdiff
path: root/gcc/go/gofrontend
diff options
context:
space:
mode:
authorbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2012-04-23 12:53:36 +0000
committerbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2012-04-23 12:53:36 +0000
commit65cbf05437b8a57ff08846beb19407c9e0dd2553 (patch)
tree0b0bd391a56275bab5bf67e4094d9b7a24ade79c /gcc/go/gofrontend
parent381399a9fee786a047529a0f7de787de475ab97c (diff)
downloadgcc-65cbf05437b8a57ff08846beb19407c9e0dd2553.tar.gz
2012-04-23 Basile Starynkevitch <basile@starynkevitch.net>
MELT branch merged with trunk rev 186692 using svnmerge [gcc/] 2012-04-23 Basile Starynkevitch <basile@starynkevitch.net> {{improvements for merging with GCC 4.8 trunk svn rev 186692}} * melt-run.proto.h (MELT_GCC_VERSION): Define, if unknown, in the generated melt-run.h * melt-runtime.c (melt_val2passflag): TODO_dump_func & TODO_dump_cgraph don't exist in GCC 4.8. * melt-build.tpl: Say flavor, not variant! Build first the quicklybuilt application modules, to catch error in macro C strings... * melt-build.mk: Regenerate. * melt/warmelt-base.melt (valdesc_strbuf): Check for MELT_GCC_VERSION also. * melt/warmelt-genobj.melt (compilobj_nrep_citeration): Use meltcit prefix in generated citerator names.. * melt/warmelt-outobj.melt (syntestgen_citerator): Use meltcitstate prefix. * melt/xtramelt-ana-base.melt (each_cgraph_fun_body) (each_cgraph_fun_entryblock, each_cgraph_fun_call_flow_graph) (each_bb_cfun, with_cfun_decl): Adapt to GCC 4.8, add documentation. (each_cgraph_decl): Only for GCC 4.6 & 4.7 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@186705 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/go/gofrontend')
-rw-r--r--gcc/go/gofrontend/expressions.cc154
-rw-r--r--gcc/go/gofrontend/gogo-tree.cc1
-rw-r--r--gcc/go/gofrontend/gogo.h3
3 files changed, 128 insertions, 30 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index baff0c9a5d9..cb94e4f8dd9 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -2403,8 +2403,7 @@ class Const_expression : public Expression
do_numeric_constant_value(Numeric_constant* nc) const;
bool
- do_string_constant_value(std::string* val) const
- { return this->constant_->const_value()->expr()->string_constant_value(val); }
+ do_string_constant_value(std::string* val) const;
Type*
do_type();
@@ -2514,6 +2513,21 @@ Const_expression::do_numeric_constant_value(Numeric_constant* nc) const
return r;
}
+bool
+Const_expression::do_string_constant_value(std::string* val) const
+{
+ if (this->seen_)
+ return false;
+
+ Expression* e = this->constant_->const_value()->expr();
+
+ this->seen_ = true;
+ bool ok = e->string_constant_value(val);
+ this->seen_ = false;
+
+ return ok;
+}
+
// Return the type of the const reference.
Type*
@@ -5633,6 +5647,7 @@ Binary_expression::do_get_tree(Translate_context* context)
enum tree_code code;
bool use_left_type = true;
bool is_shift_op = false;
+ bool is_idiv_op = false;
switch (this->op_)
{
case OPERATOR_EQEQ:
@@ -5675,11 +5690,15 @@ Binary_expression::do_get_tree(Translate_context* context)
if (t->float_type() != NULL || t->complex_type() != NULL)
code = RDIV_EXPR;
else
- code = TRUNC_DIV_EXPR;
+ {
+ code = TRUNC_DIV_EXPR;
+ is_idiv_op = true;
+ }
}
break;
case OPERATOR_MOD:
code = TRUNC_MOD_EXPR;
+ is_idiv_op = true;
break;
case OPERATOR_LSHIFT:
code = LSHIFT_EXPR;
@@ -5700,6 +5719,7 @@ Binary_expression::do_get_tree(Translate_context* context)
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())
@@ -5727,28 +5747,27 @@ Binary_expression::do_get_tree(Translate_context* context)
}
tree eval_saved = NULL_TREE;
- if (is_shift_op)
+ 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) && TREE_SIDE_EFFECTS(left))
+ if (!DECL_P(left))
{
left = save_expr(left);
eval_saved = left;
}
- if (!DECL_P(right) && TREE_SIDE_EFFECTS(right))
+ if (!DECL_P(right))
{
right = save_expr(right);
if (eval_saved == NULL_TREE)
eval_saved = right;
else
- eval_saved = fold_build2_loc(this->location().gcc_location(),
- COMPOUND_EXPR,
+ eval_saved = fold_build2_loc(gccloc, COMPOUND_EXPR,
void_type_node, eval_saved, right);
}
}
- tree ret = fold_build2_loc(this->location().gcc_location(),
- code,
+ tree ret = fold_build2_loc(gccloc, code,
compute_type != NULL_TREE ? compute_type : type,
left, right);
@@ -5766,39 +5785,116 @@ Binary_expression::do_get_tree(Translate_context* context)
tree compare = fold_build2(LT_EXPR, boolean_type_node, right,
build_int_cst_type(TREE_TYPE(right), bits));
- tree overflow_result = fold_convert_loc(this->location().gcc_location(),
- TREE_TYPE(left),
+ tree overflow_result = fold_convert_loc(gccloc, TREE_TYPE(left),
integer_zero_node);
if (this->op_ == OPERATOR_RSHIFT
&& !this->left_->type()->integer_type()->is_unsigned())
{
tree neg =
- fold_build2_loc(this->location().gcc_location(), LT_EXPR,
- boolean_type_node, left,
- fold_convert_loc(this->location().gcc_location(),
- TREE_TYPE(left),
+ 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(this->location().gcc_location(),
- MINUS_EXPR, TREE_TYPE(left),
- fold_convert_loc(this->location().gcc_location(),
- TREE_TYPE(left),
+ fold_build2_loc(gccloc, MINUS_EXPR, TREE_TYPE(left),
+ fold_convert_loc(gccloc, TREE_TYPE(left),
integer_zero_node),
- fold_convert_loc(this->location().gcc_location(),
- TREE_TYPE(left),
+ fold_convert_loc(gccloc, TREE_TYPE(left),
integer_one_node));
overflow_result =
- fold_build3_loc(this->location().gcc_location(), COND_EXPR,
- TREE_TYPE(left), neg, neg_one,
- 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);
+ }
+
+ // Add checks for division by zero and division overflow as needed.
+ if (is_idiv_op)
+ {
+ 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));
+
+ // __go_runtime_error(RUNTIME_ERROR_DIVISION_BY_ZERO), 0
+ int errcode = RUNTIME_ERROR_DIVISION_BY_ZERO;
+ tree panic = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret),
+ Gogo::runtime_error(errcode,
+ this->location()),
+ fold_convert_loc(gccloc, TREE_TYPE(ret),
+ integer_zero_node));
+
+ // right == 0 ? (__go_runtime_error(...), 0) : ret
+ ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
+ check, panic, ret);
}
- ret = fold_build3_loc(this->location().gcc_location(), COND_EXPR,
- TREE_TYPE(left), compare, ret, overflow_result);
+ if (go_check_divide_overflow)
+ {
+ // 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)))
+ {
+ // 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);
+ 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));
+ else
+ overflow = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
+ cmp,
+ fold_convert_loc(gccloc,
+ TREE_TYPE(ret),
+ integer_zero_node),
+ left);
+ }
+ 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);
+ else
+ overflow = integer_zero_node;
+ }
+ overflow = fold_convert_loc(gccloc, TREE_TYPE(ret), overflow);
+
+ // right == -1 ? - left : ret
+ ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
+ check, overflow, ret);
+ }
if (eval_saved != NULL_TREE)
- ret = fold_build2_loc(this->location().gcc_location(), COMPOUND_EXPR,
- TREE_TYPE(ret), eval_saved, ret);
+ ret = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret),
+ eval_saved, ret);
}
return ret;
diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc
index fa229320c96..762f9fc9b81 100644
--- a/gcc/go/gofrontend/gogo-tree.cc
+++ b/gcc/go/gofrontend/gogo-tree.cc
@@ -495,7 +495,6 @@ Gogo::write_initialization_function(tree fndecl, tree init_stmt_list)
gimplify_function_tree(fndecl);
cgraph_add_new_function(fndecl, false);
- cgraph_mark_needed_node(cgraph_get_node(fndecl));
current_function_decl = NULL_TREE;
pop_cfun();
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index 6c77c3bd9e9..9c5f8cb4a6b 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -2791,6 +2791,9 @@ static const int RUNTIME_ERROR_MAKE_MAP_OUT_OF_BOUNDS = 8;
// Channel capacity out of bounds in make: negative or overflow.
static const int RUNTIME_ERROR_MAKE_CHAN_OUT_OF_BOUNDS = 9;
+// Division by zero.
+static const int RUNTIME_ERROR_DIVISION_BY_ZERO = 10;
+
// This is used by some of the langhooks.
extern Gogo* go_get_gogo();