[PATCH] Improve VRP of integer division (PR rtl-optimization/38245)
Diego Novillo
dnovillo@google.com
Sun Nov 30 15:33:00 GMT 2008
On Sat, Nov 29, 2008 at 15:14, Jakub Jelinek <jakub@redhat.com> wrote:
> @@ -2289,83 +2295,189 @@ extract_range_from_binary_expr (value_ra
> MAX1) and then figure the smallest and largest values to form
> the new range. */
>
> - /* Divisions by zero result in a VARYING value. */
> else if (code != MULT_EXPR
> - && (vr0.type == VR_ANTI_RANGE || range_includes_zero_p (&vr1)))
> + && (vr0.type != VR_RANGE || symbolic_range_p (&vr0)))
> {
> - set_value_range_to_varying (vr);
> - return;
> + /* For division, if op1 has VR_RANGE, something can be deduced
> + just from that range. Say [min, max] / [4, max] gives
> + [min / 4, max / 4] range. */
> + if (vr1.type == VR_RANGE
> + && !symbolic_range_p (&vr1)
> + && !range_includes_zero_p (&vr1))
> + {
> + vr0.type = type = VR_RANGE;
> + vr0.min = vrp_val_min (TREE_TYPE (op0));
> + vr0.max = vrp_val_max (TREE_TYPE (op1));
> + if (!vr0.min || !vr0.max)
> + {
> + set_value_range_to_varying (vr);
> + return;
> + }
> + }
> + else
> + {
> + set_value_range_to_varying (vr);
> + return;
> + }
> }
>
> - /* Compute the 4 cross operations. */
> - sop = false;
> - val[0] = vrp_int_const_binop (code, vr0.min, vr1.min);
> - if (val[0] == NULL_TREE)
> - sop = true;
> -
> - if (vr1.max == vr1.min)
> - val[1] = NULL_TREE;
> - else
> + /* For divisions, if op0 is VR_RANGE, we can deduce a range
> + even if op1 is VARYING, ANTI_RANGE, symbolic or can include 0. */
> + if (code != MULT_EXPR
> + && code != RSHIFT_EXPR
> + && (vr0.type != vr1.type
> + || symbolic_range_p (&vr1)
> + || range_includes_zero_p (&vr1)))
> {
> - val[1] = vrp_int_const_binop (code, vr0.min, vr1.max);
> - if (val[1] == NULL_TREE)
> - sop = true;
> - }
> + tree zero = build_int_cst (TREE_TYPE (vr0.min), 0);
> + int cmp;
>
> - if (vr0.max == vr0.min)
> - val[2] = NULL_TREE;
> - else
> - {
> - val[2] = vrp_int_const_binop (code, vr0.max, vr1.min);
> - if (val[2] == NULL_TREE)
> - sop = true;
> + sop = false;
> + min = NULL_TREE;
> + max = NULL_TREE;
> + if (vrp_expr_computes_nonnegative (op1, &sop) && !sop)
> + {
> + /* For unsigned division or when divisor is known
> + to be non-negative, the range has to cover
> + all numbers from 0 to max for positive max
> + and all numbers from min to 0 for negative min. */
> + cmp = compare_values (vr0.max, zero);
> + if (cmp == -1)
> + max = zero;
> + else if (cmp == 0 || cmp == 1)
> + max = vr0.max;
> + else
> + type = VR_VARYING;
> + cmp = compare_values (vr0.min, zero);
> + if (cmp == 1)
> + min = zero;
> + else if (cmp == 0 || cmp == -1)
> + min = vr0.min;
> + else
> + type = VR_VARYING;
> + }
> + else
> + {
> + /* Otherwise the range is -max .. max or min .. -min
> + depending on which bound is bigger in absolute value,
> + as the division can change the sign. */
> + gcc_assert (!TYPE_UNSIGNED (TREE_TYPE (vr0.min)));
> + cmp = compare_values (vr0.min, zero);
> + if (cmp == 0 || cmp == 1)
> + {
> + min = fold_unary (NEGATE_EXPR, TREE_TYPE (vr0.min), vr0.max);
> + max = vr0.max;
> + }
> + else if (cmp == -1)
> + {
> + if (vrp_val_is_min (vr0.min))
> + type = VR_VARYING;
> + else
> + {
> + tree tem = fold_unary (NEGATE_EXPR, TREE_TYPE (vr0.min),
> + vr0.min);
> + if (tem == NULL)
> + type = VR_VARYING;
> + else
> + {
> + cmp = compare_values (tem, vr0.max);
> + if (cmp == -1 || cmp == 0)
> + {
> + min = vr0.min;
> + max = tem;
> + }
> + else if (cmp == 1)
> + {
> + min = fold_unary (NEGATE_EXPR,
> + TREE_TYPE (vr0.min), vr0.max);
> + max = vr0.max;
> + }
> + else
> + type = VR_VARYING;
> + }
> + }
> + }
> + else
> + type = VR_VARYING;
> + }
> + if (type == VR_VARYING)
> + {
> + set_value_range_to_varying (vr);
> + return;
> + }
This is very hard to follow, it should be factored out into a separate
function. VRP is already hard to follow and it needs some TLC.
The patch is fine otherwise.
Diego.
More information about the Gcc-patches
mailing list