From 1da68f560dd41ef12f15138fb1b1aff06067f4b7 Mon Sep 17 00:00:00 2001 From: Richard Kenner Date: Sat, 30 Dec 2000 13:10:51 +0000 Subject: [PATCH] alias.c (alias_sets_conflict_p): New function. * alias.c (alias_sets_conflict_p): New function. (mems_in_disjoint_alias_sets_p): Use it. (readonly_fields_p): Moved from expr.c; check for record type. (objects_must_conflict_p): New function. * calls.c (expand_call): Use assign_temp as much as possible, use readonly variant if assigned once, and don't set memory attributes. (emit_library_call_value_1, store_one_arg): Likewise. * integrate.c (expand_inline_function): Likewise. * stmt.c (expand_asm_operands, expand_return): Likewise. * expr.c (copy_blkmode_from_reg, store_constructor): Likewise. (store_field, save_noncopied_parts, expand_expr): Likewise. (expand_expr_unaligned): Likewise. (readonly_fields_p): Moved to alias.c. (safe_from_p): Rework handling of SAVE_EXPR. MEMs ony conflict if alias sets conflict; likewise for INDIRECT_REF. * function.c (struct temp_slot): Delete field ALIAS_SET; add TYPE. (assign_stack_for_temp): Use objects_must_confict_p. Set all memory attributes from type, if specified. (mark_temp_slot): Mark TYPE field. * tree.h (alias_sets_conflict_p, readonly_fields_p): New decls. (objects_must_conflict_p): Likewise. * stmt.c (expand_decl): Don't use assign_stack_temp in error case. (add_case_node): No need to copy nodes anymore. From-SVN: r38559 --- gcc/ChangeLog | 28 +++++- gcc/alias.c | 121 ++++++++++++++++++------ gcc/calls.c | 40 ++++---- gcc/expr.c | 241 +++++++++++++++++++++--------------------------- gcc/function.c | 51 +++++----- gcc/integrate.c | 7 +- gcc/stmt.c | 22 +++-- gcc/tree.h | 4 + 8 files changed, 284 insertions(+), 230 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 96db1e072f4..4256da7fab7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,9 +1,35 @@ +2000-12-30 Richard Kenner + + * alias.c (alias_sets_conflict_p): New function. + (mems_in_disjoint_alias_sets_p): Use it. + (readonly_fields_p): Moved from expr.c; check for record type. + (objects_must_conflict_p): New function. + * calls.c (expand_call): Use assign_temp as much as possible, use + readonly variant if assigned once, and don't set memory attributes. + (emit_library_call_value_1, store_one_arg): Likewise. + * integrate.c (expand_inline_function): Likewise. + * stmt.c (expand_asm_operands, expand_return): Likewise. + * expr.c (copy_blkmode_from_reg, store_constructor): Likewise. + (store_field, save_noncopied_parts, expand_expr): Likewise. + (expand_expr_unaligned): Likewise. + (readonly_fields_p): Moved to alias.c. + (safe_from_p): Rework handling of SAVE_EXPR. + MEMs ony conflict if alias sets conflict; likewise for INDIRECT_REF. + * function.c (struct temp_slot): Delete field ALIAS_SET; add TYPE. + (assign_stack_for_temp): Use objects_must_confict_p. + Set all memory attributes from type, if specified. + (mark_temp_slot): Mark TYPE field. + * tree.h (alias_sets_conflict_p, readonly_fields_p): New decls. + (objects_must_conflict_p): Likewise. + + * stmt.c (expand_decl): Don't use assign_stack_temp in error case. + (add_case_node): No need to copy nodes anymore. + 2000-12-30 Alexandre Oliva * config/sh/sh.c (split_branches): Don't dereference re-computed `beyond' before checking it's non-NULL. - 2000-12-29 Robert Lipe Remove COFF support from i?86-pc-sco3.2v5. diff --git a/gcc/alias.c b/gcc/alias.c index d11d1b389a3..41cf596cd41 100644 --- a/gcc/alias.c +++ b/gcc/alias.c @@ -211,8 +211,6 @@ mems_in_disjoint_alias_sets_p (mem1, mem2) rtx mem1; rtx mem2; { - alias_set_entry ase; - #ifdef ENABLE_CHECKING /* Perform a basic sanity check. Namely, that there are no alias sets if we're not using strict aliasing. This helps to catch bugs @@ -226,34 +224,7 @@ mems_in_disjoint_alias_sets_p (mem1, mem2) abort (); #endif - /* If have no alias set information for one of the MEMs, we have to assume - it can alias anything. */ - if (MEM_ALIAS_SET (mem1) == 0 || MEM_ALIAS_SET (mem2) == 0) - return 0; - - /* If the two alias sets are the same, they may alias. */ - if (MEM_ALIAS_SET (mem1) == MEM_ALIAS_SET (mem2)) - return 0; - - /* See if the first alias set is a subset of the second. */ - ase = get_alias_set_entry (MEM_ALIAS_SET (mem1)); - if (ase != 0 - && (ase->has_zero_child - || splay_tree_lookup (ase->children, - (splay_tree_key) MEM_ALIAS_SET (mem2)))) - return 0; - - /* Now do the same, but with the alias sets reversed. */ - ase = get_alias_set_entry (MEM_ALIAS_SET (mem2)); - if (ase != 0 - && (ase->has_zero_child - || splay_tree_lookup (ase->children, - (splay_tree_key) MEM_ALIAS_SET (mem1)))) - return 0; - - /* The two MEMs are in distinct alias sets, and neither one is the - child of the other. Therefore, they cannot alias. */ - return 1; + return ! alias_sets_conflict_p (MEM_ALIAS_SET (mem1), MEM_ALIAS_SET (mem2)); } /* Insert the NODE into the splay tree given by DATA. Used by @@ -268,6 +239,96 @@ insert_subset_children (node, data) return 0; } + +/* Return 1 if the two specified alias sets may conflict. */ + +int +alias_sets_conflict_p (set1, set2) + HOST_WIDE_INT set1, set2; +{ + alias_set_entry ase; + + /* If have no alias set information for one of the operands, we have + to assume it can alias anything. */ + if (set1 == 0 || set2 == 0 + /* If the two alias sets are the same, they may alias. */ + || set1 == set2) + return 1; + + /* See if the first alias set is a subset of the second. */ + ase = get_alias_set_entry (set1); + if (ase != 0 + && (ase->has_zero_child + || splay_tree_lookup (ase->children, + (splay_tree_key) set2))) + return 1; + + /* Now do the same, but with the alias sets reversed. */ + ase = get_alias_set_entry (set2); + if (ase != 0 + && (ase->has_zero_child + || splay_tree_lookup (ase->children, + (splay_tree_key) set1))) + return 1; + + /* The two alias sets are distinct and neither one is the + child of the other. Therefore, they cannot alias. */ + return 0; +} + +/* Return 1 if TYPE is a RECORD_TYPE, UNION_TYPE, or QUAL_UNION_TYPE and has + has any readonly fields. If any of the fields have types that + contain readonly fields, return true as well. */ + +int +readonly_fields_p (type) + tree type; +{ + tree field; + + if (TREE_CODE (type) != RECORD_TYPE && TREE_CODE (type) != UNION_TYPE + && TREE_CODE (type) != QUAL_UNION_TYPE) + return 0; + + for (field = TYPE_FIELDS (type); field != 0; field = TREE_CHAIN (field)) + if (TREE_CODE (field) == FIELD_DECL + && (TREE_READONLY (field) + || readonly_fields_p (TREE_TYPE (field)))) + return 1; + + return 0; +} + +/* Return 1 if any MEM object of type T1 will always conflict (using the + dependency routines in this file) with any MEM object of type T2. + This is used when allocating temporary storage. If T1 and/or T2 are + NULL_TREE, it means we know nothing about the storage. */ + +int +objects_must_conflict_p (t1, t2) + tree t1, t2; +{ + /* If they are the same type, they must conflict. */ + if (t1 == t2 + /* Likewise if both are volatile. */ + || (t1 != 0 && TYPE_VOLATILE (t1) && t2 != 0 && TYPE_VOLATILE (t2))) + return 1; + + /* We now know they are different types. If one or both has readonly fields + or if one is readonly and the other not, they may not conflict. + Likewise if one is aggregate and the other is scalar. */ + if ((t1 != 0 && readonly_fields_p (t1)) + || (t2 != 0 && readonly_fields_p (t2)) + || ((t1 != 0 && TYPE_READONLY (t1)) + != (t2 != 0 && TYPE_READONLY (t2))) + || ((t1 != 0 && AGGREGATE_TYPE_P (t1)) + != (t2 != 0 && AGGREGATE_TYPE_P (t2)))) + return 0; + + /* Otherwise they conflict only if the alias sets conflict. */ + return alias_sets_conflict_p (t1 ? get_alias_set (t1) : 0, + t2 ? get_alias_set (t2) : 0); +} /* T is an expression with pointer type. Find the DECL on which this expression is based. (For example, in `a[i]' this would be `a'.) diff --git a/gcc/calls.c b/gcc/calls.c index 0f031ac6ec9..89706bcc6bf 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -2260,16 +2260,11 @@ expand_call (exp, target, ignore) structure_value_addr = XEXP (target, 0); else { - rtx d; - /* For variable-sized objects, we must be called with a target specified. If we were to allocate space on the stack here, we would have no way of knowing when to free it. */ + rtx d = assign_temp (TREE_TYPE (exp), 1, 1, 1); - if (struct_value_size < 0) - abort (); - - d = assign_temp (TREE_TYPE (exp), 1, 1, 1); mark_temp_addr_taken (d); structure_value_addr = XEXP (d, 0); target = 0; @@ -3230,18 +3225,20 @@ expand_call (exp, target, ignore) The Irix 6 ABI has examples of this. */ else if (GET_CODE (valreg) == PARALLEL) { - int bytes = int_size_in_bytes (TREE_TYPE (exp)); - if (target == 0) { - target = assign_stack_temp (TYPE_MODE (TREE_TYPE (exp)), - bytes, 0); - MEM_SET_IN_STRUCT_P (target, AGGREGATE_TYPE_P (TREE_TYPE (exp))); + /* This will only be assigned once, so it can be readonly. */ + tree nt = build_qualified_type (TREE_TYPE (exp), + (TYPE_QUALS (TREE_TYPE (exp)) + | TYPE_QUAL_CONST)); + + target = assign_temp (nt, 0, 1, 1); preserve_temp_slots (target); } if (! rtx_equal_p (target, valreg)) - emit_group_store (target, valreg, bytes, + emit_group_store (target, valreg, + int_size_in_bytes (TREE_TYPE (exp)), TYPE_ALIGN (TREE_TYPE (exp))); /* We can not support sibling calls for this case. */ @@ -3562,7 +3559,7 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) if (value != 0 && GET_CODE (value) == MEM) mem_value = value; else - mem_value = assign_stack_temp (outmode, GET_MODE_SIZE (outmode), 0); + mem_value = assign_temp (type_for_mode (outmode, 0), 0, 1, 1); #endif /* This call returns a big structure. */ @@ -3666,7 +3663,8 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) { /* We do not support FUNCTION_ARG_CALLEE_COPIES here since it can be viewed as just an efficiency improvement. */ - rtx slot = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0); + rtx slot = assign_temp (type_for_mode (mode, 0), 0, 1, 1); + call_fusage = gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_USE (VOIDmode, slot), call_fusage); @@ -4339,15 +4337,15 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) if (save_mode == BLKmode) { - arg->save_area = assign_stack_temp (BLKmode, - arg->size.constant, 0); - MEM_SET_IN_STRUCT_P (arg->save_area, - AGGREGATE_TYPE_P (TREE_TYPE - (arg->tree_value))); + tree ot = TREE_TYPE (arg->tree_value); + tree nt = build_qualified_type (ot, (TYPE_QUALS (ot) + | TYPE_QUAL_CONST)); + + arg->save_area = assign_temp (nt, 0, 1, 1); preserve_temp_slots (arg->save_area); emit_block_move (validize_mem (arg->save_area), stack_area, - GEN_INT (arg->size.constant), - PARM_BOUNDARY); + expr_size (arg->tree_value), + MIN (PARM_BOUNDARY, TYPE_ALIGN (nt))); } else { diff --git a/gcc/expr.c b/gcc/expr.c index fbe5fe513c1..c4160d99d97 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -181,7 +181,6 @@ static tree save_noncopied_parts PARAMS ((tree, tree)); static tree init_noncopied_parts PARAMS ((tree, tree)); static int fixed_type_p PARAMS ((tree)); static rtx var_rtx PARAMS ((tree)); -static int readonly_fields_p PARAMS ((tree)); static rtx expand_expr_unaligned PARAMS ((tree, unsigned int *)); static rtx expand_increment PARAMS ((tree, int, int)); static void do_jump_by_parts_greater PARAMS ((tree, int, rtx, rtx)); @@ -2145,8 +2144,10 @@ copy_blkmode_from_reg (tgtblk, srcreg, type) if (tgtblk == 0) { - tgtblk = assign_stack_temp (BLKmode, bytes, 0); - MEM_SET_IN_STRUCT_P (tgtblk, AGGREGATE_TYPE_P (type)); + tgtblk = assign_temp (build_qualified_type (type, + (TYPE_QUALS (type) + | TYPE_QUAL_CONST)), + 0, 1, 1); preserve_temp_slots (tgtblk); } @@ -2822,17 +2823,17 @@ emit_move_insn_1 (x, y) enum mode_class reg_class = ((class == MODE_COMPLEX_FLOAT) ? MODE_FLOAT : MODE_INT); - enum machine_mode reg_mode = - mode_for_size (GET_MODE_BITSIZE (mode), reg_class, 1); + enum machine_mode reg_mode + = mode_for_size (GET_MODE_BITSIZE (mode), reg_class, 1); if (reg_mode != BLKmode) { rtx mem = assign_stack_temp (reg_mode, GET_MODE_SIZE (mode), 0); - rtx cmem = change_address (mem, mode, NULL_RTX); - cfun->cannot_inline = N_("function using short complex types cannot be inline"); + cfun->cannot_inline + = N_("function using short complex types cannot be inline"); if (packed_dest_p) { @@ -4921,9 +4922,11 @@ store_constructor (exp, target, align, cleared, size) if (REG_P (target)) { - targetx = assign_stack_temp (GET_MODE (target), - GET_MODE_SIZE (GET_MODE (target)), - 0); + targetx + = assign_temp + ((build_qualified_type (type_for_mode (GET_MODE (target), 0), + TYPE_QUAL_CONST)), + 0, 1, 1); emit_move_insn (targetx, target); } @@ -5022,12 +5025,13 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode, if (mode == BLKmode && (GET_CODE (target) == REG || GET_CODE (target) == SUBREG)) { - rtx object = assign_stack_temp (GET_MODE (target), - GET_MODE_SIZE (GET_MODE (target)), 0); + rtx object + = assign_temp + (build_qualified_type (type_for_mode (GET_MODE (target), 0), + TYPE_QUAL_CONST), + 0, 1, 1); rtx blk_object = copy_rtx (object); - MEM_SET_IN_STRUCT_P (object, 1); - MEM_SET_IN_STRUCT_P (blk_object, 1); PUT_MODE (blk_object, BLKmode); if (bitsize != GET_MODE_BITSIZE (GET_MODE (target))) @@ -5506,7 +5510,12 @@ save_noncopied_parts (lhs, list) tree part = TREE_VALUE (tail); tree part_type = TREE_TYPE (part); tree to_be_saved = build (COMPONENT_REF, part_type, lhs, part); - rtx target = assign_temp (part_type, 0, 1, 1); + rtx target + = assign_temp (build_qualified_type (part_type, + (TYPE_QUALS (part_type) + | TYPE_QUAL_CONST)), + 0, 1, 1); + if (! memory_address_p (TYPE_MODE (part_type), XEXP (target, 0))) target = change_address (target, TYPE_MODE (part_type), NULL_RTX); parts = tree_cons (to_be_saved, @@ -5559,10 +5568,7 @@ safe_from_p (x, exp, top_p) { rtx exp_rtl = 0; int i, nops; - static int save_expr_count; - static int save_expr_size = 0; - static tree *save_expr_rewritten; - static tree save_expr_trees[256]; + static tree save_expr_list; if (x == 0 /* If EXP has varying size, we MUST use a target since we currently @@ -5577,31 +5583,14 @@ safe_from_p (x, exp, top_p) || TYPE_ARRAY_MAX_SIZE (TREE_TYPE (exp)) == NULL_TREE || TREE_CODE (TYPE_ARRAY_MAX_SIZE (TREE_TYPE (exp))) != INTEGER_CST) - && GET_MODE (x) == BLKmode)) + && GET_MODE (x) == BLKmode) + /* If X is in the outgoing argument area, it is always safe. */ + || (GET_CODE (x) == MEM + && (XEXP (x, 0) == virtual_outgoing_args_rtx + || (GET_CODE (XEXP (x, 0)) == PLUS + && XEXP (XEXP (x, 0), 0) == virtual_outgoing_args_rtx)))) return 1; - if (top_p && save_expr_size == 0) - { - int rtn; - - save_expr_count = 0; - save_expr_size = ARRAY_SIZE (save_expr_trees); - save_expr_rewritten = &save_expr_trees[0]; - - rtn = safe_from_p (x, exp, 1); - - for (i = 0; i < save_expr_count; ++i) - { - if (TREE_CODE (save_expr_trees[i]) != ERROR_MARK) - abort (); - TREE_SET_CODE (save_expr_trees[i], SAVE_EXPR); - } - - save_expr_size = 0; - - return rtn; - } - /* If this is a subreg of a hard register, declare it unsafe, otherwise, find the underlying pseudo. */ if (GET_CODE (x) == SUBREG) @@ -5611,13 +5600,31 @@ safe_from_p (x, exp, top_p) return 0; } - /* If X is a location in the outgoing argument area, it is always safe. */ - if (GET_CODE (x) == MEM - && (XEXP (x, 0) == virtual_outgoing_args_rtx - || (GET_CODE (XEXP (x, 0)) == PLUS - && XEXP (XEXP (x, 0), 0) == virtual_outgoing_args_rtx))) - return 1; + /* A SAVE_EXPR might appear many times in the expression passed to the + top-level safe_from_p call, and if it has a complex subexpression, + examining it multiple times could result in a combinatorial explosion. + E.g. on an Alpha running at least 200MHz, a Fortran test case compiled + with optimization took about 28 minutes to compile -- even though it was + only a few lines long. So we mark each SAVE_EXPR we see with TREE_PRIVATE + and turn that off when we are done. We keep a list of the SAVE_EXPRs + we have processed. Note that the only test of top_p was above. */ + if (top_p) + { + int rtn; + tree t; + + save_expr_list = 0; + + rtn = safe_from_p (x, exp, 0); + + for (t = save_expr_list; t != 0; t = TREE_CHAIN (t)) + TREE_PRIVATE (TREE_PURPOSE (t)) = 0; + + return rtn; + } + + /* Now look at our tree code and possibly recurse. */ switch (TREE_CODE_CLASS (TREE_CODE (exp))) { case 'd': @@ -5657,11 +5664,13 @@ safe_from_p (x, exp, top_p) { case ADDR_EXPR: return (staticp (TREE_OPERAND (exp, 0)) - || safe_from_p (x, TREE_OPERAND (exp, 0), 0) - || TREE_STATIC (exp)); + || TREE_STATIC (exp) + || safe_from_p (x, TREE_OPERAND (exp, 0), 0)); case INDIRECT_REF: - if (GET_CODE (x) == MEM) + if (GET_CODE (x) == MEM + && alias_sets_conflict_p (MEM_ALIAS_SET (x), + get_alias_set (exp))) return 0; break; @@ -5695,37 +5704,20 @@ safe_from_p (x, exp, top_p) if (exp_rtl) break; - /* This SAVE_EXPR might appear many times in the top-level - safe_from_p() expression, and if it has a complex - subexpression, examining it multiple times could result - in a combinatorial explosion. E.g. on an Alpha - running at least 200MHz, a Fortran test case compiled with - optimization took about 28 minutes to compile -- even though - it was only a few lines long, and the complicated line causing - so much time to be spent in the earlier version of safe_from_p() - had only 293 or so unique nodes. + /* If we've already scanned this, don't do it again. Otherwise, + show we've scanned it and record for clearing the flag if we're + going on. */ + if (TREE_PRIVATE (exp)) + return 1; - So, turn this SAVE_EXPR into an ERROR_MARK for now, but remember - where it is so we can turn it back in the top-level safe_from_p() - when we're done. */ - - /* For now, don't bother re-sizing the array. */ - if (save_expr_count >= save_expr_size) - return 0; - save_expr_rewritten[save_expr_count++] = exp; - - nops = TREE_CODE_LENGTH (SAVE_EXPR); - for (i = 0; i < nops; i++) + TREE_PRIVATE (exp) = 1; + if (! safe_from_p (x, TREE_OPERAND (exp, 0), 0)) { - tree operand = TREE_OPERAND (exp, i); - if (operand == NULL_TREE) - continue; - TREE_SET_CODE (exp, ERROR_MARK); - if (!safe_from_p (x, operand, 0)) - return 0; - TREE_SET_CODE (exp, SAVE_EXPR); + TREE_PRIVATE (exp) = 0; + return 0; } - TREE_SET_CODE (exp, ERROR_MARK); + + save_expr_list = tree_cons (exp, NULL_TREE, save_expr_list); return 1; case BIND_EXPR: @@ -5772,10 +5764,11 @@ safe_from_p (x, exp, top_p) } /* If the rtl is X, then it is not safe. Otherwise, it is unless both - are memory and EXP is not readonly. */ + are memory and they conflict. */ return ! (rtx_equal_p (x, exp_rtl) || (GET_CODE (x) == MEM && GET_CODE (exp_rtl) == MEM - && ! TREE_READONLY (exp))); + && true_dependence (exp_rtl, GET_MODE (x), x, + rtx_addr_varies_p))); } /* If we reach here, it is safe. */ @@ -5870,26 +5863,6 @@ check_max_integer_computation_mode (exp) } #endif -/* Utility function used by expand_expr to see if TYPE, a RECORD_TYPE, - has any readonly fields. If any of the fields have types that - contain readonly fields, return true as well. */ - -static int -readonly_fields_p (type) - tree type; -{ - tree field; - - for (field = TYPE_FIELDS (type); field != 0; field = TREE_CHAIN (field)) - if (TREE_CODE (field) == FIELD_DECL - && (TREE_READONLY (field) - || (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE - && readonly_fields_p (TREE_TYPE (field))))) - return 1; - - return 0; -} - /* expand_expr: generate code for computing expression EXP. An rtx for the computed value is returned. The value is never null. In the case of a void EXP, const0_rtx is returned. @@ -6350,11 +6323,10 @@ expand_expr (exp, target, tmode, modifier) if (mode == VOIDmode) temp = const0_rtx; else - { - temp = assign_temp (type, 3, 0, 0); - if (GET_CODE (temp) == MEM) - RTX_UNCHANGING_P (temp) = 1; - } + temp = assign_temp (build_qualified_type (type, + (TYPE_QUALS (type) + | TYPE_QUAL_CONST)), + 3, 0, 0); SAVE_EXPR_RTL (exp) = temp; if (!optimize && GET_CODE (temp) == REG) @@ -6606,27 +6578,18 @@ expand_expr (exp, target, tmode, modifier) XEXP (constructor, 0)); return constructor; } - else { /* Handle calls that pass values in multiple non-contiguous locations. The Irix 6 ABI has examples of this. */ if (target == 0 || ! safe_from_p (target, exp, 1) || GET_CODE (target) == PARALLEL) - { - if (mode != BLKmode && ! TREE_ADDRESSABLE (exp)) - target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode); - else - target = assign_temp (type, 0, 1, 1); - } - - if (TREE_READONLY (exp)) - { - if (GET_CODE (target) == MEM) - target = copy_rtx (target); - - RTX_UNCHANGING_P (target) = 1; - } + target + = assign_temp (build_qualified_type (type, + (TYPE_QUALS (type) + | (TREE_READONLY (exp) + * TYPE_QUAL_CONST))), + TREE_ADDRESSABLE (exp), 1, 1); store_constructor (exp, target, TYPE_ALIGN (TREE_TYPE (exp)), 0, int_size_in_bytes (TREE_TYPE (exp))); @@ -6685,8 +6648,7 @@ expand_expr (exp, target, tmode, modifier) /* If we are writing to this object and its type is a record with readonly fields, we must mark it as readonly so it will conflict with readonly references to those fields. */ - if (modifier == EXPAND_MEMORY_USE_WO - && TREE_CODE (type) == RECORD_TYPE && readonly_fields_p (type)) + if (modifier == EXPAND_MEMORY_USE_WO && readonly_fields_p (type)) RTX_UNCHANGING_P (temp) = 1; return temp; @@ -6902,7 +6864,10 @@ expand_expr (exp, target, tmode, modifier) if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG || GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF) { - rtx memloc = assign_temp (TREE_TYPE (tem), 1, 1, 1); + tree nt = build_qualified_type (TREE_TYPE (tem), + (TYPE_QUALS (TREE_TYPE (tem)) + | TYPE_QUAL_CONST)); + rtx memloc = assign_temp (nt, 1, 1, 1); mark_temp_addr_taken (memloc); emit_move_insn (memloc, op0); @@ -7077,13 +7042,13 @@ expand_expr (exp, target, tmode, modifier) if (mode == BLKmode) { - rtx new = assign_stack_temp (ext_mode, - bitsize / BITS_PER_UNIT, 0); + tree nt = build_qualified_type (type_for_size (ext_mode, 0), + TYPE_QUAL_CONST); + rtx new = assign_temp (nt, 0, 1, 1); emit_move_insn (new, op0); op0 = copy_rtx (new); PUT_MODE (op0, BLKmode); - MEM_SET_IN_STRUCT_P (op0, 1); } return op0; @@ -7303,12 +7268,7 @@ expand_expr (exp, target, tmode, modifier) modifier); if (target == 0) - { - if (mode != BLKmode) - target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode); - else - target = assign_temp (type, 0, 1, 1); - } + target = assign_temp (type, 0, 1, 1); if (GET_CODE (target) == MEM) /* Store data into beginning of memory target. */ @@ -8514,7 +8474,10 @@ expand_expr (exp, target, tmode, modifier) /* If this object is in a register, it must be not be BLKmode. */ tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0)); - rtx memloc = assign_temp (inner_type, 1, 1, 1); + tree nt = build_qualified_type (inner_type, + (TYPE_QUALS (inner_type) + | TYPE_QUAL_CONST)); + rtx memloc = assign_temp (nt, 1, 1, 1); mark_temp_addr_taken (memloc); if (GET_CODE (op0) == PARALLEL) @@ -8914,7 +8877,10 @@ expand_expr_unaligned (exp, palign) if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG || GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF) { - rtx memloc = assign_temp (TREE_TYPE (tem), 1, 1, 1); + tree nt = build_qualified_type (TREE_TYPE (tem), + (TYPE_QUALS (TREE_TYPE (tem)) + | TYPE_QUAL_CONST)); + rtx memloc = assign_temp (nt, 1, 1, 1); mark_temp_addr_taken (memloc); emit_move_insn (memloc, op0); @@ -8996,8 +8962,9 @@ expand_expr_unaligned (exp, palign) } else { - rtx new = assign_stack_temp (ext_mode, - bitsize / BITS_PER_UNIT, 0); + tree nt = build_qualified_type (type_for_mode (ext_mode, 0), + TYPE_QUAL_CONST); + rtx new = assign_temp (nt, 0, 1, 1); op0 = extract_bit_field (validize_mem (op0), bitsize, bitpos, unsignedp, NULL_RTX, ext_mode, diff --git a/gcc/function.c b/gcc/function.c index 278c432c38c..586ef7ea92e 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -193,17 +193,11 @@ struct temp_slot int align; /* The size, in units, of the slot. */ HOST_WIDE_INT size; - /* The alias set for the slot. If the alias set is zero, we don't - know anything about the alias set of the slot. We must only - reuse a slot if it is assigned an object of the same alias set. - Otherwise, the rest of the compiler may assume that the new use - of the slot cannot alias the old use of the slot, which is - false. If the slot has alias set zero, then we can't reuse the - slot at all, since we have no idea what alias set may have been - imposed on the memory. For example, if the stack slot is the - call frame for an inline functioned, we have no idea what alias - sets will be assigned to various pieces of the call frame. */ - HOST_WIDE_INT alias_set; + /* The type of the object in the slot, or zero if it doesn't correspond + to a type. We use this to determine whether a slot can be reused. + It can be reused if objects of the type of the new slot will always + conflict with objects of the type of the old slot. */ + tree type; /* The value of `sequence_rtl_expr' when this temporary is allocated. */ tree rtl_expr; /* Non-zero if this temporary is currently in use. */ @@ -658,7 +652,6 @@ assign_stack_temp_for_type (mode, size, keep, type) tree type; { int align; - HOST_WIDE_INT alias_set; struct temp_slot *p, *best_p = 0; /* If SIZE is -1 it means that somebody tried to allocate a temporary @@ -666,14 +659,6 @@ assign_stack_temp_for_type (mode, size, keep, type) if (size == -1) abort (); - /* If we know the alias set for the memory that will be used, use - it. If there's no TYPE, then we don't know anything about the - alias set for the memory. */ - if (type) - alias_set = get_alias_set (type); - else - alias_set = 0; - if (mode == BLKmode) align = BIGGEST_ALIGNMENT; else @@ -691,8 +676,7 @@ assign_stack_temp_for_type (mode, size, keep, type) for (p = temp_slots; p; p = p->next) if (p->align >= align && p->size >= size && GET_MODE (p->slot) == mode && ! p->in_use - && (! flag_strict_aliasing - || (alias_set && p->alias_set == alias_set)) + && objects_must_conflict_p (p->type, type) && (best_p == 0 || best_p->size > p->size || (best_p->size == p->size && best_p->align > p->align))) { @@ -728,7 +712,7 @@ assign_stack_temp_for_type (mode, size, keep, type) p->align = best_p->align; p->address = 0; p->rtl_expr = 0; - p->alias_set = best_p->alias_set; + p->type = best_p->type; p->next = temp_slots; temp_slots = p; @@ -766,7 +750,6 @@ assign_stack_temp_for_type (mode, size, keep, type) align); p->align = align; - p->alias_set = alias_set; /* The following slot size computation is necessary because we don't know the actual size of the temporary slot until assign_stack_local @@ -797,6 +780,7 @@ assign_stack_temp_for_type (mode, size, keep, type) p->in_use = 1; p->addr_taken = 0; p->rtl_expr = seq_rtl_expr; + p->type = type; if (keep == 2) { @@ -819,10 +803,23 @@ assign_stack_temp_for_type (mode, size, keep, type) RTX_UNCHANGING_P (p->slot) = 0; MEM_IN_STRUCT_P (p->slot) = 0; MEM_SCALAR_P (p->slot) = 0; - MEM_ALIAS_SET (p->slot) = alias_set; + MEM_VOLATILE_P (p->slot) = 0; + /* If we know the alias set for the memory that will be used, use + it. If there's no TYPE, then we don't know anything about the + alias set for the memory. */ + if (type) + MEM_ALIAS_SET (p->slot) = get_alias_set (type); + else + MEM_ALIAS_SET (p->slot) = 0; + + /* If a type is specified, set the relevant flags. */ if (type != 0) - MEM_SET_IN_STRUCT_P (p->slot, AGGREGATE_TYPE_P (type)); + { + RTX_UNCHANGING_P (p->slot) = TYPE_READONLY (type); + MEM_VOLATILE_P (p->slot) = TYPE_VOLATILE (type); + MEM_SET_IN_STRUCT_P (p->slot, AGGREGATE_TYPE_P (type)); + } return p->slot; } @@ -1509,6 +1506,7 @@ put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p, /* Make sure that all refs to the variable, previously made when it was a register, are fixed up to be valid again. See function above for meaning of arguments. */ + static void schedule_fixup_var_refs (function, reg, type, promoted_mode, ht) struct function *function; @@ -7453,6 +7451,7 @@ mark_temp_slot (t) ggc_mark_rtx (t->slot); ggc_mark_rtx (t->address); ggc_mark_tree (t->rtl_expr); + ggc_mark_tree (t->type); t = t->next; } diff --git a/gcc/integrate.c b/gcc/integrate.c index 0db4840503a..30e13408ec0 100644 --- a/gcc/integrate.c +++ b/gcc/integrate.c @@ -716,14 +716,9 @@ expand_inline_function (fndecl, parms, target, ignore, type, if (GET_CODE (loc) == MEM && GET_CODE (XEXP (loc, 0)) == REG && REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER) { - rtx stack_slot - = assign_stack_temp (TYPE_MODE (TREE_TYPE (arg)), - int_size_in_bytes (TREE_TYPE (arg)), 1); - MEM_SET_IN_STRUCT_P (stack_slot, - AGGREGATE_TYPE_P (TREE_TYPE (arg))); + rtx stack_slot = assign_temp (TREE_TYPE (arg), 1, 1, 1); store_expr (arg, stack_slot, 0); - arg_vals[i] = XEXP (stack_slot, 0); invisiref = 1; } diff --git a/gcc/stmt.c b/gcc/stmt.c index 7489613fa40..450b0da7c1a 100644 --- a/gcc/stmt.c +++ b/gcc/stmt.c @@ -1757,7 +1757,10 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line) || GET_CODE (op) == CONCAT) { tree type = TREE_TYPE (TREE_VALUE (tail)); - rtx memloc = assign_temp (type, 1, 1, 1); + tree qual_type = build_qualified_type (type, + (TYPE_QUALS (type) + | TYPE_QUAL_CONST)); + rtx memloc = assign_temp (qual_type, 1, 1, 1); emit_move_insn (memloc, op); op = memloc; @@ -3100,8 +3103,10 @@ expand_return (retval) { /* Calculate the return value into a temporary (usually a pseudo reg). */ - val = assign_temp (TREE_TYPE (DECL_RESULT (current_function_decl)), - 0, 0, 1); + tree ot = TREE_TYPE (DECL_RESULT (current_function_decl)); + tree nt = build_qualified_type (ot, TYPE_QUALS (ot) | TYPE_QUAL_CONST); + + val = assign_temp (nt, 0, 0, 1); val = expand_expr (retval_rhs, val, GET_MODE (val), 0); val = force_not_mem (val); emit_queue (); @@ -3822,12 +3827,13 @@ expand_decl (decl) if (type == error_mark_node) DECL_RTL (decl) = gen_rtx_MEM (BLKmode, const0_rtx); + else if (DECL_SIZE (decl) == 0) /* Variable with incomplete type. */ { if (DECL_INITIAL (decl) == 0) /* Error message was already done; now avoid a crash. */ - DECL_RTL (decl) = assign_stack_temp (DECL_MODE (decl), 0, 1); + DECL_RTL (decl) = gen_rtx_MEM (BLKmode, const0_rtx); else /* An initializer is going to decide the size of this array. Until we know the size, represent its address with a reg. */ @@ -4735,18 +4741,16 @@ add_case_node (low, high, label, duplicate) } } - /* Add this label to the chain, and succeed. - Copy LOW, HIGH so they are on temporary rather than momentary - obstack and will thus survive till the end of the case statement. */ + /* Add this label to the chain, and succeed. */ r = (struct case_node *) xmalloc (sizeof (struct case_node)); - r->low = copy_node (low); + r->low = low; /* If the bounds are equal, turn this into the one-value case. */ if (tree_int_cst_equal (low, high)) r->high = r->low; else - r->high = copy_node (high); + r->high = high; r->code_label = label; expand_label (label); diff --git a/gcc/tree.h b/gcc/tree.h index 822ecf3d88b..33e921207e1 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -2623,6 +2623,10 @@ extern void rest_of_type_compilation PARAMS ((tree, int)); /* In alias.c */ extern void record_component_aliases PARAMS ((tree)); extern HOST_WIDE_INT get_alias_set PARAMS ((tree)); +extern int alias_sets_conflict_p PARAMS ((HOST_WIDE_INT, + HOST_WIDE_INT)); +extern int readonly_fields_p PARAMS ((tree)); +extern int objects_must_conflict_p PARAMS ((tree, tree)); /* In c-common.c */ extern HOST_WIDE_INT lang_get_alias_set PARAMS ((tree));