diff -upd -r gcc-clean/gcc/alias.c gcc/gcc/alias.c --- gcc-clean/gcc/alias.c 2006-03-10 01:34:10.000000000 +0300 +++ gcc/gcc/alias.c 2006-03-15 12:32:39.000000000 +0300 @@ -44,6 +44,9 @@ Software Foundation, 51 Franklin Street, #include "target.h" #include "cgraph.h" #include "varray.h" +#include "hashtab.h" +#include "tree-flow.h" +#include "diagnostic.h" #include "tree-pass.h" #include "ipa-type-escape.h" @@ -248,6 +251,529 @@ static bool *reg_known_equiv_p; NOTE_INSN_FUNCTION_BEG note. */ static bool copying_arguments; +/* Tree-SSA aliasing Export. */ + +/* Returns points-to entry for EXPR. + The result is filtered using WEAK_DEPS value: + if WEAK_DEPS == false, only entries with pt_anything == false are returned; + otherwise every entry found is returned. */ + +pts_entry_ptr +tse_get_pts_for_expr (tree expr, bool weak_deps) +{ + pts_entry_ptr entry; + var_ann_t ann; + ann = var_ann (expr); + + if (ann == NULL) + return NULL; + if (ann->alias_info == NULL) + return NULL; + + entry = ann->alias_info->points_to; + + if (entry) + { + /* If looking for weak dependency, return the entry found inspite of + pt_anything attribute set. */ + if (weak_deps || !entry->pt_anything) + return entry; + else + return NULL; + } + else + return NULL; +} + +/* Returns MEM_ORIG_EXPR corresponding to MEM. */ + +tree +tse_mem_expr (rtx mem) +{ + if (MEM_ORIG_EXPR (mem)) + return MEM_ORIG_EXPR (mem); + else + return MEM_EXPR (mem); +} + +/* Checks whether VAR is in points-to set TENTRY. */ + +bool +tse_var_in_pts_p (tree var, pts_entry_ptr tentry) +{ + return bitmap_bit_p (tentry->may_aliases, DECL_UID (var)); +} + +/* Adds VAR in points-to set ENTRY. */ + +void +tse_add_tree_to_pts(tree var, pts_entry_ptr entry) +{ + bitmap_set_bit (entry->may_aliases, DECL_UID (var)); +} + +static bool ref_has_nested_op0 (tree ref); + +/* Checks whether two points-to sets overlap. */ + +static bool +tse_pts_overlap_p (pts_entry_ptr tentry1, pts_entry_ptr tentry2) +{ + gcc_assert (tentry1 && tentry2); + + return bitmap_intersect_p (tentry1->may_aliases, tentry2->may_aliases); +} + + +/* Returns true if two mems MEM_EXPR1 and MEM_EXPR2, addressed by REG_EXPR1 and + REG_EXPR2 may alias. WEAK_DEPS affects the result, see comment for + tse_get_pts_for_expr(). */ + +static bool +tse_alias_sets_overlap_p (tree reg_expr1, tree reg_expr2, + bool weak_deps) +{ + pts_entry_ptr entry1, entry2; + + entry1 = tse_get_pts_for_expr (reg_expr1, weak_deps); + entry2 = tse_get_pts_for_expr (reg_expr2, weak_deps); + + /* If there's no entry for expression, then it originally had empty + points-to set. Assume pt_anything in this case. */ + if (!entry1 || !entry2) + return true; + + if (tse_pts_overlap_p (entry1, entry2)) + return true; + + return false; +} + +/* Returns true if MEM_EXPR is in the points-to set for REG_EXPR. */ + +static bool +tse_tree_in_pts_for_tree_p (tree mem_expr, tree reg_expr, bool weak_deps) +{ + pts_entry_ptr entry; + + entry = tse_get_pts_for_expr (reg_expr, weak_deps); + + /* If doesn't have points-to, assume that it may alias. */ + if (!entry) + return true; + + return tse_var_in_pts_p (mem_expr, entry); +} + +/* Get the REG_EXPR of reg addressing mem + i.e. if (mem (pre_inc (reg [orig:REG_EXPR]))) is given, REG_EXPR + will be returned. Reg should be located inside PRE_INC or POST_INC. */ + +static tree +tse_extract_reg_expr_from_mem (rtx expr, bool weak_deps) +{ + pts_entry_ptr entry; + tree reg_expr; + tree t1, t2; + + switch (GET_CODE (expr)) + { + /* If MEM, continuing search. */ + case MEM: + return tse_extract_reg_expr_from_mem (XEXP (expr, 0), weak_deps); + + /* If REG, try to get points-to for its REG_EXPR, + otherwise the REG_EXPR found is useless. */ + case REG: + reg_expr = REG_EXPR (expr); + if (reg_expr == NULL || ! DECL_P (reg_expr)) + return NULL; + entry = tse_get_pts_for_expr (reg_expr, weak_deps); + if (!entry) + return NULL; + else + return REG_EXPR (expr); + + /* Try both arguments. */ + case PLUS: + t1 = tse_extract_reg_expr_from_mem (XEXP (expr, 0), weak_deps); + if (t1) + return t1; + t2 = tse_extract_reg_expr_from_mem (XEXP (expr, 1), weak_deps); + if (t2) + return t2; + else + return NULL; + + /* Search inside PRE_INC and POST_INC. */ + case PRE_INC: + case POST_INC: + return tse_extract_reg_expr_from_mem (XEXP (expr, 0), weak_deps); + + default: + return NULL; + } +} + +/* Return true if T is an expression that tse_get_inner_decl handles. + The difference from handled_component_p is that this version doesn't handle + ARRAY_REFs and ARRAY_RANGE_REFs. */ + +static bool +tse_handled_component_p (tree t) +{ + switch (TREE_CODE (t)) + { + case BIT_FIELD_REF: + case COMPONENT_REF: + case REALPART_EXPR: + case IMAGPART_EXPR: + return true; + + default: + return false; + } +} + +/* If EXPR contains conversions at the root of the tree, all of them + will be removed. */ + +tree +skip_conversions (tree expr) +{ + tree inner = expr; + /* Remove any conversions: they don't change what the underlying + object is. Likewise for SAVE_EXPR. */ + while (TREE_CODE (inner) == NOP_EXPR || TREE_CODE (inner) == CONVERT_EXPR + || TREE_CODE (inner) == NON_LVALUE_EXPR + || TREE_CODE (inner) == VIEW_CONVERT_EXPR + || TREE_CODE (inner) == SAVE_EXPR) + inner = TREE_OPERAND (inner, 0); + return inner; +} + +/* 'Unwraps' expression from COMPONENT_REFS and others, i.e. for p[i].a.b + it will return p[i]. All type conversions are also eliminated. */ + +static tree +tse_get_inner_decl1 (tree expr) +{ + while (expr && tse_handled_component_p (expr)) + expr = TREE_OPERAND (skip_conversions (expr), 0); + + expr = skip_conversions (expr); + return expr; +} + + +/* Returns inner declaration for EXPR, i.e. for p[i].field it will return p, + so points-to for p should contain memory location occupied by EXPR. + Double inderect references are not supported. */ + +static tree +tse_get_dereferenced_ptr (tree expr) +{ + expr = tse_get_inner_decl1 (expr); + + if (expr != NULL + && (TREE_CODE (expr) == ARRAY_REF || TREE_CODE (expr) == INDIRECT_REF)) + expr = TREE_OPERAND (expr, 0); + expr = skip_conversions (expr); + + if (expr && DECL_P (expr)) + return expr; + else + return NULL; +} + +/* Check whether we have TREE_OPERAND (p, 0) for every nesting level, + becuase we shouldn't handle references like .level1.level2, + where exact is unknown. */ + +static bool +ref_has_nested_op0 (tree ref) +{ + tree p = TREE_OPERAND (ref, 0); + + while (p && handled_component_p (p)) + { + p = TREE_OPERAND (p, 0); + } + return p ? true : false; +} + +/* MEM should be a COMPONENT_REF or ARRAY_REF, which may have structure + aliasing's subvars. We will search for the field referenced in subvars, + fetch the SFT and check whether it is in the exported alias set for the + reg. Returns 0 if REG can point to MEM, 1 if location referenced by REG + and MEM are non-overlapping and -1 if this routine is not applicable. */ + +static int +tse_try_struct_aliasing (tree mem, tree reg, bool weak_deps) +{ + tree ref; + HOST_WIDE_INT offset, size, maxsize; + + gcc_assert (TREE_CODE (mem) == COMPONENT_REF + || TREE_CODE (mem) == ARRAY_REF); + gcc_assert (ref_has_nested_op0 (mem)); + + + ref = get_ref_base_and_extent (mem, &offset, &size, &maxsize); + + if (!INDIRECT_REF_P (ref) && get_subvars_for_var (ref)) + { + subvar_t sv; + subvar_t svars; + bool has_dependence = false; + + svars = get_subvars_for_var (ref); + for (sv = svars; sv; sv = sv->next) + { + if (overlap_subvar (offset, size, sv->var, NULL)) + if (tse_tree_in_pts_for_tree_p (sv->var, reg, weak_deps)) + { + has_dependence = true; + break; + } + } + if (!has_dependence) + return 1; + + return 0; + } + + return -1; +} + +/* Returns true if MEM1 and MEM2 are non-overlapping fields of a structure. */ + +static bool +different_struct_fields_p (tree mem1, tree mem2) +{ + tree ref1, ref2; + HOST_WIDE_INT offset1, size1, maxsize1; + HOST_WIDE_INT offset2, size2, maxsize2; + + if (TREE_CODE (mem1) != COMPONENT_REF || TREE_CODE (mem2) != COMPONENT_REF) + return false; + if (!ref_has_nested_op0 (mem1) || !ref_has_nested_op0 (mem2)) + return false; + + ref1 = get_ref_base_and_extent (mem1, &offset1, &size1, &maxsize1); + ref2 = get_ref_base_and_extent (mem2, &offset2, &size2, &maxsize2); + + if (!INDIRECT_REF_P (ref1) && !INDIRECT_REF_P (ref2)) + { + subvar_t sv1, sv2; + subvar_t svars1, svars2; + + gcc_assert (DECL_P (ref1) && DECL_P (ref2)); + + /* If ref1 != ref2 then we need to check whether this different + vars were given different stack locations. */ + if (ref1 != ref2 && !tse_different_stack_vars_partitions_p (ref1, ref2)) + return false; + + svars1 = get_subvars_for_var (ref1); + svars2 = get_subvars_for_var (ref2); + + if (svars1 && svars2) + { + for (sv1 = svars1; sv1; sv1 = sv1->next) + if (overlap_subvar (offset1, size1, sv1->var, NULL)) + for (sv2 = svars2; sv2; sv2 = sv2->next) + { + if (overlap_subvar (offset2, size2, sv2->var, NULL)) + { + if (sv1 == sv2) + goto has_dependence; + } + } + return true; + } + } + +has_dependence: + return false; +} + +/* Get base variable distinguishable by stack locations for tree t, + i.e. it will be a for a.x, NULL - for p->x (cause .x may be located + not on stack). */ + +static tree +tse_get_base_var (tree t) +{ + if (t == NULL) + return NULL; + switch (TREE_CODE (t)) + { + case COMPONENT_REF: + return tse_get_base_var (TREE_OPERAND (t, 0)); + case VAR_DECL: + case PARM_DECL: + return t; + default: + return NULL; + } +} + +/* Returns true if memory location M is not referenced by R in some way. + This is an internal function for different_tree_ssa_alias_sets_p(). */ + +static bool +tse_try_disambiguate_refs_p (tree m, tree r, bool weak_deps) +{ + int ret; + + if (TREE_CODE (m) == COMPONENT_REF) + { + tree op0 = TREE_OPERAND (m, 0); + + if (!ref_has_nested_op0 (m)) + return false; + + ret = tse_try_struct_aliasing (m, r, weak_deps); + if (ret >= 0) + return ret ? true : false; + + if (TREE_CODE (op0) == INDIRECT_REF) + { + tree ptr = TREE_OPERAND (op0, 0); + + /* No points-to data available for tree, if it is not DECL_P. */ + if (DECL_P (ptr) + && !tse_alias_sets_overlap_p (ptr, r, weak_deps)) + return true; + } + else if (TREE_CODE (op0) == ARRAY_REF) + { + tree arr = TREE_OPERAND (op0, 0); + + if (DECL_P (arr) + && !tse_tree_in_pts_for_tree_p (arr, r, weak_deps)) + return true; + } + + return false; + } + else if (TREE_CODE (m) == ARRAY_REF) + { + tree arr = TREE_OPERAND (m, 0); + + if (var_can_have_subvars (arr) && get_subvars_for_var (arr)) + { + /* Here, we should check subvars. */ + + ret = tse_try_struct_aliasing (m, r, weak_deps); + if (ret >= 0) + return ret ? true : false; + } + + if (TREE_CODE (arr) != COMPONENT_REF + && tse_get_base_var (arr) != NULL + && !tse_tree_in_pts_for_tree_p (arr, r, weak_deps)) + return true; + } + else if (DECL_P (m)) + { + /* If m can have subvars, we should try look at then first. */ + + if (var_can_have_subvars (m) && get_subvars_for_var (m)) + { + subvar_t sv; + subvar_t svars; + + svars = get_subvars_for_var (m); + for (sv = svars; sv; sv = sv->next) + { + if (tse_tree_in_pts_for_tree_p (sv->var, r, weak_deps)) + return false; + } + + return true; + } + else + { + if (!tse_tree_in_pts_for_tree_p (m, r, weak_deps)) + return true; + } + } + return false; +} + +/* Returns whether base variables for V1 and V2 occupy different stack + locations. I.e. given V1 == A.B and V2 == C.D it will compare stack + partition numbers for A and C. */ + +static bool +different_base_var_stack_partitions_p (tree v1, tree v2) +{ + if (v1 && v2) + { + tree t1, t2; + t1 = tse_get_base_var (v1); + t2 = tse_get_base_var (v2); + if (tse_different_stack_vars_partitions_p (t1, t2)) + return true; + } + return false; +} + +/* Returns true, if it can determine that X and MEM do not alias. */ + +static bool +tse_nonoverlapping_rtxes_p (rtx x, rtx mem, bool weak_deps) +{ + tree reg_expr1, reg_expr2; + tree mem_expr1, mem_expr2; + tree m = NULL, r = NULL; + + if (!flag_propagate_points_to_sets) + return false; + + if (x == mem) + return false; + + mem_expr1 = tse_mem_expr (x); + mem_expr2 = tse_mem_expr (mem); + + reg_expr1 = tse_extract_reg_expr_from_mem (x, weak_deps); + reg_expr2 = tse_extract_reg_expr_from_mem (mem, weak_deps); + + /* Try to disambiguate by different memory classes. */ + if (mem_expr1 && mem_expr2) + { + if (different_base_var_stack_partitions_p (mem_expr1, mem_expr2)) + return true; + + if (different_struct_fields_p (mem_expr1, mem_expr2)) + return true; + } + if (reg_expr1 && reg_expr2) + if (!tse_alias_sets_overlap_p (reg_expr1, reg_expr2, weak_deps)) + return true; + + if (mem_expr1 && reg_expr2) + { + m = mem_expr1; + r = reg_expr2; + + if (tse_try_disambiguate_refs_p (m, r, weak_deps)) + return true; + } + else if (mem_expr2 && reg_expr1) + { + m = mem_expr2; + r = reg_expr1; + + if (tse_try_disambiguate_refs_p (m, r, weak_deps)) + return true; + } + return false; +} + /* The splay-tree used to store the various alias set entries. */ static GTY ((param_is (struct alias_set_entry))) varray_type alias_sets; @@ -273,7 +799,7 @@ mems_in_disjoint_alias_sets_p (rtx mem1, gen_rtx_MEM, and the MEM_ALIAS_SET is not cleared. If we begin to use alias sets to indicate that spilled registers cannot alias each other, we might need to remove this check. */ - gcc_assert (flag_strict_aliasing + gcc_assert (flag_strict_aliasing || flag_propagate_alias_sets || (!MEM_ALIAS_SET (mem1) && !MEM_ALIAS_SET (mem2))); return ! alias_sets_conflict_p (MEM_ALIAS_SET (mem1), MEM_ALIAS_SET (mem2)); @@ -290,6 +816,60 @@ insert_subset_children (splay_tree_node return 0; } +/* We'll enumerate our extended alias sets downwards starting with + EXT_ALIAS_SETS_BASE - 1. */ +#define EXT_ALIAS_SETS_BASE -3 +static GTY (()) HOST_WIDE_INT last_extended_alias_set = EXT_ALIAS_SETS_BASE; + +/* Convert positive index into negative extended alias set number and back. */ + +static HOST_WIDE_INT +convert_ext_alias_set_number (HOST_WIDE_INT i) +{ + return -i + EXT_ALIAS_SETS_BASE - 1; +} + +/* Memory disambiguation with -fpropagate-alias-sets. + The idea is as follows: we need some mechanism to disambiguate mems not + only based on their type, but also on information obtained during tree-ssa + may_alias pass. We're trying to minimize the amount of information to be + saved. So we extend MEM_ALIAS_SET values with negative numbers, and check + whether this negative alias set numbers conflict, when we have them, or + just use ordinary (positive) alias sets numbers, when we don't have more + precise information from the tree-ssa level. The checking procedure of + whether two mems conflict using MEM_ALIAS_SETs will consist of the + following steps: + + 1) if only one of two MEM_ALIAS_SETs is negative, then take saved + original (positive) alias sets from table and handle them in ordinary + way; + 2) if both MEM_ALIAS_SETs are negative, check if they conflict. If they + don't, return that this two mems do not conflict (cause negative + MEM_ALIAS_SETs were computed based upon more precise information + from tree-ssa level); + 3) if negative MEM_ALIAS_SETs conflict, then retrieve original positive + values, and check them in the ordinary way. */ + +/* Returns whether SET is extended alias set (negative). */ + +bool +extended_alias_set_p (HOST_WIDE_INT set) +{ + return (set < EXT_ALIAS_SETS_BASE); +} + +/* Returns whether two extended (negative) alias sets conflict. */ + +static bool +extended_alias_sets_conflict_p (HOST_WIDE_INT set1, HOST_WIDE_INT set2) +{ + gcc_assert (extended_alias_set_p (set1)); + gcc_assert (extended_alias_set_p (set2)); + + return (get_extended_alias_set_part_num (set1) + == get_extended_alias_set_part_num (set2)); +} + /* Return 1 if the two specified alias sets may conflict. */ int @@ -297,6 +877,25 @@ alias_sets_conflict_p (HOST_WIDE_INT set { alias_set_entry ase; + if (flag_propagate_alias_sets) + { + /* If both alias set numbers are negative, then they both were + introduced by tree-ssa alias sets exporting, so they are comparable + and we try to disambiguate them. + Otherwise (or if the disambiguation failed because negative numbers + turned to be equal) we'll replace negative number by original one. */ + + if (extended_alias_set_p (set1) + && extended_alias_set_p (set2) + && !extended_alias_sets_conflict_p (set1, set2)) + return 0; + + if (extended_alias_set_p (set1)) + set1 = get_original_alias_set (set1); + if (extended_alias_set_p (set2)) + set2 = get_original_alias_set (set2); + } + /* If have no alias set information for one of the operands, we have to assume it can alias anything. */ if (set1 == 0 || set2 == 0 @@ -495,6 +1094,7 @@ get_alias_set (tree t) something with this tree before we look at it. */ STRIP_NOPS (t); set = lang_hooks.get_alias_set (t); + gcc_assert (!extended_alias_set_p (set)); if (set != -1) return set; @@ -528,6 +1128,8 @@ get_alias_set (tree t) HOST_WIDE_INT pointed_to_alias_set = get_alias_set (pointed_to_type); + gcc_assert (!extended_alias_set_p (pointed_to_alias_set)); + if (pointed_to_alias_set == 0) /* It's not legal to make a subset of alias set zero. */ DECL_POINTER_ALIAS_SET (decl) = 0; @@ -576,7 +1178,13 @@ get_alias_set (tree t) variables don't look like union members (boo!). */ if (TREE_CODE (t) == VAR_DECL && DECL_RTL_SET_P (t) && MEM_P (DECL_RTL (t))) - return MEM_ALIAS_SET (DECL_RTL (t)); + { + HOST_WIDE_INT set = MEM_ALIAS_SET (DECL_RTL (t)); + if (extended_alias_set_p (set)) + set = get_original_alias_set (set); + gcc_assert (!extended_alias_set_p (set)); + return set; + } /* Now all we care about is the type. */ t = TREE_TYPE (t); @@ -620,6 +1228,376 @@ get_alias_set (tree t) return set; } +/* True if N can be an alias set partition number. Used only in asserts. */ + +static bool +valid_ext_alias_set_part_num_p (HOST_WIDE_INT n) +{ + return ((n >= 0) + && (n < (HOST_WIDE_INT) VARRAY_SIZE (cfun->ext_alias_set_partitions))); +} + +/* Returns "partition number" for extended alias set. */ + +HOST_WIDE_INT +get_extended_alias_set_part_num (HOST_WIDE_INT extended_alias_set) +{ + HOST_WIDE_INT part_num; + HOST_WIDE_INT index = convert_ext_alias_set_number (extended_alias_set); + + gcc_assert (extended_alias_set_p (extended_alias_set)); + gcc_assert (cfun); + gcc_assert (cfun->ext_alias_set_to_partition); + + part_num = VARRAY_WIDE_INT (cfun->ext_alias_set_to_partition, index); + + gcc_assert (valid_ext_alias_set_part_num_p (part_num)); + + return part_num; +} + +/* Returns saved original (positive) alias set number for extended + NEW_ALIAS_SET given. */ + +HOST_WIDE_INT +get_original_alias_set (HOST_WIDE_INT new_alias_set) +{ + HOST_WIDE_INT index = convert_ext_alias_set_number (new_alias_set); + HOST_WIDE_INT original_alias_set; + + gcc_assert (extended_alias_set_p (new_alias_set)); + gcc_assert (cfun); + gcc_assert (cfun->ext_alias_set_to_original); + + original_alias_set = VARRAY_WIDE_INT (cfun->ext_alias_set_to_original, index); + gcc_assert (!extended_alias_set_p (original_alias_set)); + return original_alias_set; +} + +/* Returns new extended negative alias set number, and record that it + corresponds to original_alias_set and has partition number part_num. */ + +static HOST_WIDE_INT +allocate_extended_alias_set (HOST_WIDE_INT original_alias_set, + HOST_WIDE_INT part_num) +{ + gcc_assert (cfun); + gcc_assert (valid_ext_alias_set_part_num_p (part_num)); + + /* Initialize varrays. */ + if (!cfun->ext_alias_set_to_original) + { + VARRAY_WIDE_INT_INIT (cfun->ext_alias_set_to_original, 128, + "original alias sets"); + last_extended_alias_set = EXT_ALIAS_SETS_BASE; + } + + if (!cfun->ext_alias_set_to_partition) + VARRAY_WIDE_INT_INIT (cfun->ext_alias_set_to_partition, 128, + "alias set partition numbers"); + + + last_extended_alias_set--; + + VARRAY_PUSH_WIDE_INT (cfun->ext_alias_set_to_original, original_alias_set); + VARRAY_PUSH_WIDE_INT (cfun->ext_alias_set_to_partition, part_num); + + return last_extended_alias_set; +} + +/* Merges OLD_PART_NUM with NEW_PART_NUM: bitmaps are merged, all extended + alias sets that earlier corresponded to OLD_PART_NUM in + EXT_ALIAS_SET_TO_PARTITION now correspond to NEW_PART_NUM partition. */ + +static void +merge_ext_alias_set_partitions (HOST_WIDE_INT old_part_num, + HOST_WIDE_INT new_part_num) +{ + size_t i; + ext_alias_set_partition_p old_part, new_part; + + gcc_assert (old_part_num != new_part_num); + gcc_assert (valid_ext_alias_set_part_num_p (old_part_num) + && valid_ext_alias_set_part_num_p (new_part_num)); + + /* Replace extended alias sets correspondences. */ + for (i = 0; i < VARRAY_ACTIVE_SIZE (cfun->ext_alias_set_to_partition); i++) + if (VARRAY_WIDE_INT (cfun->ext_alias_set_to_partition, i) == + old_part_num) + VARRAY_WIDE_INT (cfun->ext_alias_set_to_partition, i) = new_part_num; + + /* Add all may aliases from old partition to new. */ + old_part = VARRAY_GENERIC_PTR (cfun->ext_alias_set_partitions, old_part_num); + new_part = VARRAY_GENERIC_PTR (cfun->ext_alias_set_partitions, new_part_num); + + bitmap_ior_into (new_part->may_aliases, old_part->may_aliases); + bitmap_ior_into (new_part->stack_partitions, old_part->stack_partitions); +} + +/* Internal helper function for get_extended_alias_set(). + CONFLICTING_PART_NUM - partition that was found conflicting before, or + -1 if none was found so far. If CONFLICTING_PART_NUM == 0, set + CONFLICTING_PART_NUM to CURRENT_PART_NUM, else merge these two extended + alias set partitions. */ + +static void +record_ext_alias_sets_conflict (HOST_WIDE_INT * conflicting_part_num, + HOST_WIDE_INT current_part_num) +{ + gcc_assert (valid_ext_alias_set_part_num_p (current_part_num)); + gcc_assert (*conflicting_part_num == -1 + || valid_ext_alias_set_part_num_p (*conflicting_part_num)); + + /* If there was no any conflicts before, just remember + conflicting alias set number. */ + if (*conflicting_part_num == -1) + *conflicting_part_num = current_part_num; + else + { + if (current_part_num != *conflicting_part_num) + merge_ext_alias_set_partitions (current_part_num, + *conflicting_part_num); + } +} + +/* Internal function for get_extended_alias_set(). + Returns apropriate extended alias set such that it conflicts with + CONFLICTING_PARTITION_NUM and has original alias set == + ORIGINAL_ALIAS_SET_NUM, allocating new extended alias set if needed. */ + +static HOST_WIDE_INT +choose_extended_alias_set_num (HOST_WIDE_INT conflicting_partition_num, + HOST_WIDE_INT original_alias_set_num) +{ + size_t i; + + gcc_assert (valid_ext_alias_set_part_num_p (conflicting_partition_num)); + + /* If the extended alias set with original alias set == original_alias_set_num + and partition number == conflicting_partition_num already have been + allocated, then find it. */ + for (i = 0; i < VARRAY_ACTIVE_SIZE (cfun->ext_alias_set_to_partition); i++) + { + HOST_WIDE_INT part_num = + VARRAY_WIDE_INT (cfun->ext_alias_set_to_partition, i); + if (part_num == conflicting_partition_num) + { + HOST_WIDE_INT set_num = convert_ext_alias_set_number (i); + if (get_original_alias_set (set_num) == original_alias_set_num) + return set_num; + } + } + + /* Otherwise allocate new extended alias set with conflicting_partition_num + as its partition number. */ + return allocate_extended_alias_set (original_alias_set_num, + conflicting_partition_num); +} + +/* This bitmap holds the set of T's SFTs or points-to set, if T is the + pointer dereference. */ +static GTY(()) bitmap conflicting_set = NULL; + + +/* Function that may also return extended (negative) alias sets. + We use it when setting mem attributes instead of get_alias_set(). It uses + get_alias_set() routine to save original alias sets. */ + +HOST_WIDE_INT +get_extended_alias_set (tree t) +{ + size_t i; + HOST_WIDE_INT original_alias_set = get_alias_set (t); + HOST_WIDE_INT conflicting_part_num; + tree ref; + HOST_WIDE_INT offset, size, maxsize; + subvar_t svars; + int stack_part; + + gcc_assert (!extended_alias_set_p (original_alias_set)); + + /* Avoid create extended alias sets for type trees. */ + if (TYPE_P (t)) + return original_alias_set; + + if (!flag_propagate_alias_sets) + return original_alias_set; + + /* If it has been called earlier then tree-out-of-ssa pass (i.e. in parser), + just returns original alias set, cause we can't use tree-ssa points-to + info yet. */ + if (!cfun || !cfun->tse_export_done) + return original_alias_set; + + if (!conflicting_set) + conflicting_set = BITMAP_GGC_ALLOC(); + bitmap_clear (conflicting_set); + + /* Build the the conflicting set for the T. This is the set which T may + alias with, including structure field tags and points-to set for + pointer dereferences. */ + + /* Get the variable containing subvars for expr. */ + if (handled_component_p (t)) + ref = get_ref_base_and_extent (t, &offset, &size, &maxsize); + else + { + ref = t; + offset = -1; + } + + if (ref && DECL_P (ref) && var_can_have_subvars (ref) + && var_ann (ref) && (svars = get_subvars_for_var (ref))) + { + /* Handle COMPONENT_REFs, ARRAY_REFs, and DECL_P if they have SFTs. */ + + subvar_t sv; + + /* Avoid update alias set numbers for global vars cause these numbers are + only valid within a function. */ + if (is_global_var (ref)) + return original_alias_set; + + /* Add corresponding SFT for field, or all SFTs for the array or the + structure. */ + for (sv = svars; sv; sv = sv->next) + if (offset == -1 || overlap_subvar (offset, size, sv->var, NULL)) + bitmap_set_bit (conflicting_set, DECL_UID (sv->var)); + + /* If corresponding subvar not found in subvars, give up. */ + if (bitmap_empty_p (conflicting_set)) + return original_alias_set; + + /* Do not check whether stack locations overlap for variables + that have SFTs. */ + stack_part = -1; + } + else + { + /* Handle other cases. */ + + tree ptr_base = NULL; + tree base_stack_var = NULL; + pts_entry_ptr ptr_points_to = NULL; + + base_stack_var = tse_get_base_var (t); + + if (base_stack_var) + { + /* Avoid update alias set numbers for global vars cause these + numbers are only valid within a function. */ + + if (is_global_var (base_stack_var)) + return original_alias_set; + + stack_part = tse_get_stack_var_partition (base_stack_var); + /* We should be able to distinguish the variables on stack. */ + if (stack_part < 0) + return original_alias_set; + + /* Put the variable itself into conflicting set. */ + bitmap_set_bit (conflicting_set, DECL_UID (base_stack_var)); + } + else + { + /* A tree can have points-to iff base_var(tree) == NULL. */ + + /* Get the pointer that was dereferenced. */ + ptr_base = tse_get_dereferenced_ptr (t); + if (ptr_base) + ptr_points_to = tse_get_pts_for_expr (ptr_base, false); + + if (!ptr_base || !ptr_points_to) + return original_alias_set; + + if (ptr_points_to->pt_anything) + return original_alias_set; + + if (ptr_points_to) + bitmap_ior_into (conflicting_set, ptr_points_to->may_aliases); + + /* Do not check stack locations overlap for pointer dereferences. */ + stack_part = -1; + } + } + + /* Stack variable should at least alias itself, dereferenced ptr with empty + points-to set is also weird. */ + gcc_assert (!bitmap_empty_p (conflicting_set)); + + if (!cfun->ext_alias_set_partitions) + VARRAY_GENERIC_PTR_INIT (cfun->ext_alias_set_partitions, 128, + "extended alias sets partitions"); + + conflicting_part_num = -1; + + /* Loop through other partitions and see whether T conflicts with any + variable from previous function calls. */ + for (i = 0; i < VARRAY_ACTIVE_SIZE (cfun->ext_alias_set_partitions); i++) + { + ext_alias_set_partition_p part = (ext_alias_set_partition_p) + VARRAY_GENERIC_PTR (cfun->ext_alias_set_partitions, i); + + if (bitmap_intersect_p (conflicting_set, part->may_aliases) + || (stack_part >= 0 && bitmap_bit_p (part->stack_partitions, + stack_part))) + { + /* Add current points-to into partition's may aliases set, + so conflicting arguments arrived later receive the same + alias set partition. */ + + bitmap_ior_into (part->may_aliases, conflicting_set); + if (stack_part >= 0) + { + bitmap_set_bit (part->stack_partitions, stack_part); + } + record_ext_alias_sets_conflict (&conflicting_part_num, i); + } + } + + if (conflicting_part_num != -1) + { + /* If conflicting partition was found. */ + HOST_WIDE_INT allocated_alias_set_num = + choose_extended_alias_set_num (conflicting_part_num, + original_alias_set); + + gcc_assert (extended_alias_set_p (allocated_alias_set_num)); + + return allocated_alias_set_num; + } + else + { + /* Allocate new alias set number and record that it corresponds to + original_alias_set old number, and has it's own number as + partition number. */ + + HOST_WIDE_INT new_alias_set, last_part_num; + ext_alias_set_partition_p part = + ggc_alloc (sizeof (struct ext_alias_set_partition)); + + part->may_aliases = bitmap_gc_alloc (); + part->stack_partitions = bitmap_gc_alloc (); + + bitmap_ior_into (part->may_aliases, conflicting_set); + if (stack_part >= 0) + { + bitmap_set_bit (part->stack_partitions, stack_part); + } + + /* Create new partition. */ + VARRAY_PUSH_GENERIC_PTR (cfun->ext_alias_set_partitions, part); + last_part_num = VARRAY_ACTIVE_SIZE (cfun->ext_alias_set_partitions) - 1; + + /* Create new extended alias set with new partition number, we've just + created. */ + new_alias_set = + allocate_extended_alias_set (original_alias_set, last_part_num); + + return new_alias_set; + } +} + /* Return a brand-new alias set. */ static GTY(()) HOST_WIDE_INT last_alias_set; @@ -2192,6 +3170,11 @@ true_dependence (rtx mem, enum machine_m SIZE_FOR_MODE (x), x_addr, 0)) return 0; + /* Try to disambiguate mems using info exported from tree-ssa may_alias + pass. */ + if (tse_nonoverlapping_rtxes_p (x, mem, false)) + return 0; + if (aliases_everything_p (x)) return 1; @@ -2329,6 +3312,11 @@ write_dependence_p (rtx mem, rtx x, int SIZE_FOR_MODE (x), x_addr, 0)) return 0; + /* Try to disambiguate mems using info exported from tree-ssa may_alias + pass. */ + if (tse_nonoverlapping_rtxes_p (x, mem, false)) + return 0; + fixed_scalar = fixed_scalar_and_varying_struct_p (mem, x, mem_addr, x_addr, rtx_addr_varies_p); diff -upd -r gcc-clean/gcc/cfgexpand.c gcc/gcc/cfgexpand.c --- gcc-clean/gcc/cfgexpand.c 2006-03-10 01:34:13.000000000 +0300 +++ gcc/gcc/cfgexpand.c 2006-03-14 17:25:18.000000000 +0300 @@ -37,6 +37,8 @@ Boston, MA 02110-1301, USA. */ #include "flags.h" #include "diagnostic.h" #include "toplev.h" +#include "hashtab.h" +#include "ggc.h" #include "debug.h" #include "params.h" @@ -503,6 +505,65 @@ dump_stack_var_partition (void) } } +/* Save the generated partitions for alias.c, so we can say whether two + vars actually occupy different stack locations. */ + +static void +tse_save_stack_var_partition (void) +{ + size_t i; + + /* Save all stack_vars partition info in the annotations. */ + for (i = 0; i < stack_vars_num; i++) + { + var_ann_t ann = get_var_ann (stack_vars[i].decl); + gcc_assert (ann); + ann->alias_info = tse_create_alias_info_entry (); + gcc_assert (ann->alias_info); + ann->alias_info->stack_part_num = stack_vars[i].representative; + } +} + + +/* Returns saved stack partition number for a variable. */ + +int +tse_get_stack_var_partition (tree var) +{ + var_ann_t ann = var_ann (var); + + if (!ann || !ann->alias_info || ann->alias_info->stack_part_num < 0) + return -1; + + return ann->alias_info->stack_part_num; +} + +/* Returns whether variables were given different stack locations during rtl + generation, i.e. whether these two locations can be disambiguated using + tree-ssa alias analysis information. */ + +bool +tse_different_stack_vars_partitions_p (tree var1, tree var2) +{ + var_ann_t ann1, ann2; + + if (var1 == NULL || var2 == NULL || var1 == var2) + return false; + + ann1 = var_ann (var1); + ann2 = var_ann (var2); + + if (ann1 == NULL || ann2 == NULL || ann1->alias_info == NULL + || ann2->alias_info == NULL) + return false; + + if (ann1->alias_info->stack_part_num == -1 + || ann2->alias_info->stack_part_num == -1) + return false; + + return (ann1->alias_info->stack_part_num != ann2->alias_info->stack_part_num); +} + /* Assign rtl to DECL at frame offset OFFSET. */ static void @@ -1041,6 +1102,9 @@ expand_used_vars (void) expand_stack_vars (NULL); + /* Save stack partitioning info for alias.c */ + tse_save_stack_var_partition (); + /* Free up stack variable graph data. */ XDELETEVEC (stack_vars); XDELETEVEC (stack_vars_sorted); diff -upd -r gcc-clean/gcc/common.opt gcc/gcc/common.opt --- gcc-clean/gcc/common.opt 2006-03-10 01:34:15.000000000 +0300 +++ gcc/gcc/common.opt 2006-03-13 21:05:48.000000000 +0300 @@ -379,6 +379,14 @@ fearly-inlining Common Report Var(flag_early_inlining) Init(1) Perform early inlining +fpropagate-points-to-sets +Common Report Var(flag_propagate_points_to_sets) +Propagate points-to sets from tree-ssa aliasing and use them for mems disambiguation in rtl + +fpropagate-alias-sets +Common Report Var(flag_propagate_alias_sets) +Propagate tree-ssa aliasing information through alias set numbers + feliminate-dwarf2-dups Common Report Var(flag_eliminate_dwarf2_dups) Perform DWARF2 duplicate elimination diff -upd -r gcc-clean/gcc/doc/invoke.texi gcc/gcc/doc/invoke.texi --- gcc-clean/gcc/doc/invoke.texi 2006-03-10 01:32:32.000000000 +0300 +++ gcc/gcc/doc/invoke.texi 2006-03-10 16:10:30.000000000 +0300 @@ -13218,6 +13218,19 @@ alias each other and do not alias global Each language will automatically use whatever option is required by the language standard. You should not need to use these options yourself. +@item -fpropagate-points-to-sets +@opindex fpropagate-points-to-sets +Use points-to information from tree-ssa aliasing during rtl optimization +passes for memory rtxes disambiguation. With this flag memory disambiguations +are made based on the rtx structure and corresponding expr trees for rtxes, +while with @option{-fpropagate-alias-sets} only alias set numbers are used. + +@item -fpropagate-alias-sets +@opindex fpropagate-alias-sets +Use extended alias set numbers for memory rtxes disambiguations. With this flag +tree-ssa aliasing information is used along with type information to create +alias set numbers. + @item -fleading-underscore @opindex fleading-underscore This option and its counterpart, @option{-fno-leading-underscore}, forcibly diff -upd -r gcc-clean/gcc/emit-rtl.c gcc/gcc/emit-rtl.c --- gcc-clean/gcc/emit-rtl.c 2006-03-10 01:34:13.000000000 +0300 +++ gcc/gcc/emit-rtl.c 2006-03-15 01:30:34.000000000 +0300 @@ -177,8 +177,8 @@ static int const_double_htab_eq (const v static rtx lookup_const_double (rtx); static hashval_t mem_attrs_htab_hash (const void *); static int mem_attrs_htab_eq (const void *, const void *); -static mem_attrs *get_mem_attrs (HOST_WIDE_INT, tree, rtx, rtx, unsigned int, - enum machine_mode); +static mem_attrs *get_mem_attrs (HOST_WIDE_INT, tree, tree, rtx, rtx, + unsigned int, enum machine_mode); static hashval_t reg_attrs_htab_hash (const void *); static int reg_attrs_htab_eq (const void *, const void *); static reg_attrs *get_reg_attrs (tree, int); @@ -270,7 +270,10 @@ mem_attrs_htab_eq (const void *x, const && p->size == q->size && p->align == q->align && (p->expr == q->expr || (p->expr != NULL_TREE && q->expr != NULL_TREE - && operand_equal_p (p->expr, q->expr, 0)))); + && operand_equal_p (p->expr, q->expr, 0))) + && (p->orig_expr == q->orig_expr + || (p->orig_expr != NULL_TREE && q->orig_expr != NULL_TREE + && operand_equal_p (p->orig_expr, q->orig_expr, 0)))); } /* Allocate a new mem_attrs structure and insert it into the hash table if @@ -278,8 +281,8 @@ mem_attrs_htab_eq (const void *x, const MEM of mode MODE. */ static mem_attrs * -get_mem_attrs (HOST_WIDE_INT alias, tree expr, rtx offset, rtx size, - unsigned int align, enum machine_mode mode) +get_mem_attrs (HOST_WIDE_INT alias, tree expr, tree orig_expr, rtx offset, + rtx size, unsigned int align, enum machine_mode mode) { mem_attrs attrs; void **slot; @@ -287,7 +290,7 @@ get_mem_attrs (HOST_WIDE_INT alias, tree /* If everything is the default, we can just return zero. This must match what the corresponding MEM_* macros return when the field is not present. */ - if (alias == 0 && expr == 0 && offset == 0 + if (alias == 0 && expr == 0 && orig_expr == 0 && offset == 0 && (size == 0 || (mode != BLKmode && GET_MODE_SIZE (mode) == INTVAL (size))) && (STRICT_ALIGNMENT && mode != BLKmode @@ -296,6 +299,7 @@ get_mem_attrs (HOST_WIDE_INT alias, tree attrs.alias = alias; attrs.expr = expr; + attrs.orig_expr = orig_expr; attrs.offset = offset; attrs.size = size; attrs.align = align; @@ -1354,6 +1358,37 @@ operand_subword_force (rtx op, unsigned return result; } + +/* Remove conversions from the expression tree. */ + +static tree +cleanup_tree_from_conversions (tree ref) +{ + tree inner; + tree res = NULL; + + if (EXPR_P (ref)) + inner = TREE_OPERAND (ref, 0); + else + inner = NULL; + + if (inner == NULL) + return ref; + + inner = skip_conversions (inner); + + res = cleanup_tree_from_conversions (inner); + + if (res != TREE_OPERAND (ref, 0)) + { + tree new_tree = copy_node (ref); + TREE_OPERAND (new_tree, 0) = res; + return new_tree; + } + else + return ref; +} + /* Within a MEM_EXPR, we care about either (1) a component ref of a decl, or (2) a component ref of something variable. Represent the later with a NULL expression. */ @@ -1363,27 +1398,36 @@ component_ref_for_mem_expr (tree ref) { tree inner = TREE_OPERAND (ref, 0); - if (TREE_CODE (inner) == COMPONENT_REF) + /* Remove any conversions: they don't change what the underlying + object is. Likewise for SAVE_EXPR. */ + while (TREE_CODE (inner) == NOP_EXPR || TREE_CODE (inner) == CONVERT_EXPR + || TREE_CODE (inner) == NON_LVALUE_EXPR + || TREE_CODE (inner) == VIEW_CONVERT_EXPR + || TREE_CODE (inner) == SAVE_EXPR) + inner = TREE_OPERAND (inner, 0); + + if (TREE_CODE (inner) == COMPONENT_REF || TREE_CODE (inner) == INDIRECT_REF) inner = component_ref_for_mem_expr (inner); else - { - /* Now remove any conversions: they don't change what the underlying - object is. Likewise for SAVE_EXPR. */ - while (TREE_CODE (inner) == NOP_EXPR || TREE_CODE (inner) == CONVERT_EXPR - || TREE_CODE (inner) == NON_LVALUE_EXPR - || TREE_CODE (inner) == VIEW_CONVERT_EXPR - || TREE_CODE (inner) == SAVE_EXPR) - inner = TREE_OPERAND (inner, 0); - - if (! DECL_P (inner)) - inner = NULL_TREE; - } - + { + if (!DECL_P (inner)) + inner = NULL_TREE; + } + if (inner == TREE_OPERAND (ref, 0)) return ref; - else - return build3 (COMPONENT_REF, TREE_TYPE (ref), inner, - TREE_OPERAND (ref, 1), NULL_TREE); + else if (TREE_CODE (ref) == COMPONENT_REF) + { + return build3 (COMPONENT_REF, TREE_TYPE (ref), inner, + TREE_OPERAND (ref, 1), NULL_TREE); + } + else /* INDIRECT_REF. */ + { + if (inner == NULL_TREE) + return NULL_TREE; + else + return build1 (INDIRECT_REF, TREE_TYPE (ref), inner); + } } /* Returns 1 if both MEM_EXPR can be considered equal @@ -1431,6 +1475,7 @@ set_mem_attributes_minus_bitpos (rtx ref { HOST_WIDE_INT alias = MEM_ALIAS_SET (ref); tree expr = MEM_EXPR (ref); + tree orig_expr = NULL; rtx offset = MEM_OFFSET (ref); rtx size = MEM_SIZE (ref); unsigned int align = MEM_ALIGN (ref); @@ -1455,7 +1500,7 @@ set_mem_attributes_minus_bitpos (rtx ref /* Get the alias set from the expression or type (perhaps using a front-end routine) and use it. */ - alias = get_alias_set (t); + alias = get_extended_alias_set (t); MEM_VOLATILE_P (ref) |= TYPE_VOLATILE (type); MEM_IN_STRUCT_P (ref) = AGGREGATE_TYPE_P (type); @@ -1492,6 +1537,8 @@ set_mem_attributes_minus_bitpos (rtx ref { tree base; + orig_expr = cleanup_tree_from_conversions (t); + if (TREE_THIS_VOLATILE (t)) MEM_VOLATILE_P (ref) = 1; @@ -1666,11 +1713,13 @@ set_mem_attributes_minus_bitpos (rtx ref we're overlapping. */ offset = NULL; expr = NULL; + orig_expr = NULL; } /* Now set the attributes we computed above. */ MEM_ATTRS (ref) - = get_mem_attrs (alias, expr, offset, size, align, GET_MODE (ref)); + = get_mem_attrs (alias, expr, orig_expr, offset, size, align, + GET_MODE (ref)); /* If this is already known to be a scalar or aggregate, we are done. */ if (MEM_IN_STRUCT_P (ref) || MEM_SCALAR_P (ref)) @@ -1696,7 +1745,7 @@ void set_mem_attrs_from_reg (rtx mem, rtx reg) { MEM_ATTRS (mem) - = get_mem_attrs (MEM_ALIAS_SET (mem), REG_EXPR (reg), + = get_mem_attrs (MEM_ALIAS_SET (mem), REG_EXPR (reg), NULL_TREE, GEN_INT (REG_OFFSET (reg)), MEM_SIZE (mem), MEM_ALIGN (mem), GET_MODE (mem)); } @@ -1711,9 +1760,9 @@ set_mem_alias_set (rtx mem, HOST_WIDE_IN gcc_assert (alias_sets_conflict_p (set, MEM_ALIAS_SET (mem))); #endif - MEM_ATTRS (mem) = get_mem_attrs (set, MEM_EXPR (mem), MEM_OFFSET (mem), - MEM_SIZE (mem), MEM_ALIGN (mem), - GET_MODE (mem)); + MEM_ATTRS (mem) = get_mem_attrs (set, MEM_EXPR (mem), MEM_ORIG_EXPR (mem), + MEM_OFFSET (mem), MEM_SIZE (mem), + MEM_ALIGN (mem), GET_MODE (mem)); } /* Set the alignment of MEM to ALIGN bits. */ @@ -1722,8 +1771,8 @@ void set_mem_align (rtx mem, unsigned int align) { MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem), - MEM_OFFSET (mem), MEM_SIZE (mem), align, - GET_MODE (mem)); + MEM_ORIG_EXPR (mem), MEM_OFFSET (mem), + MEM_SIZE (mem), align, GET_MODE (mem)); } /* Set the expr for MEM to EXPR. */ @@ -1731,9 +1780,29 @@ set_mem_align (rtx mem, unsigned int ali void set_mem_expr (rtx mem, tree expr) { + tree orig_expr = MEM_ORIG_EXPR (mem); + + /* If MEM_EXPR changes, clear MEM_ORIG_EXPR. If we still can preserve it, + we insert set_mem_orig_expr call right after this function call. */ + if (!expr || !mem_expr_equal_p (MEM_EXPR (mem), expr)) + orig_expr = NULL_TREE; + MEM_ATTRS (mem) - = get_mem_attrs (MEM_ALIAS_SET (mem), expr, MEM_OFFSET (mem), - MEM_SIZE (mem), MEM_ALIGN (mem), GET_MODE (mem)); + = get_mem_attrs (MEM_ALIAS_SET (mem), expr, orig_expr, + MEM_OFFSET (mem), MEM_SIZE (mem), MEM_ALIGN (mem), + GET_MODE (mem)); +} + + +/* Set the original expr for MEM to ORIG_EXPR. */ + +void +set_mem_orig_expr (rtx mem, tree orig_expr) +{ + MEM_ATTRS (mem) + = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem), orig_expr, + MEM_OFFSET (mem), MEM_SIZE (mem), MEM_ALIGN (mem), + GET_MODE (mem)); } /* Set the offset of MEM to OFFSET. */ @@ -1741,9 +1810,16 @@ set_mem_expr (rtx mem, tree expr) void set_mem_offset (rtx mem, rtx offset) { + tree orig_expr = MEM_ORIG_EXPR (mem); + + /* If MEM_EXPR changes, clear MEM_ORIG_EXPR. If we still can preserve it, + we insert set_mem_orig_expr call right after this function call. */ + if (offset != MEM_OFFSET (mem)) + orig_expr = NULL_TREE; + MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem), - offset, MEM_SIZE (mem), MEM_ALIGN (mem), - GET_MODE (mem)); + orig_expr, offset, MEM_SIZE (mem), + MEM_ALIGN (mem), GET_MODE (mem)); } /* Set the size of MEM to SIZE. */ @@ -1752,8 +1828,8 @@ void set_mem_size (rtx mem, rtx size) { MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem), - MEM_OFFSET (mem), size, MEM_ALIGN (mem), - GET_MODE (mem)); + MEM_ORIG_EXPR (mem), MEM_OFFSET (mem), + size, MEM_ALIGN (mem), GET_MODE (mem)); } /* Return a memory reference like MEMREF, but with its mode changed to MODE @@ -1820,7 +1896,8 @@ change_address (rtx memref, enum machine } MEM_ATTRS (new) - = get_mem_attrs (MEM_ALIAS_SET (memref), 0, 0, size, align, mmode); + = get_mem_attrs (MEM_ALIAS_SET (memref), NULL_TREE, NULL_TREE, 0, + size, align, mmode); return new; } @@ -1887,7 +1964,8 @@ adjust_address_1 (rtx memref, enum machi size = plus_constant (MEM_SIZE (memref), -offset); MEM_ATTRS (new) = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref), - memoffset, size, memalign, GET_MODE (new)); + MEM_ORIG_EXPR (memref), memoffset, size, + memalign, GET_MODE (new)); /* At some point, we should validate that this offset is within the object, if all the appropriate values are known. */ @@ -1943,7 +2021,8 @@ offset_address (rtx memref, rtx offset, /* Update the alignment to reflect the offset. Reset the offset, which we don't know. */ MEM_ATTRS (new) - = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref), 0, 0, + = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref), + MEM_ORIG_EXPR (memref), 0, 0, MIN (MEM_ALIGN (memref), pow2 * BITS_PER_UNIT), GET_MODE (new)); return new; @@ -1983,6 +2062,7 @@ widen_memory_access (rtx memref, enum ma tree expr = MEM_EXPR (new); rtx memoffset = MEM_OFFSET (new); unsigned int size = GET_MODE_SIZE (mode); + tree orig_expr = MEM_ORIG_EXPR (new); /* If there are no changes, just return the original memory reference. */ if (new == memref) @@ -2048,8 +2128,11 @@ widen_memory_access (rtx memref, enum ma /* The widened memory may alias other stuff, so zap the alias set. */ /* ??? Maybe use get_alias_set on any remaining expression. */ - MEM_ATTRS (new) = get_mem_attrs (0, expr, memoffset, GEN_INT (size), - MEM_ALIGN (new), mode); + if (expr != MEM_EXPR (new)) + orig_expr = NULL_TREE; + + MEM_ATTRS (new) = get_mem_attrs (0, expr, orig_expr, memoffset, + GEN_INT (size), MEM_ALIGN (new), mode); return new; } Only in gcc/gcc: emit-rtl.c.orig Only in gcc/gcc: emit-rtl.c.rej diff -upd -r gcc-clean/gcc/emit-rtl.h gcc/gcc/emit-rtl.h --- gcc-clean/gcc/emit-rtl.h 2006-03-10 01:34:13.000000000 +0300 +++ gcc/gcc/emit-rtl.h 2006-03-10 16:04:47.000000000 +0300 @@ -30,6 +30,9 @@ extern void set_mem_align (rtx, unsigned /* Set the expr for MEM to EXPR. */ extern void set_mem_expr (rtx, tree); +/* Set the original expr for MEM to ORIG_EXPR. */ +extern void set_mem_orig_expr (rtx, tree); + /* Set the offset for MEM to OFFSET. */ extern void set_mem_offset (rtx, rtx); diff -upd -r gcc-clean/gcc/final.c gcc/gcc/final.c --- gcc-clean/gcc/final.c 2006-03-10 01:32:38.000000000 +0300 +++ gcc/gcc/final.c 2006-03-10 16:04:47.000000000 +0300 @@ -76,6 +76,7 @@ Software Foundation, 51 Franklin Street, #include "timevar.h" #include "cgraph.h" #include "coverage.h" +#include "tree-flow.h" #ifdef XCOFF_DEBUGGING_INFO #include "xcoffout.h" /* Needed for external data @@ -4011,6 +4012,19 @@ rest_of_clean_state (void) { rtx insn, next; + referenced_var_iterator rvi; + tree var; + + /* Remove annotations from every referenced variable. */ + /* Migrated from tree-ssa.c. */ + FOR_EACH_REFERENCED_VAR (var, rvi) + { + ggc_free (var->common.ann); + var->common.ann = NULL; + } + htab_delete (referenced_vars); + referenced_vars = NULL; + /* It is very important to decompose the RTL instruction chain here: debug information keeps pointing into CODE_LABEL insns inside the function body. If these remain pointing to the other insns, we end up preserving diff -upd -r gcc-clean/gcc/function.c gcc/gcc/function.c --- gcc-clean/gcc/function.c 2006-03-10 01:34:10.000000000 +0300 +++ gcc/gcc/function.c 2006-03-10 16:04:47.000000000 +0300 @@ -2944,7 +2944,10 @@ assign_parms_unsplit_complex (struct ass /* Set MEM_EXPR to the original decl, i.e. to PARM, instead of the copy of decl, i.e. FNARGS. */ if (DECL_INCOMING_RTL (parm) && MEM_P (DECL_INCOMING_RTL (parm))) - set_mem_expr (DECL_INCOMING_RTL (parm), parm); + { + set_mem_expr (DECL_INCOMING_RTL (parm), parm); + set_mem_orig_expr (DECL_INCOMING_RTL (parm), parm); + } } fnargs = TREE_CHAIN (fnargs); diff -upd -r gcc-clean/gcc/function.h gcc/gcc/function.h --- gcc-clean/gcc/function.h 2006-03-10 01:34:10.000000000 +0300 +++ gcc/gcc/function.h 2006-03-14 18:28:49.000000000 +0300 @@ -23,6 +23,7 @@ Software Foundation, 51 Franklin Street, #define GCC_FUNCTION_H #include "tree.h" +#include "varray.h" struct var_refs_queue GTY(()) { @@ -452,6 +453,28 @@ struct function GTY(()) /* Number of units of floating point registers that need saving in stdarg function. */ unsigned int va_list_fpr_size : 8; + + /* Receives true value after the points-to sets in the function has been + saved in tree-outof-ssa.c. */ + bool tse_export_done; + + /* Maps new extended (negative) alias set numbers to original (positive). + first element (index 0) of this array corresponds + to (EXT_ALIAS_SETS_BASE - 1). */ + struct varray_head_tag * GTY (()) ext_alias_set_to_original; + + /* Alias partition numbers correspond to multiple original + alias sets numbers. Only partitions are used to determine conflicts + between alias sets, and extended alias set numbers themselves we use + just to restore original alias set numbers. + ext_alias_set_to_partition array reflects the mapping of extended alias + sets to partitions. */ + struct varray_head_tag * GTY (()) ext_alias_set_to_partition; + + /* Array of may aliases and stack partitions for each alias set + partiton number. */ + struct varray_head_tag * GTY ((param_is (struct ext_alias_set_partition))) + ext_alias_set_partitions; }; /* If va_list_[gf]pr_size is set to this, it means we don't know how diff -upd -r gcc-clean/gcc/opts.c gcc/gcc/opts.c --- gcc-clean/gcc/opts.c 2006-03-10 01:33:55.000000000 +0300 +++ gcc/gcc/opts.c 2006-03-13 21:05:48.000000000 +0300 @@ -509,6 +509,9 @@ decode_options (unsigned int argc, const } } + flag_propagate_points_to_sets = 1; + flag_propagate_alias_sets = 1; + if (!optimize) { flag_merge_constants = 0; diff -upd -r gcc-clean/gcc/passes.c gcc/gcc/passes.c --- gcc-clean/gcc/passes.c 2006-03-10 01:34:16.000000000 +0300 +++ gcc/gcc/passes.c 2006-03-14 13:12:56.000000000 +0300 @@ -580,6 +580,12 @@ init_optimization_passes (void) NEXT_PASS (pass_tail_calls); NEXT_PASS (pass_rename_ssa_copies); NEXT_PASS (pass_uncprop); + /* ??? We need this additional aliasing pass to be able to provide correct + alias information for rtl level, after all tree optimizations have been + completed. Unfortunately, the mainline up to March 2006 was failed to + bootstrap with pass_may_alias after pass_iv_optimize due to possible + "bug" in the latter pass. */ +/* NEXT_PASS (pass_may_alias);*/ NEXT_PASS (pass_del_ssa); NEXT_PASS (pass_nrv); NEXT_PASS (pass_mark_used_blocks); diff -upd -r gcc-clean/gcc/print-rtl.c gcc/gcc/print-rtl.c --- gcc-clean/gcc/print-rtl.c 2006-03-10 01:34:10.000000000 +0300 +++ gcc/gcc/print-rtl.c 2006-03-12 01:38:12.000000000 +0300 @@ -32,6 +32,7 @@ Software Foundation, 51 Franklin Street, #include "coretypes.h" #include "tm.h" #include "rtl.h" +#include "diagnostic.h" /* These headers all define things which are not available in generator programs. */ @@ -562,7 +563,20 @@ print_rtx (rtx in_rtx) { #ifndef GENERATOR_FILE case MEM: - fprintf (outfile, " [" HOST_WIDE_INT_PRINT_DEC, MEM_ALIAS_SET (in_rtx)); + if (!extended_alias_set_p (MEM_ALIAS_SET (in_rtx))) + { + fprintf (outfile, " [" HOST_WIDE_INT_PRINT_DEC, + MEM_ALIAS_SET (in_rtx)); + } + else + { + fprintf (outfile, " [" HOST_WIDE_INT_PRINT_DEC " {part:" \ + HOST_WIDE_INT_PRINT_DEC " orig: " HOST_WIDE_INT_PRINT_DEC \ + "} ", MEM_ALIAS_SET (in_rtx), + get_extended_alias_set_part_num (MEM_ALIAS_SET (in_rtx)), + get_original_alias_set (MEM_ALIAS_SET (in_rtx))); + } + if (MEM_EXPR (in_rtx)) print_mem_expr (outfile, MEM_EXPR (in_rtx)); diff -upd -r gcc-clean/gcc/rtl.h gcc/gcc/rtl.h --- gcc-clean/gcc/rtl.h 2006-03-10 01:34:15.000000000 +0300 +++ gcc/gcc/rtl.h 2006-03-14 18:33:03.000000000 +0300 @@ -144,6 +144,7 @@ typedef struct mem_attrs GTY(()) rtx offset; /* Offset from start of DECL, as CONST_INT. */ rtx size; /* Size in bytes, as a CONST_INT. */ unsigned int align; /* Alignment of MEM in bits. */ + tree orig_expr; /* Explicit original tree expression. */ } mem_attrs; /* Structure used to describe the attributes of a REG in similar way as @@ -1183,6 +1184,11 @@ do { \ : (STRICT_ALIGNMENT && GET_MODE (RTX) != BLKmode \ ? GET_MODE_ALIGNMENT (GET_MODE (RTX)) : BITS_PER_UNIT)) +/* For a MEM rtx, the decl it is known to refer to, if it is known to + refer to part of a DECL. It may also be a COMPONENT_REF. */ +#define MEM_ORIG_EXPR(RTX) \ +(MEM_ATTRS (RTX) == 0 ? 0 : MEM_ATTRS (RTX)->orig_expr) + /* For a REG rtx, the decl it is known to refer to, if it is known to refer to part of a DECL. */ #define REG_EXPR(RTX) (REG_ATTRS (RTX) == 0 ? 0 : REG_ATTRS (RTX)->decl) @@ -2223,6 +2229,9 @@ extern int read_rtx_lineno; /* In alias.c */ extern void clear_reg_alias_info (rtx); +extern tree tse_mem_expr (rtx); +extern tree skip_conversions (tree); + extern rtx canon_rtx (rtx); extern int true_dependence (rtx, enum machine_mode, rtx, int (*)(rtx, int)); extern rtx get_addr (rtx); diff -upd -r gcc-clean/gcc/tree-flow.h gcc/gcc/tree-flow.h --- gcc-clean/gcc/tree-flow.h 2006-03-10 01:34:16.000000000 +0300 +++ gcc/gcc/tree-flow.h 2006-03-10 16:04:47.000000000 +0300 @@ -153,6 +153,49 @@ struct subvar GTY(()) subvar_t next; }; +/* Structure where points-to set for alias export is saved. */ +struct tse_pts_entry GTY (()) +{ + /* Original tree. */ + tree ptr; + + /* Pointer's may_aliases - bitmap of trees that can be pointed to by the + pointer. */ + bitmap may_aliases; + + /* True, if this pointer may point to anything. In this case points-to + set may not be used for disambiguation, only in weak dependence + heuristics. */ + bool pt_anything; +}; + +typedef struct tse_pts_entry *pts_entry_ptr; + +/* Structure for saving tree-ssa aliasing export information. */ +struct tse_alias_info_entry GTY(()) +{ + /* Points-to set. */ + pts_entry_ptr points_to; + + /* Saved stack partition number. */ + int stack_part_num; +}; + +typedef struct tse_alias_info_entry *tse_alias_info_entry_t; + +/* Structure for saving extended alias set partitions. */ +struct ext_alias_set_partition GTY(()) +{ + /* Joint may aliases set for all pointers in this partition. */ + bitmap may_aliases; + + /* Joint set of stack partitions for all variables that are in the + partition. */ + bitmap stack_partitions; +}; + +typedef struct ext_alias_set_partition * ext_alias_set_partition_p; + struct var_ann_d GTY(()) { struct tree_ann_common_d common; @@ -211,6 +254,9 @@ struct var_ann_d GTY(()) /* Mask of values saying the reasons why this variable has escaped the function. */ unsigned int escape_mask; + + /* Alias export information. */ + tse_alias_info_entry_t alias_info; }; struct function_ann_d GTY(()) @@ -533,6 +579,9 @@ extern void end_recording_case_labels (v extern basic_block move_sese_region_to_fn (struct function *, basic_block, basic_block); +/* In tree-outof-ssa.c. */ +extern tse_alias_info_entry_t tse_create_alias_info_entry (void); + /* In tree-cfgcleanup.c */ extern bool cleanup_tree_cfg (void); extern void cleanup_tree_cfg_loop (void); @@ -933,6 +982,12 @@ void sort_fieldstack (VEC(fieldoff_s,hea void init_alias_heapvars (void); void delete_alias_heapvars (void); +extern pts_entry_ptr tse_get_pts_for_expr (tree expr, bool weak_deps); +extern int tse_get_stack_var_partition (tree var); +extern bool tse_different_stack_vars_partitions_p (tree var1, tree var2); +extern bool tse_var_in_pts_p (tree, pts_entry_ptr); +extern void tse_add_tree_to_pts(tree, pts_entry_ptr); + #include "tree-flow-inline.h" void swap_tree_operands (tree, tree *, tree *); diff -upd -r gcc-clean/gcc/tree.h gcc/gcc/tree.h --- gcc-clean/gcc/tree.h 2006-03-10 01:32:36.000000000 +0300 +++ gcc/gcc/tree.h 2006-03-12 01:37:07.000000000 +0300 @@ -4226,6 +4226,11 @@ extern tree strip_float_extensions (tree /* In alias.c */ extern void record_component_aliases (tree); extern HOST_WIDE_INT get_alias_set (tree); +extern HOST_WIDE_INT get_extended_alias_set (tree); +extern HOST_WIDE_INT get_original_alias_set (HOST_WIDE_INT); +extern HOST_WIDE_INT get_extended_alias_set_part_num (HOST_WIDE_INT); +extern bool extended_alias_set_p (HOST_WIDE_INT set); + extern int alias_sets_conflict_p (HOST_WIDE_INT, HOST_WIDE_INT); extern int alias_sets_might_conflict_p (HOST_WIDE_INT, HOST_WIDE_INT); extern int objects_must_conflict_p (tree, tree); diff -upd -r gcc-clean/gcc/tree-outof-ssa.c gcc/gcc/tree-outof-ssa.c --- gcc-clean/gcc/tree-outof-ssa.c 2006-03-10 01:34:15.000000000 +0300 +++ gcc/gcc/tree-outof-ssa.c 2006-03-13 21:05:48.000000000 +0300 @@ -347,6 +347,146 @@ do { \ } \ } while (0) +/* Creates new points-to entry. */ + +static pts_entry_ptr +tse_create_pts_entry (tree ptr) +{ + pts_entry_ptr p = ggc_alloc (sizeof (struct tse_pts_entry)); + + p->ptr = ptr; + p->pt_anything = false; + + p->may_aliases = BITMAP_GGC_ALLOC (); + + return p; +} + +/* Creates new entry for saving alias information. */ + +tse_alias_info_entry_t +tse_create_alias_info_entry (void) +{ + tse_alias_info_entry_t p = ggc_alloc (sizeof (struct tse_alias_info_entry)); + + p->points_to = NULL; + p->stack_part_num = -1; + + return p; +} + +/* Saves PTR's points-to in its var_ann. */ + +static void +tse_update_var_ann_with_pts_info (tree ptr, struct ptr_info_def *pi) +{ + pts_entry_ptr entry; + unsigned ix; + bitmap_iterator bi; + var_ann_t ptr_ann; + + ptr_ann = var_ann (ptr); + gcc_assert (ptr_ann); + + if (ptr_ann->alias_info == NULL) + ptr_ann->alias_info = tse_create_alias_info_entry (); + + if (ptr_ann->alias_info->points_to == NULL) + entry = tse_create_pts_entry (ptr); + else + entry = ptr_ann->alias_info->points_to; + + gcc_assert (entry); + + /* Set pt_anything for the whole set, if one ssa version var has + pt_anything attr set to true. We can use it for recognizing weak deps. */ + if (!pi->pt_vars || bitmap_empty_p (pi->pt_vars) || pi->pt_anything) + entry->pt_anything = true; + + if (pi->pt_vars && !bitmap_empty_p (pi->pt_vars)) + { + EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, ix, bi) + { + tree t1 = referenced_var (ix); + + /* Don't add duplicate entries. */ + if (! tse_var_in_pts_p (t1, entry)) + { + gcc_assert (var_ann (t1)); + if (TREE_CODE (t1) != SYMBOL_MEMORY_TAG) + tse_add_tree_to_pts (t1, entry); + else + entry->pt_anything = true; + } + } + } + + ptr_ann->alias_info->points_to = entry; +} + + +/* Save pointer and its points-to information in the variable annotations + for future use on the rtl level. */ + +static void +tse_export_one_ptr (var_map map, tree ptr) +{ + struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr); + if (pi) + { + tree mapped_ptr = var_to_partition_to_var (map, ptr); + + if (mapped_ptr) + tse_update_var_ann_with_pts_info (mapped_ptr, pi); + } +} + +/* Save tree-ssa pointer analysis information for the rtl level. */ + +static void +tse_export_alias_info (var_map map) +{ + basic_block bb; + block_stmt_iterator si; + ssa_op_iter iter; + tree var; + referenced_var_iterator rvi; + + /* First traverse all default definitions of + pointer variables. This is necessary because default definitions are + not part of the code. */ + FOR_EACH_REFERENCED_VAR (var, rvi) + { + if (POINTER_TYPE_P (TREE_TYPE (var))) + { + tree def = default_def (var); + if (def) + tse_export_one_ptr (map, def); + } + } + + /* Loop through all pointers defined in the program. */ + FOR_EACH_BB (bb) + { + tree phi; + + for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi)) + { + tree ptr = PHI_RESULT (phi); + if (POINTER_TYPE_P (TREE_TYPE (ptr))) + tse_export_one_ptr (map, ptr); + } + + for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si)) + { + tree stmt = bsi_stmt (si); + tree def; + FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF) + if (POINTER_TYPE_P (TREE_TYPE (def))) + tse_export_one_ptr (map, def); + } + } +} /* Add T to elimination graph G. */ @@ -2391,6 +2531,15 @@ remove_ssa_form (var_map map, int flags) if (liveinfo) delete_tree_live_info (liveinfo); + if (flag_propagate_points_to_sets || flag_propagate_alias_sets) + { + cfun->ext_alias_set_partitions = NULL; + cfun->ext_alias_set_to_original = NULL; + cfun->ext_alias_set_to_partition = NULL; + tse_export_alias_info (map); + cfun->tse_export_done = true; + } + rewrite_trees (map, values); if (values) diff -upd -r gcc-clean/gcc/tree-ssa.c gcc/gcc/tree-ssa.c --- gcc-clean/gcc/tree-ssa.c 2006-03-10 01:34:15.000000000 +0300 +++ gcc/gcc/tree-ssa.c 2006-03-10 16:04:47.000000000 +0300 @@ -810,8 +810,6 @@ delete_tree_ssa (void) size_t i; basic_block bb; block_stmt_iterator bsi; - referenced_var_iterator rvi; - tree var; /* Release any ssa_names still in use. */ for (i = 0; i < num_ssa_names; i++) @@ -840,15 +838,6 @@ delete_tree_ssa (void) set_phi_nodes (bb, NULL); } - /* Remove annotations from every referenced variable. */ - FOR_EACH_REFERENCED_VAR (var, rvi) - { - ggc_free (var->common.ann); - var->common.ann = NULL; - } - htab_delete (referenced_vars); - referenced_vars = NULL; - fini_ssanames (); fini_phinodes ();