diff options
author | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-04-23 12:53:36 +0000 |
---|---|---|
committer | bstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-04-23 12:53:36 +0000 |
commit | 65cbf05437b8a57ff08846beb19407c9e0dd2553 (patch) | |
tree | 0b0bd391a56275bab5bf67e4094d9b7a24ade79c /gcc/go/gofrontend | |
parent | 381399a9fee786a047529a0f7de787de475ab97c (diff) | |
download | gcc-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.cc | 154 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo-tree.cc | 1 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 3 |
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(); |