diff options
author | mrs <mrs@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-04-02 19:51:52 +0000 |
---|---|---|
committer | mrs <mrs@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-04-02 19:51:52 +0000 |
commit | aa7e537c6a038e81382606468e484576c2cee3d5 (patch) | |
tree | 149b47cc2c398d20f882c4307d0f320170375137 /gcc/gimple-fold.c | |
parent | 7f646368a7a7679a8c4a349c4130b49d9a64d9cd (diff) | |
parent | b28b448fdb7865fc64094a799dd396f0d732a7c2 (diff) | |
download | gcc-aa7e537c6a038e81382606468e484576c2cee3d5.tar.gz |
Merge in trunk.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/wide-int@209030 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/gimple-fold.c')
-rw-r--r-- | gcc/gimple-fold.c | 141 |
1 files changed, 125 insertions, 16 deletions
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index f9eef645fb3..f0fd30d3635 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -1153,8 +1153,13 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace) { tree var = create_tmp_var (TREE_TYPE (lhs), NULL); tree def = get_or_create_ssa_default_def (cfun, var); - gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT); + + /* To satisfy condition for + cgraph_update_edges_for_call_stmt_node, + we need to preserve GIMPLE_CALL statement + at position of GSI iterator. */ update_call_from_tree (gsi, def); + gsi_insert_before (gsi, new_stmt, GSI_NEW_STMT); } else gsi_replace (gsi, new_stmt, true); @@ -1181,6 +1186,63 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace) else if (gimple_call_builtin_p (stmt, BUILT_IN_MD)) changed |= targetm.gimple_fold_builtin (gsi); } + else if (gimple_call_internal_p (stmt)) + { + enum tree_code subcode = ERROR_MARK; + tree result = NULL_TREE; + switch (gimple_call_internal_fn (stmt)) + { + case IFN_BUILTIN_EXPECT: + result = fold_builtin_expect (gimple_location (stmt), + gimple_call_arg (stmt, 0), + gimple_call_arg (stmt, 1), + gimple_call_arg (stmt, 2)); + break; + case IFN_UBSAN_CHECK_ADD: + subcode = PLUS_EXPR; + break; + case IFN_UBSAN_CHECK_SUB: + subcode = MINUS_EXPR; + break; + case IFN_UBSAN_CHECK_MUL: + subcode = MULT_EXPR; + break; + default: + break; + } + if (subcode != ERROR_MARK) + { + tree arg0 = gimple_call_arg (stmt, 0); + tree arg1 = gimple_call_arg (stmt, 1); + /* x = y + 0; x = y - 0; x = y * 0; */ + if (integer_zerop (arg1)) + result = subcode == MULT_EXPR + ? build_zero_cst (TREE_TYPE (arg0)) + : arg0; + /* x = 0 + y; x = 0 * y; */ + else if (subcode != MINUS_EXPR && integer_zerop (arg0)) + result = subcode == MULT_EXPR + ? build_zero_cst (TREE_TYPE (arg0)) + : arg1; + /* x = y - y; */ + else if (subcode == MINUS_EXPR && operand_equal_p (arg0, arg1, 0)) + result = build_zero_cst (TREE_TYPE (arg0)); + /* x = y * 1; x = 1 * y; */ + else if (subcode == MULT_EXPR) + { + if (integer_onep (arg1)) + result = arg0; + else if (integer_onep (arg0)) + result = arg1; + } + } + if (result) + { + if (!update_call_from_tree (gsi, result)) + gimplify_and_update_call_from_tree (gsi, result); + changed = true; + } + } return changed; } @@ -2669,15 +2731,32 @@ gimple_fold_stmt_to_constant_1 (gimple stmt, tree (*valueize) (tree)) default: return NULL_TREE; } - tree op0 = (*valueize) (gimple_call_arg (stmt, 0)); - tree op1 = (*valueize) (gimple_call_arg (stmt, 1)); + tree arg0 = gimple_call_arg (stmt, 0); + tree arg1 = gimple_call_arg (stmt, 1); + tree op0 = (*valueize) (arg0); + tree op1 = (*valueize) (arg1); if (TREE_CODE (op0) != INTEGER_CST || TREE_CODE (op1) != INTEGER_CST) - return NULL_TREE; - tree res = fold_binary_loc (loc, subcode, - TREE_TYPE (gimple_call_arg (stmt, 0)), - op0, op1); + { + switch (subcode) + { + case MULT_EXPR: + /* x * 0 = 0 * x = 0 without overflow. */ + if (integer_zerop (op0) || integer_zerop (op1)) + return build_zero_cst (TREE_TYPE (arg0)); + break; + case MINUS_EXPR: + /* y - y = 0 without overflow. */ + if (operand_equal_p (op0, op1, 0)) + return build_zero_cst (TREE_TYPE (arg0)); + break; + default: + break; + } + } + tree res + = fold_binary_loc (loc, subcode, TREE_TYPE (arg0), op0, op1); if (res && TREE_CODE (res) == INTEGER_CST && !TREE_OVERFLOW (res)) @@ -3172,22 +3251,35 @@ fold_const_aggregate_ref (tree t) } /* Lookup virtual method with index TOKEN in a virtual table V - at OFFSET. */ + at OFFSET. + Set CAN_REFER if non-NULL to false if method + is not referable or if the virtual table is ill-formed (such as rewriten + by non-C++ produced symbol). Otherwise just return NULL in that calse. */ tree gimple_get_virt_method_for_vtable (HOST_WIDE_INT token, tree v, - unsigned HOST_WIDE_INT offset) + unsigned HOST_WIDE_INT offset, + bool *can_refer) { tree vtable = v, init, fn; unsigned HOST_WIDE_INT size; unsigned HOST_WIDE_INT elt_size, access_index; tree domain_type; + if (can_refer) + *can_refer = true; + /* First of all double check we have virtual table. */ if (TREE_CODE (v) != VAR_DECL || !DECL_VIRTUAL_P (v)) - return NULL_TREE; + { + gcc_assert (in_lto_p); + /* Pass down that we lost track of the target. */ + if (can_refer) + *can_refer = false; + return NULL_TREE; + } init = ctor_for_folding (v); @@ -3199,6 +3291,9 @@ gimple_get_virt_method_for_vtable (HOST_WIDE_INT token, if (init == error_mark_node) { gcc_assert (in_lto_p); + /* Pass down that we lost track of the target. */ + if (can_refer) + *can_refer = false; return NULL_TREE; } gcc_checking_assert (TREE_CODE (TREE_TYPE (v)) == ARRAY_TYPE); @@ -3249,7 +3344,14 @@ gimple_get_virt_method_for_vtable (HOST_WIDE_INT token, ends up in other partition, because we found devirtualization possibility too late. */ if (!can_refer_decl_in_current_unit_p (fn, vtable)) - return NULL_TREE; + { + if (can_refer) + { + *can_refer = false; + return fn; + } + return NULL_TREE; + } } /* Make sure we create a cgraph node for functions we'll reference. @@ -3263,10 +3365,14 @@ gimple_get_virt_method_for_vtable (HOST_WIDE_INT token, /* Return a declaration of a function which an OBJ_TYPE_REF references. TOKEN is integer form of OBJ_TYPE_REF_TOKEN of the reference expression. KNOWN_BINFO carries the binfo describing the true type of - OBJ_TYPE_REF_OBJECT(REF). */ + OBJ_TYPE_REF_OBJECT(REF). + Set CAN_REFER if non-NULL to false if method + is not referable or if the virtual table is ill-formed (such as rewriten + by non-C++ produced symbol). Otherwise just return NULL in that calse. */ tree -gimple_get_virt_method_for_binfo (HOST_WIDE_INT token, tree known_binfo) +gimple_get_virt_method_for_binfo (HOST_WIDE_INT token, tree known_binfo, + bool *can_refer) { unsigned HOST_WIDE_INT offset; tree v; @@ -3277,9 +3383,12 @@ gimple_get_virt_method_for_binfo (HOST_WIDE_INT token, tree known_binfo) return NULL_TREE; if (!vtable_pointer_value_to_vtable (v, &v, &offset)) - return NULL_TREE; - - return gimple_get_virt_method_for_vtable (token, v, offset); + { + if (can_refer) + *can_refer = false; + return NULL_TREE; + } + return gimple_get_virt_method_for_vtable (token, v, offset, can_refer); } /* Return true iff VAL is a gimple expression that is known to be |