@@ -719,5 +719,8 @@ tree build_ref_for_offset (location_t, tree, HOST_WIDE_INT, tree,
gimple_stmt_iterator *, bool);
bool ipa_sra_modify_function_body (ipa_parm_adjustment_vec);
bool sra_ipa_modify_expr (tree *, bool, ipa_parm_adjustment_vec);
+ipa_parm_adjustment *sra_ipa_get_adjustment_candidate (tree *&, bool *,
+ ipa_parm_adjustment_vec,
+ bool);
#endif /* IPA_PROP_H */
@@ -11049,33 +11049,81 @@ simd_clone_init_simd_arrays (struct cgraph_node *node,
return seq;
}
+/* Callback info for ipa_simd_modify_stmt_ops below. */
+
+struct modify_stmt_info {
+ ipa_parm_adjustment_vec adjustments;
+ gimple stmt;
+ /* True if the parent statement was modified by
+ ipa_simd_modify_stmt_ops. */
+ bool modified;
+};
+
+/* Callback for walk_gimple_op.
+
+ Adjust operands from a given statement as specified in the
+ adjustments vector in the callback data. */
+
static tree
-ipa_simd_modify_function_body_ops_1 (tree *tp, int *walk_subtrees, void *data)
+ipa_simd_modify_stmt_ops (tree *tp,
+ int *walk_subtrees ATTRIBUTE_UNUSED,
+ void *data)
{
struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
- ipa_parm_adjustment_vec *adjustments = (ipa_parm_adjustment_vec *) wi->info;
+ if (!SSA_VAR_P (*tp))
+ {
+ /* Make sure we treat subtrees as a RHS. This makes sure that
+ when examining the `*foo' in *foo=x, the `foo' get treated as
+ a use properly. */
+ wi->is_lhs = false;
+ wi->val_only = true;
+ return NULL_TREE;
+ }
+ struct modify_stmt_info *info = (struct modify_stmt_info *) wi->info;
+ struct ipa_parm_adjustment *cand
+ = sra_ipa_get_adjustment_candidate (tp, NULL, info->adjustments, true);
+ if (!cand)
+ return NULL_TREE;
+
tree t = *tp;
+ tree repl = make_ssa_name (create_tmp_var (TREE_TYPE (t), NULL), NULL);
- if (DECL_P (t) || TREE_CODE (t) == SSA_NAME)
- return (tree) sra_ipa_modify_expr (tp, true, *adjustments);
+ gimple stmt;
+ gimple_stmt_iterator gsi = gsi_for_stmt (info->stmt);
+ if (wi->is_lhs)
+ {
+ stmt = gimple_build_assign (unshare_expr (cand->reduction), repl);
+ gsi_insert_after (&gsi, stmt, GSI_SAME_STMT);
+ SSA_NAME_DEF_STMT (repl) = info->stmt;
+ }
else
- *walk_subtrees = 1;
- return NULL_TREE;
-}
+ {
+ /* You'd think we could skip the extra SSA variable when
+ wi->val_only=true, but we may have `*var' which will get
+ replaced into `*var_array[iter]' and will likely be something
+ not gimple. */
+ stmt = gimple_build_assign (repl, unshare_expr (cand->reduction));
+ gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
+ }
-/* Helper function for ipa_simd_modify_function_body. Make any
- necessary adjustments for tree operators. */
+ if (!useless_type_conversion_p (TREE_TYPE (*tp), TREE_TYPE (repl)))
+ {
+ tree vce = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (*tp), repl);
+ *tp = vce;
+ }
+ else
+ *tp = repl;
-static bool
-ipa_simd_modify_function_body_ops (tree *tp,
- ipa_parm_adjustment_vec *adjustments)
-{
- struct walk_stmt_info wi;
- memset (&wi, 0, sizeof (wi));
- wi.info = adjustments;
- bool res = (bool) walk_tree (tp, ipa_simd_modify_function_body_ops_1,
- &wi, NULL);
- return res;
+ /* We have modified in place; update the SSA operands. */
+ info->modified = false;
+ stmt = info->stmt;
+ update_stmt (stmt);
+ if (maybe_clean_eh_stmt (stmt))
+ gimple_purge_dead_eh_edges (gimple_bb (stmt));
+
+ wi->is_lhs = false;
+ wi->val_only = true;
+ return NULL_TREE;
}
/* Traverse the function body and perform all modifications as
@@ -11111,6 +11159,9 @@ ipa_simd_modify_function_body (struct cgraph_node *node,
NULL_TREE, NULL_TREE);
}
+ struct modify_stmt_info info;
+ info.adjustments = adjustments;
+
FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
{
gimple_stmt_iterator gsi;
@@ -11119,9 +11170,13 @@ ipa_simd_modify_function_body (struct cgraph_node *node,
while (!gsi_end_p (gsi))
{
gimple stmt = gsi_stmt (gsi);
+ info.stmt = stmt;
bool modified = false;
- tree *t;
- unsigned i;
+ struct walk_stmt_info wi;
+
+ memset (&wi, 0, sizeof (wi));
+ info.modified = false;
+ wi.info = &info;
switch (gimple_code (stmt))
{
@@ -11147,56 +11202,9 @@ ipa_simd_modify_function_body (struct cgraph_node *node,
break;
}
- case GIMPLE_ASSIGN:
- t = gimple_assign_lhs_ptr (stmt);
- modified |= sra_ipa_modify_expr (t, false, adjustments);
-
- /* The LHS may have operands that also need adjusting
- (e.g. `foo' in array[foo]). */
- modified |= ipa_simd_modify_function_body_ops (t, &adjustments);
-
- for (i = 0; i < gimple_num_ops (stmt); ++i)
- {
- t = gimple_op_ptr (stmt, i);
- modified |= sra_ipa_modify_expr (t, false, adjustments);
- }
- break;
-
- case GIMPLE_CALL:
- /* Operands must be processed before the lhs. */
- for (i = 0; i < gimple_call_num_args (stmt); i++)
- {
- t = gimple_call_arg_ptr (stmt, i);
- modified |= sra_ipa_modify_expr (t, true, adjustments);
- }
-
- if (gimple_call_lhs (stmt))
- {
- t = gimple_call_lhs_ptr (stmt);
- modified |= sra_ipa_modify_expr (t, false, adjustments);
- }
- break;
-
- case GIMPLE_ASM:
- for (i = 0; i < gimple_asm_ninputs (stmt); i++)
- {
- t = &TREE_VALUE (gimple_asm_input_op (stmt, i));
- modified |= sra_ipa_modify_expr (t, true, adjustments);
- }
- for (i = 0; i < gimple_asm_noutputs (stmt); i++)
- {
- t = &TREE_VALUE (gimple_asm_output_op (stmt, i));
- modified |= sra_ipa_modify_expr (t, false, adjustments);
- }
- break;
-
default:
- for (i = 0; i < gimple_num_ops (stmt); ++i)
- {
- t = gimple_op_ptr (stmt, i);
- if (*t)
- modified |= sra_ipa_modify_expr (t, true, adjustments);
- }
+ walk_gimple_op (stmt, ipa_simd_modify_stmt_ops, &wi);
+ modified |= info.modified;
break;
}
new file mode 100644
@@ -0,0 +1,16 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fopenmp -w" } */
+
+int array[1000];
+
+#pragma omp declare simd notinbranch simdlen(4)
+void foo (int *a, int b)
+{
+ a[b] = 555;
+}
+
+#pragma omp declare simd notinbranch simdlen(4)
+void bar (int *a)
+{
+ *a = 555;
+}
@@ -785,15 +785,17 @@ type_internals_preclude_sra_p (tree type, const char **msg)
}
}
-/* If T is an SSA_NAME, return NULL if it is not a default def or return its
- base variable if it is. Return T if it is not an SSA_NAME. */
+/* If T is an SSA_NAME, return NULL if it is not a default def or
+ return its base variable if it is. If IGNORE_DEFAULT_DEF is true,
+ the base variable is always returned, regardless if it is a default
+ def. Return T if it is not an SSA_NAME. */
static tree
-get_ssa_base_param (tree t)
+get_ssa_base_param (tree t, bool ignore_default_def)
{
if (TREE_CODE (t) == SSA_NAME)
{
- if (SSA_NAME_IS_DEFAULT_DEF (t))
+ if (ignore_default_def || SSA_NAME_IS_DEFAULT_DEF (t))
return SSA_NAME_VAR (t);
else
return NULL_TREE;
@@ -874,7 +876,7 @@ create_access (tree expr, gimple stmt, bool write)
if (sra_mode == SRA_MODE_EARLY_IPA
&& TREE_CODE (base) == MEM_REF)
{
- base = get_ssa_base_param (TREE_OPERAND (base, 0));
+ base = get_ssa_base_param (TREE_OPERAND (base, 0), false);
if (!base)
return NULL;
ptr = true;
@@ -1039,7 +1041,7 @@ disqualify_base_of_expr (tree t, const char *reason)
t = get_base_address (t);
if (sra_mode == SRA_MODE_EARLY_IPA
&& TREE_CODE (t) == MEM_REF)
- t = get_ssa_base_param (TREE_OPERAND (t, 0));
+ t = get_ssa_base_param (TREE_OPERAND (t, 0), false);
if (t && DECL_P (t))
disqualify_candidate (t, reason);
@@ -4485,35 +4487,35 @@ replace_removed_params_ssa_names (gimple stmt,
return true;
}
-/* If the expression *EXPR should be replaced by a reduction of a parameter, do
- so. ADJUSTMENTS is a pointer to a vector of adjustments. CONVERT
- specifies whether the function should care about type incompatibility the
- current and new expressions. If it is false, the function will leave
- incompatibility issues to the caller. Return true iff the expression
- was modified. */
+/* Given an expression, return an adjustment entry specifying the
+ transformation to be done on EXPR. If no suitable adjustment entry
+ was found, returns NULL.
-bool
-sra_ipa_modify_expr (tree *expr, bool convert,
- ipa_parm_adjustment_vec adjustments)
-{
- int i, len;
- struct ipa_parm_adjustment *adj, *cand = NULL;
- HOST_WIDE_INT offset, size, max_size;
- tree base, src;
+ If IGNORE_DEFAULT_DEF is set, consider SSA_NAMEs which are not a
+ default def, otherwise bail on them.
- len = adjustments.length ();
+ If CONVERT is non-NULL, this function will set *CONVERT if the
+ expression provided is a component reference that must be converted
+ upon return. ADJUSTMENTS is the adjustments vector. */
+ipa_parm_adjustment *
+sra_ipa_get_adjustment_candidate (tree *&expr, bool *convert,
+ ipa_parm_adjustment_vec adjustments,
+ bool ignore_default_def)
+{
if (TREE_CODE (*expr) == BIT_FIELD_REF
|| TREE_CODE (*expr) == IMAGPART_EXPR
|| TREE_CODE (*expr) == REALPART_EXPR)
{
expr = &TREE_OPERAND (*expr, 0);
- convert = true;
+ if (convert)
+ *convert = true;
}
- base = get_ref_base_and_extent (*expr, &offset, &size, &max_size);
+ HOST_WIDE_INT offset, size, max_size;
+ tree base = get_ref_base_and_extent (*expr, &offset, &size, &max_size);
if (!base || size == -1 || max_size == -1)
- return false;
+ return NULL;
if (TREE_CODE (base) == MEM_REF)
{
@@ -4521,13 +4523,15 @@ sra_ipa_modify_expr (tree *expr, bool convert,
base = TREE_OPERAND (base, 0);
}
- base = get_ssa_base_param (base);
+ base = get_ssa_base_param (base, ignore_default_def);
if (!base || TREE_CODE (base) != PARM_DECL)
- return false;
+ return NULL;
- for (i = 0; i < len; i++)
+ struct ipa_parm_adjustment *cand = NULL;
+ unsigned int len = adjustments.length ();
+ for (unsigned i = 0; i < len; i++)
{
- adj = &adjustments[i];
+ struct ipa_parm_adjustment *adj = &adjustments[i];
if (adj->base == base
&& (adj->offset == offset || adj->remove_param))
@@ -4536,9 +4540,29 @@ sra_ipa_modify_expr (tree *expr, bool convert,
break;
}
}
+
if (!cand || cand->copy_param || cand->remove_param)
+ return NULL;
+ return cand;
+}
+
+/* If the expression *EXPR should be replaced by a reduction of a parameter, do
+ so. ADJUSTMENTS is a pointer to a vector of adjustments. CONVERT
+ specifies whether the function should care about type incompatibility the
+ current and new expressions. If it is false, the function will leave
+ incompatibility issues to the caller. Return true iff the expression
+ was modified. */
+
+bool
+sra_ipa_modify_expr (tree *expr, bool convert,
+ ipa_parm_adjustment_vec adjustments)
+{
+ struct ipa_parm_adjustment *cand
+ = sra_ipa_get_adjustment_candidate (expr, &convert, adjustments, false);
+ if (!cand)
return false;
+ tree src;
if (cand->by_ref)
src = build_simple_mem_ref (cand->reduction);
else