diff options
Diffstat (limited to 'gcc/tree-sra.c')
-rw-r--r-- | gcc/tree-sra.c | 93 |
1 files changed, 56 insertions, 37 deletions
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c index 8d4dc90d179..1a0622ef8eb 100644 --- a/gcc/tree-sra.c +++ b/gcc/tree-sra.c @@ -1039,7 +1039,7 @@ build_ref_for_offset_1 (tree *res, tree type, HOST_WIDE_INT offset, while (1) { tree fld; - tree tr_size, index; + tree tr_size, index, minidx; HOST_WIDE_INT el_size; if (offset == 0 && exp_type @@ -1090,13 +1090,14 @@ build_ref_for_offset_1 (tree *res, tree type, HOST_WIDE_INT offset, return false; el_size = tree_low_cst (tr_size, 1); + minidx = TYPE_MIN_VALUE (TYPE_DOMAIN (type)); + if (TREE_CODE (minidx) != INTEGER_CST) + return false; if (res) { index = build_int_cst (TYPE_DOMAIN (type), offset / el_size); - if (!integer_zerop (TYPE_MIN_VALUE (TYPE_DOMAIN (type)))) - index = int_const_binop (PLUS_EXPR, index, - TYPE_MIN_VALUE (TYPE_DOMAIN (type)), - 0); + if (!integer_zerop (minidx)) + index = int_const_binop (PLUS_EXPR, index, minidx, 0); *res = build4 (ARRAY_REF, TREE_TYPE (type), *res, index, NULL_TREE, NULL_TREE); } @@ -1164,7 +1165,13 @@ find_var_candidates (void) || !COMPLETE_TYPE_P (type) || !host_integerp (TYPE_SIZE (type), 1) || tree_low_cst (TYPE_SIZE (type), 1) == 0 - || type_internals_preclude_sra_p (type)) + || type_internals_preclude_sra_p (type) + /* Fix for PR 41089. tree-stdarg.c needs to have va_lists intact but + we also want to schedule it rather late. Thus we ignore it in + the early pass. */ + || (sra_mode == SRA_MODE_EARLY_INTRA + && (TYPE_MAIN_VARIANT (TREE_TYPE (var)) + == TYPE_MAIN_VARIANT (va_list_type_node)))) continue; bitmap_set_bit (candidate_bitmap, DECL_UID (var)); @@ -1378,6 +1385,22 @@ build_access_trees (struct access *access) } } +/* Return true if expr contains some ARRAY_REFs into a variable bounded + array. */ + +static bool +expr_with_var_bounded_array_refs_p (tree expr) +{ + while (handled_component_p (expr)) + { + if (TREE_CODE (expr) == ARRAY_REF + && !host_integerp (array_ref_low_bound (expr), 0)) + return true; + expr = TREE_OPERAND (expr, 0); + } + return false; +} + /* Analyze the subtree of accesses rooted in ROOT, scheduling replacements when both seeming beneficial and when ALLOW_REPLACEMENTS allows it. Also set all sorts of access flags appropriately along the way, notably always ser @@ -1407,6 +1430,9 @@ analyze_access_subtree (struct access *root, bool allow_replacements, if (root->grp_unscalarizable_region) allow_replacements = false; + if (allow_replacements && expr_with_var_bounded_array_refs_p (root->expr)) + allow_replacements = false; + for (child = root->first_child; child; child = child->next_sibling) { if (!hole && child->offset < covered_to) @@ -1496,31 +1522,11 @@ child_would_conflict_in_lacc (struct access *lacc, HOST_WIDE_INT norm_offset, return false; } -/* Set the expr of TARGET to one just like MODEL but with is own base at the - bottom of the handled components. */ - -static void -duplicate_expr_for_different_base (struct access *target, - struct access *model) -{ - tree t, expr = unshare_expr (model->expr); - - gcc_assert (handled_component_p (expr)); - t = expr; - while (handled_component_p (TREE_OPERAND (t, 0))) - t = TREE_OPERAND (t, 0); - gcc_assert (TREE_OPERAND (t, 0) == model->base); - TREE_OPERAND (t, 0) = target->base; - - target->expr = expr; -} - - /* Create a new child access of PARENT, with all properties just like MODEL except for its offset and with its grp_write false and grp_read true. - Return the new access. Note that this access is created long after all - splicing and sorting, it's not located in any access vector and is - automatically a representative of its group. */ + Return the new access or NULL if it cannot be created. Note that this access + is created long after all splicing and sorting, it's not located in any + access vector and is automatically a representative of its group. */ static struct access * create_artificial_child_access (struct access *parent, struct access *model, @@ -1528,15 +1534,20 @@ create_artificial_child_access (struct access *parent, struct access *model, { struct access *access; struct access **child; + tree expr = parent->base;; gcc_assert (!model->grp_unscalarizable_region); + if (!build_ref_for_offset (&expr, TREE_TYPE (expr), new_offset, + model->type, false)) + return NULL; + access = (struct access *) pool_alloc (access_pool); memset (access, 0, sizeof (struct access)); access->base = parent->base; + access->expr = expr; access->offset = new_offset; access->size = model->size; - duplicate_expr_for_different_base (access, model); access->type = model->type; access->grp_write = true; access->grp_read = false; @@ -1554,7 +1565,7 @@ create_artificial_child_access (struct access *parent, struct access *model, /* Propagate all subaccesses of RACC across an assignment link to LACC. Return true if any new subaccess was created. Additionally, if RACC is a scalar - access but LACC is not, change the type of the latter. */ + access but LACC is not, change the type of the latter, if possible. */ static bool propagate_subacesses_accross_link (struct access *lacc, struct access *racc) @@ -1571,8 +1582,14 @@ propagate_subacesses_accross_link (struct access *lacc, struct access *racc) if (!lacc->first_child && !racc->first_child && is_gimple_reg_type (racc->type)) { - duplicate_expr_for_different_base (lacc, racc); - lacc->type = racc->type; + tree t = lacc->base; + + if (build_ref_for_offset (&t, TREE_TYPE (t), lacc->offset, racc->type, + false)) + { + lacc->expr = t; + lacc->type = racc->type; + } return false; } @@ -1606,10 +1623,12 @@ propagate_subacesses_accross_link (struct access *lacc, struct access *racc) rchild->grp_hint = 1; new_acc = create_artificial_child_access (lacc, rchild, norm_offset); - if (racc->first_child) - propagate_subacesses_accross_link (new_acc, rchild); - - ret = true; + if (new_acc) + { + ret = true; + if (racc->first_child) + propagate_subacesses_accross_link (new_acc, rchild); + } } return ret; |