diff options
Diffstat (limited to 'gcc/tree-ssa-copy.c')
-rw-r--r-- | gcc/tree-ssa-copy.c | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/gcc/tree-ssa-copy.c b/gcc/tree-ssa-copy.c index 1f87c1b..5d96fae 100644 --- a/gcc/tree-ssa-copy.c +++ b/gcc/tree-ssa-copy.c @@ -55,6 +55,103 @@ Boston, MA 02111-1307, USA. */ APIs defined in this file. */ +/* Return true if we may propagate ORIG into DEST, false otherwise. */ + +bool +may_propagate_copy (tree dest, tree orig) +{ + tree type_d = TREE_TYPE (dest); + tree type_o = TREE_TYPE (orig); + + /* Do not copy between types for which we *do* need a conversion. */ + if (!tree_ssa_useless_type_conversion_1 (type_d, type_o)) + return false; + + /* 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. + + This was showing up in libjava/java/util/zip/ZipFile.java with code + like: + + struct java.io.BufferedInputStream *T.660; + struct java.io.BufferedInputStream *T.647; + struct java.io.InputStream *is; + struct java.io.InputStream *is.662; + [ ... ] + T.660 = T.647; + is = T.660; <-- This ought to be type-casted + is.662 = is; + + Also, f/name.c exposed a similar problem with a COND_EXPR predicate + that was causing DOM to generate and equivalence with two pointers of + alias-incompatible types: + + struct _ffename_space *n; + struct _ffename *ns; + [ ... ] + if (n == ns) + goto lab; + ... + lab: + return n; + + I think that GIMPLE should emit the appropriate type-casts. For the + time being, blocking copy-propagation in these cases is the safe thing + to do. */ + if (TREE_CODE (dest) == SSA_NAME && TREE_CODE (orig) == SSA_NAME + && POINTER_TYPE_P (type_d) && POINTER_TYPE_P (type_o)) + { + tree mt_dest = var_ann (SSA_NAME_VAR (dest))->type_mem_tag; + tree mt_orig = var_ann (SSA_NAME_VAR (orig))->type_mem_tag; + if (mt_dest && mt_orig && mt_dest != mt_orig) + return false; + } + + /* If the destination is a SSA_NAME for a virtual operand, then we have + some special cases to handle. */ + if (TREE_CODE (dest) == SSA_NAME && !is_gimple_reg (dest)) + { + /* If both operands are SSA_NAMEs referring to virtual operands, then + we can always propagate. */ + if (TREE_CODE (orig) == SSA_NAME) + { + if (!is_gimple_reg (orig)) + return true; + +#ifdef ENABLE_CHECKING + /* If we have one real and one virtual operand, then something has + gone terribly wrong. */ + if (is_gimple_reg (orig)) + abort (); +#endif + } + + /* We have a "copy" from something like a constant into a virtual + operand. Reject these. */ + return false; + } + + /* If ORIG flows in from an abnormal edge, it cannot be propagated. */ + if (TREE_CODE (orig) == SSA_NAME + && 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 (TREE_CODE (dest) == SSA_NAME + && (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (dest) + || DECL_HARD_REGISTER (SSA_NAME_VAR (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. |