X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Ftree-ssa-ccp.c;h=76ea0e49e1c2059106161097d3ca7e6184b11a69;hp=c331619189765cc9bdc0d649b64164f36ab2f95d;hb=f16404e36172337a1a48d0c4d16ae0090056d057;hpb=4c5fd53c3bdc9889c269a9ae4056ca81f79def16 diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index c3316191897..76ea0e49e1c 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -229,6 +229,7 @@ typedef enum static prop_value_t *const_val; static void canonicalize_float_value (prop_value_t *); +static bool ccp_fold_stmt (gimple_stmt_iterator *); /* Dump constant propagation value VAL to file OUTF prefixed by PREFIX. */ @@ -276,7 +277,8 @@ tree get_symbol_constant_value (tree sym) { if (TREE_STATIC (sym) - && TREE_READONLY (sym)) + && (TREE_READONLY (sym) + || TREE_CODE (sym) == CONST_DECL)) { tree val = DECL_INITIAL (sym); if (val) @@ -288,7 +290,11 @@ get_symbol_constant_value (tree sym) { tree base = get_base_address (TREE_OPERAND (val, 0)); if (base && TREE_CODE (base) == VAR_DECL) - add_referenced_var (base); + { + TREE_ADDRESSABLE (base) = 1; + if (gimple_referenced_vars (cfun)) + add_referenced_var (base); + } } return val; } @@ -645,7 +651,15 @@ ccp_initialize (void) for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i)) { gimple stmt = gsi_stmt (i); - bool is_varying = surely_varying_stmt_p (stmt); + bool is_varying; + + /* If the statement is a control insn, then we do not + want to avoid simulating the statement once. Failure + to do so means that those edges will never get added. */ + if (stmt_ends_bb_p (stmt)) + is_varying = false; + else + is_varying = surely_varying_stmt_p (stmt); if (is_varying) { @@ -711,7 +725,7 @@ ccp_finalize (void) do_dbg_cnt (); /* Perform substitutions based on the known constant values. */ - something_changed = substitute_and_fold (const_val, false); + something_changed = substitute_and_fold (const_val, ccp_fold_stmt); free (const_val); const_val = NULL; @@ -910,6 +924,7 @@ may_propagate_address_into_dereference (tree addr, tree deref) static tree ccp_fold (gimple stmt) { + location_t loc = gimple_location (stmt); switch (gimple_code (stmt)) { case GIMPLE_ASSIGN: @@ -958,6 +973,30 @@ ccp_fold (gimple stmt) } } } + else if (TREE_CODE (rhs) == CONSTRUCTOR + && TREE_CODE (TREE_TYPE (rhs)) == VECTOR_TYPE + && (CONSTRUCTOR_NELTS (rhs) + == TYPE_VECTOR_SUBPARTS (TREE_TYPE (rhs)))) + { + unsigned i; + tree val, list; + + list = NULL_TREE; + FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (rhs), i, val) + { + if (TREE_CODE (val) == SSA_NAME + && get_value (val)->lattice_val == CONSTANT) + val = get_value (val)->value; + if (TREE_CODE (val) == INTEGER_CST + || TREE_CODE (val) == REAL_CST + || TREE_CODE (val) == FIXED_CST) + list = tree_cons (NULL_TREE, val, list); + else + return NULL_TREE; + } + + return build_vector (TREE_TYPE (rhs), nreverse (list)); + } if (kind == tcc_reference) { @@ -968,7 +1007,8 @@ ccp_fold (gimple stmt) { prop_value_t *val = get_value (TREE_OPERAND (rhs, 0)); if (val->lattice_val == CONSTANT) - return fold_unary (TREE_CODE (rhs), + return fold_unary_loc (EXPR_LOCATION (rhs), + TREE_CODE (rhs), TREE_TYPE (rhs), val->value); } else if (TREE_CODE (rhs) == INDIRECT_REF @@ -1024,14 +1064,16 @@ ccp_fold (gimple stmt) if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (op0)) && ((tem = maybe_fold_offset_to_address - (op0, integer_zero_node, TREE_TYPE (lhs))) + (loc, + op0, integer_zero_node, TREE_TYPE (lhs))) != NULL_TREE)) return tem; return op0; } - return fold_unary_ignore_overflow (subcode, - gimple_expr_type (stmt), op0); + return + fold_unary_ignore_overflow_loc (loc, subcode, + gimple_expr_type (stmt), op0); } case GIMPLE_BINARY_RHS: @@ -1060,14 +1102,14 @@ ccp_fold (gimple stmt) && TREE_CODE (op0) == ADDR_EXPR && TREE_CODE (op1) == INTEGER_CST) { - tree lhs = gimple_assign_lhs (stmt); - tree tem = maybe_fold_offset_to_address (op0, op1, - TREE_TYPE (lhs)); + tree tem = maybe_fold_offset_to_address + (loc, op0, op1, TREE_TYPE (op0)); if (tem != NULL_TREE) return tem; } - return fold_binary (subcode, gimple_expr_type (stmt), op0, op1); + return fold_binary_loc (loc, subcode, + gimple_expr_type (stmt), op0, op1); } default: @@ -1104,9 +1146,10 @@ ccp_fold (gimple stmt) args[i] = val->value; } } - call = build_call_array (gimple_call_return_type (stmt), - fn, gimple_call_num_args (stmt), args); - retval = fold_call_expr (call, false); + call = build_call_array_loc (loc, + gimple_call_return_type (stmt), + fn, gimple_call_num_args (stmt), args); + retval = fold_call_expr (EXPR_LOCATION (call), call, false); if (retval) /* fold_call_expr wraps the result inside a NOP_EXPR. */ STRIP_NOPS (retval); @@ -1137,7 +1180,7 @@ ccp_fold (gimple stmt) op1 = val->value; } - return fold_binary (code, boolean_type_node, op0, op1); + return fold_binary_loc (loc, code, boolean_type_node, op0, op1); } case GIMPLE_SWITCH: @@ -1319,7 +1362,8 @@ fold_const_aggregate_ref (tree t) { tree c = fold_const_aggregate_ref (TREE_OPERAND (t, 0)); if (c && TREE_CODE (c) == COMPLEX_CST) - return fold_build1 (TREE_CODE (t), TREE_TYPE (t), c); + return fold_build1_loc (EXPR_LOCATION (t), + TREE_CODE (t), TREE_TYPE (t), c); break; } @@ -1380,8 +1424,8 @@ evaluate_stmt (gimple stmt) else if (code == GIMPLE_SWITCH) simplified = gimple_switch_index (stmt); else - /* These cannot satisfy is_gimple_min_invariant without folding. */ - gcc_assert (code == GIMPLE_CALL || code == GIMPLE_COND); + /* These cannot satisfy is_gimple_min_invariant without folding. */ + gcc_assert (code == GIMPLE_CALL || code == GIMPLE_COND); } is_constant = simplified && is_gimple_min_invariant (simplified); @@ -1429,6 +1473,34 @@ evaluate_stmt (gimple stmt) return val; } +/* Fold the stmt at *GSI with CCP specific information that propagating + and regular folding does not catch. */ + +static bool +ccp_fold_stmt (gimple_stmt_iterator *gsi) +{ + gimple stmt = gsi_stmt (*gsi); + prop_value_t val; + + if (gimple_code (stmt) != GIMPLE_COND) + return false; + + /* Statement evaluation will handle type mismatches in constants + more gracefully than the final propagation. This allows us to + fold more conditionals here. */ + val = evaluate_stmt (stmt); + if (val.lattice_val != CONSTANT + || TREE_CODE (val.value) != INTEGER_CST) + return false; + + if (integer_zerop (val.value)) + gimple_cond_make_false (stmt); + else + gimple_cond_make_true (stmt); + + return true; +} + /* Visit the assignment statement STMT. Set the value of its LHS to the value computed by the RHS and store LHS in *OUTPUT_P. If STMT creates virtual definitions, set the value of each new name to that @@ -1620,10 +1692,13 @@ struct gimple_opt_pass pass_ccp = /* A subroutine of fold_stmt. Attempts to fold *(A+O) to A[X]. BASE is an array type. OFFSET is a byte displacement. ORIG_TYPE - is the desired result type. */ + is the desired result type. + + LOC is the location of the original expression. */ static tree -maybe_fold_offset_to_array_ref (tree base, tree offset, tree orig_type, +maybe_fold_offset_to_array_ref (location_t loc, tree base, tree offset, + tree orig_type, bool allow_negative_idx) { tree min_idx, idx, idx_type, elt_offset = integer_zero_node; @@ -1756,17 +1831,23 @@ maybe_fold_offset_to_array_ref (tree base, tree offset, tree orig_type, && compare_tree_int (idx, 0) < 0) return NULL_TREE; - return build4 (ARRAY_REF, elt_type, base, idx, NULL_TREE, NULL_TREE); + { + tree t = build4 (ARRAY_REF, elt_type, base, idx, NULL_TREE, NULL_TREE); + SET_EXPR_LOCATION (t, loc); + return t; + } } /* Attempt to fold *(S+O) to S.X. BASE is a record type. OFFSET is a byte displacement. ORIG_TYPE - is the desired result type. */ + is the desired result type. + + LOC is the location of the original expression. */ static tree -maybe_fold_offset_to_component_ref (tree record_type, tree base, tree offset, - tree orig_type, bool base_is_ptr) +maybe_fold_offset_to_component_ref (location_t loc, tree record_type, + tree base, tree offset, tree orig_type) { tree f, t, field_type, tail_array_field, field_offset; tree ret; @@ -1818,8 +1899,6 @@ maybe_fold_offset_to_component_ref (tree record_type, tree base, tree offset, if (cmp == 0 && useless_type_conversion_p (orig_type, field_type)) { - if (base_is_ptr) - base = build1 (INDIRECT_REF, record_type, base); t = build3 (COMPONENT_REF, field_type, base, f, NULL_TREE); return t; } @@ -1844,19 +1923,16 @@ maybe_fold_offset_to_component_ref (tree record_type, tree base, tree offset, /* If we matched, then set offset to the displacement into this field. */ - if (base_is_ptr) - new_base = build1 (INDIRECT_REF, record_type, base); - else - new_base = base; - new_base = build3 (COMPONENT_REF, field_type, new_base, f, NULL_TREE); + new_base = build3 (COMPONENT_REF, field_type, base, f, NULL_TREE); + SET_EXPR_LOCATION (new_base, loc); /* Recurse to possibly find the match. */ - ret = maybe_fold_offset_to_array_ref (new_base, t, orig_type, + ret = maybe_fold_offset_to_array_ref (loc, new_base, t, orig_type, f == TYPE_FIELDS (record_type)); if (ret) return ret; - ret = maybe_fold_offset_to_component_ref (field_type, new_base, t, - orig_type, false); + ret = maybe_fold_offset_to_component_ref (loc, field_type, new_base, t, + orig_type); if (ret) return ret; } @@ -1870,97 +1946,90 @@ maybe_fold_offset_to_component_ref (tree record_type, tree base, tree offset, /* If we get here, we've got an aggregate field, and a possibly nonzero offset into them. Recurse and hope for a valid match. */ - if (base_is_ptr) - base = build1 (INDIRECT_REF, record_type, base); base = build3 (COMPONENT_REF, field_type, base, f, NULL_TREE); + SET_EXPR_LOCATION (base, loc); - t = maybe_fold_offset_to_array_ref (base, offset, orig_type, + t = maybe_fold_offset_to_array_ref (loc, base, offset, orig_type, f == TYPE_FIELDS (record_type)); if (t) return t; - return maybe_fold_offset_to_component_ref (field_type, base, offset, - orig_type, false); + return maybe_fold_offset_to_component_ref (loc, field_type, base, offset, + orig_type); } /* Attempt to express (ORIG_TYPE)BASE+OFFSET as BASE->field_of_orig_type - or BASE[index] or by combination of those. + or BASE[index] or by combination of those. + + LOC is the location of original expression. Before attempting the conversion strip off existing ADDR_EXPRs and handled component refs. */ tree -maybe_fold_offset_to_reference (tree base, tree offset, tree orig_type) +maybe_fold_offset_to_reference (location_t loc, tree base, tree offset, + tree orig_type) { tree ret; tree type; - bool base_is_ptr = true; STRIP_NOPS (base); - if (TREE_CODE (base) == ADDR_EXPR) - { - base_is_ptr = false; - - base = TREE_OPERAND (base, 0); + if (TREE_CODE (base) != ADDR_EXPR) + return NULL_TREE; - /* Handle case where existing COMPONENT_REF pick e.g. wrong field of union, - so it needs to be removed and new COMPONENT_REF constructed. - The wrong COMPONENT_REF are often constructed by folding the - (type *)&object within the expression (type *)&object+offset */ - if (handled_component_p (base)) + base = TREE_OPERAND (base, 0); + + /* Handle case where existing COMPONENT_REF pick e.g. wrong field of union, + so it needs to be removed and new COMPONENT_REF constructed. + The wrong COMPONENT_REF are often constructed by folding the + (type *)&object within the expression (type *)&object+offset */ + if (handled_component_p (base)) + { + HOST_WIDE_INT sub_offset, size, maxsize; + tree newbase; + newbase = get_ref_base_and_extent (base, &sub_offset, + &size, &maxsize); + gcc_assert (newbase); + if (size == maxsize + && size != -1 + && !(sub_offset & (BITS_PER_UNIT - 1))) { - HOST_WIDE_INT sub_offset, size, maxsize; - tree newbase; - newbase = get_ref_base_and_extent (base, &sub_offset, - &size, &maxsize); - gcc_assert (newbase); - if (size == maxsize - && size != -1 - && !(sub_offset & (BITS_PER_UNIT - 1))) - { - base = newbase; - if (sub_offset) - offset = int_const_binop (PLUS_EXPR, offset, - build_int_cst (TREE_TYPE (offset), - sub_offset / BITS_PER_UNIT), 1); - } + base = newbase; + if (sub_offset) + offset = int_const_binop (PLUS_EXPR, offset, + build_int_cst (TREE_TYPE (offset), + sub_offset / BITS_PER_UNIT), 1); } - if (useless_type_conversion_p (orig_type, TREE_TYPE (base)) - && integer_zerop (offset)) - return base; - type = TREE_TYPE (base); } - else - { - base_is_ptr = true; - if (!POINTER_TYPE_P (TREE_TYPE (base))) - return NULL_TREE; - type = TREE_TYPE (TREE_TYPE (base)); - } - ret = maybe_fold_offset_to_component_ref (type, base, offset, - orig_type, base_is_ptr); + if (useless_type_conversion_p (orig_type, TREE_TYPE (base)) + && integer_zerop (offset)) + return base; + type = TREE_TYPE (base); + + ret = maybe_fold_offset_to_component_ref (loc, type, base, offset, orig_type); if (!ret) - { - if (base_is_ptr) - base = build1 (INDIRECT_REF, type, base); - ret = maybe_fold_offset_to_array_ref (base, offset, orig_type, true); - } + ret = maybe_fold_offset_to_array_ref (loc, base, offset, orig_type, true); + return ret; } /* Attempt to express (ORIG_TYPE)&BASE+OFFSET as &BASE->field_of_orig_type or &BASE[index] or by combination of those. + LOC is the location of the original expression. + Before attempting the conversion strip off existing component refs. */ tree -maybe_fold_offset_to_address (tree addr, tree offset, tree orig_type) +maybe_fold_offset_to_address (location_t loc, tree addr, tree offset, + tree orig_type) { tree t; gcc_assert (POINTER_TYPE_P (TREE_TYPE (addr)) && POINTER_TYPE_P (orig_type)); - t = maybe_fold_offset_to_reference (addr, offset, TREE_TYPE (orig_type)); + t = maybe_fold_offset_to_reference (loc, addr, offset, + TREE_TYPE (orig_type)); if (t != NULL_TREE) { tree orig = addr; @@ -1997,7 +2066,7 @@ maybe_fold_offset_to_address (tree addr, tree offset, tree orig_type) ptr_type = build_pointer_type (TREE_TYPE (t)); if (!useless_type_conversion_p (orig_type, ptr_type)) return NULL_TREE; - return build_fold_addr_expr_with_type (t, ptr_type); + return build_fold_addr_expr_with_type_loc (loc, t, ptr_type); } return NULL_TREE; @@ -2011,6 +2080,7 @@ maybe_fold_stmt_indirect (tree expr, tree base, tree offset) { tree t; bool volatile_p = TREE_THIS_VOLATILE (expr); + location_t loc = EXPR_LOCATION (expr); /* We may well have constructed a double-nested PLUS_EXPR via multiple substitutions. Fold that down to one. Remove NON_LVALUE_EXPRs that @@ -2051,7 +2121,7 @@ maybe_fold_stmt_indirect (tree expr, tree base, tree offset) return DECL_INITIAL (base); /* Try folding *(&B+O) to B.X. */ - t = maybe_fold_offset_to_reference (base_addr, offset, + t = maybe_fold_offset_to_reference (loc, base_addr, offset, TREE_TYPE (expr)); if (t) { @@ -2090,7 +2160,7 @@ maybe_fold_stmt_indirect (tree expr, tree base, tree offset) /* Try folding *(B+O) to B->X. Still an improvement. */ if (POINTER_TYPE_P (TREE_TYPE (base))) { - t = maybe_fold_offset_to_reference (base, offset, + t = maybe_fold_offset_to_reference (loc, base, offset, TREE_TYPE (expr)); if (t) return t; @@ -2115,7 +2185,7 @@ maybe_fold_stmt_indirect (tree expr, tree base, tree offset) which may be able to propagate further. */ tree -maybe_fold_stmt_addition (tree res_type, tree op0, tree op1) +maybe_fold_stmt_addition (location_t loc, tree res_type, tree op0, tree op1) { tree ptd_type; tree t; @@ -2143,16 +2213,16 @@ maybe_fold_stmt_addition (tree res_type, tree op0, tree op1) && TREE_CODE (gimple_assign_rhs2 (offset_def)) == INTEGER_CST && tree_int_cst_equal (gimple_assign_rhs2 (offset_def), TYPE_SIZE_UNIT (TREE_TYPE (op0)))) - return build1 (ADDR_EXPR, res_type, - build4 (ARRAY_REF, TREE_TYPE (op0), + return build_fold_addr_expr + (build4 (ARRAY_REF, TREE_TYPE (op0), TREE_OPERAND (op0, 0), gimple_assign_rhs1 (offset_def), TREE_OPERAND (op0, 2), TREE_OPERAND (op0, 3))); else if (integer_onep (TYPE_SIZE_UNIT (TREE_TYPE (op0))) && gimple_assign_rhs_code (offset_def) != MULT_EXPR) - return build1 (ADDR_EXPR, res_type, - build4 (ARRAY_REF, TREE_TYPE (op0), + return build_fold_addr_expr + (build4 (ARRAY_REF, TREE_TYPE (op0), TREE_OPERAND (op0, 0), op1, TREE_OPERAND (op0, 2), @@ -2212,12 +2282,15 @@ maybe_fold_stmt_addition (tree res_type, tree op0, tree op1) ptd_type = TREE_TYPE (TREE_TYPE (op0)); /* At which point we can try some of the same things as for indirects. */ - t = maybe_fold_offset_to_array_ref (op0, op1, ptd_type, true); + t = maybe_fold_offset_to_array_ref (loc, op0, op1, ptd_type, true); if (!t) - t = maybe_fold_offset_to_component_ref (TREE_TYPE (op0), op0, op1, - ptd_type, false); + t = maybe_fold_offset_to_component_ref (loc, TREE_TYPE (op0), op0, op1, + ptd_type); if (t) - t = build1 (ADDR_EXPR, res_type, t); + { + t = build1 (ADDR_EXPR, res_type, t); + SET_EXPR_LOCATION (t, loc); + } return t; } @@ -2275,6 +2348,19 @@ maybe_fold_reference (tree expr, bool is_lhs) return expr; } } + else if (!is_lhs + && DECL_P (*t)) + { + tree tem = get_symbol_constant_value (*t); + if (tem) + { + *t = tem; + tem = maybe_fold_reference (expr, is_lhs); + if (tem) + return tem; + return expr; + } + } return NULL_TREE; } @@ -2413,6 +2499,7 @@ ccp_fold_builtin (gimple stmt) bitmap visited; bool ignore; int nargs; + location_t loc = gimple_location (stmt); gcc_assert (is_gimple_call (stmt)); @@ -2509,7 +2596,7 @@ ccp_fold_builtin (gimple stmt) case BUILT_IN_STRCPY: if (val[1] && is_gimple_val (val[1]) && nargs == 2) - result = fold_builtin_strcpy (callee, + result = fold_builtin_strcpy (loc, callee, gimple_call_arg (stmt, 0), gimple_call_arg (stmt, 1), val[1]); @@ -2517,7 +2604,7 @@ ccp_fold_builtin (gimple stmt) case BUILT_IN_STRNCPY: if (val[1] && is_gimple_val (val[1]) && nargs == 3) - result = fold_builtin_strncpy (callee, + result = fold_builtin_strncpy (loc, callee, gimple_call_arg (stmt, 0), gimple_call_arg (stmt, 1), gimple_call_arg (stmt, 2), @@ -2526,14 +2613,14 @@ ccp_fold_builtin (gimple stmt) case BUILT_IN_FPUTS: if (nargs == 2) - result = fold_builtin_fputs (gimple_call_arg (stmt, 0), + result = fold_builtin_fputs (loc, gimple_call_arg (stmt, 0), gimple_call_arg (stmt, 1), ignore, false, val[0]); break; case BUILT_IN_FPUTS_UNLOCKED: if (nargs == 2) - result = fold_builtin_fputs (gimple_call_arg (stmt, 0), + result = fold_builtin_fputs (loc, gimple_call_arg (stmt, 0), gimple_call_arg (stmt, 1), ignore, true, val[0]); break; @@ -2543,7 +2630,7 @@ ccp_fold_builtin (gimple stmt) case BUILT_IN_MEMMOVE_CHK: case BUILT_IN_MEMSET_CHK: if (val[2] && is_gimple_val (val[2]) && nargs == 4) - result = fold_builtin_memory_chk (callee, + result = fold_builtin_memory_chk (loc, callee, gimple_call_arg (stmt, 0), gimple_call_arg (stmt, 1), gimple_call_arg (stmt, 2), @@ -2555,7 +2642,7 @@ ccp_fold_builtin (gimple stmt) case BUILT_IN_STRCPY_CHK: case BUILT_IN_STPCPY_CHK: if (val[1] && is_gimple_val (val[1]) && nargs == 3) - result = fold_builtin_stxcpy_chk (callee, + result = fold_builtin_stxcpy_chk (loc, callee, gimple_call_arg (stmt, 0), gimple_call_arg (stmt, 1), gimple_call_arg (stmt, 2), @@ -2565,7 +2652,7 @@ ccp_fold_builtin (gimple stmt) case BUILT_IN_STRNCPY_CHK: if (val[2] && is_gimple_val (val[2]) && nargs == 4) - result = fold_builtin_strncpy_chk (gimple_call_arg (stmt, 0), + result = fold_builtin_strncpy_chk (loc, gimple_call_arg (stmt, 0), gimple_call_arg (stmt, 1), gimple_call_arg (stmt, 2), gimple_call_arg (stmt, 3), @@ -2598,6 +2685,7 @@ fold_gimple_assign (gimple_stmt_iterator *si) { gimple stmt = gsi_stmt (*si); enum tree_code subcode = gimple_assign_rhs_code (stmt); + location_t loc = gimple_location (stmt); tree result = NULL_TREE; @@ -2613,11 +2701,13 @@ fold_gimple_assign (gimple_stmt_iterator *si) tree op0 = COND_EXPR_COND (rhs); tree tem; bool set = false; + location_t cond_loc = EXPR_LOCATION (rhs); if (COMPARISON_CLASS_P (op0)) { fold_defer_overflow_warnings (); - tem = fold_binary (TREE_CODE (op0), TREE_TYPE (op0), + tem = fold_binary_loc (cond_loc, + TREE_CODE (op0), TREE_TYPE (op0), TREE_OPERAND (op0, 0), TREE_OPERAND (op0, 1)); /* This is actually a conditional expression, not a GIMPLE @@ -2636,7 +2726,7 @@ fold_gimple_assign (gimple_stmt_iterator *si) return NULL_TREE; if (set) - result = fold_build3 (COND_EXPR, TREE_TYPE (rhs), tem, + result = fold_build3_loc (cond_loc, COND_EXPR, TREE_TYPE (rhs), tem, COND_EXPR_THEN (rhs), COND_EXPR_ELSE (rhs)); } @@ -2651,9 +2741,31 @@ fold_gimple_assign (gimple_stmt_iterator *si) tree tem = maybe_fold_reference (TREE_OPERAND (rhs, 0), true); if (tem) result = fold_convert (TREE_TYPE (rhs), - build_fold_addr_expr (tem)); + build_fold_addr_expr_loc (loc, tem)); + } + + else if (TREE_CODE (rhs) == CONSTRUCTOR + && TREE_CODE (TREE_TYPE (rhs)) == VECTOR_TYPE + && (CONSTRUCTOR_NELTS (rhs) + == TYPE_VECTOR_SUBPARTS (TREE_TYPE (rhs)))) + { + /* Fold a constant vector CONSTRUCTOR to VECTOR_CST. */ + unsigned i; + tree val; + + FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (rhs), i, val) + if (TREE_CODE (val) != INTEGER_CST + && TREE_CODE (val) != REAL_CST + && TREE_CODE (val) != FIXED_CST) + return NULL_TREE; + + return build_vector_from_ctor (TREE_TYPE (rhs), + CONSTRUCTOR_ELTS (rhs)); } + else if (DECL_P (rhs)) + return get_symbol_constant_value (rhs); + /* If we couldn't fold the RHS, hand over to the generic fold routines. */ if (result == NULL_TREE) @@ -2675,7 +2787,7 @@ fold_gimple_assign (gimple_stmt_iterator *si) { tree rhs = gimple_assign_rhs1 (stmt); - result = fold_unary (subcode, gimple_expr_type (stmt), rhs); + result = fold_unary_loc (loc, subcode, gimple_expr_type (stmt), rhs); if (result) { /* If the operation was a conversion do _not_ mark a @@ -2697,7 +2809,8 @@ fold_gimple_assign (gimple_stmt_iterator *si) && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))) { tree type = gimple_expr_type (stmt); - tree t = maybe_fold_offset_to_address (gimple_assign_rhs1 (stmt), + tree t = maybe_fold_offset_to_address (loc, + gimple_assign_rhs1 (stmt), integer_zero_node, type); if (t) return t; @@ -2717,13 +2830,14 @@ fold_gimple_assign (gimple_stmt_iterator *si) (TREE_TYPE (gimple_assign_lhs (stmt)), type)) type = TREE_TYPE (gimple_assign_rhs1 (stmt)); } - result = maybe_fold_stmt_addition (type, + result = maybe_fold_stmt_addition (gimple_location (stmt), + type, gimple_assign_rhs1 (stmt), gimple_assign_rhs2 (stmt)); } if (!result) - result = fold_binary (subcode, + result = fold_binary_loc (loc, subcode, TREE_TYPE (gimple_assign_lhs (stmt)), gimple_assign_rhs1 (stmt), gimple_assign_rhs2 (stmt)); @@ -2762,7 +2876,8 @@ fold_gimple_assign (gimple_stmt_iterator *si) static bool fold_gimple_cond (gimple stmt) { - tree result = fold_binary (gimple_cond_code (stmt), + tree result = fold_binary_loc (gimple_location (stmt), + gimple_cond_code (stmt), boolean_type_node, gimple_cond_lhs (stmt), gimple_cond_rhs (stmt)); @@ -2780,6 +2895,7 @@ fold_gimple_cond (gimple stmt) return false; } +static void gimplify_and_update_call_from_tree (gimple_stmt_iterator *, tree); /* Attempt to fold a call statement referenced by the statement iterator GSI. The statement may be replaced by another statement, e.g., if the call @@ -2800,7 +2916,11 @@ fold_gimple_call (gimple_stmt_iterator *gsi) tree result = ccp_fold_builtin (stmt); if (result) - return update_call_from_tree (gsi, result); + { + if (!update_call_from_tree (gsi, result)) + gimplify_and_update_call_from_tree (gsi, result); + return true; + } } else { @@ -2974,9 +3094,8 @@ fold_stmt_inplace (gimple stmt) static tree optimize_stack_restore (gimple_stmt_iterator i) { - tree callee, rhs; - gimple stmt, stack_save; - gimple_stmt_iterator stack_save_gsi; + tree callee; + gimple stmt; basic_block bb = gsi_bb (i); gimple call = gsi_stmt (i); @@ -3000,32 +3119,49 @@ optimize_stack_restore (gimple_stmt_iterator i) return NULL_TREE; if (DECL_FUNCTION_CODE (callee) == BUILT_IN_STACK_RESTORE) - break; + goto second_stack_restore; } - if (gsi_end_p (i) - && (! single_succ_p (bb) - || single_succ_edge (bb)->dest != EXIT_BLOCK_PTR)) + if (!gsi_end_p (i)) return NULL_TREE; - stack_save = SSA_NAME_DEF_STMT (gimple_call_arg (call, 0)); - if (gimple_code (stack_save) != GIMPLE_CALL - || gimple_call_lhs (stack_save) != gimple_call_arg (call, 0) - || stmt_could_throw_p (stack_save) - || !has_single_use (gimple_call_arg (call, 0))) - return NULL_TREE; + /* Allow one successor of the exit block, or zero successors. */ + switch (EDGE_COUNT (bb->succs)) + { + case 0: + break; + case 1: + if (single_succ_edge (bb)->dest != EXIT_BLOCK_PTR) + return NULL_TREE; + break; + default: + return NULL_TREE; + } + second_stack_restore: - callee = gimple_call_fndecl (stack_save); - if (!callee - || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL - || DECL_FUNCTION_CODE (callee) != BUILT_IN_STACK_SAVE - || gimple_call_num_args (stack_save) != 0) - return NULL_TREE; + /* If there's exactly one use, then zap the call to __builtin_stack_save. + If there are multiple uses, then the last one should remove the call. + In any case, whether the call to __builtin_stack_save can be removed + or not is irrelevant to removing the call to __builtin_stack_restore. */ + if (has_single_use (gimple_call_arg (call, 0))) + { + gimple stack_save = SSA_NAME_DEF_STMT (gimple_call_arg (call, 0)); + if (is_gimple_call (stack_save)) + { + callee = gimple_call_fndecl (stack_save); + if (callee + && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL + && DECL_FUNCTION_CODE (callee) == BUILT_IN_STACK_SAVE) + { + gimple_stmt_iterator stack_save_gsi; + tree rhs; - stack_save_gsi = gsi_for_stmt (stack_save); - rhs = build_int_cst (TREE_TYPE (gimple_call_arg (call, 0)), 0); - if (!update_call_from_tree (&stack_save_gsi, rhs)) - return NULL_TREE; + stack_save_gsi = gsi_for_stmt (stack_save); + rhs = build_int_cst (TREE_TYPE (gimple_call_arg (call, 0)), 0); + update_call_from_tree (&stack_save_gsi, rhs); + } + } + } /* No effect, so the statement will be deleted. */ return integer_zero_node; @@ -3041,6 +3177,7 @@ optimize_stdarg_builtin (gimple call) { tree callee, lhs, rhs, cfun_va_list; bool va_list_simple_ptr; + location_t loc = gimple_location (call); if (gimple_code (call) != GIMPLE_CALL) return NULL_TREE; @@ -3069,10 +3206,10 @@ optimize_stdarg_builtin (gimple call) != TYPE_MAIN_VARIANT (cfun_va_list)) return NULL_TREE; - lhs = build_fold_indirect_ref (lhs); - rhs = build_call_expr (built_in_decls[BUILT_IN_NEXT_ARG], + lhs = build_fold_indirect_ref_loc (loc, lhs); + rhs = build_call_expr_loc (loc, built_in_decls[BUILT_IN_NEXT_ARG], 1, integer_zero_node); - rhs = fold_convert (TREE_TYPE (lhs), rhs); + rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs); return build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, rhs); case BUILT_IN_VA_COPY: @@ -3088,13 +3225,13 @@ optimize_stdarg_builtin (gimple call) != TYPE_MAIN_VARIANT (cfun_va_list)) return NULL_TREE; - lhs = build_fold_indirect_ref (lhs); + lhs = build_fold_indirect_ref_loc (loc, lhs); rhs = gimple_call_arg (call, 1); if (TYPE_MAIN_VARIANT (TREE_TYPE (rhs)) != TYPE_MAIN_VARIANT (cfun_va_list)) return NULL_TREE; - rhs = fold_convert (TREE_TYPE (lhs), rhs); + rhs = fold_convert_loc (loc, TREE_TYPE (lhs), rhs); return build2 (MODIFY_EXPR, TREE_TYPE (lhs), lhs, rhs); case BUILT_IN_VA_END: