From patchwork Tue Jun 22 13:17:57 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Andrew MacLeod X-Patchwork-Id: 1495678 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=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=ZiH7A0hy; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4G8Rnw0bwWz9sS8 for ; Tue, 22 Jun 2021 23:19:48 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D75E73891C1B for ; Tue, 22 Jun 2021 13:19:44 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D75E73891C1B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1624367984; bh=e9hqhgeEewldJbGXTNR6PzRk8RHw+jYrD/r22atqUcA=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=ZiH7A0hyt+l7SMiPgI12aCJBkCBvO4WF9PTJDXmmEgnS5q2lNYhNsuI980WGo9hZo iME8OuMhNRYueCc7gQ+i/Hx01ketMbAkAWVIVhAllSYS7RjWrIRk3KsZvre9xlGY2G QZRveZ9OMR6nNAH6omgpN3UJM0xXFkhYNf5OCbLE= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id 368333892473 for ; Tue, 22 Jun 2021 13:18:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 368333892473 Received: from mail-qk1-f198.google.com (mail-qk1-f198.google.com [209.85.222.198]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-504-VQIVfh1vN_aWpM3pDEoRhg-1; Tue, 22 Jun 2021 09:18:01 -0400 X-MC-Unique: VQIVfh1vN_aWpM3pDEoRhg-1 Received: by mail-qk1-f198.google.com with SMTP id c3-20020a37b3030000b02903ad0001a2e8so17939533qkf.3 for ; Tue, 22 Jun 2021 06:18:00 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:to:cc:from:subject:message-id:date:user-agent :mime-version:content-language; bh=e9hqhgeEewldJbGXTNR6PzRk8RHw+jYrD/r22atqUcA=; b=S69keJSsLZwyjLb60/Yc/nKsR0Z9V1F0UxPKKVmBhqPd1T4JpS+kCjSG6qjTH28ICg 16KwMsLeJ1Lmzsh5SE2+ZR1Qazv1KB0vgnHmiTJdfmqHDR92JMqFUV6pIIadRJjqn93n u63xBUBPhybIbQZ6TyGSLFmSYuWVKRMuLTsp7gTVRJJTR8g0ERCRiE7cbsOoaMU9YAcD QStnPFijAdseKwqh1c4SV91tUS96rAtTX+kAXYPBPuh6dzl8HjSf4pXMYwvYfd9a9x0+ cpkghJxQPXDCGm2rIn3Mdc40ZubGJt0mE1aXCRaAl+6RdbKtSZS8h8oeJhCQq/DFrLE/ LqYw== X-Gm-Message-State: AOAM53230mcCc4FGzI32SJufqHwhB2HMExaDrzfmzWXaAkyraVVrHA4V Tsdqa0Iekc87SrmFNwBL5of2eA9BC4GEv1x4JCAaTDRMvC5gxqqJCvunq+Kb2jtGCZB5ofajyES c2aYMcbRJbKXrlyPqmA== X-Received: by 2002:a37:cc1:: with SMTP id 184mr4302008qkm.218.1624367880627; Tue, 22 Jun 2021 06:18:00 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwosZGZAv6tGvueymBRFs7cnn8OuNlb2L2M4v2NkPS/JmzYncsjr3mELdCcH1uD9OZwh1evZA== X-Received: by 2002:a37:cc1:: with SMTP id 184mr4301989qkm.218.1624367880459; Tue, 22 Jun 2021 06:18:00 -0700 (PDT) Received: from ?IPv6:2607:fea8:a241:4600:84d5:145a:ba5d:a5af? ([2607:fea8:a241:4600:84d5:145a:ba5d:a5af]) by smtp.gmail.com with ESMTPSA id m3sm10244733qkk.27.2021.06.22.06.17.58 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 22 Jun 2021 06:17:59 -0700 (PDT) To: gcc-patches Subject: [COMMITTED 2/7] Add relational support to range-op. Message-ID: <9cdb3a62-6be5-4d71-651f-bcd19a3ab454@redhat.com> Date: Tue, 22 Jun 2021 09:17:57 -0400 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.10.0 MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-CA X-Spam-Status: No, score=-12.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Andrew MacLeod via Gcc-patches From: Andrew MacLeod Reply-To: Andrew MacLeod Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" THis patch adds relation support to range-ops. a relation_kind is added to all fold and op1/2_range operations, which will allow any known relation to be applied during calculations. 4 more routines are provided which enable range-ops to indicate when a relation is caused by an expression/result and what effects it may have.    All relations are driven from these routines. virtual enum tree_code lhs_op1_relation (const irange &lhs, const irange &op1, const irange &op2) const; virtual enum tree_code lhs_op2_relation (const irange &lhs, const irange &op1, const irange &op2) const; virtual enum tree_code op1_op2_relation (const irange &lhs) const; virtual bool op1_op2_relation_effect (irange &lhs_range, tree type, const irange &op1_range, const irange &op2_range, relation_kind rel) const; This initial patch provides the basic of the relation opcodes. Ie,  operator_equal has added enum tree_code operator_equal::op1_op2_relation (const irange &lhs) const {   if (lhs.undefined_p ())     return VREL_EMPTY;   // FALSE = op1 == op2 indicates NE_EXPR.   if (lhs.zero_p ())     return NE_EXPR;   // TRUE = op1 == op2 indicates EQ_EXPR.   if (!lhs.contains_p (build_zero_cst (lhs.type ())))     return EQ_EXPR;   return VREL_NONE; } This teaches range-ops that there is a relation between op1 and op2 is the LHS has a range of FALSE, or TRUE.  Otherwise, we don't know what the relation is. All 6 basic relations are implemented, as well as folding of these opcodes when a relation is to be applied.  Ie, how to fold it ( if a_2 == b_2 is being folded., and the known relation coming into this expression is a_2 > b_2, it will fold to [0,0] or false. Again, this patch on its own will not cause anything to actually happen, that will be enabled in the next patch. Virtually all relation generation and application is handled via these range-ops routines.  Bootstraps on x86_64-pc-linux-gnu with no regressions.  Pushed. Andrew From 80dd13f5c3bdc7899ee6e863e05b254815ec0cef Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Thu, 17 Jun 2021 11:49:21 -0400 Subject: [PATCH 2/7] Add relational support to range-op. This patch integrates relations with range-op functionality so that any known relations can be used to help reduce or resolve ranges. Initially handle EQ_EXPR, NE_EXPR, LE_EXPR, LT_EXPR, GT_EXPR and GE_EXPR. * range-op.cc (range_operator::wi_fold): Apply relation effect. (range_operator::fold_range): Adjust and apply relation effect. (*::fold_range): Add relation parameters. (*::op1_range): Ditto. (*::op2_range): Ditto. (range_operator::lhs_op1_relation): New. (range_operator::lhs_op2_relation): New. (range_operator::op1_op2_relation): New. (range_operator::op1_op2_relation_effect): New. (relop_early_resolve): New. (operator_equal::op1_op2_relation): New. (operator_equal::fold_range): Call relop_early_resolve. (operator_not_equal::op1_op2_relation): New. (operator_not_equal::fold_range): Call relop_early_resolve. (operator_lt::op1_op2_relation): New. (operator_lt::fold_range): Call relop_early_resolve. (operator_le::op1_op2_relation): New. (operator_le::fold_range): Call relop_early_resolve. (operator_gt::op1_op2_relation): New. (operator_gt::fold_range): Call relop_early_resolve. (operator_ge::op1_op2_relation): New. (operator_ge::fold_range): Call relop_early_resolve. * range-op.h (class range_operator): Adjust parameters and methods. --- gcc/range-op.cc | 584 +++++++++++++++++++++++++++++++++++++----------- gcc/range-op.h | 24 +- 2 files changed, 469 insertions(+), 139 deletions(-) diff --git a/gcc/range-op.cc b/gcc/range-op.cc index e805f26a333..d807693900a 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see #include "gimple-walk.h" #include "tree-cfg.h" #include "wide-int.h" +#include "value-relation.h" #include "range-op.h" // Return the upper limit for a type. @@ -138,7 +139,8 @@ range_operator::wi_fold (irange &r, tree type, bool range_operator::fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const + const irange &rh, + relation_kind rel) const { gcc_checking_assert (irange::supports_type_p (type)); if (empty_range_varying (r, type, lh, rh)) @@ -152,6 +154,7 @@ range_operator::fold_range (irange &r, tree type, { wi_fold (r, type, lh.lower_bound (0), lh.upper_bound (0), rh.lower_bound (0), rh.upper_bound (0)); + op1_op2_relation_effect (r, type, lh, rh, rel); return true; } @@ -167,8 +170,12 @@ range_operator::fold_range (irange &r, tree type, wi_fold (tmp, type, lh_lb, lh_ub, rh_lb, rh_ub); r.union_ (tmp); if (r.varying_p ()) - return true; + { + op1_op2_relation_effect (r, type, lh, rh, rel); + return true; + } } + op1_op2_relation_effect (r, type, lh, rh, rel); return true; } @@ -178,7 +185,8 @@ bool range_operator::op1_range (irange &r ATTRIBUTE_UNUSED, tree type ATTRIBUTE_UNUSED, const irange &lhs ATTRIBUTE_UNUSED, - const irange &op2 ATTRIBUTE_UNUSED) const + const irange &op2 ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const { return false; } @@ -189,11 +197,47 @@ bool range_operator::op2_range (irange &r ATTRIBUTE_UNUSED, tree type ATTRIBUTE_UNUSED, const irange &lhs ATTRIBUTE_UNUSED, - const irange &op1 ATTRIBUTE_UNUSED) const + const irange &op1 ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const { return false; } +// The default relation routines return VREL_NONE. + +enum tree_code +range_operator::lhs_op1_relation (const irange &lhs ATTRIBUTE_UNUSED, + const irange &op1 ATTRIBUTE_UNUSED, + const irange &op2 ATTRIBUTE_UNUSED) const +{ + return VREL_NONE; +} + +enum tree_code +range_operator::lhs_op2_relation (const irange &lhs ATTRIBUTE_UNUSED, + const irange &op1 ATTRIBUTE_UNUSED, + const irange &op2 ATTRIBUTE_UNUSED) const +{ + return VREL_NONE; +} + +enum tree_code +range_operator::op1_op2_relation (const irange &lhs ATTRIBUTE_UNUSED) const +{ + return VREL_NONE; +} + +// Default is no relation affects the LHS. + +bool +range_operator::op1_op2_relation_effect (irange &lhs_range ATTRIBUTE_UNUSED, + tree type ATTRIBUTE_UNUSED, + const irange &op1_range ATTRIBUTE_UNUSED, + const irange &op2_range ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const +{ + return false; +} // Create and return a range from a pair of wide-ints that are known // to have overflowed (or underflowed). @@ -385,27 +429,82 @@ get_bool_state (irange &r, const irange &lhs, tree val_type) return BRS_TRUE; } +// For relation opcodes, first try to see if the supplied relation +// forces a true or false result, and return that. +// Then check for undefined operands. If none of this applies, +// return false. + +static inline bool +relop_early_resolve (irange &r, tree type, const irange &op1, + const irange &op2, relation_kind rel, + relation_kind my_rel) +{ + // If known relation is a complete subset of this relation, always true. + if (relation_union (rel, my_rel) == my_rel) + { + r = range_true (type); + return true; + } + + // If known relation has no subset of this relation, always false. + if (relation_intersect (rel, my_rel) == VREL_EMPTY) + { + r = range_false (type); + return true; + } + + // If either operand is undefined, return VARYING. + if (empty_range_varying (r, type, op1, op2)) + return true; + + return false; +} + class operator_equal : public range_operator { public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &val) const; + const irange &val, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &val) const; + const irange &val, + relation_kind rel = VREL_NONE) const; + virtual enum tree_code op1_op2_relation (const irange &lhs) const; } op_equal; +// Check if the LHS range indicates a relation between OP1 and OP2. + +enum tree_code +operator_equal::op1_op2_relation (const irange &lhs) const +{ + if (lhs.undefined_p ()) + return VREL_EMPTY; + + // FALSE = op1 == op2 indicates NE_EXPR. + if (lhs.zero_p ()) + return NE_EXPR; + + // TRUE = op1 == op2 indicates EQ_EXPR. + if (!lhs.contains_p (build_zero_cst (lhs.type ()))) + return EQ_EXPR; + return VREL_NONE; +} + + bool operator_equal::fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const + const irange &op2, + relation_kind rel) const { - if (empty_range_varying (r, type, op1, op2)) + if (relop_early_resolve (r, type, op1, op2, rel, EQ_EXPR)) return true; // We can be sure the values are always equal or not if both ranges @@ -435,7 +534,8 @@ operator_equal::fold_range (irange &r, tree type, bool operator_equal::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -465,32 +565,55 @@ operator_equal::op1_range (irange &r, tree type, bool operator_equal::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel) const { - return operator_equal::op1_range (r, type, lhs, op1); + return operator_equal::op1_range (r, type, lhs, op1, rel); } - class operator_not_equal : public range_operator { public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; + virtual enum tree_code op1_op2_relation (const irange &lhs) const; } op_not_equal; +// Check if the LHS range indicates a relation between OP1 and OP2. + +enum tree_code +operator_not_equal::op1_op2_relation (const irange &lhs) const +{ + if (lhs.undefined_p ()) + return VREL_EMPTY; + + // FALSE = op1 != op2 indicates EQ_EXPR. + if (lhs.zero_p ()) + return EQ_EXPR; + + // TRUE = op1 != op2 indicates NE_EXPR. + if (!lhs.contains_p (build_zero_cst (lhs.type ()))) + return NE_EXPR; + return VREL_NONE; +} + bool operator_not_equal::fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const + const irange &op2, + relation_kind rel) const { - if (empty_range_varying (r, type, op1, op2)) + if (relop_early_resolve (r, type, op1, op2, rel, NE_EXPR)) return true; // We can be sure the values are always equal or not if both ranges @@ -520,7 +643,8 @@ operator_not_equal::fold_range (irange &r, tree type, bool operator_not_equal::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -551,9 +675,10 @@ operator_not_equal::op1_range (irange &r, tree type, bool operator_not_equal::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel) const { - return operator_not_equal::op1_range (r, type, lhs, op1); + return operator_not_equal::op1_range (r, type, lhs, op1, rel); } // (X < VAL) produces the range of [MIN, VAL - 1]. @@ -607,21 +732,44 @@ class operator_lt : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; + virtual enum tree_code op1_op2_relation (const irange &lhs) const; } op_lt; +// Check if the LHS range indicates a relation between OP1 and OP2. + +enum tree_code +operator_lt::op1_op2_relation (const irange &lhs) const +{ + if (lhs.undefined_p ()) + return VREL_EMPTY; + + // FALSE = op1 < op2 indicates GE_EXPR. + if (lhs.zero_p ()) + return GE_EXPR; + + // TRUE = op1 < op2 indicates LT_EXPR. + if (!lhs.contains_p (build_zero_cst (lhs.type ()))) + return LT_EXPR; + return VREL_NONE; +} + bool operator_lt::fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const + const irange &op2, + relation_kind rel) const { - if (empty_range_varying (r, type, op1, op2)) + if (relop_early_resolve (r, type, op1, op2, rel, LT_EXPR)) return true; signop sign = TYPE_SIGN (op1.type ()); @@ -639,7 +787,8 @@ operator_lt::fold_range (irange &r, tree type, bool operator_lt::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -660,7 +809,8 @@ operator_lt::op1_range (irange &r, tree type, bool operator_lt::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -684,21 +834,44 @@ class operator_le : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; + virtual enum tree_code op1_op2_relation (const irange &lhs) const; } op_le; +// Check if the LHS range indicates a relation between OP1 and OP2. + +enum tree_code +operator_le::op1_op2_relation (const irange &lhs) const +{ + if (lhs.undefined_p ()) + return VREL_EMPTY; + + // FALSE = op1 <= op2 indicates GT_EXPR. + if (lhs.zero_p ()) + return GT_EXPR; + + // TRUE = op1 <= op2 indicates LE_EXPR. + if (!lhs.contains_p (build_zero_cst (lhs.type ()))) + return LE_EXPR; + return VREL_NONE; +} + bool operator_le::fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const + const irange &op2, + relation_kind rel) const { - if (empty_range_varying (r, type, op1, op2)) + if (relop_early_resolve (r, type, op1, op2, rel, LE_EXPR)) return true; signop sign = TYPE_SIGN (op1.type ()); @@ -716,7 +889,8 @@ operator_le::fold_range (irange &r, tree type, bool operator_le::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -737,7 +911,8 @@ operator_le::op1_range (irange &r, tree type, bool operator_le::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -761,20 +936,44 @@ class operator_gt : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; + virtual enum tree_code op1_op2_relation (const irange &lhs) const; } op_gt; +// Check if the LHS range indicates a relation between OP1 and OP2. + +enum tree_code +operator_gt::op1_op2_relation (const irange &lhs) const +{ + if (lhs.undefined_p ()) + return VREL_EMPTY; + + // FALSE = op1 > op2 indicates LE_EXPR. + if (lhs.zero_p ()) + return LE_EXPR; + + // TRUE = op1 > op2 indicates GT_EXPR. + if (!lhs.contains_p (build_zero_cst (lhs.type ()))) + return GT_EXPR; + return VREL_NONE; +} + + bool operator_gt::fold_range (irange &r, tree type, - const irange &op1, const irange &op2) const + const irange &op1, const irange &op2, + relation_kind rel) const { - if (empty_range_varying (r, type, op1, op2)) + if (relop_early_resolve (r, type, op1, op2, rel, GT_EXPR)) return true; signop sign = TYPE_SIGN (op1.type ()); @@ -791,7 +990,8 @@ operator_gt::fold_range (irange &r, tree type, bool operator_gt::op1_range (irange &r, tree type, - const irange &lhs, const irange &op2) const + const irange &lhs, const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -812,7 +1012,8 @@ operator_gt::op1_range (irange &r, tree type, bool operator_gt::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -836,21 +1037,44 @@ class operator_ge : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; + virtual enum tree_code op1_op2_relation (const irange &lhs) const; } op_ge; +// Check if the LHS range indicates a relation between OP1 and OP2. + +enum tree_code +operator_ge::op1_op2_relation (const irange &lhs) const +{ + if (lhs.undefined_p ()) + return VREL_EMPTY; + + // FALSE = op1 >= op2 indicates LT_EXPR. + if (lhs.zero_p ()) + return LT_EXPR; + + // TRUE = op1 >= op2 indicates GE_EXPR. + if (!lhs.contains_p (build_zero_cst (lhs.type ()))) + return GE_EXPR; + return VREL_NONE; +} + bool operator_ge::fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const + const irange &op2, + relation_kind rel) const { - if (empty_range_varying (r, type, op1, op2)) + if (relop_early_resolve (r, type, op1, op2, rel, GE_EXPR)) return true; signop sign = TYPE_SIGN (op1.type ()); @@ -868,7 +1092,8 @@ operator_ge::fold_range (irange &r, tree type, bool operator_ge::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -889,7 +1114,8 @@ operator_ge::op1_range (irange &r, tree type, bool operator_ge::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -913,10 +1139,12 @@ class operator_plus : public range_operator public: virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, @@ -939,7 +1167,8 @@ operator_plus::wi_fold (irange &r, tree type, bool operator_plus::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op2); } @@ -947,7 +1176,8 @@ operator_plus::op1_range (irange &r, tree type, bool operator_plus::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op1); } @@ -958,10 +1188,12 @@ class operator_minus : public range_operator public: virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, @@ -984,7 +1216,8 @@ operator_minus::wi_fold (irange &r, tree type, bool operator_minus::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { return range_op_handler (PLUS_EXPR, type)->fold_range (r, type, lhs, op2); } @@ -992,7 +1225,8 @@ operator_minus::op1_range (irange &r, tree type, bool operator_minus::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { return fold_range (r, type, op1, lhs); } @@ -1127,15 +1361,18 @@ public: const wide_int &w0, const wide_int &w1) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const; } op_mult; bool operator_mult::op1_range (irange &r, tree type, - const irange &lhs, const irange &op2) const + const irange &lhs, const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { tree offset; @@ -1153,9 +1390,10 @@ operator_mult::op1_range (irange &r, tree type, bool operator_mult::op2_range (irange &r, tree type, - const irange &lhs, const irange &op1) const + const irange &lhs, const irange &op1, + relation_kind rel) const { - return operator_mult::op1_range (r, type, lhs, op1); + return operator_mult::op1_range (r, type, lhs, op1, rel); } bool @@ -1391,14 +1629,16 @@ public: operator_exact_divide () : operator_div (TRUNC_DIV_EXPR) { } virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const; } op_exact_div; bool operator_exact_divide::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { tree offset; // [2, 4] = op1 / [3,3] since its exact divide, no need to worry about @@ -1419,10 +1659,12 @@ class operator_lshift : public cross_product_operator public: virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, @@ -1438,7 +1680,8 @@ class operator_rshift : public cross_product_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, @@ -1450,14 +1693,16 @@ public: const wide_int &w1) const; virtual bool op1_range (irange &, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; } op_rshift; bool operator_lshift::fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { int_range_max shift_range; if (!get_shift_range (shift_range, type, op2)) @@ -1572,7 +1817,8 @@ bool operator_lshift::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { tree shift_amount; if (op2.singleton_p (&shift_amount)) @@ -1632,7 +1878,8 @@ bool operator_rshift::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { tree shift; if (op2.singleton_p (&shift)) @@ -1708,7 +1955,8 @@ operator_rshift::wi_op_overflows (wide_int &res, bool operator_rshift::fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { int_range_max shift; if (!get_shift_range (shift, type, op2)) @@ -1737,10 +1985,12 @@ class operator_cast: public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; private: bool truncating_cast_p (const irange &inner, const irange &outer) const; bool inside_domain_p (const wide_int &min, const wide_int &max, @@ -1818,7 +2068,8 @@ operator_cast::fold_pair (irange &r, unsigned index, bool operator_cast::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, const irange &inner, - const irange &outer) const + const irange &outer, + relation_kind rel ATTRIBUTE_UNUSED) const { if (empty_range_varying (r, type, inner, outer)) return true; @@ -1844,7 +2095,8 @@ operator_cast::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, bool operator_cast::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { tree lhs_type = lhs.type (); gcc_checking_assert (types_compatible_p (op2.type(), type)); @@ -1954,20 +2206,24 @@ class operator_logical_and : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const; + const irange &rh, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; } op_logical_and; bool operator_logical_and::fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const + const irange &rh, + relation_kind rel ATTRIBUTE_UNUSED) const { if (empty_range_varying (r, type, lh, rh)) return true; @@ -1989,7 +2245,8 @@ operator_logical_and::fold_range (irange &r, tree type, bool operator_logical_and::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2 ATTRIBUTE_UNUSED) const + const irange &op2 ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -2010,7 +2267,8 @@ operator_logical_and::op1_range (irange &r, tree type, bool operator_logical_and::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { return operator_logical_and::op1_range (r, type, lhs, op1); } @@ -2021,13 +2279,16 @@ class operator_bitwise_and : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const; + const irange &rh, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, @@ -2106,7 +2367,8 @@ operator_bitwise_and::remove_impossible_ranges (irange &r, bool operator_bitwise_and::fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const + const irange &rh, + relation_kind rel ATTRIBUTE_UNUSED) const { if (range_operator::fold_range (r, type, lh, rh)) { @@ -2397,7 +2659,8 @@ operator_bitwise_and::simple_op1_range_solver (irange &r, tree type, bool operator_bitwise_and::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { if (types_compatible_p (type, boolean_type_node)) return op_logical_and.op1_range (r, type, lhs, op2); @@ -2420,7 +2683,8 @@ operator_bitwise_and::op1_range (irange &r, tree type, bool operator_bitwise_and::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { return operator_bitwise_and::op1_range (r, type, lhs, op1); } @@ -2431,19 +2695,23 @@ class operator_logical_or : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const; + const irange &rh, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; } op_logical_or; bool operator_logical_or::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, const irange &lh, - const irange &rh) const + const irange &rh, + relation_kind rel ATTRIBUTE_UNUSED) const { if (empty_range_varying (r, type, lh, rh)) return true; @@ -2456,7 +2724,8 @@ operator_logical_or::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, bool operator_logical_or::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2 ATTRIBUTE_UNUSED) const + const irange &op2 ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const { switch (get_bool_state (r, lhs, type)) { @@ -2477,7 +2746,8 @@ operator_logical_or::op1_range (irange &r, tree type, bool operator_logical_or::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { return operator_logical_or::op1_range (r, type, lhs, op1); } @@ -2488,10 +2758,12 @@ class operator_bitwise_or : public range_operator public: virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel= VREL_NONE) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, @@ -2553,7 +2825,8 @@ operator_bitwise_or::wi_fold (irange &r, tree type, bool operator_bitwise_or::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { // If this is really a logical wi_fold, call that. if (types_compatible_p (type, boolean_type_node)) @@ -2572,7 +2845,8 @@ operator_bitwise_or::op1_range (irange &r, tree type, bool operator_bitwise_or::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { return operator_bitwise_or::op1_range (r, type, lhs, op1); } @@ -2588,10 +2862,12 @@ public: const wide_int &rh_ub) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; } op_bitwise_xor; void @@ -2628,7 +2904,8 @@ operator_bitwise_xor::wi_fold (irange &r, tree type, bool operator_bitwise_xor::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { if (lhs.undefined_p () || lhs.varying_p ()) { @@ -2662,7 +2939,8 @@ operator_bitwise_xor::op1_range (irange &r, tree type, bool operator_bitwise_xor::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { return operator_bitwise_xor::op1_range (r, type, lhs, op1); } @@ -2677,10 +2955,12 @@ public: const wide_int &rh_ub) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const; } op_trunc_mod; void @@ -2730,7 +3010,8 @@ operator_trunc_mod::wi_fold (irange &r, tree type, bool operator_trunc_mod::op1_range (irange &r, tree type, const irange &lhs, - const irange &) const + const irange &, + relation_kind rel ATTRIBUTE_UNUSED) const { // PR 91029. signop sign = TYPE_SIGN (type); @@ -2753,7 +3034,8 @@ operator_trunc_mod::op1_range (irange &r, tree type, bool operator_trunc_mod::op2_range (irange &r, tree type, const irange &lhs, - const irange &) const + const irange &, + relation_kind rel ATTRIBUTE_UNUSED) const { // PR 91029. signop sign = TYPE_SIGN (type); @@ -2792,10 +3074,12 @@ class operator_logical_not : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const; + const irange &rh, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; } op_logical_not; // Folding a logical NOT, oddly enough, involves doing nothing on the @@ -2815,7 +3099,8 @@ public: bool operator_logical_not::fold_range (irange &r, tree type, const irange &lh, - const irange &rh ATTRIBUTE_UNUSED) const + const irange &rh ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const { if (empty_range_varying (r, type, lh, rh)) return true; @@ -2831,7 +3116,8 @@ bool operator_logical_not::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { // Logical NOT is involutary...do it again. return fold_range (r, type, lhs, op2); @@ -2843,16 +3129,19 @@ class operator_bitwise_not : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const; + const irange &rh, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; } op_bitwise_not; bool operator_bitwise_not::fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const + const irange &rh, + relation_kind rel ATTRIBUTE_UNUSED) const { if (empty_range_varying (r, type, lh, rh)) return true; @@ -2870,7 +3159,8 @@ operator_bitwise_not::fold_range (irange &r, tree type, bool operator_bitwise_not::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { if (types_compatible_p (type, boolean_type_node)) return op_logical_not.op1_range (r, type, lhs, op2); @@ -2885,13 +3175,15 @@ class operator_cst : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; } op_integer_cst; bool operator_cst::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, const irange &lh, - const irange &rh ATTRIBUTE_UNUSED) const + const irange &rh ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const { r = lh; return true; @@ -2903,16 +3195,19 @@ class operator_identity : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; } op_identity; bool operator_identity::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, const irange &lh, - const irange &rh ATTRIBUTE_UNUSED) const + const irange &rh ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const { r = lh; return true; @@ -2921,7 +3216,8 @@ operator_identity::fold_range (irange &r, tree type ATTRIBUTE_UNUSED, bool operator_identity::op1_range (irange &r, tree type ATTRIBUTE_UNUSED, const irange &lhs, - const irange &op2 ATTRIBUTE_UNUSED) const + const irange &op2 ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const { r = lhs; return true; @@ -2933,13 +3229,15 @@ class operator_unknown : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; } op_unknown; bool operator_unknown::fold_range (irange &r, tree type, const irange &lh ATTRIBUTE_UNUSED, - const irange &rh ATTRIBUTE_UNUSED) const + const irange &rh ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const { r.set_varying (type); return true; @@ -2956,7 +3254,8 @@ class operator_abs : public range_operator const wide_int &rh_ub) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const; } op_abs; void @@ -3036,7 +3335,8 @@ operator_abs::wi_fold (irange &r, tree type, bool operator_abs::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { if (empty_range_varying (r, type, lhs, op2)) return true; @@ -3108,16 +3408,19 @@ class operator_negate : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; } op_negate; bool operator_negate::fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const + const irange &rh, + relation_kind rel ATTRIBUTE_UNUSED) const { if (empty_range_varying (r, type, lh, rh)) return true; @@ -3130,7 +3433,8 @@ operator_negate::fold_range (irange &r, tree type, bool operator_negate::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { // NEGATE is involutory. return fold_range (r, type, lhs, op2); @@ -3142,16 +3446,19 @@ class operator_addr_expr : public range_operator public: virtual bool fold_range (irange &r, tree type, const irange &op1, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; } op_addr; bool operator_addr_expr::fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const + const irange &rh, + relation_kind rel ATTRIBUTE_UNUSED) const { if (empty_range_varying (r, type, lh, rh)) return true; @@ -3169,7 +3476,8 @@ operator_addr_expr::fold_range (irange &r, tree type, bool operator_addr_expr::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const + const irange &op2, + relation_kind rel ATTRIBUTE_UNUSED) const { return operator_addr_expr::fold_range (r, type, lhs, op2); } @@ -3288,10 +3596,12 @@ class pointer_or_operator : public range_operator public: virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; virtual void wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const; @@ -3300,7 +3610,8 @@ public: bool pointer_or_operator::op1_range (irange &r, tree type, const irange &lhs, - const irange &op2 ATTRIBUTE_UNUSED) const + const irange &op2 ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const { if (lhs.zero_p ()) { @@ -3315,7 +3626,8 @@ pointer_or_operator::op1_range (irange &r, tree type, bool pointer_or_operator::op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const + const irange &op1, + relation_kind rel ATTRIBUTE_UNUSED) const { return pointer_or_operator::op1_range (r, type, lhs, op1); } diff --git a/gcc/range-op.h b/gcc/range-op.h index d3d44083093..2b5db64bb98 100644 --- a/gcc/range-op.h +++ b/gcc/range-op.h @@ -52,7 +52,8 @@ public: // Perform an operation between 2 ranges and return it. virtual bool fold_range (irange &r, tree type, const irange &lh, - const irange &rh) const; + const irange &rh, + relation_kind rel = VREL_NONE) 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 @@ -67,11 +68,23 @@ public: // is re-formed as R = [LHS] - OP2. virtual bool op1_range (irange &r, tree type, const irange &lhs, - const irange &op2) const; + const irange &op2, + relation_kind rel = VREL_NONE) const; virtual bool op2_range (irange &r, tree type, const irange &lhs, - const irange &op1) const; + const irange &op1, + relation_kind rel = VREL_NONE) const; + // The following routines are used to represent relations between the + // various operations. If the caller knows where the symbolics are, + // it can query for relationships between them given known ranges. + virtual enum tree_code lhs_op1_relation (const irange &lhs, + const irange &op1, + const irange &op2) const; + virtual enum tree_code lhs_op2_relation (const irange &lhs, + const irange &op1, + const irange &op2) const; + virtual enum tree_code op1_op2_relation (const irange &lhs) const; protected: // Perform an integral operation between 2 sub-ranges and return it. virtual void wi_fold (irange &r, tree type, @@ -79,6 +92,11 @@ protected: const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const; + // Side effect of relation for generic fold_range clients. + virtual bool op1_op2_relation_effect (irange &lhs_range, tree type, + const irange &op1_range, + const irange &op2_range, + relation_kind rel) const; }; extern range_operator *range_op_handler (enum tree_code code, tree type); -- 2.17.2