#include "tm.h"
#include "ggc.h"
#include "tree.h"
+#include "real.h"
#include "diagnostic.h"
#include "varray.h"
#include "cfgloop.h"
#include "tree-chrec.h"
#include "tree-pass.h"
#include "params.h"
+#include "tree-scalar-evolution.h"
\f
(CHREC_VARIABLE (poly1),
chrec_fold_minus (type, poly0, CHREC_LEFT (poly1)),
chrec_fold_multiply (type, CHREC_RIGHT (poly1),
- build_int_cst_type (type, -1)));
+ SCALAR_FLOAT_TYPE_P (type)
+ ? build_real (type, dconstm1)
+ : build_int_cst_type (type, -1)));
}
if (CHREC_VARIABLE (poly0) > CHREC_VARIABLE (poly1))
tree poly0,
tree poly1)
{
+ tree t0, t1, t2;
+ int var;
+
gcc_assert (poly0);
gcc_assert (poly1);
gcc_assert (TREE_CODE (poly0) == POLYNOMIAL_CHREC);
/* poly0 and poly1 are two polynomials in the same variable,
{a, +, b}_x * {c, +, d}_x -> {a*c, +, a*d + b*c + b*d, +, 2*b*d}_x. */
- return
- build_polynomial_chrec
- (CHREC_VARIABLE (poly0),
- build_polynomial_chrec
- (CHREC_VARIABLE (poly0),
-
- /* "a*c". */
- chrec_fold_multiply (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1)),
- /* "a*d + b*c + b*d". */
- chrec_fold_plus
- (type, chrec_fold_multiply (type, CHREC_LEFT (poly0), CHREC_RIGHT (poly1)),
-
- chrec_fold_plus
- (type,
- chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_LEFT (poly1)),
- chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1))))),
-
- /* "2*b*d". */
- chrec_fold_multiply
- (type, build_int_cst (NULL_TREE, 2),
- chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1))));
+ /* "a*c". */
+ t0 = chrec_fold_multiply (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1));
+
+ /* "a*d + b*c + b*d". */
+ t1 = chrec_fold_multiply (type, CHREC_LEFT (poly0), CHREC_RIGHT (poly1));
+ t1 = chrec_fold_plus (type, t1, chrec_fold_multiply (type,
+ CHREC_RIGHT (poly0),
+ CHREC_LEFT (poly1)));
+ t1 = chrec_fold_plus (type, t1, chrec_fold_multiply (type,
+ CHREC_RIGHT (poly0),
+ CHREC_RIGHT (poly1)));
+ /* "2*b*d". */
+ t2 = chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1));
+ t2 = chrec_fold_multiply (type, SCALAR_FLOAT_TYPE_P (type)
+ ? build_real (type, dconst2)
+ : build_int_cst_type (type, 2), t2);
+
+ var = CHREC_VARIABLE (poly0);
+ return build_polynomial_chrec (var, t0,
+ build_polynomial_chrec (var, t1, t2));
}
/* When the operands are automatically_generated_chrec_p, the fold has
return build_polynomial_chrec
(CHREC_VARIABLE (op1),
chrec_fold_minus (type, op0, CHREC_LEFT (op1)),
- chrec_fold_multiply (type, CHREC_RIGHT (op1),
- build_int_cst_type (type, -1)));
+ chrec_fold_multiply (type, CHREC_RIGHT (op1),
+ SCALAR_FLOAT_TYPE_P (type)
+ ? build_real (type, dconstm1)
+ : build_int_cst_type (type, -1)));
default:
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "(chrec_apply \n");
+ if (TREE_CODE (x) == INTEGER_CST && SCALAR_FLOAT_TYPE_P (type))
+ x = build_real_from_int_cst (type, x);
+
if (evolution_function_is_affine_p (chrec))
{
/* "{a, +, b} (x)" -> "a + b*x". */
chrec))
return true;
- if (TREE_CODE (chrec) == POLYNOMIAL_CHREC
- && CHREC_VARIABLE (chrec) == (unsigned) loopnum)
- return false;
+ if (TREE_CODE (chrec) == POLYNOMIAL_CHREC)
+ {
+ if (CHREC_VARIABLE (chrec) == (unsigned) loopnum
+ || !evolution_function_is_invariant_rec_p (CHREC_RIGHT (chrec),
+ loopnum)
+ || !evolution_function_is_invariant_rec_p (CHREC_LEFT (chrec),
+ loopnum))
+ return false;
+ return true;
+ }
switch (TREE_CODE_LENGTH (TREE_CODE (chrec)))
{
if (evolution_function_is_affine_p (chrec))
{
- tree step = convert_step (current_loops->parray[CHREC_VARIABLE (chrec)],
- type, CHREC_LEFT (chrec), CHREC_RIGHT (chrec),
- at_stmt);
+ tree base, step;
+ bool dummy;
+ struct loop *loop = current_loops->parray[CHREC_VARIABLE (chrec)];
+
+ base = instantiate_parameters (loop, CHREC_LEFT (chrec));
+ step = instantiate_parameters (loop, CHREC_RIGHT (chrec));
+
+ /* Avoid conversion of (signed char) {(uchar)1, +, (uchar)1}_x
+ when it is not possible to prove that the scev does not wrap.
+ See PR22236, where a sequence 1, 2, ..., 255 has to be
+ converted to signed char, but this would wrap:
+ 1, 2, ..., 127, -128, ... The result should not be
+ {(schar)1, +, (schar)1}_x, but instead, we should keep the
+ conversion: (schar) {(uchar)1, +, (uchar)1}_x. */
+ if (scev_probably_wraps_p (type, base, step, at_stmt, loop,
+ &dummy, &dummy))
+ goto failed_to_convert;
+
+ step = convert_step (loop, type, base, step, at_stmt);
if (!step)
- return fold_convert (type, chrec);
+ {
+ failed_to_convert:;
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "(failed conversion:");
+ fprintf (dump_file, "\n type: ");
+ print_generic_expr (dump_file, type, 0);
+ fprintf (dump_file, "\n base: ");
+ print_generic_expr (dump_file, base, 0);
+ fprintf (dump_file, "\n step: ");
+ print_generic_expr (dump_file, step, 0);
+ fprintf (dump_file, "\n estimated_nb_iterations: ");
+ print_generic_expr (dump_file, loop->estimated_nb_iterations, 0);
+ fprintf (dump_file, "\n)\n");
+ }
+
+ return fold_convert (type, chrec);
+ }
return build_polynomial_chrec (CHREC_VARIABLE (chrec),
chrec_convert (type, CHREC_LEFT (chrec),
return res;
}
+/* 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. */
+
+tree
+chrec_convert_aggressive (tree type, tree chrec)
+{
+ tree inner_type, left, right, lc, rc;
+
+ if (automatically_generated_chrec_p (chrec)
+ || TREE_CODE (chrec) != POLYNOMIAL_CHREC)
+ return NULL_TREE;
+
+ inner_type = TREE_TYPE (chrec);
+ if (TYPE_PRECISION (type) > TYPE_PRECISION (inner_type))
+ return NULL_TREE;
+
+ left = CHREC_LEFT (chrec);
+ right = CHREC_RIGHT (chrec);
+ lc = chrec_convert_aggressive (type, left);
+ if (!lc)
+ lc = chrec_convert (type, left, NULL_TREE);
+ rc = chrec_convert_aggressive (type, right);
+ if (!rc)
+ rc = chrec_convert (type, right, NULL_TREE);
+
+ return build_polynomial_chrec (CHREC_VARIABLE (chrec), lc, rc);
+}
+
/* Returns the type of the chrec. */
tree