static tree chrec_evaluate (unsigned var, tree chrec, tree n, unsigned int k) { tree arg0, arg1, binomial_n_k; tree type = TREE_TYPE (chrec); while (TREE_CODE (chrec) == POLYNOMIAL_CHREC && CHREC_VARIABLE (chrec) > var) chrec = CHREC_LEFT (chrec); if (TREE_CODE (chrec) == POLYNOMIAL_CHREC && CHREC_VARIABLE (chrec) == var) { arg0 = chrec_evaluate (var, CHREC_RIGHT (chrec), n, k + 1); if (arg0 == chrec_dont_know) return chrec_dont_know; binomial_n_k = tree_fold_binomial (type, n, k); if (!binomial_n_k) return chrec_dont_know; arg1 = fold_build2 (MULT_EXPR, type, CHREC_LEFT (chrec), binomial_n_k); return chrec_fold_plus (type, arg0, arg1); } binomial_n_k = tree_fold_binomial (type, n, k); if (!binomial_n_k) return chrec_dont_know; return fold_build2 (MULT_EXPR, type, chrec, binomial_n_k); }
tree hide_evolution_in_other_loops_than_loop (tree chrec, unsigned loop_num) { if (automatically_generated_chrec_p (chrec)) return chrec; switch (TREE_CODE (chrec)) { case POLYNOMIAL_CHREC: if (CHREC_VARIABLE (chrec) == loop_num) return build_polynomial_chrec (loop_num, hide_evolution_in_other_loops_than_loop (CHREC_LEFT (chrec), loop_num), CHREC_RIGHT (chrec)); else if (CHREC_VARIABLE (chrec) < loop_num) /* There is no evolution in this loop. */ return initial_condition (chrec); else return hide_evolution_in_other_loops_than_loop (CHREC_LEFT (chrec), loop_num); default: return chrec; } }
bool eq_evolutions_p (tree chrec0, tree chrec1) { if (chrec0 == NULL_TREE || chrec1 == NULL_TREE || TREE_CODE (chrec0) != TREE_CODE (chrec1)) return false; if (chrec0 == chrec1) return true; switch (TREE_CODE (chrec0)) { case INTEGER_CST: return operand_equal_p (chrec0, chrec1, 0); case POLYNOMIAL_CHREC: return (CHREC_VARIABLE (chrec0) == CHREC_VARIABLE (chrec1) && eq_evolutions_p (CHREC_LEFT (chrec0), CHREC_LEFT (chrec1)) && eq_evolutions_p (CHREC_RIGHT (chrec0), CHREC_RIGHT (chrec1))); default: return false; } }
tree reset_evolution_in_loop (unsigned loop_num, tree chrec, tree new_evol) { struct loop *loop = get_loop (loop_num); if (POINTER_TYPE_P (chrec_type (chrec))) gcc_assert (sizetype == chrec_type (new_evol)); else gcc_assert (chrec_type (chrec) == chrec_type (new_evol)); if (TREE_CODE (chrec) == POLYNOMIAL_CHREC && flow_loop_nested_p (loop, get_chrec_loop (chrec))) { tree left = reset_evolution_in_loop (loop_num, CHREC_LEFT (chrec), new_evol); tree right = reset_evolution_in_loop (loop_num, CHREC_RIGHT (chrec), new_evol); return build3 (POLYNOMIAL_CHREC, TREE_TYPE (left), build_int_cst (NULL_TREE, CHREC_VARIABLE (chrec)), left, right); } while (TREE_CODE (chrec) == POLYNOMIAL_CHREC && CHREC_VARIABLE (chrec) == loop_num) chrec = CHREC_LEFT (chrec); return build_polynomial_chrec (loop_num, chrec, new_evol); }
static inline tree chrec_fold_poly_cst (enum tree_code code, tree type, tree poly, tree cst) { gcc_assert (poly); gcc_assert (cst); gcc_assert (TREE_CODE (poly) == POLYNOMIAL_CHREC); gcc_assert (!is_not_constant_evolution (cst)); switch (code) { case PLUS_EXPR: return build_polynomial_chrec (CHREC_VARIABLE (poly), chrec_fold_plus (type, CHREC_LEFT (poly), cst), CHREC_RIGHT (poly)); case MINUS_EXPR: return build_polynomial_chrec (CHREC_VARIABLE (poly), chrec_fold_minus (type, CHREC_LEFT (poly), cst), CHREC_RIGHT (poly)); case MULT_EXPR: return build_polynomial_chrec (CHREC_VARIABLE (poly), chrec_fold_multiply (type, CHREC_LEFT (poly), cst), chrec_fold_multiply (type, CHREC_RIGHT (poly), cst)); default: return chrec_dont_know; } }
bool eq_evolutions_p (const_tree chrec0, const_tree chrec1) { if (chrec0 == NULL_TREE || chrec1 == NULL_TREE || TREE_CODE (chrec0) != TREE_CODE (chrec1)) return false; if (chrec0 == chrec1) return true; switch (TREE_CODE (chrec0)) { case INTEGER_CST: return operand_equal_p (chrec0, chrec1, 0); case POLYNOMIAL_CHREC: return (CHREC_VARIABLE (chrec0) == CHREC_VARIABLE (chrec1) && eq_evolutions_p (CHREC_LEFT (chrec0), CHREC_LEFT (chrec1)) && eq_evolutions_p (CHREC_RIGHT (chrec0), CHREC_RIGHT (chrec1))); case PLUS_EXPR: case MULT_EXPR: case MINUS_EXPR: case POINTER_PLUS_EXPR: return eq_evolutions_p (TREE_OPERAND (chrec0, 0), TREE_OPERAND (chrec1, 0)) && eq_evolutions_p (TREE_OPERAND (chrec0, 1), TREE_OPERAND (chrec1, 1)); default: return false; } }
tree reset_evolution_in_loop (unsigned loop_num, tree chrec, tree new_evol) { gcc_assert (chrec_type (chrec) == chrec_type (new_evol)); if (TREE_CODE (chrec) == POLYNOMIAL_CHREC && CHREC_VARIABLE (chrec) > loop_num) { tree left = reset_evolution_in_loop (loop_num, CHREC_LEFT (chrec), new_evol); tree right = reset_evolution_in_loop (loop_num, CHREC_RIGHT (chrec), new_evol); return build3 (POLYNOMIAL_CHREC, TREE_TYPE (left), build_int_cst (NULL_TREE, CHREC_VARIABLE (chrec)), left, right); } while (TREE_CODE (chrec) == POLYNOMIAL_CHREC && CHREC_VARIABLE (chrec) == loop_num) chrec = CHREC_LEFT (chrec); return build_polynomial_chrec (loop_num, chrec, new_evol); }
static inline tree chrec_fold_multiply_poly_poly (tree type, tree poly0, tree poly1) { tree t0, t1, t2; int var; struct loop *loop0 = get_chrec_loop (poly0); struct loop *loop1 = get_chrec_loop (poly1); gcc_assert (poly0); gcc_assert (poly1); gcc_assert (TREE_CODE (poly0) == POLYNOMIAL_CHREC); gcc_assert (TREE_CODE (poly1) == POLYNOMIAL_CHREC); gcc_checking_assert (useless_type_conversion_p (type, chrec_type (poly0)) && useless_type_conversion_p (type, chrec_type (poly1))); /* {a, +, b}_1 * {c, +, d}_2 -> {c*{a, +, b}_1, +, d}_2, {a, +, b}_2 * {c, +, d}_1 -> {a*{c, +, d}_1, +, b}_2, {a, +, b}_x * {c, +, d}_x -> {a*c, +, a*d + b*c + b*d, +, 2*b*d}_x. */ if (flow_loop_nested_p (loop0, loop1)) /* poly0 is a constant wrt. poly1. */ return build_polynomial_chrec (CHREC_VARIABLE (poly1), chrec_fold_multiply (type, CHREC_LEFT (poly1), poly0), CHREC_RIGHT (poly1)); if (flow_loop_nested_p (loop1, loop0)) /* poly1 is a constant wrt. poly0. */ return build_polynomial_chrec (CHREC_VARIABLE (poly0), chrec_fold_multiply (type, CHREC_LEFT (poly0), poly1), CHREC_RIGHT (poly0)); gcc_assert (loop0 == loop1); /* 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. */ /* "a*c". */ t0 = chrec_fold_multiply (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1)); /* "a*d + b*c". */ 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))); /* "b*d". */ t2 = chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1)); /* "a*d + b*c + b*d". */ t1 = chrec_fold_plus (type, t1, t2); /* "2*b*d". */ t2 = chrec_fold_multiply (type, SCALAR_FLOAT_TYPE_P (type) ? build_real (type, dconst2) : build_int_cst (type, 2), t2); var = CHREC_VARIABLE (poly0); return build_polynomial_chrec (var, t0, build_polynomial_chrec (var, t1, t2)); }
static tree chrec_component_in_loop_num (tree chrec, unsigned loop_num, bool right) { tree component; struct loop *loop = get_loop (cfun, loop_num), *chloop; if (automatically_generated_chrec_p (chrec)) return chrec; switch (TREE_CODE (chrec)) { case POLYNOMIAL_CHREC: chloop = get_chrec_loop (chrec); if (chloop == loop) { if (right) component = CHREC_RIGHT (chrec); else component = CHREC_LEFT (chrec); if (TREE_CODE (CHREC_LEFT (chrec)) != POLYNOMIAL_CHREC || CHREC_VARIABLE (CHREC_LEFT (chrec)) != CHREC_VARIABLE (chrec)) return component; else return build_polynomial_chrec (loop_num, chrec_component_in_loop_num (CHREC_LEFT (chrec), loop_num, right), component); } else if (flow_loop_nested_p (chloop, loop)) /* There is no evolution part in this loop. */ return NULL_TREE; else { gcc_assert (flow_loop_nested_p (loop, chloop)); return chrec_component_in_loop_num (CHREC_LEFT (chrec), loop_num, right); } default: if (right) return NULL_TREE; else return chrec; } }
tree chrec_fold_multiply (tree type, tree op0, tree op1) { if (automatically_generated_chrec_p (op0) || automatically_generated_chrec_p (op1)) return chrec_fold_automatically_generated_operands (op0, op1); switch (TREE_CODE (op0)) { case POLYNOMIAL_CHREC: switch (TREE_CODE (op1)) { case POLYNOMIAL_CHREC: return chrec_fold_multiply_poly_poly (type, op0, op1); default: if (integer_onep (op1)) return op0; if (integer_zerop (op1)) return build_int_cst (type, 0); return build_polynomial_chrec (CHREC_VARIABLE (op0), chrec_fold_multiply (type, CHREC_LEFT (op0), op1), chrec_fold_multiply (type, CHREC_RIGHT (op0), op1)); } default: if (integer_onep (op0)) return op1; if (integer_zerop (op0)) return build_int_cst (type, 0); switch (TREE_CODE (op1)) { case POLYNOMIAL_CHREC: return build_polynomial_chrec (CHREC_VARIABLE (op1), chrec_fold_multiply (type, CHREC_LEFT (op1), op0), chrec_fold_multiply (type, CHREC_RIGHT (op1), op0)); default: if (integer_onep (op1)) return op0; if (integer_zerop (op1)) return build_int_cst (type, 0); return fold_build2 (MULT_EXPR, type, op0, op1); } } }
bool is_multivariate_chrec (const_tree chrec) { if (chrec == NULL_TREE) return false; if (TREE_CODE (chrec) == POLYNOMIAL_CHREC) return (is_multivariate_chrec_rec (CHREC_LEFT (chrec), CHREC_VARIABLE (chrec)) || is_multivariate_chrec_rec (CHREC_RIGHT (chrec), CHREC_VARIABLE (chrec))); else return false; }
static tree chrec_component_in_loop_num (tree chrec, unsigned loop_num, bool right) { tree component; if (automatically_generated_chrec_p (chrec)) return chrec; switch (TREE_CODE (chrec)) { case POLYNOMIAL_CHREC: if (CHREC_VARIABLE (chrec) == loop_num) { if (right) component = CHREC_RIGHT (chrec); else component = CHREC_LEFT (chrec); if (TREE_CODE (CHREC_LEFT (chrec)) != POLYNOMIAL_CHREC || CHREC_VARIABLE (CHREC_LEFT (chrec)) != CHREC_VARIABLE (chrec)) return component; else return build_polynomial_chrec (loop_num, chrec_component_in_loop_num (CHREC_LEFT (chrec), loop_num, right), component); } else if (CHREC_VARIABLE (chrec) < loop_num) /* There is no evolution part in this loop. */ return NULL_TREE; else return chrec_component_in_loop_num (CHREC_LEFT (chrec), loop_num, right); default: if (right) return NULL_TREE; else return chrec; } }
tree chrec_convert_aggressive (tree type, tree chrec) { tree inner_type, left, right, lc, rc, rtype; 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; /* If we cannot perform arithmetic in TYPE, avoid creating an scev. */ if (avoid_arithmetics_in_type_p (type)) return NULL_TREE; rtype = POINTER_TYPE_P (type) ? sizetype : type; left = CHREC_LEFT (chrec); right = CHREC_RIGHT (chrec); lc = chrec_convert_aggressive (type, left); if (!lc) lc = chrec_convert (type, left, NULL); rc = chrec_convert_aggressive (rtype, right); if (!rc) rc = chrec_convert (rtype, right, NULL); return build_polynomial_chrec (CHREC_VARIABLE (chrec), lc, rc); }
bool evolution_function_is_univariate_p (const_tree chrec) { if (chrec == NULL_TREE) return true; switch (TREE_CODE (chrec)) { case POLYNOMIAL_CHREC: switch (TREE_CODE (CHREC_LEFT (chrec))) { case POLYNOMIAL_CHREC: if (CHREC_VARIABLE (chrec) != CHREC_VARIABLE (CHREC_LEFT (chrec))) return false; if (!evolution_function_is_univariate_p (CHREC_LEFT (chrec))) return false; break; default: if (tree_contains_chrecs (CHREC_LEFT (chrec), NULL)) return false; break; } switch (TREE_CODE (CHREC_RIGHT (chrec))) { case POLYNOMIAL_CHREC: if (CHREC_VARIABLE (chrec) != CHREC_VARIABLE (CHREC_RIGHT (chrec))) return false; if (!evolution_function_is_univariate_p (CHREC_RIGHT (chrec))) return false; break; default: if (tree_contains_chrecs (CHREC_RIGHT (chrec), NULL)) return false; break; } default: return true; } }
tree reset_evolution_in_loop (unsigned loop_num, tree chrec, tree new_evol) { if (TREE_CODE (chrec) == POLYNOMIAL_CHREC && CHREC_VARIABLE (chrec) > loop_num) return build2 (TREE_CODE (chrec), build_int_cst (NULL_TREE, CHREC_VARIABLE (chrec)), reset_evolution_in_loop (loop_num, CHREC_LEFT (chrec), new_evol), reset_evolution_in_loop (loop_num, CHREC_RIGHT (chrec), new_evol)); while (TREE_CODE (chrec) == POLYNOMIAL_CHREC && CHREC_VARIABLE (chrec) == loop_num) chrec = CHREC_LEFT (chrec); return build_polynomial_chrec (loop_num, chrec, new_evol); }
bool evolution_function_is_affine_multivariate_p (const_tree chrec, int loopnum) { if (chrec == NULL_TREE) return false; switch (TREE_CODE (chrec)) { case POLYNOMIAL_CHREC: if (evolution_function_is_invariant_rec_p (CHREC_LEFT (chrec), loopnum)) { if (evolution_function_is_invariant_rec_p (CHREC_RIGHT (chrec), loopnum)) return true; else { if (TREE_CODE (CHREC_RIGHT (chrec)) == POLYNOMIAL_CHREC && CHREC_VARIABLE (CHREC_RIGHT (chrec)) != CHREC_VARIABLE (chrec) && evolution_function_is_affine_multivariate_p (CHREC_RIGHT (chrec), loopnum)) return true; else return false; } } else { if (evolution_function_is_invariant_rec_p (CHREC_RIGHT (chrec), loopnum) && TREE_CODE (CHREC_LEFT (chrec)) == POLYNOMIAL_CHREC && CHREC_VARIABLE (CHREC_LEFT (chrec)) != CHREC_VARIABLE (chrec) && evolution_function_is_affine_multivariate_p (CHREC_LEFT (chrec), loopnum)) return true; else return false; } default: return false; } }
static inline tree chrec_fold_multiply_poly_poly (tree type, tree poly0, tree poly1) { tree t0, t1, t2; int var; gcc_assert (poly0); gcc_assert (poly1); gcc_assert (TREE_CODE (poly0) == POLYNOMIAL_CHREC); gcc_assert (TREE_CODE (poly1) == POLYNOMIAL_CHREC); gcc_assert (chrec_type (poly0) == chrec_type (poly1)); gcc_assert (type == chrec_type (poly0)); /* {a, +, b}_1 * {c, +, d}_2 -> {c*{a, +, b}_1, +, d}_2, {a, +, b}_2 * {c, +, d}_1 -> {a*{c, +, d}_1, +, b}_2, {a, +, b}_x * {c, +, d}_x -> {a*c, +, a*d + b*c + b*d, +, 2*b*d}_x. */ if (CHREC_VARIABLE (poly0) < CHREC_VARIABLE (poly1)) /* poly0 is a constant wrt. poly1. */ return build_polynomial_chrec (CHREC_VARIABLE (poly1), chrec_fold_multiply (type, CHREC_LEFT (poly1), poly0), CHREC_RIGHT (poly1)); if (CHREC_VARIABLE (poly1) < CHREC_VARIABLE (poly0)) /* poly1 is a constant wrt. poly0. */ return build_polynomial_chrec (CHREC_VARIABLE (poly0), chrec_fold_multiply (type, CHREC_LEFT (poly0), poly1), CHREC_RIGHT (poly0)); /* 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. */ /* "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, 2), t2); var = CHREC_VARIABLE (poly0); return build_polynomial_chrec (var, t0, build_polynomial_chrec (var, t1, t2)); }
static tree chrec_convert_1 (tree type, tree chrec, tree at_stmt, bool use_overflow_semantics) { tree ct, res; tree base, step; struct loop *loop; if (automatically_generated_chrec_p (chrec)) return chrec; ct = chrec_type (chrec); if (ct == type) return chrec; if (!evolution_function_is_affine_p (chrec)) goto keep_cast; loop = current_loops->parray[CHREC_VARIABLE (chrec)]; base = CHREC_LEFT (chrec); step = CHREC_RIGHT (chrec); if (convert_affine_scev (loop, type, &base, &step, at_stmt, use_overflow_semantics)) return build_polynomial_chrec (loop->num, base, step); /* If we cannot propagate the cast inside the chrec, just keep the cast. */ keep_cast: res = fold_convert (type, chrec); /* Don't propagate overflows. */ if (CONSTANT_CLASS_P (res)) { TREE_CONSTANT_OVERFLOW (res) = 0; TREE_OVERFLOW (res) = 0; } /* But reject constants that don't fit in their type after conversion. This can happen if TYPE_MIN_VALUE or TYPE_MAX_VALUE are not the natural values associated with TYPE_PRECISION and TYPE_UNSIGNED, and can cause problems later when computing niters of loops. Note that we don't do the check before converting because we don't want to reject conversions of negative chrecs to unsigned types. */ if (TREE_CODE (res) == INTEGER_CST && TREE_CODE (type) == INTEGER_TYPE && !int_fits_type_p (res, type)) res = chrec_dont_know; return res; }
tree chrec_convert (tree type, tree chrec) { tree ct; if (automatically_generated_chrec_p (chrec)) return chrec; ct = chrec_type (chrec); if (ct == type) return chrec; if (TYPE_PRECISION (ct) < TYPE_PRECISION (type)) return count_ev_in_wider_type (type, chrec); switch (TREE_CODE (chrec)) { case POLYNOMIAL_CHREC: return build_polynomial_chrec (CHREC_VARIABLE (chrec), chrec_convert (type, CHREC_LEFT (chrec)), chrec_convert (type, CHREC_RIGHT (chrec))); default: { tree res = fold_convert (type, chrec); /* Don't propagate overflows. */ TREE_OVERFLOW (res) = 0; if (CONSTANT_CLASS_P (res)) TREE_CONSTANT_OVERFLOW (res) = 0; /* But reject constants that don't fit in their type after conversion. This can happen if TYPE_MIN_VALUE or TYPE_MAX_VALUE are not the natural values associated with TYPE_PRECISION and TYPE_UNSIGNED, and can cause problems later when computing niters of loops. Note that we don't do the check before converting because we don't want to reject conversions of negative chrecs to unsigned types. */ if (TREE_CODE (res) == INTEGER_CST && TREE_CODE (type) == INTEGER_TYPE && !int_fits_type_p (res, type)) res = chrec_dont_know; return res; } } }
unsigned nb_vars_in_chrec (tree chrec) { if (chrec == NULL_TREE) return 0; switch (TREE_CODE (chrec)) { case POLYNOMIAL_CHREC: return 1 + nb_vars_in_chrec (initial_condition_in_loop_num (chrec, CHREC_VARIABLE (chrec))); default: return 0; } }
static bool is_multivariate_chrec_rec (const_tree chrec, unsigned int rec_var) { if (chrec == NULL_TREE) return false; if (TREE_CODE (chrec) == POLYNOMIAL_CHREC) { if (CHREC_VARIABLE (chrec) != rec_var) return true; else return (is_multivariate_chrec_rec (CHREC_LEFT (chrec), rec_var) || is_multivariate_chrec_rec (CHREC_RIGHT (chrec), rec_var)); } else return false; }
tree 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; inner_type = TREE_TYPE (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, fold_conversions); if (!lc) lc = chrec_convert (type, left, NULL); 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); }
tree chrec_replace_initial_condition (tree chrec, tree init_cond) { if (automatically_generated_chrec_p (chrec)) return chrec; switch (TREE_CODE (chrec)) { case POLYNOMIAL_CHREC: return build_polynomial_chrec (CHREC_VARIABLE (chrec), chrec_replace_initial_condition (CHREC_LEFT (chrec), init_cond), CHREC_RIGHT (chrec)); default: return init_cond; } }
static bool evolution_function_is_invariant_rec_p (tree chrec, int loopnum) { if (evolution_function_is_constant_p (chrec)) return true; if (TREE_CODE (chrec) == SSA_NAME && (loopnum == 0 || expr_invariant_in_loop_p (get_loop (cfun, loopnum), chrec))) return true; if (TREE_CODE (chrec) == POLYNOMIAL_CHREC) { if (CHREC_VARIABLE (chrec) == (unsigned) loopnum || flow_loop_nested_p (get_loop (cfun, loopnum), get_chrec_loop (chrec)) || !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_OPERAND_LENGTH (chrec)) { case 2: if (!evolution_function_is_invariant_rec_p (TREE_OPERAND (chrec, 1), loopnum)) return false; case 1: if (!evolution_function_is_invariant_rec_p (TREE_OPERAND (chrec, 0), loopnum)) return false; return true; default: return false; } return false; }
static bool evolution_function_is_invariant_rec_p (tree chrec, int loopnum) { if (evolution_function_is_constant_p (chrec)) return true; if (TREE_CODE (chrec) == SSA_NAME && expr_invariant_in_loop_p (current_loops->parray[loopnum], chrec)) return true; 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))) { case 2: if (!evolution_function_is_invariant_rec_p (TREE_OPERAND (chrec, 1), loopnum)) return false; case 1: if (!evolution_function_is_invariant_rec_p (TREE_OPERAND (chrec, 0), loopnum)) return false; return true; default: return false; } return false; }
bool scev_is_linear_expression (tree scev) { if (scev == NULL || !operator_is_linear (scev)) return false; if (TREE_CODE (scev) == MULT_EXPR) return !(tree_contains_chrecs (TREE_OPERAND (scev, 0), NULL) && tree_contains_chrecs (TREE_OPERAND (scev, 1), NULL)); if (TREE_CODE (scev) == POLYNOMIAL_CHREC && !evolution_function_is_affine_multivariate_p (scev, CHREC_VARIABLE (scev))) return false; switch (TREE_CODE_LENGTH (TREE_CODE (scev))) { case 3: return scev_is_linear_expression (TREE_OPERAND (scev, 0)) && scev_is_linear_expression (TREE_OPERAND (scev, 1)) && scev_is_linear_expression (TREE_OPERAND (scev, 2)); case 2: return scev_is_linear_expression (TREE_OPERAND (scev, 0)) && scev_is_linear_expression (TREE_OPERAND (scev, 1)); case 1: return scev_is_linear_expression (TREE_OPERAND (scev, 0)); case 0: return true; default: return false; } }
static inline tree chrec_fold_plus_poly_poly (enum tree_code code, tree type, tree poly0, tree poly1) { tree left, right; struct loop *loop0 = get_chrec_loop (poly0); struct loop *loop1 = get_chrec_loop (poly1); tree rtype = code == POINTER_PLUS_EXPR ? chrec_type (poly1) : type; gcc_assert (poly0); gcc_assert (poly1); gcc_assert (TREE_CODE (poly0) == POLYNOMIAL_CHREC); gcc_assert (TREE_CODE (poly1) == POLYNOMIAL_CHREC); if (POINTER_TYPE_P (chrec_type (poly0))) gcc_checking_assert (ptrofftype_p (chrec_type (poly1)) && useless_type_conversion_p (type, chrec_type (poly0))); else gcc_checking_assert (useless_type_conversion_p (type, chrec_type (poly0)) && useless_type_conversion_p (type, chrec_type (poly1))); /* {a, +, b}_1 + {c, +, d}_2 -> {{a, +, b}_1 + c, +, d}_2, {a, +, b}_2 + {c, +, d}_1 -> {{c, +, d}_1 + a, +, b}_2, {a, +, b}_x + {c, +, d}_x -> {a+c, +, b+d}_x. */ if (flow_loop_nested_p (loop0, loop1)) { if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR) return build_polynomial_chrec (CHREC_VARIABLE (poly1), chrec_fold_plus (type, poly0, CHREC_LEFT (poly1)), CHREC_RIGHT (poly1)); else return build_polynomial_chrec (CHREC_VARIABLE (poly1), chrec_fold_minus (type, poly0, CHREC_LEFT (poly1)), chrec_fold_multiply (type, CHREC_RIGHT (poly1), SCALAR_FLOAT_TYPE_P (type) ? build_real (type, dconstm1) : build_int_cst_type (type, -1))); } if (flow_loop_nested_p (loop1, loop0)) { if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR) return build_polynomial_chrec (CHREC_VARIABLE (poly0), chrec_fold_plus (type, CHREC_LEFT (poly0), poly1), CHREC_RIGHT (poly0)); else return build_polynomial_chrec (CHREC_VARIABLE (poly0), chrec_fold_minus (type, CHREC_LEFT (poly0), poly1), CHREC_RIGHT (poly0)); } /* This function should never be called for chrecs of loops that do not belong to the same loop nest. */ gcc_assert (loop0 == loop1); if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR) { left = chrec_fold_plus (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1)); right = chrec_fold_plus (rtype, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1)); } else { left = chrec_fold_minus (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1)); right = chrec_fold_minus (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1)); } if (chrec_zerop (right)) return left; else return build_polynomial_chrec (CHREC_VARIABLE (poly0), left, right); }
static tree chrec_fold_plus_1 (enum tree_code code, tree type, tree op0, tree op1) { if (automatically_generated_chrec_p (op0) || automatically_generated_chrec_p (op1)) return chrec_fold_automatically_generated_operands (op0, op1); switch (TREE_CODE (op0)) { case POLYNOMIAL_CHREC: gcc_checking_assert (!chrec_contains_symbols_defined_in_loop (op0, CHREC_VARIABLE (op0))); switch (TREE_CODE (op1)) { case POLYNOMIAL_CHREC: gcc_checking_assert (!chrec_contains_symbols_defined_in_loop (op1, CHREC_VARIABLE (op1))); return chrec_fold_plus_poly_poly (code, type, op0, op1); CASE_CONVERT: if (tree_contains_chrecs (op1, NULL)) return chrec_dont_know; default: if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR) return build_polynomial_chrec (CHREC_VARIABLE (op0), chrec_fold_plus (type, CHREC_LEFT (op0), op1), CHREC_RIGHT (op0)); else return build_polynomial_chrec (CHREC_VARIABLE (op0), chrec_fold_minus (type, CHREC_LEFT (op0), op1), CHREC_RIGHT (op0)); } CASE_CONVERT: if (tree_contains_chrecs (op0, NULL)) return chrec_dont_know; default: switch (TREE_CODE (op1)) { case POLYNOMIAL_CHREC: gcc_checking_assert (!chrec_contains_symbols_defined_in_loop (op1, CHREC_VARIABLE (op1))); if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR) return build_polynomial_chrec (CHREC_VARIABLE (op1), chrec_fold_plus (type, op0, CHREC_LEFT (op1)), CHREC_RIGHT (op1)); else return build_polynomial_chrec (CHREC_VARIABLE (op1), chrec_fold_minus (type, op0, CHREC_LEFT (op1)), chrec_fold_multiply (type, CHREC_RIGHT (op1), SCALAR_FLOAT_TYPE_P (type) ? build_real (type, dconstm1) : build_int_cst_type (type, -1))); CASE_CONVERT: if (tree_contains_chrecs (op1, NULL)) return chrec_dont_know; default: { int size = 0; if ((tree_contains_chrecs (op0, &size) || tree_contains_chrecs (op1, &size)) && size < PARAM_VALUE (PARAM_SCEV_MAX_EXPR_SIZE)) return build2 (code, type, op0, op1); else if (size < PARAM_VALUE (PARAM_SCEV_MAX_EXPR_SIZE)) { if (code == POINTER_PLUS_EXPR) return fold_build_pointer_plus (fold_convert (type, op0), op1); else return fold_build2 (code, type, fold_convert (type, op0), fold_convert (type, op1)); } else return chrec_dont_know; } } } }
tree chrec_apply (unsigned var, tree chrec, tree x) { tree type = chrec_type (chrec); tree res = chrec_dont_know; if (automatically_generated_chrec_p (chrec) || automatically_generated_chrec_p (x) /* When the symbols are defined in an outer loop, it is possible to symbolically compute the apply, since the symbols are constants with respect to the varying loop. */ || chrec_contains_symbols_defined_in_loop (chrec, var)) return chrec_dont_know; if (dump_file && (dump_flags & TDF_SCEV)) 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); switch (TREE_CODE (chrec)) { case POLYNOMIAL_CHREC: if (evolution_function_is_affine_p (chrec)) { if (CHREC_VARIABLE (chrec) != var) return build_polynomial_chrec (CHREC_VARIABLE (chrec), chrec_apply (var, CHREC_LEFT (chrec), x), chrec_apply (var, CHREC_RIGHT (chrec), x)); /* "{a, +, b} (x)" -> "a + b*x". */ x = chrec_convert_rhs (type, x, NULL); res = chrec_fold_multiply (TREE_TYPE (x), CHREC_RIGHT (chrec), x); res = chrec_fold_plus (type, CHREC_LEFT (chrec), res); } else if (TREE_CODE (x) == INTEGER_CST && tree_int_cst_sgn (x) == 1) /* testsuite/.../ssa-chrec-38.c. */ res = chrec_evaluate (var, chrec, x, 0); else res = chrec_dont_know; break; CASE_CONVERT: res = chrec_convert (TREE_TYPE (chrec), chrec_apply (var, TREE_OPERAND (chrec, 0), x), NULL); break; default: res = chrec; break; } if (dump_file && (dump_flags & TDF_SCEV)) { fprintf (dump_file, " (varying_loop = %d\n", var); fprintf (dump_file, ")\n (chrec = "); print_generic_expr (dump_file, chrec, 0); fprintf (dump_file, ")\n (x = "); print_generic_expr (dump_file, x, 0); fprintf (dump_file, ")\n (res = "); print_generic_expr (dump_file, res, 0); fprintf (dump_file, "))\n"); } return res; }
tree chrec_fold_multiply (tree type, tree op0, tree op1) { if (automatically_generated_chrec_p (op0) || automatically_generated_chrec_p (op1)) return chrec_fold_automatically_generated_operands (op0, op1); switch (TREE_CODE (op0)) { case POLYNOMIAL_CHREC: gcc_checking_assert (!chrec_contains_symbols_defined_in_loop (op0, CHREC_VARIABLE (op0))); switch (TREE_CODE (op1)) { case POLYNOMIAL_CHREC: gcc_checking_assert (!chrec_contains_symbols_defined_in_loop (op1, CHREC_VARIABLE (op1))); return chrec_fold_multiply_poly_poly (type, op0, op1); CASE_CONVERT: if (tree_contains_chrecs (op1, NULL)) return chrec_dont_know; default: if (integer_onep (op1)) return op0; if (integer_zerop (op1)) return build_int_cst (type, 0); return build_polynomial_chrec (CHREC_VARIABLE (op0), chrec_fold_multiply (type, CHREC_LEFT (op0), op1), chrec_fold_multiply (type, CHREC_RIGHT (op0), op1)); } CASE_CONVERT: if (tree_contains_chrecs (op0, NULL)) return chrec_dont_know; default: if (integer_onep (op0)) return op1; if (integer_zerop (op0)) return build_int_cst (type, 0); switch (TREE_CODE (op1)) { case POLYNOMIAL_CHREC: gcc_checking_assert (!chrec_contains_symbols_defined_in_loop (op1, CHREC_VARIABLE (op1))); return build_polynomial_chrec (CHREC_VARIABLE (op1), chrec_fold_multiply (type, CHREC_LEFT (op1), op0), chrec_fold_multiply (type, CHREC_RIGHT (op1), op0)); CASE_CONVERT: if (tree_contains_chrecs (op1, NULL)) return chrec_dont_know; default: if (integer_onep (op1)) return op0; if (integer_zerop (op1)) return build_int_cst (type, 0); return fold_build2 (MULT_EXPR, type, op0, op1); } } }