diff options
Diffstat (limited to 'gcc/tree-chrec.c')
-rw-r--r-- | gcc/tree-chrec.c | 104 |
1 files changed, 63 insertions, 41 deletions
diff --git a/gcc/tree-chrec.c b/gcc/tree-chrec.c index b599c2c..9357a56 100644 --- a/gcc/tree-chrec.c +++ b/gcc/tree-chrec.c @@ -1178,8 +1178,6 @@ nb_vars_in_chrec (tree chrec) } } -static tree chrec_convert_1 (tree, tree, gimple, bool); - /* Converts BASE and STEP of affine scev to TYPE. LOOP is the loop whose iv the scev corresponds to. AT_STMT is the statement at that the scev is evaluated. USE_OVERFLOW_SEMANTICS is true if this function should assume that @@ -1254,8 +1252,7 @@ convert_affine_scev (struct loop *loop, tree type, use_overflow_semantics)) return false; - new_base = chrec_convert_1 (type, *base, at_stmt, - use_overflow_semantics); + new_base = chrec_convert (type, *base, at_stmt, use_overflow_semantics); /* The step must be sign extended, regardless of the signedness of CT and TYPE. This only needs to be handled specially when CT is unsigned -- to avoid e.g. unsigned char [100, +, 255] @@ -1266,10 +1263,11 @@ convert_affine_scev (struct loop *loop, tree type, if (TYPE_PRECISION (step_type) > TYPE_PRECISION (ct) && TYPE_UNSIGNED (ct)) { tree signed_ct = build_nonstandard_integer_type (TYPE_PRECISION (ct), 0); - new_step = chrec_convert_1 (signed_ct, new_step, at_stmt, - use_overflow_semantics); + new_step = chrec_convert (signed_ct, new_step, at_stmt, + use_overflow_semantics); } - new_step = chrec_convert_1 (step_type, new_step, at_stmt, use_overflow_semantics); + new_step = chrec_convert (step_type, new_step, at_stmt, + use_overflow_semantics); if (automatically_generated_chrec_p (new_base) || automatically_generated_chrec_p (new_step)) @@ -1306,36 +1304,6 @@ chrec_convert_rhs (tree type, tree chrec, gimple at_stmt) determining a more accurate estimation of the number of iterations. By default AT_STMT could be safely set to NULL_TREE. - The following rule is always true: TREE_TYPE (chrec) == - TREE_TYPE (CHREC_LEFT (chrec)) == TREE_TYPE (CHREC_RIGHT (chrec)). - An example of what could happen when adding two chrecs and the type - of the CHREC_RIGHT is different than CHREC_LEFT is: - - {(uint) 0, +, (uchar) 10} + - {(uint) 0, +, (uchar) 250} - - that would produce a wrong result if CHREC_RIGHT is not (uint): - - {(uint) 0, +, (uchar) 4} - - instead of - - {(uint) 0, +, (uint) 260} -*/ - -tree -chrec_convert (tree type, tree chrec, gimple at_stmt) -{ - return chrec_convert_1 (type, chrec, at_stmt, true); -} - -/* Convert CHREC to TYPE. When the analyzer knows the context in - which the CHREC is built, it sets AT_STMT to the statement that - contains the definition of the analyzed variable, otherwise the - conversion is less accurate: the information is used for - determining a more accurate estimation of the number of iterations. - By default AT_STMT could be safely set to NULL_TREE. - USE_OVERFLOW_SEMANTICS is true if this function should assume that the rules for overflow of the given language apply (e.g., that signed arithmetics in C does not overflow) -- i.e., to use them to avoid unnecessary @@ -1420,15 +1388,53 @@ keep_cast: return res; } +/* Convert CHREC to TYPE. When the analyzer knows the context in + which the CHREC is built, it sets AT_STMT to the statement that + contains the definition of the analyzed variable, otherwise the + conversion is less accurate: the information is used for + determining a more accurate estimation of the number of iterations. + By default AT_STMT could be safely set to NULL_TREE. + + The following rule is always true: TREE_TYPE (chrec) == + TREE_TYPE (CHREC_LEFT (chrec)) == TREE_TYPE (CHREC_RIGHT (chrec)). + An example of what could happen when adding two chrecs and the type + of the CHREC_RIGHT is different than CHREC_LEFT is: + + {(uint) 0, +, (uchar) 10} + + {(uint) 0, +, (uchar) 250} + + that would produce a wrong result if CHREC_RIGHT is not (uint): + + {(uint) 0, +, (uchar) 4} + + instead of + + {(uint) 0, +, (uint) 260} + + USE_OVERFLOW_SEMANTICS is true if this function should assume that + the rules for overflow of the given language apply (e.g., that signed + arithmetics in C does not overflow) -- i.e., to use them to avoid unnecessary + tests, but also to enforce that the result follows them. */ + +tree +chrec_convert (tree type, tree chrec, gimple at_stmt, + bool use_overflow_semantics) +{ + return chrec_convert_1 (type, chrec, at_stmt, use_overflow_semantics); +} + /* Convert CHREC to TYPE, without regard to signed overflows. Returns the new chrec if something else than what chrec_convert would do happens, NULL_TREE - otherwise. */ + otherwise. This function set TRUE to variable pointed by FOLD_CONVERSIONS + if the result chrec may overflow. */ tree -chrec_convert_aggressive (tree type, tree chrec) +chrec_convert_aggressive (tree type, tree chrec, bool *fold_conversions) { tree inner_type, left, right, lc, rc, rtype; + gcc_assert (fold_conversions != NULL); + if (automatically_generated_chrec_p (chrec) || TREE_CODE (chrec) != POLYNOMIAL_CHREC) return NULL_TREE; @@ -1437,17 +1443,33 @@ chrec_convert_aggressive (tree type, tree chrec) if (TYPE_PRECISION (type) > TYPE_PRECISION (inner_type)) return NULL_TREE; + if (useless_type_conversion_p (type, inner_type)) + return NULL_TREE; + + if (!*fold_conversions && evolution_function_is_affine_p (chrec)) + { + tree base, step; + struct loop *loop; + + loop = get_chrec_loop (chrec); + base = CHREC_LEFT (chrec); + step = CHREC_RIGHT (chrec); + if (convert_affine_scev (loop, type, &base, &step, NULL, true)) + return build_polynomial_chrec (loop->num, base, step); + } rtype = POINTER_TYPE_P (type) ? sizetype : type; left = CHREC_LEFT (chrec); right = CHREC_RIGHT (chrec); - lc = chrec_convert_aggressive (type, left); + lc = chrec_convert_aggressive (type, left, fold_conversions); if (!lc) lc = chrec_convert (type, left, NULL); - rc = chrec_convert_aggressive (rtype, right); + rc = chrec_convert_aggressive (rtype, right, fold_conversions); if (!rc) rc = chrec_convert (rtype, right, NULL); + *fold_conversions = true; + return build_polynomial_chrec (CHREC_VARIABLE (chrec), lc, rc); } |