annotations up-to-date.
We require that for any copy operation where the RHS and LHS have
- a non-null memory tag that the memory tag be the same. It is OK
+ a non-null memory tag the memory tag be the same. It is OK
for one or both of the memory tags to be NULL.
We also require tracking if a variable is dereferenced in a load or
/* FIXME. GIMPLE is allowing pointer assignments and comparisons of
pointers that have different alias sets. This means that these
pointers will have different memory tags associated to them.
-
+
If we allow copy propagation in these cases, statements de-referencing
the new pointer will now have a reference to a different memory tag
with potentially incorrect SSA information.
tree mt_orig = var_ann (SSA_NAME_VAR (orig))->type_mem_tag;
if (mt_dest && mt_orig && mt_dest != mt_orig)
return false;
+ else if (!lang_hooks.types_compatible_p (type_d, type_o))
+ return false;
+ else if (get_alias_set (TREE_TYPE (type_d)) !=
+ get_alias_set (TREE_TYPE (type_o)))
+ return false;
}
/* If the destination is a SSA_NAME for a virtual operand, then we have
#ifdef ENABLE_CHECKING
/* If we have one real and one virtual operand, then something has
gone terribly wrong. */
- if (is_gimple_reg (orig))
- abort ();
+ gcc_assert (!is_gimple_reg (orig));
#endif
}
&& SSA_NAME_OCCURS_IN_ABNORMAL_PHI (orig))
return false;
- /* If DEST is an SSA_NAME that flows from an abnormal edge or if it
- represents a hard register, then it cannot be replaced. */
+ /* If DEST is an SSA_NAME that flows from an abnormal edge, then it
+ cannot be replaced. */
if (TREE_CODE (dest) == SSA_NAME
- && (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (dest)
- || DECL_HARD_REGISTER (SSA_NAME_VAR (dest))))
+ && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (dest))
return false;
/* Anything else is OK. */
return true;
}
-/* Given two SSA_NAMEs, replace the annotations for the one referred to by OP
- with VAR's annotations.
+/* Similarly, but we know that we're propagating into an ASM_EXPR. */
+
+bool
+may_propagate_copy_into_asm (tree dest)
+{
+ /* Hard register operands of asms are special. Do not bypass. */
+ return !(TREE_CODE (dest) == SSA_NAME
+ && TREE_CODE (SSA_NAME_VAR (dest)) == VAR_DECL
+ && DECL_HARD_REGISTER (SSA_NAME_VAR (dest)));
+}
- If OP is a pointer, copy the memory tag used originally by OP into
- VAR. This is needed in cases where VAR had never been dereferenced in the
- program.
- If FOR_PROPAGATION is true, then perform additional checks to ensure
- that const/copy propagation of var for OP is valid. */
-
+/* Given two SSA_NAMEs pointers ORIG and NEW such that we are copy
+ propagating NEW into ORIG, consolidate aliasing information so that
+ they both share the same memory tags. */
+
static void
-replace_ssa_names_ann (tree op,
- tree var,
- bool for_propagation ATTRIBUTE_UNUSED)
+merge_alias_info (tree orig, tree new)
{
+ tree new_sym = SSA_NAME_VAR (new);
+ tree orig_sym = SSA_NAME_VAR (orig);
+ var_ann_t new_ann = var_ann (new_sym);
+ var_ann_t orig_ann = var_ann (orig_sym);
+ struct ptr_info_def *orig_ptr_info;
+
+ gcc_assert (POINTER_TYPE_P (TREE_TYPE (orig)));
+ gcc_assert (POINTER_TYPE_P (TREE_TYPE (new)));
#if defined ENABLE_CHECKING
- if (for_propagation && !may_propagate_copy (op, var))
- abort ();
+ gcc_assert (lang_hooks.types_compatible_p (TREE_TYPE (orig),
+ TREE_TYPE (new)));
+
+ /* If the pointed-to alias sets are different, these two pointers
+ would never have the same memory tag. In this case, NEW should
+ not have been propagated into ORIG. */
+ gcc_assert (get_alias_set (TREE_TYPE (TREE_TYPE (new_sym)))
+ == get_alias_set (TREE_TYPE (TREE_TYPE (orig_sym))));
#endif
- /* If VAR doesn't have a memory tag, copy the one from the original
- operand. Also copy the dereferenced flags. */
- if (POINTER_TYPE_P (TREE_TYPE (op)))
+ /* Synchronize the type tags. If both pointers had a tag and they
+ are different, then something has gone wrong. */
+ if (new_ann->type_mem_tag == NULL_TREE)
+ new_ann->type_mem_tag = orig_ann->type_mem_tag;
+ else if (orig_ann->type_mem_tag == NULL_TREE)
+ orig_ann->type_mem_tag = new_ann->type_mem_tag;
+ else
+ gcc_assert (new_ann->type_mem_tag == orig_ann->type_mem_tag);
+
+ orig_ptr_info = SSA_NAME_PTR_INFO (orig);
+ if (orig_ptr_info && orig_ptr_info->name_mem_tag)
{
- var_ann_t new_ann = var_ann (SSA_NAME_VAR (var));
- var_ann_t orig_ann = var_ann (SSA_NAME_VAR (op));
-
- if (new_ann->type_mem_tag == NULL_TREE)
- new_ann->type_mem_tag = orig_ann->type_mem_tag;
- else if (orig_ann->type_mem_tag == NULL_TREE)
- orig_ann->type_mem_tag = new_ann->type_mem_tag;
- else if (new_ann->type_mem_tag != orig_ann->type_mem_tag)
- abort ();
- }
+ struct ptr_info_def *new_ptr_info = get_ptr_info (new);
+ if (new_ptr_info->name_mem_tag == NULL_TREE)
+ {
+ /* If ORIG had a name tag, it means that was dereferenced in
+ the code, and since pointer NEW will now replace every
+ occurrence of ORIG, we have to make sure that NEW has an
+ appropriate tag. If, NEW did not have a name tag, get it
+ from ORIG. */
+ memcpy (new_ptr_info, orig_ptr_info, sizeof (*new_ptr_info));
+ new_ptr_info->pt_vars = BITMAP_GGC_ALLOC ();
+ bitmap_copy (new_ptr_info->pt_vars, orig_ptr_info->pt_vars);
+ new_ptr_info->name_mem_tag = orig_ptr_info->name_mem_tag;
+ }
+ else
+ {
+ /* If NEW already had a name tag, nothing needs to be done.
+ Note that pointer NEW may actually have a different set of
+ pointed-to variables.
+
+ However, since NEW is being copy-propagated into ORIG, it must
+ always be true that the pointed-to set for pointer NEW is the
+ same, or a subset, of the pointed-to set for pointer ORIG. If
+ this isn't the case, we shouldn't have been able to do the
+ propagation of NEW into ORIG. */
+#if defined ENABLE_CHECKING
+ if (orig_ptr_info->pt_vars && new_ptr_info->pt_vars)
+ gcc_assert (bitmap_intersect_p (new_ptr_info->pt_vars,
+ orig_ptr_info->pt_vars));
+#endif
+ }
+ }
}
/* Common code for propagate_value and replace_exp.
- Replace use operand OP_P with VAL. FOR_PROPAGATION indicates if the
+ Replace use operand OP_P with VAL. FOR_PROPAGATION indicates if the
replacement is done to propagate a value or not. */
static void
-replace_exp_1 (use_operand_p op_p, tree val, bool for_propagation)
+replace_exp_1 (use_operand_p op_p, tree val,
+ bool for_propagation ATTRIBUTE_UNUSED)
{
+ tree op = USE_FROM_PTR (op_p);
+
+#if defined ENABLE_CHECKING
+ gcc_assert (!(for_propagation
+ && TREE_CODE (op) == SSA_NAME
+ && TREE_CODE (val) == SSA_NAME
+ && !may_propagate_copy (op, val)));
+#endif
+
if (TREE_CODE (val) == SSA_NAME)
{
- if (TREE_CODE (USE_FROM_PTR (op_p)) == SSA_NAME)
- replace_ssa_names_ann (USE_FROM_PTR (op_p), val, for_propagation);
+ if (TREE_CODE (op) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (op)))
+ merge_alias_info (op, val);
SET_USE (op_p, val);
}
else
- SET_USE (op_p, lhd_unsave_expr_now (val));
+ SET_USE (op_p, unsave_expr_now (val));
}
/* Propagate the value VAL (assumed to be a constant or another SSA_NAME)
into the tree pointed by OP_P.
- Use this version for const/copy propagation when SSA operands are not
- available. It will perform the additional checks to ensure validity of
+ Use this version for const/copy propagation when SSA operands are not
+ available. It will perform the additional checks to ensure validity of
the const/copy propagation, but will not update any operand information.
Be sure to mark the stmt as modified. */
void
propagate_tree_value (tree *op_p, tree val)
{
+#if defined ENABLE_CHECKING
+ gcc_assert (!(TREE_CODE (val) == SSA_NAME
+ && TREE_CODE (*op_p) == SSA_NAME
+ && !may_propagate_copy (*op_p, val)));
+#endif
+
if (TREE_CODE (val) == SSA_NAME)
{
- if (TREE_CODE (*op_p) == SSA_NAME)
- replace_ssa_names_ann (*op_p, val, true);
+ if (TREE_CODE (*op_p) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (*op_p)))
+ merge_alias_info (*op_p, val);
*op_p = val;
}
else
- *op_p = lhd_unsave_expr_now (val);
+ *op_p = unsave_expr_now (val);
}