+error:
+ isl_ast_expr_free(expr);
+ isl_val_free(v);
+ return NULL;
+}
+
+/* Check if "aff" involves any (implicit) modulo computations based
+ * on div "j".
+ * If so, remove them from aff and add expressions corresponding
+ * to those modulo computations to *pos and/or *neg.
+ * "v" is the coefficient of div "j".
+ *
+ * In particular, check if (v * div_j) / d is of the form
+ *
+ * (f * m * floor(a / m)) / d
+ *
+ * and, if so, rewrite it as
+ *
+ * (f * (a - (a mod m))) / d = (f * a) / d - (f * (a mod m)) / d
+ *
+ * and extract out -f * (a mod m).
+ * In particular, if f > 0, we add (f * (a mod m)) to *neg.
+ * If f < 0, we add ((-f) * (a mod m)) to *pos.
+ *
+ * Note that in order to represent "a mod m" as
+ *
+ * (isl_ast_op_pdiv_r, a, m)
+ *
+ * we need to make sure that a is non-negative.
+ * If not, we check if "-a + m - 1" is non-negative.
+ * If so, we can rewrite
+ *
+ * floor(a/m) = -ceil(-a/m) = -floor((-a + m - 1)/m)
+ *
+ * and still extract a modulo.
+ *
+ * The caller is responsible for dividing *neg and/or *pos by d.
+ */
+static __isl_give isl_aff *extract_modulo(__isl_take isl_aff *aff,
+ __isl_keep isl_ast_expr **pos, __isl_keep isl_ast_expr **neg,
+ __isl_keep isl_ast_build *build, int j, __isl_take isl_val *v)
+{
+ isl_ast_expr *expr;
+ isl_aff *div;
+ int s;
+ int mod;
+ isl_val *d;
+
+ div = isl_aff_get_div(aff, j);
+ d = isl_aff_get_denominator_val(div);
+ mod = isl_val_is_divisible_by(v, d);
+ if (mod) {
+ div = isl_aff_scale_val(div, isl_val_copy(d));
+ mod = isl_ast_build_aff_is_nonneg(build, div);
+ if (mod >= 0 && !mod) {
+ isl_aff *opp = oppose_div_arg(isl_aff_copy(div),
+ isl_val_copy(d));
+ mod = isl_ast_build_aff_is_nonneg(build, opp);
+ if (mod >= 0 && mod) {
+ isl_aff_free(div);
+ div = opp;
+ v = isl_val_neg(v);
+ } else
+ isl_aff_free(opp);
+ }
+ }
+ if (mod < 0) {
+ isl_aff_free(div);
+ isl_val_free(d);
+ isl_val_free(v);
+ return isl_aff_free(aff);
+ } else if (!mod) {
+ isl_aff_free(div);
+ isl_val_free(d);
+ isl_val_free(v);
+ return aff;
+ }
+ v = isl_val_div(v, isl_val_copy(d));
+ s = isl_val_sgn(v);
+ v = isl_val_abs(v);
+ expr = isl_ast_expr_mod(v, div, d, build);
+ isl_val_free(d);
+ if (s > 0)
+ *neg = ast_expr_add(*neg, expr);
+ else
+ *pos = ast_expr_add(*pos, expr);
+ aff = isl_aff_set_coefficient_si(aff, isl_dim_div, j, 0);
+ if (s < 0)
+ v = isl_val_neg(v);
+ div = isl_aff_scale_val(div, v);
+ d = isl_aff_get_denominator_val(aff);
+ div = isl_aff_scale_down_val(div, d);
+ aff = isl_aff_add(aff, div);
+
+ return aff;