From a365af4ab8c38176b09c461b12b11b728dd0abed Mon Sep 17 00:00:00 2001 From: Sven Verdoolaege Date: Sun, 26 Feb 2023 12:54:30 +0100 Subject: [PATCH] isl_pw_qpolynomial_bound: special case affine polynomials If one or more of the quasi-polynomials is actually a quasi-affine expression, then the bound on the corresponding domain can always be computed exactly. Do this instead of using the generic bound computation. Signed-off-by: Sven Verdoolaege --- isl_bound.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++ isl_test.c | 2 ++ 2 files changed, 101 insertions(+) diff --git a/isl_bound.c b/isl_bound.c index fbd9dd2e..d2829d95 100644 --- a/isl_bound.c +++ b/isl_bound.c @@ -8,6 +8,8 @@ * 91893 Orsay, France */ +#include +#include #include #include #include @@ -263,10 +265,107 @@ static isl_stat guarded_poly_bound(__isl_take isl_basic_set *bset, return unwrap(bset, poly, &unwrapped_guarded_poly_bound, bound); } +/* Is "bset" bounded and is "qp" a quasi-affine expression? + */ +static isl_bool is_bounded_affine(__isl_keep isl_basic_set *bset, + __isl_keep isl_qpolynomial *qp) +{ + isl_bool affine; + + affine = isl_qpolynomial_isa_aff(qp); + if (affine < 0 || !affine) + return affine; + return isl_basic_set_is_bounded(bset); +} + +/* Update bound->pwf and bound->pwf_tight with a bound + * of type bound->type on the quasi-polynomial "qp" over the domain "bset", + * for the case where "bset" is bounded and + * "qp" is a quasi-affine expression and + * they have both been unwrapped already if needed. + * + * Consider the set of possible function values of "qp" over "bset" and + * take the minimum or maximum value in this set, depending + * on whether a lower or an upper bound is being computed. + * Do this by calling isl_set_lexmin_pw_multi_aff or + * isl_set_lexmax_pw_multi_aff, which compute a regular minimum or maximum + * since the set is one-dimensional. + * Since this computation is exact, the bound is always tight. + * + * Note that the minimum or maximum integer value is being computed, + * so if "qp" has some non-trivial denominator, then it needs + * to be multiplied out first and then taken into account again + * after computing the minimum or maximum. + */ +static isl_stat unwrapped_affine_qp(__isl_take isl_basic_set *bset, + __isl_take isl_qpolynomial *qp, struct isl_bound *bound) +{ + isl_val *d; + isl_aff *aff; + isl_basic_map *bmap; + isl_set *range; + isl_pw_multi_aff *opt; + isl_pw_aff *pa; + isl_pw_qpolynomial *pwqp; + isl_pw_qpolynomial_fold *pwf; + + aff = isl_qpolynomial_as_aff(qp); + d = isl_aff_get_denominator_val(aff); + aff = isl_aff_scale_val(aff, isl_val_copy(d)); + bmap = isl_basic_map_from_aff(aff); + bmap = isl_basic_map_intersect_domain(bmap, bset); + range = isl_set_from_basic_set(isl_basic_map_range(bmap)); + if (bound->type == isl_fold_min) + opt = isl_set_lexmin_pw_multi_aff(range); + else + opt = isl_set_lexmax_pw_multi_aff(range); + pa = isl_pw_multi_aff_get_at(opt, 0); + isl_pw_multi_aff_free(opt); + pa = isl_pw_aff_scale_down_val(pa, d); + pwqp = isl_pw_qpolynomial_from_pw_aff(pa); + pwf = isl_pw_qpolynomial_fold_from_pw_qpolynomial(bound->type, pwqp); + + bound->pwf_tight = isl_pw_qpolynomial_fold_fold(bound->pwf_tight, pwf); + + return isl_stat_non_null(bound->pwf_tight); +} + +/* Update bound->pwf and bound->pwf_tight with a bound + * of type bound->type on the quasi-polynomial "qp" over the domain bound->bset, + * for the case where bound->bset is bounded and + * "qp" is a quasi-affine expression, + * handling any wrapping in the domain. + */ +static isl_stat affine_qp(__isl_take isl_qpolynomial *qp, + struct isl_bound *bound) +{ + isl_basic_set *bset; + + bset = isl_basic_set_copy(bound->bset); + return unwrap(bset, qp, &unwrapped_affine_qp, bound); +} + +/* Update bound->pwf and bound->pwf_tight with a bound + * of type bound->type on the quasi-polynomial "qp" over the domain bound->bset. + * + * If bound->bset is bounded and if "qp" is a quasi-affine expression, + * then use a specialized version. + * + * Otherwise, treat the integer divisions as extra variables and + * compute a bound over the polynomial in terms of the original and + * the extra variables. + */ static isl_stat guarded_qp(__isl_take isl_qpolynomial *qp, void *user) { struct isl_bound *bound = (struct isl_bound *)user; isl_stat r; + isl_bool bounded_affine; + + bounded_affine = is_bounded_affine(bound->bset, qp); + if (bounded_affine < 0) + qp = isl_qpolynomial_free(qp); + else if (bounded_affine) + return affine_qp(qp, bound); r = isl_qpolynomial_as_polynomial_on_domain(qp, bound->bset, &guarded_poly_bound, user); diff --git a/isl_test.c b/isl_test.c index 9b262d19..9e0401d1 100644 --- a/isl_test.c +++ b/isl_test.c @@ -4036,6 +4036,8 @@ static struct { { 1, isl_fold_max, "{ [0:10] -> 1 }", "{ max(1) }" }, { 1, isl_fold_max, "{ [[m] -> [0:m]] -> m^2 }", "{ [m] -> max(m^2) : m >= 0 }" }, + { 1, isl_fold_max, "{ [[a=0:1] -> [b=0:1]] -> (floor((a + b)/2)) }", + "{ [a=0:1] -> max(a) }" }, }; /* Check that the bound computation can handle differences