From patchwork Fri Nov 8 17:52:00 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Andrew MacLeod X-Patchwork-Id: 1192089 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-512852-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="GsSLYMoT"; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="ht3Uecnq"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 478nsp3N09z9sP4 for ; Sat, 9 Nov 2019 04:52:30 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :subject:to:message-id:date:mime-version:content-type; q=dns; s= default; b=bSRw/P0VAspgCH8GbuNEF5snkMq6xT3kZgrU1IFBPvhNgY58emqhg ZfZavnYVlH2Pa4xj2aPWT4HrTBYnGqKqX6aAbdpYCTUONt1DaqoLo/Lbbsxl1aqm ma0DgK1MfevX11GMTMRu2ph7ucZnqE6dd8Ah7EqNWQlhW/PujTTzdA= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :subject:to:message-id:date:mime-version:content-type; s= default; bh=PLKPivOO7ip/zbiuRzQFb2rsqsI=; b=GsSLYMoTtDKQ0HQDNlAi Rkbpx97W/OqHQT8QycRJx61V8gAlBsvGvBGdWYC/A/0amCEXrU32ZGxj7Np5b4Ra cqFA7v1FKKEwyapz4BAoi4SEYdi2emcVCwjtaBpQZ5hcsdUAUW/8Z4GaHgGYVySr CycrqRdu2zhe5pSYdLtYmgA= Received: (qmail 8385 invoked by alias); 8 Nov 2019 17:52:16 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 8377 invoked by uid 89); 8 Nov 2019 17:52:16 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-4.6 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_2, KAM_ASCII_DIVIDERS, SPF_PASS autolearn=ham version=3.3.1 spammy=cp1, sgn, ***************, rangeoph X-HELO: us-smtp-delivery-1.mimecast.com Received: from us-smtp-1.mimecast.com (HELO us-smtp-delivery-1.mimecast.com) (207.211.31.81) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 08 Nov 2019 17:52:07 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1573235525; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type; bh=y9cOOdai6yJu0LOPUGSh54/SvnFgHImbg8niaOJ/Kas=; b=ht3UecnqMUN/xeIyBJ+luTWUapAESiIIcbJMoJ+dzgx44EdVluRUutYkca//5bVDq0CN3U h4NpnBUzZcoUSxkR5xtC/vJdIS9ne1Z8ZVNMGVaG1OemHdFi9ApzwCd1Kb0lGodNYrROyn OdaXft0pxgXqpmIwrAxhQq9OW/ikgd0= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-243-HTZDqoh1NHGeZCdFZ2eVqg-1; Fri, 08 Nov 2019 12:52:03 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 126D5800C72 for ; Fri, 8 Nov 2019 17:52:02 +0000 (UTC) Received: from [10.10.123.247] (ovpn-123-247.rdu2.redhat.com [10.10.123.247]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1A9E45C1BB for ; Fri, 8 Nov 2019 17:52:00 +0000 (UTC) From: Andrew MacLeod Subject: [COMMITTED] Change fold_range() and wi_fold() to return the result via reference parameter. To: gcc-patches Message-ID: Date: Fri, 8 Nov 2019 12:52:00 -0500 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.3.1 MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-IsSubscribed: yes The call to range_operator::fold_range() and wi_fold() originally returned the resulting range in a reference parameter.  When prepping for trunk,  we got excited about something else and I changed it to return the result by value. As we move towards multiple sub-ranges in value_range, I  recalled the rationale for the reference parameter was to allow us to better support a variable number of sub-ranges.   range-ops will work with as many subranges as are available, and this allows the caller to provide a range object with the desired number.       It also makes fold_range a bit more consistent with the way op1_range and op2_range work. The fundamental change is moving from:     virtual value_range fold_range (tree type, const value_range &lh, const value_range &rh) const; to     virtual void fold_range (value_range &r, tree type, const value_range &lh, const value_range &rh) const; and likewise for wi_fold. The change is quite mechanical.  Bootstraps all languages and causes no regressions. Checked in as SVN revision 277979 Andrew Change range_operator methods 'fold_range' and 'wi_fold' to return the result range by a reference parameter instead of by value. 2019-11-08 Andrew MacLeod * range-op.h (range_operator::fold_range): Return result in a reference parameter instead of by value. (range_operator::wi_fold): Same. * range-op.cc (range_operator::wi_fold): Return result in a reference parameter instead of by value. (range_operator::fold_range): Same. (value_range_from_overflowed_bounds): Same. (value_range_with_overflow): Same (create_possibly_reversed_range): Same. (operator_equal::fold_range): Same. (operator_not_equal::fold_range): Same. (operator_lt::fold_range): Same. (operator_le::fold_range): Same. (operator_gt::fold_range): Same. (operator_ge::fold_range): Same. (operator_plus::wi_fold): Same. (operator_plus::op1_range): Change call to fold_range. (operator_plus::op2_range): Change call to fold_range. (operator_minus::wi_fold): Return result via reference parameter. (operator_minus::op1_range): Change call to fold_range. (operator_minus::op2_range): Change call to fold_range. (operator_min::wi_fold): Return result via reference parameter. (operator_max::wi_fold): Same. (cross_product_operator::wi_cross_product): Same. (operator_mult::wi_fold): Same. (operator_div::wi_fold): Same. (operator_div op_floor_div): Fix whitespace. (operator_exact_divide::op1_range): Change call to fold_range. (operator_lshift::fold_range): Return result via reference parameter. (operator_lshift::wi_fold): Same. (operator_rshift::fold_range): Same. (operator_rshift::wi_fold): Same. (operator_cast::fold_range): Same. (operator_cast::op1_range): Change calls to fold_range. (operator_logical_and::fold_range): Return result via reference. (wi_optimize_and_or): Adjust call to value_range_with_overflow. (operator_bitwise_and::wi_fold): Return result via reference. (operator_logical_or::fold_range): Same. (operator_bitwise_or::wi_fold): Same. (operator_bitwise_xor::wi_fold): Same. (operator_trunc_mod::wi_fold): Same. (operator_logical_not::fold_range): Same. (operator_bitwise_not::fold_range): Same. (operator_bitwise_not::op1_range): Change call to fold_range. (operator_cst::fold_range): Return result via reference. (operator_identity::fold_range): Same. (operator_abs::wi_fold): Same. (operator_absu::wi_fold): Same. (operator_negate::fold_range): Same. (operator_negate::op1_range): Change call to fold_range. (operator_addr_expr::fold_range): Return result via reference. (operator_addr_expr::op1_range): Change call to fold_range. (operator_pointer_plus::wi_fold): Return result via reference. (operator_pointer_min_max::wi_fold): Same. (operator_pointer_and::wi_fold): Same. (operator_pointer_or::wi_fold): Same. (range_op_handler): Change call to fold_range. (range_cast): Same. * tree-vrp.c (range_fold_binary_symbolics_p): Change call to fold_range. (range_fold_unary_symbolics_p): Same. (range_fold_binary_expr): Same. (range_fold_unary_expr): Same. Index: range-op.h =================================================================== *** range-op.h (revision 277853) --- range-op.h (working copy) *************** class range_operator *** 50,58 **** { public: // Perform an operation between 2 ranges and return it. ! virtual value_range fold_range (tree type, ! const value_range &lh, ! const value_range &rh) const; // Return the range for op[12] in the general case. LHS is the range for // the LHS of the expression, OP[12]is the range for the other --- 50,58 ---- { public: // Perform an operation between 2 ranges and return it. ! virtual void fold_range (value_range &r, tree type, ! const value_range &lh, ! const value_range &rh) const; // Return the range for op[12] in the general case. LHS is the range for // the LHS of the expression, OP[12]is the range for the other *************** public: *** 74,84 **** protected: // Perform an operation between 2 sub-ranges and return it. ! virtual value_range wi_fold (tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; }; extern range_operator *range_op_handler (enum tree_code code, tree type); --- 74,84 ---- protected: // Perform an operation between 2 sub-ranges and return it. ! virtual void wi_fold (value_range &r, tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; }; extern range_operator *range_op_handler (enum tree_code code, tree type); Index: range-op.cc =================================================================== *** range-op.cc (revision 277853) --- range-op.cc (working copy) *************** wi_zero_p (tree type, const wide_int &wm *** 124,151 **** // Default wide_int fold operation returns [MIN, MAX]. ! value_range ! range_operator::wi_fold (tree type, const wide_int &lh_lb ATTRIBUTE_UNUSED, const wide_int &lh_ub ATTRIBUTE_UNUSED, const wide_int &rh_lb ATTRIBUTE_UNUSED, const wide_int &rh_ub ATTRIBUTE_UNUSED) const { ! return value_range (type); } // The default for fold is to break all ranges into sub-ranges and // invoke the wi_fold method on each sub-range pair. ! value_range ! range_operator::fold_range (tree type, const value_range &lh, const value_range &rh) const { - value_range r; if (empty_range_check (r, lh, rh)) ! return r; for (unsigned x = 0; x < lh.num_pairs (); ++x) for (unsigned y = 0; y < rh.num_pairs (); ++y) { --- 124,151 ---- // Default wide_int fold operation returns [MIN, MAX]. ! void ! range_operator::wi_fold (value_range &r, tree type, const wide_int &lh_lb ATTRIBUTE_UNUSED, const wide_int &lh_ub ATTRIBUTE_UNUSED, const wide_int &rh_lb ATTRIBUTE_UNUSED, const wide_int &rh_ub ATTRIBUTE_UNUSED) const { ! r = value_range (type); } // The default for fold is to break all ranges into sub-ranges and // invoke the wi_fold method on each sub-range pair. ! void ! range_operator::fold_range (value_range &r, tree type, const value_range &lh, const value_range &rh) const { if (empty_range_check (r, lh, rh)) ! return; + value_range tmp; for (unsigned x = 0; x < lh.num_pairs (); ++x) for (unsigned y = 0; y < rh.num_pairs (); ++y) { *************** range_operator::fold_range (tree type, *** 153,163 **** wide_int lh_ub = lh.upper_bound (x); wide_int rh_lb = rh.lower_bound (y); wide_int rh_ub = rh.upper_bound (y); ! r.union_ (wi_fold (type, lh_lb, lh_ub, rh_lb, rh_ub)); if (r.varying_p ()) ! return r; } - return r; } // The default for op1_range is to return false. --- 153,163 ---- wide_int lh_ub = lh.upper_bound (x); wide_int rh_lb = rh.lower_bound (y); wide_int rh_ub = rh.upper_bound (y); ! wi_fold (tmp, type, lh_lb, lh_ub, rh_lb, rh_ub); ! r.union_ (tmp); if (r.varying_p ()) ! return; } } // The default for op1_range is to return false. *************** range_operator::op2_range (value_range & *** 186,193 **** // Create and return a range from a pair of wide-ints that are known // to have overflowed (or underflowed). ! static value_range ! value_range_from_overflowed_bounds (tree type, const wide_int &wmin, const wide_int &wmax) { --- 186,193 ---- // Create and return a range from a pair of wide-ints that are known // to have overflowed (or underflowed). ! static void ! value_range_from_overflowed_bounds (value_range &r, tree type, const wide_int &wmin, const wide_int &wmax) { *************** value_range_from_overflowed_bounds (tree *** 210,226 **** // Likewise if the anti-range bounds are outside of the types // values. if (covers || wi::cmp (tmin, tmax, sgn) > 0) ! return value_range (type); ! ! return value_range (VR_ANTI_RANGE, type, tmin, tmax); } // Create and return a range from a pair of wide-ints. MIN_OVF and // MAX_OVF describe any overflow that might have occurred while // calculating WMIN and WMAX respectively. ! static value_range ! value_range_with_overflow (tree type, const wide_int &wmin, const wide_int &wmax, wi::overflow_type min_ovf = wi::OVF_NONE, wi::overflow_type max_ovf = wi::OVF_NONE) --- 210,226 ---- // Likewise if the anti-range bounds are outside of the types // values. if (covers || wi::cmp (tmin, tmax, sgn) > 0) ! r = value_range (type); ! else ! r = value_range (VR_ANTI_RANGE, type, tmin, tmax); } // Create and return a range from a pair of wide-ints. MIN_OVF and // MAX_OVF describe any overflow that might have occurred while // calculating WMIN and WMAX respectively. ! static void ! value_range_with_overflow (value_range &r, tree type, const wide_int &wmin, const wide_int &wmax, wi::overflow_type min_ovf = wi::OVF_NONE, wi::overflow_type max_ovf = wi::OVF_NONE) *************** value_range_with_overflow (tree type, *** 232,238 **** // For one bit precision if max != min, then the range covers all // values. if (prec == 1 && wi::ne_p (wmax, wmin)) ! return value_range (type); if (overflow_wraps) { --- 232,241 ---- // For one bit precision if max != min, then the range covers all // values. if (prec == 1 && wi::ne_p (wmax, wmin)) ! { ! r = value_range (type); ! return; ! } if (overflow_wraps) { *************** value_range_with_overflow (tree type, *** 245,263 **** // If the limits are swapped, we wrapped around and cover // the entire range. if (wi::gt_p (tmin, tmax, sgn)) ! return value_range (type); ! ! // No overflow or both overflow or underflow. The range ! // kind stays normal. ! return value_range (type, tmin, tmax); } if ((min_ovf == wi::OVF_UNDERFLOW && max_ovf == wi::OVF_NONE) || (max_ovf == wi::OVF_OVERFLOW && min_ovf == wi::OVF_NONE)) ! return value_range_from_overflowed_bounds (type, wmin, wmax); ! ! // Other underflow and/or overflow, drop to VR_VARYING. ! return value_range (type); } else { --- 248,267 ---- // If the limits are swapped, we wrapped around and cover // the entire range. if (wi::gt_p (tmin, tmax, sgn)) ! r = value_range (type); ! else ! // No overflow or both overflow or underflow. The range ! // kind stays normal. ! r = value_range (type, tmin, tmax); ! return; } if ((min_ovf == wi::OVF_UNDERFLOW && max_ovf == wi::OVF_NONE) || (max_ovf == wi::OVF_OVERFLOW && min_ovf == wi::OVF_NONE)) ! value_range_from_overflowed_bounds (r, type, wmin, wmax); ! else ! // Other underflow and/or overflow, drop to VR_VARYING. ! r = value_range (type); } else { *************** value_range_with_overflow (tree type, *** 277,283 **** else new_ub = wmax; ! return value_range (type, new_lb, new_ub); } } --- 281,287 ---- else new_ub = wmax; ! r = value_range (type, new_lb, new_ub); } } *************** value_range_with_overflow (tree type, *** 285,301 **** // the case where the bounds are swapped. In which case, we transform // [10,5] into [MIN,5][10,MAX]. ! static inline value_range ! create_possibly_reversed_range (tree type, const wide_int &new_lb, const wide_int &new_ub) { signop s = TYPE_SIGN (type); // If the bounds are swapped, treat the result as if an overflow occured. if (wi::gt_p (new_lb, new_ub, s)) ! return value_range_from_overflowed_bounds (type, new_lb, new_ub); ! ! // Otherwise its just a normal range. ! return value_range (type, new_lb, new_ub); } // Return a value_range instance that is a boolean TRUE. --- 289,305 ---- // the case where the bounds are swapped. In which case, we transform // [10,5] into [MIN,5][10,MAX]. ! static inline void ! create_possibly_reversed_range (value_range &r, tree type, const wide_int &new_lb, const wide_int &new_ub) { signop s = TYPE_SIGN (type); // If the bounds are swapped, treat the result as if an overflow occured. if (wi::gt_p (new_lb, new_ub, s)) ! value_range_from_overflowed_bounds (r, type, new_lb, new_ub); ! else ! // Otherwise its just a normal range. ! r = value_range (type, new_lb, new_ub); } // Return a value_range instance that is a boolean TRUE. *************** get_bool_state (value_range &r, const va *** 359,367 **** class operator_equal : public range_operator { public: ! virtual value_range fold_range (tree type, ! const value_range &op1, ! const value_range &op2) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &val) const; --- 363,371 ---- class operator_equal : public range_operator { public: ! virtual void fold_range (value_range &r, tree type, ! const value_range &op1, ! const value_range &op2) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &val) const; *************** public: *** 370,383 **** const value_range &val) const; } op_equal; ! value_range ! operator_equal::fold_range (tree type, const value_range &op1, const value_range &op2) const { - value_range r; if (empty_range_check (r, op1, op2)) ! return r; // We can be sure the values are always equal or not if both ranges // consist of a single value, and then compare them. --- 374,386 ---- const value_range &val) const; } op_equal; ! void ! operator_equal::fold_range (value_range &r, tree type, const value_range &op1, const value_range &op2) const { if (empty_range_check (r, op1, op2)) ! return; // We can be sure the values are always equal or not if both ranges // consist of a single value, and then compare them. *************** operator_equal::fold_range (tree type, *** 399,406 **** else r = range_true_and_false (type); } - - return r; } bool --- 402,407 ---- *************** operator_equal::op2_range (value_range & *** 442,450 **** class operator_not_equal : public range_operator { public: ! virtual value_range fold_range (tree type, ! const value_range &op1, ! const value_range &op2) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; --- 443,451 ---- class operator_not_equal : public range_operator { public: ! virtual void fold_range (value_range &r, tree type, ! const value_range &op1, ! const value_range &op2) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; *************** public: *** 453,466 **** const value_range &op1) const; } op_not_equal; ! value_range ! operator_not_equal::fold_range (tree type, const value_range &op1, const value_range &op2) const { - value_range r; if (empty_range_check (r, op1, op2)) ! return r; // We can be sure the values are always equal or not if both ranges // consist of a single value, and then compare them. --- 454,466 ---- const value_range &op1) const; } op_not_equal; ! void ! operator_not_equal::fold_range (value_range &r, tree type, const value_range &op1, const value_range &op2) const { if (empty_range_check (r, op1, op2)) ! return; // We can be sure the values are always equal or not if both ranges // consist of a single value, and then compare them. *************** operator_not_equal::fold_range (tree typ *** 482,489 **** else r = range_true_and_false (type); } - - return r; } bool --- 482,487 ---- *************** build_ge (value_range &r, tree type, con *** 571,579 **** class operator_lt : public range_operator { public: ! virtual value_range fold_range (tree type, ! const value_range &op1, ! const value_range &op2) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; --- 569,577 ---- class operator_lt : public range_operator { public: ! virtual void fold_range (value_range &r, tree type, ! const value_range &op1, ! const value_range &op2) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; *************** public: *** 582,595 **** const value_range &op1) const; } op_lt; ! value_range ! operator_lt::fold_range (tree type, const value_range &op1, const value_range &op2) const { - value_range r; if (empty_range_check (r, op1, op2)) ! return r; signop sign = TYPE_SIGN (op1.type ()); gcc_checking_assert (sign == TYPE_SIGN (op2.type ())); --- 580,592 ---- const value_range &op1) const; } op_lt; ! void ! operator_lt::fold_range (value_range &r, tree type, const value_range &op1, const value_range &op2) const { if (empty_range_check (r, op1, op2)) ! return; signop sign = TYPE_SIGN (op1.type ()); gcc_checking_assert (sign == TYPE_SIGN (op2.type ())); *************** operator_lt::fold_range (tree type, *** 600,606 **** r = range_false (type); else r = range_true_and_false (type); - return r; } bool --- 597,602 ---- *************** operator_lt::op2_range (value_range &r, *** 649,657 **** class operator_le : public range_operator { public: ! virtual value_range fold_range (tree type, ! const value_range &op1, ! const value_range &op2) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; --- 645,653 ---- class operator_le : public range_operator { public: ! virtual void fold_range (value_range &r, tree type, ! const value_range &op1, ! const value_range &op2) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; *************** public: *** 660,673 **** const value_range &op1) const; } op_le; ! value_range ! operator_le::fold_range (tree type, const value_range &op1, const value_range &op2) const { - value_range r; if (empty_range_check (r, op1, op2)) ! return r; signop sign = TYPE_SIGN (op1.type ()); gcc_checking_assert (sign == TYPE_SIGN (op2.type ())); --- 656,668 ---- const value_range &op1) const; } op_le; ! void ! operator_le::fold_range (value_range &r, tree type, const value_range &op1, const value_range &op2) const { if (empty_range_check (r, op1, op2)) ! return; signop sign = TYPE_SIGN (op1.type ()); gcc_checking_assert (sign == TYPE_SIGN (op2.type ())); *************** operator_le::fold_range (tree type, *** 678,684 **** r = range_false (type); else r = range_true_and_false (type); - return r; } bool --- 673,678 ---- *************** operator_le::op2_range (value_range &r, *** 727,735 **** class operator_gt : public range_operator { public: ! virtual value_range fold_range (tree type, ! const value_range &op1, ! const value_range &op2) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; --- 721,729 ---- class operator_gt : public range_operator { public: ! virtual void fold_range (value_range &r, tree type, ! const value_range &op1, ! const value_range &op2) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; *************** public: *** 738,750 **** const value_range &op1) const; } op_gt; ! value_range ! operator_gt::fold_range (tree type, const value_range &op1, const value_range &op2) const { - value_range r; if (empty_range_check (r, op1, op2)) ! return r; signop sign = TYPE_SIGN (op1.type ()); gcc_checking_assert (sign == TYPE_SIGN (op2.type ())); --- 732,743 ---- const value_range &op1) const; } op_gt; ! void ! operator_gt::fold_range (value_range &r, tree type, const value_range &op1, const value_range &op2) const { if (empty_range_check (r, op1, op2)) ! return; signop sign = TYPE_SIGN (op1.type ()); gcc_checking_assert (sign == TYPE_SIGN (op2.type ())); *************** operator_gt::fold_range (tree type, *** 755,761 **** r = range_false (type); else r = range_true_and_false (type); - return r; } bool --- 748,753 ---- *************** operator_gt::op2_range (value_range &r, *** 803,811 **** class operator_ge : public range_operator { public: ! virtual value_range fold_range (tree type, ! const value_range &op1, ! const value_range &op2) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; --- 795,803 ---- class operator_ge : public range_operator { public: ! virtual void fold_range (value_range &r, tree type, ! const value_range &op1, ! const value_range &op2) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; *************** public: *** 814,827 **** const value_range &op1) const; } op_ge; ! value_range ! operator_ge::fold_range (tree type, const value_range &op1, const value_range &op2) const { - value_range r; if (empty_range_check (r, op1, op2)) ! return r; signop sign = TYPE_SIGN (op1.type ()); gcc_checking_assert (sign == TYPE_SIGN (op2.type ())); --- 806,818 ---- const value_range &op1) const; } op_ge; ! void ! operator_ge::fold_range (value_range &r, tree type, const value_range &op1, const value_range &op2) const { if (empty_range_check (r, op1, op2)) ! return; signop sign = TYPE_SIGN (op1.type ()); gcc_checking_assert (sign == TYPE_SIGN (op2.type ())); *************** operator_ge::fold_range (tree type, *** 832,838 **** r = range_false (type); else r = range_true_and_false (type); - return r; } bool --- 823,828 ---- *************** public: *** 887,901 **** virtual bool op2_range (value_range &r, tree type, const value_range &lhs, const value_range &op1) const; ! virtual value_range wi_fold (tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; } op_plus; ! value_range ! operator_plus::wi_fold (tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { --- 877,891 ---- virtual bool op2_range (value_range &r, tree type, const value_range &lhs, const value_range &op1) const; ! virtual void wi_fold (value_range &r, tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; } op_plus; ! void ! operator_plus::wi_fold (value_range &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { *************** operator_plus::wi_fold (tree type, *** 903,909 **** signop s = TYPE_SIGN (type); wide_int new_lb = wi::add (lh_lb, rh_lb, s, &ov_lb); wide_int new_ub = wi::add (lh_ub, rh_ub, s, &ov_ub); ! return value_range_with_overflow (type, new_lb, new_ub, ov_lb, ov_ub); } bool --- 893,899 ---- signop s = TYPE_SIGN (type); wide_int new_lb = wi::add (lh_lb, rh_lb, s, &ov_lb); wide_int new_ub = wi::add (lh_ub, rh_ub, s, &ov_ub); ! value_range_with_overflow (r, type, new_lb, new_ub, ov_lb, ov_ub); } bool *************** operator_plus::op1_range (value_range &r *** 911,917 **** const value_range &lhs, const value_range &op2) const { ! r = range_op_handler (MINUS_EXPR, type)->fold_range (type, lhs, op2); return true; } --- 901,907 ---- const value_range &lhs, const value_range &op2) const { ! range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op2); return true; } *************** operator_plus::op2_range (value_range &r *** 920,926 **** const value_range &lhs, const value_range &op1) const { ! r = range_op_handler (MINUS_EXPR, type)->fold_range (type, lhs, op1); return true; } --- 910,916 ---- const value_range &lhs, const value_range &op1) const { ! range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op1); return true; } *************** public: *** 934,948 **** virtual bool op2_range (value_range &r, tree type, const value_range &lhs, const value_range &op1) const; ! virtual value_range wi_fold (tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; } op_minus; ! value_range ! operator_minus::wi_fold (tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { --- 924,938 ---- virtual bool op2_range (value_range &r, tree type, const value_range &lhs, const value_range &op1) const; ! virtual void wi_fold (value_range &r, tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; } op_minus; ! void ! operator_minus::wi_fold (value_range &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { *************** operator_minus::wi_fold (tree type, *** 950,956 **** signop s = TYPE_SIGN (type); wide_int new_lb = wi::sub (lh_lb, rh_ub, s, &ov_lb); wide_int new_ub = wi::sub (lh_ub, rh_lb, s, &ov_ub); ! return value_range_with_overflow (type, new_lb, new_ub, ov_lb, ov_ub); } bool --- 940,946 ---- signop s = TYPE_SIGN (type); wide_int new_lb = wi::sub (lh_lb, rh_ub, s, &ov_lb); wide_int new_ub = wi::sub (lh_ub, rh_lb, s, &ov_ub); ! value_range_with_overflow (r, type, new_lb, new_ub, ov_lb, ov_ub); } bool *************** operator_minus::op1_range (value_range & *** 958,964 **** const value_range &lhs, const value_range &op2) const { ! r = range_op_handler (PLUS_EXPR, type)->fold_range (type, lhs, op2); return true; } --- 948,954 ---- const value_range &lhs, const value_range &op2) const { ! range_op_handler (PLUS_EXPR, type)->fold_range (r, type, lhs, op2); return true; } *************** operator_minus::op2_range (value_range & *** 967,973 **** const value_range &lhs, const value_range &op1) const { ! r = fold_range (type, op1, lhs); return true; } --- 957,963 ---- const value_range &lhs, const value_range &op1) const { ! fold_range (r, type, op1, lhs); return true; } *************** operator_minus::op2_range (value_range & *** 975,1018 **** class operator_min : public range_operator { public: ! virtual value_range wi_fold (tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; } op_min; ! value_range ! operator_min::wi_fold (tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { signop s = TYPE_SIGN (type); wide_int new_lb = wi::min (lh_lb, rh_lb, s); wide_int new_ub = wi::min (lh_ub, rh_ub, s); ! return value_range_with_overflow (type, new_lb, new_ub); } class operator_max : public range_operator { public: ! virtual value_range wi_fold (tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; } op_max; ! value_range ! operator_max::wi_fold (tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { signop s = TYPE_SIGN (type); wide_int new_lb = wi::max (lh_lb, rh_lb, s); wide_int new_ub = wi::max (lh_ub, rh_ub, s); ! return value_range_with_overflow (type, new_lb, new_ub); } --- 965,1008 ---- class operator_min : public range_operator { public: ! virtual void wi_fold (value_range &r, tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; } op_min; ! void ! operator_min::wi_fold (value_range &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { signop s = TYPE_SIGN (type); wide_int new_lb = wi::min (lh_lb, rh_lb, s); wide_int new_ub = wi::min (lh_ub, rh_ub, s); ! value_range_with_overflow (r, type, new_lb, new_ub); } class operator_max : public range_operator { public: ! virtual void wi_fold (value_range &r, tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; } op_max; ! void ! operator_max::wi_fold (value_range &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { signop s = TYPE_SIGN (type); wide_int new_lb = wi::max (lh_lb, rh_lb, s); wide_int new_ub = wi::max (lh_ub, rh_ub, s); ! value_range_with_overflow (r, type, new_lb, new_ub); } *************** public: *** 1027,1037 **** const wide_int &) const = 0; // Calculate the cross product of two sets of sub-ranges and return it. ! value_range wi_cross_product (tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; }; // Calculate the cross product of two sets of ranges and return it. --- 1017,1027 ---- const wide_int &) const = 0; // Calculate the cross product of two sets of sub-ranges and return it. ! void wi_cross_product (value_range &r, tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; }; // Calculate the cross product of two sets of ranges and return it. *************** public: *** 1047,1077 **** // MIN1, MIN0 OP MAX1, MAX0 OP MIN1 and MAX0 OP MAX0 OP MAX1) and then // figure the smallest and largest values to form the new range. ! value_range ! cross_product_operator::wi_cross_product (tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { wide_int cp1, cp2, cp3, cp4; // Compute the 4 cross operations, bailing if we get an overflow we // can't handle. if (wi_op_overflows (cp1, type, lh_lb, rh_lb)) ! return value_range (type); if (wi::eq_p (lh_lb, lh_ub)) cp3 = cp1; else if (wi_op_overflows (cp3, type, lh_ub, rh_lb)) ! return value_range (type); if (wi::eq_p (rh_lb, rh_ub)) cp2 = cp1; else if (wi_op_overflows (cp2, type, lh_lb, rh_ub)) ! return value_range (type); if (wi::eq_p (lh_lb, lh_ub)) cp4 = cp2; else if (wi_op_overflows (cp4, type, lh_ub, rh_ub)) ! return value_range (type); // Order pairs. signop sign = TYPE_SIGN (type); --- 1037,1069 ---- // MIN1, MIN0 OP MAX1, MAX0 OP MIN1 and MAX0 OP MAX0 OP MAX1) and then // figure the smallest and largest values to form the new range. ! void ! cross_product_operator::wi_cross_product (value_range &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { wide_int cp1, cp2, cp3, cp4; + // Default to varying. + r = value_range (type); // Compute the 4 cross operations, bailing if we get an overflow we // can't handle. if (wi_op_overflows (cp1, type, lh_lb, rh_lb)) ! return; if (wi::eq_p (lh_lb, lh_ub)) cp3 = cp1; else if (wi_op_overflows (cp3, type, lh_ub, rh_lb)) ! return; if (wi::eq_p (rh_lb, rh_ub)) cp2 = cp1; else if (wi_op_overflows (cp2, type, lh_lb, rh_ub)) ! return; if (wi::eq_p (lh_lb, lh_ub)) cp4 = cp2; else if (wi_op_overflows (cp4, type, lh_ub, rh_ub)) ! return; // Order pairs. signop sign = TYPE_SIGN (type); *************** cross_product_operator::wi_cross_product *** 1083,1100 **** // Choose min and max from the ordered pairs. wide_int res_lb = wi::min (cp1, cp3, sign); wide_int res_ub = wi::max (cp2, cp4, sign); ! return value_range_with_overflow (type, res_lb, res_ub); } class operator_mult : public cross_product_operator { public: ! virtual value_range wi_fold (tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; virtual bool wi_op_overflows (wide_int &res, tree type, const wide_int &w0, const wide_int &w1) const; } op_mult; --- 1075,1092 ---- // Choose min and max from the ordered pairs. wide_int res_lb = wi::min (cp1, cp3, sign); wide_int res_ub = wi::max (cp2, cp4, sign); ! value_range_with_overflow (r, type, res_lb, res_ub); } class operator_mult : public cross_product_operator { public: ! virtual void wi_fold (value_range &r, tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; virtual bool wi_op_overflows (wide_int &res, tree type, const wide_int &w0, const wide_int &w1) const; } op_mult; *************** operator_mult::wi_op_overflows (wide_int *** 1119,1131 **** return overflow; } ! value_range ! operator_mult::wi_fold (tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { if (TYPE_OVERFLOW_UNDEFINED (type)) ! return wi_cross_product (type, lh_lb, lh_ub, rh_lb, rh_ub); // Multiply the ranges when overflow wraps. This is basically fancy // code so we don't drop to varying with an unsigned --- 1111,1126 ---- return overflow; } ! void ! operator_mult::wi_fold (value_range &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { if (TYPE_OVERFLOW_UNDEFINED (type)) ! { ! wi_cross_product (r, type, lh_lb, lh_ub, rh_lb, rh_ub); ! return; ! } // Multiply the ranges when overflow wraps. This is basically fancy // code so we don't drop to varying with an unsigned *************** operator_mult::wi_fold (tree type, *** 1186,1196 **** prod2 = prod3 - prod0; if (wi::geu_p (prod2, sizem1)) // The range covers all values. ! return value_range (type); ! ! wide_int new_lb = wide_int::from (prod0, prec, sign); ! wide_int new_ub = wide_int::from (prod3, prec, sign); ! return create_possibly_reversed_range (type, new_lb, new_ub); } --- 1181,1193 ---- prod2 = prod3 - prod0; if (wi::geu_p (prod2, sizem1)) // The range covers all values. ! r = value_range (type); ! else ! { ! wide_int new_lb = wide_int::from (prod0, prec, sign); ! wide_int new_ub = wide_int::from (prod3, prec, sign); ! create_possibly_reversed_range (r, type, new_lb, new_ub); ! } } *************** class operator_div : public cross_produc *** 1198,1208 **** { public: operator_div (enum tree_code c) { code = c; } ! virtual value_range wi_fold (tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; virtual bool wi_op_overflows (wide_int &res, tree type, const wide_int &, const wide_int &) const; private: --- 1195,1205 ---- { public: operator_div (enum tree_code c) { code = c; } ! virtual void wi_fold (value_range &r, tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; virtual bool wi_op_overflows (wide_int &res, tree type, const wide_int &, const wide_int &) const; private: *************** operator_div::wi_op_overflows (wide_int *** 1251,1264 **** return overflow; } ! value_range ! operator_div::wi_fold (tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { // If we know we will divide by zero, return undefined. if (rh_lb == 0 && rh_ub == 0) ! return value_range (); const wide_int dividend_min = lh_lb; const wide_int dividend_max = lh_ub; --- 1248,1264 ---- return overflow; } ! void ! operator_div::wi_fold (value_range &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { // If we know we will divide by zero, return undefined. if (rh_lb == 0 && rh_ub == 0) ! { ! r = value_range (); ! return; ! } const wide_int dividend_min = lh_lb; const wide_int dividend_max = lh_ub; *************** operator_div::wi_fold (tree type, *** 1270,1307 **** // If we know we won't divide by zero, just do the division. if (!wi_includes_zero_p (type, divisor_min, divisor_max)) ! return wi_cross_product (type, dividend_min, dividend_max, ! divisor_min, divisor_max); // If flag_non_call_exceptions, we must not eliminate a division by zero. if (cfun->can_throw_non_call_exceptions) ! return value_range (type); // If we're definitely dividing by zero, there's nothing to do. if (wi_zero_p (type, divisor_min, divisor_max)) ! return value_range (); // Perform the division in 2 parts, [LB, -1] and [1, UB], which will // skip any division by zero. // First divide by the negative numbers, if any. - value_range r; if (wi::neg_p (divisor_min, sign)) ! r = wi_cross_product (type, dividend_min, dividend_max, ! divisor_min, wi::minus_one (prec)); // Then divide by the non-zero positive numbers, if any. if (wi::gt_p (divisor_max, wi::zero (prec), sign)) { value_range tmp; ! tmp = wi_cross_product (type, dividend_min, dividend_max, ! wi::one (prec), divisor_max); r.union_ (tmp); } ! return r; } operator_div op_trunc_div (TRUNC_DIV_EXPR); ! operator_div op_floor_div(FLOOR_DIV_EXPR); operator_div op_round_div (ROUND_DIV_EXPR); operator_div op_ceil_div (CEIL_DIV_EXPR); --- 1270,1319 ---- // If we know we won't divide by zero, just do the division. if (!wi_includes_zero_p (type, divisor_min, divisor_max)) ! { ! wi_cross_product (r, type, dividend_min, dividend_max, ! divisor_min, divisor_max); ! return; ! } // If flag_non_call_exceptions, we must not eliminate a division by zero. if (cfun->can_throw_non_call_exceptions) ! { ! r = value_range (type); ! return; ! } // If we're definitely dividing by zero, there's nothing to do. if (wi_zero_p (type, divisor_min, divisor_max)) ! { ! r = value_range (); ! return; ! } // Perform the division in 2 parts, [LB, -1] and [1, UB], which will // skip any division by zero. // First divide by the negative numbers, if any. if (wi::neg_p (divisor_min, sign)) ! wi_cross_product (r, type, dividend_min, dividend_max, ! divisor_min, wi::minus_one (prec)); ! else ! r = value_range (); ! // Then divide by the non-zero positive numbers, if any. if (wi::gt_p (divisor_max, wi::zero (prec), sign)) { value_range tmp; ! wi_cross_product (tmp, type, dividend_min, dividend_max, ! wi::one (prec), divisor_max); r.union_ (tmp); } ! // We shouldn't still have undefined here. ! gcc_checking_assert (!r.undefined_p ()); } operator_div op_trunc_div (TRUNC_DIV_EXPR); ! operator_div op_floor_div (FLOOR_DIV_EXPR); operator_div op_round_div (ROUND_DIV_EXPR); operator_div op_ceil_div (CEIL_DIV_EXPR); *************** operator_exact_divide::op1_range (value_ *** 1331,1337 **** if (op2.singleton_p (&offset) && !integer_zerop (offset)) { ! r = range_op_handler (MULT_EXPR, type)->fold_range (type, lhs, op2); return true; } return false; --- 1343,1349 ---- if (op2.singleton_p (&offset) && !integer_zerop (offset)) { ! range_op_handler (MULT_EXPR, type)->fold_range (r, type, lhs, op2); return true; } return false; *************** operator_exact_divide::op1_range (value_ *** 1341,1367 **** class operator_lshift : public cross_product_operator { public: ! virtual value_range fold_range (tree type, ! const value_range &op1, ! const value_range &op2) const; ! virtual value_range wi_fold (tree type, ! const wide_int &lh_lb, const wide_int &lh_ub, ! const wide_int &rh_lb, const wide_int &rh_ub) const; virtual bool wi_op_overflows (wide_int &res, tree type, const wide_int &, const wide_int &) const; } op_lshift; ! value_range ! operator_lshift::fold_range (tree type, const value_range &op1, const value_range &op2) const { - value_range r; if (undefined_shift_range_check (r, type, op2)) ! return r; // Transform left shifts by constants into multiplies. if (op2.singleton_p ()) --- 1353,1378 ---- class operator_lshift : public cross_product_operator { public: ! virtual void fold_range (value_range &r, tree type, ! const value_range &op1, ! const value_range &op2) const; ! virtual void wi_fold (value_range &r, tree type, ! const wide_int &lh_lb, const wide_int &lh_ub, ! const wide_int &rh_lb, const wide_int &rh_ub) const; virtual bool wi_op_overflows (wide_int &res, tree type, const wide_int &, const wide_int &) const; } op_lshift; ! void ! operator_lshift::fold_range (value_range &r, tree type, const value_range &op1, const value_range &op2) const { if (undefined_shift_range_check (r, type, op2)) ! return; // Transform left shifts by constants into multiplies. if (op2.singleton_p ()) *************** operator_lshift::fold_range (tree type, *** 1375,1392 **** bool saved_flag_wrapv_pointer = flag_wrapv_pointer; flag_wrapv = 1; flag_wrapv_pointer = 1; ! r = range_op_handler (MULT_EXPR, type)->fold_range (type, op1, mult); flag_wrapv = saved_flag_wrapv; flag_wrapv_pointer = saved_flag_wrapv_pointer; ! return r; } // Otherwise, invoke the generic fold routine. ! return range_operator::fold_range (type, op1, op2); } ! value_range ! operator_lshift::wi_fold (tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { --- 1386,1403 ---- bool saved_flag_wrapv_pointer = flag_wrapv_pointer; flag_wrapv = 1; flag_wrapv_pointer = 1; ! range_op_handler (MULT_EXPR, type)->fold_range (r, type, op1, mult); flag_wrapv = saved_flag_wrapv; flag_wrapv_pointer = saved_flag_wrapv_pointer; ! return; } // Otherwise, invoke the generic fold routine. ! range_operator::fold_range (r, type, op1, op2); } ! void ! operator_lshift::wi_fold (value_range &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { *************** operator_lshift::wi_fold (tree type, *** 1440,1448 **** } if (in_bounds) ! return wi_cross_product (type, lh_lb, lh_ub, rh_lb, rh_ub); ! ! return value_range (type); } bool --- 1451,1459 ---- } if (in_bounds) ! wi_cross_product (r, type, lh_lb, lh_ub, rh_lb, rh_ub); ! else ! r = value_range (type); } bool *************** operator_lshift::wi_op_overflows (wide_i *** 1466,1479 **** class operator_rshift : public cross_product_operator { public: ! virtual value_range fold_range (tree type, ! const value_range &op1, ! const value_range &op2) const; ! virtual value_range wi_fold (tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; virtual bool wi_op_overflows (wide_int &res, tree type, const wide_int &w0, --- 1477,1490 ---- class operator_rshift : public cross_product_operator { public: ! virtual void fold_range (value_range &r, tree type, ! const value_range &op1, ! const value_range &op2) const; ! virtual void wi_fold (value_range &r, tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; virtual bool wi_op_overflows (wide_int &res, tree type, const wide_int &w0, *************** operator_rshift::wi_op_overflows (wide_i *** 1499,1547 **** return false; } ! value_range ! operator_rshift::fold_range (tree type, const value_range &op1, const value_range &op2) const { - value_range r; if (undefined_shift_range_check (r, type, op2)) ! return r; // Otherwise, invoke the generic fold routine. ! return range_operator::fold_range (type, op1, op2); } ! value_range ! operator_rshift::wi_fold (tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { ! return wi_cross_product (type, lh_lb, lh_ub, rh_lb, rh_ub); } class operator_cast: public range_operator { public: ! virtual value_range fold_range (tree type, ! const value_range &op1, ! const value_range &op2) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; } op_convert; ! value_range ! operator_cast::fold_range (tree type ATTRIBUTE_UNUSED, const value_range &lh, const value_range &rh) const { - value_range r; if (empty_range_check (r, lh, rh)) ! return r; ! tree inner = lh.type (); tree outer = rh.type (); gcc_checking_assert (rh.varying_p ()); --- 1510,1556 ---- return false; } ! void ! operator_rshift::fold_range (value_range &r, tree type, const value_range &op1, const value_range &op2) const { if (undefined_shift_range_check (r, type, op2)) ! return; // Otherwise, invoke the generic fold routine. ! range_operator::fold_range (r, type, op1, op2); } ! void ! operator_rshift::wi_fold (value_range &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { ! wi_cross_product (r, type, lh_lb, lh_ub, rh_lb, rh_ub); } class operator_cast: public range_operator { public: ! virtual void fold_range (value_range &r, tree type, ! const value_range &op1, ! const value_range &op2) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; } op_convert; ! void ! operator_cast::fold_range (value_range &r, tree type ATTRIBUTE_UNUSED, const value_range &lh, const value_range &rh) const { if (empty_range_check (r, lh, rh)) ! return; ! tree inner = lh.type (); tree outer = rh.type (); gcc_checking_assert (rh.varying_p ()); *************** operator_cast::fold_range (tree type ATT *** 1551,1556 **** --- 1560,1567 ---- unsigned inner_prec = TYPE_PRECISION (inner); unsigned outer_prec = TYPE_PRECISION (outer); + // Start with an empty range and add subranges. + r = value_range (); for (unsigned x = 0; x < lh.num_pairs (); ++x) { wide_int lh_lb = lh.lower_bound (x); *************** operator_cast::fold_range (tree type ATT *** 1572,1585 **** || !wi::eq_p (max, wi::max_value (outer_prec, outer_sign))) { value_range tmp; ! tmp = create_possibly_reversed_range (type, min, max); r.union_ (tmp); continue; } } ! return value_range (type); } - return r; } bool --- 1583,1596 ---- || !wi::eq_p (max, wi::max_value (outer_prec, outer_sign))) { value_range tmp; ! create_possibly_reversed_range (tmp, type, min, max); r.union_ (tmp); continue; } } ! r = value_range (type); ! return; } } bool *************** operator_cast::op1_range (value_range &r *** 1588,1593 **** --- 1599,1605 ---- const value_range &op2) const { tree lhs_type = lhs.type (); + value_range tmp; gcc_checking_assert (types_compatible_p (op2.type(), type)); // If the precision of the LHS is smaller than the precision of the *************** operator_cast::op1_range (value_range &r *** 1598,1612 **** // If we've been passed an actual value for the RHS rather than // the type, see if it fits the LHS, and if so, then we can allow // it. ! r = op2; ! r = fold_range (lhs_type, r, value_range (lhs_type)); ! r = fold_range (type, r, value_range (type)); ! if (r == op2) { // We know the value of the RHS fits in the LHS type, so // convert the LHS and remove any values that arent in OP2. ! r = lhs; ! r = fold_range (type, r, value_range (type)); r.intersect (op2); return true; } --- 1610,1622 ---- // If we've been passed an actual value for the RHS rather than // the type, see if it fits the LHS, and if so, then we can allow // it. ! fold_range (r, lhs_type, op2, value_range (lhs_type)); ! fold_range (tmp, type, r, value_range (type)); ! if (tmp == op2) { // We know the value of the RHS fits in the LHS type, so // convert the LHS and remove any values that arent in OP2. ! fold_range (r, type, lhs, value_range (type)); r.intersect (op2); return true; } *************** operator_cast::op1_range (value_range &r *** 1646,1662 **** if (TYPE_PRECISION (lhs_type) > TYPE_PRECISION (type)) { // Cast the range of the RHS to the type of the LHS. ! value_range op_type (type); ! op_type = fold_range (lhs_type, op_type, value_range (lhs_type)); ! ! // Intersect this with the LHS range will produce the RHS range. ! r = range_intersect (lhs, op_type); } else ! r = lhs; // Cast the calculated range to the type of the RHS. ! r = fold_range (type, r, value_range (type)); return true; } --- 1656,1671 ---- if (TYPE_PRECISION (lhs_type) > TYPE_PRECISION (type)) { // Cast the range of the RHS to the type of the LHS. ! fold_range (tmp, lhs_type, value_range (type), value_range (lhs_type)); ! // Intersect this with the LHS range will produce the range, which ! // will be cast to the RHS type before returning. ! tmp.intersect (lhs); } else ! tmp = lhs; // Cast the calculated range to the type of the RHS. ! fold_range (r, type, tmp, value_range (type)); return true; } *************** operator_cast::op1_range (value_range &r *** 1664,1672 **** class operator_logical_and : public range_operator { public: ! virtual value_range fold_range (tree type, ! const value_range &lh, ! const value_range &rh) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; --- 1673,1681 ---- class operator_logical_and : public range_operator { public: ! virtual void fold_range (value_range &r, tree type, ! const value_range &lh, ! const value_range &rh) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; *************** public: *** 1676,1702 **** } op_logical_and; ! value_range ! operator_logical_and::fold_range (tree type, const value_range &lh, const value_range &rh) const { - value_range r; if (empty_range_check (r, lh, rh)) ! return r; // 0 && anything is 0. if ((wi::eq_p (lh.lower_bound (), 0) && wi::eq_p (lh.upper_bound (), 0)) || (wi::eq_p (lh.lower_bound (), 0) && wi::eq_p (rh.upper_bound (), 0))) ! return range_false (type); ! ! // To reach this point, there must be a logical 1 on each side, and ! // the only remaining question is whether there is a zero or not. ! if (lh.contains_p (build_zero_cst (lh.type ())) ! || rh.contains_p (build_zero_cst (rh.type ()))) ! return range_true_and_false (type); ! ! return range_true (type); } bool --- 1685,1709 ---- } op_logical_and; ! void ! operator_logical_and::fold_range (value_range &r, tree type, const value_range &lh, const value_range &rh) const { if (empty_range_check (r, lh, rh)) ! return; // 0 && anything is 0. if ((wi::eq_p (lh.lower_bound (), 0) && wi::eq_p (lh.upper_bound (), 0)) || (wi::eq_p (lh.lower_bound (), 0) && wi::eq_p (rh.upper_bound (), 0))) ! r = range_false (type); ! else if (lh.contains_p (build_zero_cst (lh.type ())) ! || rh.contains_p (build_zero_cst (rh.type ()))) ! // To reach this point, there must be a logical 1 on each side, and ! // the only remaining question is whether there is a zero or not. ! r = range_true_and_false (type); ! else ! r = range_true (type); } bool *************** public: *** 1738,1748 **** virtual bool op2_range (value_range &r, tree type, const value_range &lhs, const value_range &op1) const; ! virtual value_range wi_fold (tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; } op_bitwise_and; // Optimize BIT_AND_EXPR and BIT_IOR_EXPR in terms of a mask if --- 1745,1755 ---- virtual bool op2_range (value_range &r, tree type, const value_range &lhs, const value_range &op1) const; ! virtual void wi_fold (value_range &r, tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; } op_bitwise_and; // Optimize BIT_AND_EXPR and BIT_IOR_EXPR in terms of a mask if *************** wi_optimize_and_or (value_range &r, *** 1820,1826 **** } else gcc_unreachable (); ! r = value_range_with_overflow (type, res_lb, res_ub); return true; } --- 1827,1833 ---- } else gcc_unreachable (); ! value_range_with_overflow (r, type, res_lb, res_ub); return true; } *************** wi_set_zero_nonzero_bits (tree type, *** 1864,1879 **** } } ! value_range ! operator_bitwise_and::wi_fold (tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { - value_range r; if (wi_optimize_and_or (r, BIT_AND_EXPR, type, lh_lb, lh_ub, rh_lb, rh_ub)) ! return r; wide_int maybe_nonzero_lh, mustbe_nonzero_lh; wide_int maybe_nonzero_rh, mustbe_nonzero_rh; --- 1871,1885 ---- } } ! void ! operator_bitwise_and::wi_fold (value_range &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { if (wi_optimize_and_or (r, BIT_AND_EXPR, type, lh_lb, lh_ub, rh_lb, rh_ub)) ! return; wide_int maybe_nonzero_lh, mustbe_nonzero_lh; wide_int maybe_nonzero_rh, mustbe_nonzero_rh; *************** operator_bitwise_and::wi_fold (tree type *** 1918,1926 **** } // If the limits got swapped around, return varying. if (wi::gt_p (new_lb, new_ub,sign)) ! return value_range (type); ! ! return value_range_with_overflow (type, new_lb, new_ub); } bool --- 1924,1932 ---- } // If the limits got swapped around, return varying. if (wi::gt_p (new_lb, new_ub,sign)) ! r = value_range (type); ! else ! value_range_with_overflow (r, type, new_lb, new_ub); } bool *************** operator_bitwise_and::op2_range (value_r *** 1949,1957 **** class operator_logical_or : public range_operator { public: ! virtual value_range fold_range (tree type, ! const value_range &lh, ! const value_range &rh) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; --- 1955,1963 ---- class operator_logical_or : public range_operator { public: ! virtual void fold_range (value_range &r, tree type, ! const value_range &lh, ! const value_range &rh) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; *************** public: *** 1960,1975 **** const value_range &op1) const; } op_logical_or; ! value_range ! operator_logical_or::fold_range (tree type ATTRIBUTE_UNUSED, const value_range &lh, const value_range &rh) const { - value_range r; if (empty_range_check (r, lh, rh)) ! return r; ! return range_union (lh, rh); } bool --- 1966,1980 ---- const value_range &op1) const; } op_logical_or; ! void ! operator_logical_or::fold_range (value_range &r, tree type ATTRIBUTE_UNUSED, const value_range &lh, const value_range &rh) const { if (empty_range_check (r, lh, rh)) ! return; ! r = range_union (lh, rh); } bool *************** public: *** 2011,2033 **** virtual bool op2_range (value_range &r, tree type, const value_range &lhs, const value_range &op1) const; ! virtual value_range wi_fold (tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; } op_bitwise_or; ! value_range ! operator_bitwise_or::wi_fold (tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { - value_range r; if (wi_optimize_and_or (r, BIT_IOR_EXPR, type, lh_lb, lh_ub, rh_lb, rh_ub)) ! return r; wide_int maybe_nonzero_lh, mustbe_nonzero_lh; wide_int maybe_nonzero_rh, mustbe_nonzero_rh; --- 2016,2037 ---- virtual bool op2_range (value_range &r, tree type, const value_range &lhs, const value_range &op1) const; ! virtual void wi_fold (value_range &r, tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; } op_bitwise_or; ! void ! operator_bitwise_or::wi_fold (value_range &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const { if (wi_optimize_and_or (r, BIT_IOR_EXPR, type, lh_lb, lh_ub, rh_lb, rh_ub)) ! return; wide_int maybe_nonzero_lh, mustbe_nonzero_lh; wide_int maybe_nonzero_rh, mustbe_nonzero_rh; *************** operator_bitwise_or::wi_fold (tree type, *** 2056,2064 **** new_lb = wi::max (new_lb, rh_lb, sign); // If the limits got swapped around, return varying. if (wi::gt_p (new_lb, new_ub,sign)) ! return value_range (type); ! ! return value_range_with_overflow (type, new_lb, new_ub); } bool --- 2060,2068 ---- new_lb = wi::max (new_lb, rh_lb, sign); // If the limits got swapped around, return varying. if (wi::gt_p (new_lb, new_ub,sign)) ! r = value_range (type); ! else ! value_range_with_overflow (r, type, new_lb, new_ub); } bool *************** operator_bitwise_or::op2_range (value_ra *** 2087,2101 **** class operator_bitwise_xor : public range_operator { public: ! virtual value_range wi_fold (tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; } op_bitwise_xor; ! value_range ! operator_bitwise_xor::wi_fold (tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, --- 2091,2105 ---- class operator_bitwise_xor : public range_operator { public: ! virtual void wi_fold (value_range &r, tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; } op_bitwise_xor; ! void ! operator_bitwise_xor::wi_fold (value_range &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, *************** operator_bitwise_xor::wi_fold (tree type *** 2120,2143 **** // If the range has all positive or all negative values, the result // is better than VARYING. if (wi::lt_p (new_lb, 0, sign) || wi::ge_p (new_ub, 0, sign)) ! return value_range_with_overflow (type, new_lb, new_ub); ! ! return value_range (type); } class operator_trunc_mod : public range_operator { public: ! virtual value_range wi_fold (tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; } op_trunc_mod; ! value_range ! operator_trunc_mod::wi_fold (tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, --- 2124,2147 ---- // If the range has all positive or all negative values, the result // is better than VARYING. if (wi::lt_p (new_lb, 0, sign) || wi::ge_p (new_ub, 0, sign)) ! value_range_with_overflow (r, type, new_lb, new_ub); ! else ! r = value_range (type); } class operator_trunc_mod : public range_operator { public: ! virtual void wi_fold (value_range &r, tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; } op_trunc_mod; ! void ! operator_trunc_mod::wi_fold (value_range &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, *************** operator_trunc_mod::wi_fold (tree type, *** 2149,2155 **** // Mod 0 is undefined. Return undefined. if (wi_zero_p (type, rh_lb, rh_ub)) ! return value_range (); // ABS (A % B) < ABS (B) and either 0 <= A % B <= A or A <= A % B <= 0. new_ub = rh_ub - 1; --- 2153,2162 ---- // Mod 0 is undefined. Return undefined. if (wi_zero_p (type, rh_lb, rh_ub)) ! { ! r = value_range (); ! return; ! } // ABS (A % B) < ABS (B) and either 0 <= A % B <= A or A <= A % B <= 0. new_ub = rh_ub - 1; *************** operator_trunc_mod::wi_fold (tree type, *** 2174,2189 **** tmp = wi::zero (prec); new_ub = wi::min (new_ub, tmp, sign); ! return value_range_with_overflow (type, new_lb, new_ub); } class operator_logical_not : public range_operator { public: ! virtual value_range fold_range (tree type, ! const value_range &lh, ! const value_range &rh) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; --- 2181,2196 ---- tmp = wi::zero (prec); new_ub = wi::min (new_ub, tmp, sign); ! value_range_with_overflow (r, type, new_lb, new_ub); } class operator_logical_not : public range_operator { public: ! virtual void fold_range (value_range &r, tree type, ! const value_range &lh, ! const value_range &rh) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; *************** public: *** 2203,2223 **** // b_2 = x_1 < 20 [0,0] = x_1 < 20, false, so x_1 == [20, 255] // which is the result we are looking for.. so.. pass it through. ! value_range ! operator_logical_not::fold_range (tree type, const value_range &lh, const value_range &rh ATTRIBUTE_UNUSED) const { - value_range r; if (empty_range_check (r, lh, rh)) ! return r; if (lh.varying_p () || lh.undefined_p ()) r = lh; else r = range_invert (lh); gcc_checking_assert (lh.type() == type); ! return r; } bool --- 2210,2229 ---- // b_2 = x_1 < 20 [0,0] = x_1 < 20, false, so x_1 == [20, 255] // which is the result we are looking for.. so.. pass it through. ! void ! operator_logical_not::fold_range (value_range &r, tree type, const value_range &lh, const value_range &rh ATTRIBUTE_UNUSED) const { if (empty_range_check (r, lh, rh)) ! return; if (lh.varying_p () || lh.undefined_p ()) r = lh; else r = range_invert (lh); gcc_checking_assert (lh.type() == type); ! return; } bool *************** operator_logical_not::op1_range (value_r *** 2237,2264 **** class operator_bitwise_not : public range_operator { public: ! virtual value_range fold_range (tree type, ! const value_range &lh, ! const value_range &rh) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; } op_bitwise_not; ! value_range ! operator_bitwise_not::fold_range (tree type, const value_range &lh, const value_range &rh) const { - value_range r; if (empty_range_check (r, lh, rh)) ! return r; // ~X is simply -1 - X. value_range minusone (type, wi::minus_one (TYPE_PRECISION (type)), wi::minus_one (TYPE_PRECISION (type))); ! r = range_op_handler (MINUS_EXPR, type)->fold_range (type, minusone, lh); ! return r; } bool --- 2243,2269 ---- class operator_bitwise_not : public range_operator { public: ! virtual void fold_range (value_range &r, tree type, ! const value_range &lh, ! const value_range &rh) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; } op_bitwise_not; ! void ! operator_bitwise_not::fold_range (value_range &r, tree type, const value_range &lh, const value_range &rh) const { if (empty_range_check (r, lh, rh)) ! return; // ~X is simply -1 - X. value_range minusone (type, wi::minus_one (TYPE_PRECISION (type)), wi::minus_one (TYPE_PRECISION (type))); ! range_op_handler (MINUS_EXPR, type)->fold_range (r, type, minusone, lh); ! return; } bool *************** operator_bitwise_not::op1_range (value_r *** 2267,2273 **** const value_range &op2) const { // ~X is -1 - X and since bitwise NOT is involutary...do it again. ! r = fold_range (type, lhs, op2); return true; } --- 2272,2278 ---- const value_range &op2) const { // ~X is -1 - X and since bitwise NOT is involutary...do it again. ! fold_range (r, type, lhs, op2); return true; } *************** operator_bitwise_not::op1_range (value_r *** 2275,2311 **** class operator_cst : public range_operator { public: ! virtual value_range fold_range (tree type, ! const value_range &op1, ! const value_range &op2) const; } op_integer_cst; ! value_range ! operator_cst::fold_range (tree type ATTRIBUTE_UNUSED, const value_range &lh, const value_range &rh ATTRIBUTE_UNUSED) const { ! return lh; } class operator_identity : public range_operator { public: ! virtual value_range fold_range (tree type, ! const value_range &op1, ! const value_range &op2) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; } op_identity; ! value_range ! operator_identity::fold_range (tree type ATTRIBUTE_UNUSED, const value_range &lh, const value_range &rh ATTRIBUTE_UNUSED) const { ! return lh; } bool --- 2280,2316 ---- class operator_cst : public range_operator { public: ! virtual void fold_range (value_range &r, tree type, ! const value_range &op1, ! const value_range &op2) const; } op_integer_cst; ! void ! operator_cst::fold_range (value_range &r, tree type ATTRIBUTE_UNUSED, const value_range &lh, const value_range &rh ATTRIBUTE_UNUSED) const { ! r = lh; } class operator_identity : public range_operator { public: ! virtual void fold_range (value_range &r, tree type, ! const value_range &op1, ! const value_range &op2) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; } op_identity; ! void ! operator_identity::fold_range (value_range &r, tree type ATTRIBUTE_UNUSED, const value_range &lh, const value_range &rh ATTRIBUTE_UNUSED) const { ! r = lh; } bool *************** operator_identity::op1_range (value_rang *** 2321,2338 **** class operator_abs : public range_operator { public: ! virtual value_range wi_fold (tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; } op_abs; ! value_range ! operator_abs::wi_fold (tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb ATTRIBUTE_UNUSED, const wide_int &rh_ub ATTRIBUTE_UNUSED) const --- 2326,2343 ---- class operator_abs : public range_operator { public: ! virtual void wi_fold (value_range &r, tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; } op_abs; ! void ! operator_abs::wi_fold (value_range &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb ATTRIBUTE_UNUSED, const wide_int &rh_ub ATTRIBUTE_UNUSED) const *************** operator_abs::wi_fold (tree type, *** 2343,2356 **** // Pass through LH for the easy cases. if (sign == UNSIGNED || wi::ge_p (lh_lb, 0, sign)) ! return value_range (type, lh_lb, lh_ub); // -TYPE_MIN_VALUE = TYPE_MIN_VALUE with flag_wrapv so we can't get // a useful range. wide_int min_value = wi::min_value (prec, sign); wide_int max_value = wi::max_value (prec, sign); if (!TYPE_OVERFLOW_UNDEFINED (type) && wi::eq_p (lh_lb, min_value)) ! return value_range (type); // ABS_EXPR may flip the range around, if the original range // included negative values. --- 2348,2367 ---- // Pass through LH for the easy cases. if (sign == UNSIGNED || wi::ge_p (lh_lb, 0, sign)) ! { ! r = value_range (type, lh_lb, lh_ub); ! return; ! } // -TYPE_MIN_VALUE = TYPE_MIN_VALUE with flag_wrapv so we can't get // a useful range. wide_int min_value = wi::min_value (prec, sign); wide_int max_value = wi::max_value (prec, sign); if (!TYPE_OVERFLOW_UNDEFINED (type) && wi::eq_p (lh_lb, min_value)) ! { ! r = value_range (type, lh_lb, lh_ub); ! return; ! } // ABS_EXPR may flip the range around, if the original range // included negative values. *************** operator_abs::wi_fold (tree type, *** 2386,2392 **** min = wi::zero (prec); max = max_value; } ! return value_range (type, min, max); } bool --- 2397,2403 ---- min = wi::zero (prec); max = max_value; } ! r = value_range (type, min, max); } bool *************** operator_abs::op1_range (value_range &r, *** 2418,2430 **** class operator_absu : public range_operator { public: ! virtual value_range wi_fold (tree type, ! const wide_int &lh_lb, const wide_int &lh_ub, ! const wide_int &rh_lb, const wide_int &rh_ub) const; } op_absu; ! value_range ! operator_absu::wi_fold (tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb ATTRIBUTE_UNUSED, const wide_int &rh_ub ATTRIBUTE_UNUSED) const --- 2429,2441 ---- class operator_absu : public range_operator { public: ! virtual void wi_fold (value_range &r, tree type, ! const wide_int &lh_lb, const wide_int &lh_ub, ! const wide_int &rh_lb, const wide_int &rh_ub) const; } op_absu; ! void ! operator_absu::wi_fold (value_range &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb ATTRIBUTE_UNUSED, const wide_int &rh_ub ATTRIBUTE_UNUSED) const *************** operator_absu::wi_fold (tree type, *** 2455,2487 **** } gcc_checking_assert (TYPE_UNSIGNED (type)); ! return value_range (type, new_lb, new_ub); } class operator_negate : public range_operator { public: ! virtual value_range fold_range (tree type, ! const value_range &op1, ! const value_range &op2) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; } op_negate; ! value_range ! operator_negate::fold_range (tree type, const value_range &lh, const value_range &rh) const { - value_range r; if (empty_range_check (r, lh, rh)) ! return r; // -X is simply 0 - X. ! return ! range_op_handler (MINUS_EXPR, type)->fold_range (type, ! range_zero (type), lh); } bool --- 2466,2496 ---- } gcc_checking_assert (TYPE_UNSIGNED (type)); ! r = value_range (type, new_lb, new_ub); } class operator_negate : public range_operator { public: ! virtual void fold_range (value_range &r, tree type, ! const value_range &op1, ! const value_range &op2) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; } op_negate; ! void ! operator_negate::fold_range (value_range &r, tree type, const value_range &lh, const value_range &rh) const { if (empty_range_check (r, lh, rh)) ! return; // -X is simply 0 - X. ! range_op_handler (MINUS_EXPR, type)->fold_range (r, type, ! range_zero (type), lh); } bool *************** operator_negate::op1_range (value_range *** 2490,2496 **** const value_range &op2) const { // NEGATE is involutory. ! r = fold_range (type, lhs, op2); return true; } --- 2499,2505 ---- const value_range &op2) const { // NEGATE is involutory. ! fold_range (r, type, lhs, op2); return true; } *************** operator_negate::op1_range (value_range *** 2498,2526 **** class operator_addr_expr : public range_operator { public: ! virtual value_range fold_range (tree type, ! const value_range &op1, ! const value_range &op2) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; } op_addr; ! value_range ! operator_addr_expr::fold_range (tree type, const value_range &lh, const value_range &rh) const { - value_range r; if (empty_range_check (r, lh, rh)) ! return r; // Return a non-null pointer of the LHS type (passed in op2). if (lh.zero_p ()) ! return range_zero (type); ! if (!lh.contains_p (build_zero_cst (lh.type ()))) ! return range_nonzero (type); ! return value_range (type); } bool --- 2507,2535 ---- class operator_addr_expr : public range_operator { public: ! virtual void fold_range (value_range &r, tree type, ! const value_range &op1, ! const value_range &op2) const; virtual bool op1_range (value_range &r, tree type, const value_range &lhs, const value_range &op2) const; } op_addr; ! void ! operator_addr_expr::fold_range (value_range &r, tree type, const value_range &lh, const value_range &rh) const { if (empty_range_check (r, lh, rh)) ! return; // Return a non-null pointer of the LHS type (passed in op2). if (lh.zero_p ()) ! r = range_zero (type); ! else if (!lh.contains_p (build_zero_cst (lh.type ()))) ! r = range_nonzero (type); ! else ! r = value_range (type); } bool *************** operator_addr_expr::op1_range (value_ran *** 2528,2534 **** const value_range &lhs, const value_range &op2) const { ! r = operator_addr_expr::fold_range (type, lhs, op2); return true; } --- 2537,2543 ---- const value_range &lhs, const value_range &op2) const { ! operator_addr_expr::fold_range (r, type, lhs, op2); return true; } *************** operator_addr_expr::op1_range (value_ran *** 2536,2550 **** class pointer_plus_operator : public range_operator { public: ! virtual value_range wi_fold (tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; } op_pointer_plus; ! value_range ! pointer_plus_operator::wi_fold (tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, --- 2545,2559 ---- class pointer_plus_operator : public range_operator { public: ! virtual void wi_fold (value_range &r, tree type, ! const wide_int &lh_lb, ! const wide_int &lh_ub, ! const wide_int &rh_lb, ! const wide_int &rh_ub) const; } op_pointer_plus; ! void ! pointer_plus_operator::wi_fold (value_range &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, *************** pointer_plus_operator::wi_fold (tree typ *** 2571,2594 **** && !TYPE_OVERFLOW_WRAPS (type) && (flag_delete_null_pointer_checks || !wi::sign_mask (rh_ub))) ! return range_nonzero (type); ! if (lh_lb == lh_ub && lh_lb == 0 ! && rh_lb == rh_ub && rh_lb == 0) ! return range_zero (type); ! return value_range (type); } class pointer_min_max_operator : public range_operator { public: ! virtual value_range wi_fold (tree type, ! const wide_int &lh_lb, const wide_int &lh_ub, ! const wide_int &rh_lb, const wide_int &rh_ub) const; } op_ptr_min_max; ! value_range ! pointer_min_max_operator::wi_fold (tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, --- 2580,2604 ---- && !TYPE_OVERFLOW_WRAPS (type) && (flag_delete_null_pointer_checks || !wi::sign_mask (rh_ub))) ! r = range_nonzero (type); ! else if (lh_lb == lh_ub && lh_lb == 0 ! && rh_lb == rh_ub && rh_lb == 0) ! r = range_zero (type); ! else ! r = value_range (type); } class pointer_min_max_operator : public range_operator { public: ! virtual void wi_fold (value_range & r, tree type, ! const wide_int &lh_lb, const wide_int &lh_ub, ! const wide_int &rh_lb, const wide_int &rh_ub) const; } op_ptr_min_max; ! void ! pointer_min_max_operator::wi_fold (value_range &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, *************** pointer_min_max_operator::wi_fold (tree *** 2600,2622 **** // are varying. if (!wi_includes_zero_p (type, lh_lb, lh_ub) && !wi_includes_zero_p (type, rh_lb, rh_ub)) ! return range_nonzero (type); ! if (wi_zero_p (type, lh_lb, lh_ub) && wi_zero_p (type, rh_lb, rh_ub)) ! return range_zero (type); ! return value_range (type); } class pointer_and_operator : public range_operator { public: ! virtual value_range wi_fold (tree type, ! const wide_int &lh_lb, const wide_int &lh_ub, ! const wide_int &rh_lb, const wide_int &rh_ub) const; } op_pointer_and; ! value_range ! pointer_and_operator::wi_fold (tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb ATTRIBUTE_UNUSED, --- 2610,2633 ---- // are varying. if (!wi_includes_zero_p (type, lh_lb, lh_ub) && !wi_includes_zero_p (type, rh_lb, rh_ub)) ! r = range_nonzero (type); ! else if (wi_zero_p (type, lh_lb, lh_ub) && wi_zero_p (type, rh_lb, rh_ub)) ! r = range_zero (type); ! else ! r = value_range (type); } class pointer_and_operator : public range_operator { public: ! virtual void wi_fold (value_range &r, tree type, ! const wide_int &lh_lb, const wide_int &lh_ub, ! const wide_int &rh_lb, const wide_int &rh_ub) const; } op_pointer_and; ! void ! pointer_and_operator::wi_fold (value_range &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb ATTRIBUTE_UNUSED, *************** pointer_and_operator::wi_fold (tree type *** 2625,2646 **** // For pointer types, we are really only interested in asserting // whether the expression evaluates to non-NULL. if (wi_zero_p (type, lh_lb, lh_ub) || wi_zero_p (type, lh_lb, lh_ub)) ! return range_zero (type); ! ! return value_range (type); } class pointer_or_operator : public range_operator { public: ! virtual value_range wi_fold (tree type, ! const wide_int &lh_lb, const wide_int &lh_ub, ! const wide_int &rh_lb, const wide_int &rh_ub) const; } op_pointer_or; ! value_range ! pointer_or_operator::wi_fold (tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, --- 2636,2657 ---- // For pointer types, we are really only interested in asserting // whether the expression evaluates to non-NULL. if (wi_zero_p (type, lh_lb, lh_ub) || wi_zero_p (type, lh_lb, lh_ub)) ! r = range_zero (type); ! else ! r = value_range (type); } class pointer_or_operator : public range_operator { public: ! virtual void wi_fold (value_range &r, tree type, ! const wide_int &lh_lb, const wide_int &lh_ub, ! const wide_int &rh_lb, const wide_int &rh_ub) const; } op_pointer_or; ! void ! pointer_or_operator::wi_fold (value_range &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, *************** pointer_or_operator::wi_fold (tree type, *** 2650,2659 **** // whether the expression evaluates to non-NULL. if (!wi_includes_zero_p (type, lh_lb, lh_ub) && !wi_includes_zero_p (type, rh_lb, rh_ub)) ! return range_nonzero (type); ! if (wi_zero_p (type, lh_lb, lh_ub) && wi_zero_p (type, rh_lb, rh_ub)) ! return range_zero (type); ! return value_range (type); } // This implements the range operator tables as local objects in this file. --- 2661,2671 ---- // whether the expression evaluates to non-NULL. if (!wi_includes_zero_p (type, lh_lb, lh_ub) && !wi_includes_zero_p (type, rh_lb, rh_ub)) ! r = range_nonzero (type); ! else if (wi_zero_p (type, lh_lb, lh_ub) && wi_zero_p (type, rh_lb, rh_ub)) ! r = range_zero (type); ! else ! r = value_range (type); } // This implements the range operator tables as local objects in this file. *************** range_op_handler (enum tree_code code, t *** 2782,2789 **** void range_cast (value_range &r, tree type) { range_operator *op = range_op_handler (CONVERT_EXPR, type); ! r = op->fold_range (type, r, value_range (type)); } #if CHECKING_P --- 2794,2802 ---- void range_cast (value_range &r, tree type) { + value_range tmp = r; range_operator *op = range_op_handler (CONVERT_EXPR, type); ! op->fold_range (r, type, tmp, value_range (type)); } #if CHECKING_P Index: tree-vrp.c =================================================================== *** tree-vrp.c (revision 277853) --- tree-vrp.c (working copy) *************** range_fold_binary_symbolics_p (value_ran *** 1781,1789 **** return true; } const range_operator *op = get_range_op_handler (vr, code, expr_type); ! *vr = op->fold_range (expr_type, ! vr0->normalize_symbolics (), ! vr1->normalize_symbolics ()); return true; } return false; --- 1781,1788 ---- return true; } const range_operator *op = get_range_op_handler (vr, code, expr_type); ! op->fold_range (*vr, expr_type, vr0->normalize_symbolics (), ! vr1->normalize_symbolics ()); return true; } return false; *************** range_fold_unary_symbolics_p (value_rang *** 1817,1825 **** return true; } const range_operator *op = get_range_op_handler (vr, code, expr_type); ! *vr = op->fold_range (expr_type, ! vr0->normalize_symbolics (), ! value_range (expr_type)); return true; } return false; --- 1816,1823 ---- return true; } const range_operator *op = get_range_op_handler (vr, code, expr_type); ! op->fold_range (*vr, expr_type, vr0->normalize_symbolics (), ! value_range (expr_type)); return true; } return false; *************** range_fold_binary_expr (value_range *vr, *** 1846,1854 **** if (range_fold_binary_symbolics_p (vr, code, expr_type, &vr0, &vr1)) return; ! *vr = op->fold_range (expr_type, ! vr0.normalize_addresses (), ! vr1.normalize_addresses ()); } /* Perform a unary operation on a range. */ --- 1844,1851 ---- if (range_fold_binary_symbolics_p (vr, code, expr_type, &vr0, &vr1)) return; ! op->fold_range (*vr, expr_type, vr0.normalize_addresses (), ! vr1.normalize_addresses ()); } /* Perform a unary operation on a range. */ *************** range_fold_unary_expr (value_range *vr, *** 1869,1877 **** if (range_fold_unary_symbolics_p (vr, code, expr_type, vr0)) return; ! *vr = op->fold_range (expr_type, ! vr0->normalize_addresses (), ! value_range (expr_type)); } /* Given a COND_EXPR COND of the form 'V OP W', and an SSA name V, --- 1866,1873 ---- if (range_fold_unary_symbolics_p (vr, code, expr_type, vr0)) return; ! op->fold_range (*vr, expr_type, vr0->normalize_addresses (), ! value_range (expr_type)); } /* Given a COND_EXPR COND of the form 'V OP W', and an SSA name V,