From patchwork Mon May 30 13:27:48 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aldy Hernandez X-Patchwork-Id: 54528 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E57BF3838006 for ; Mon, 30 May 2022 13:29:34 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E57BF3838006 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1653917374; bh=C0D5TERBfk+Viwm6mnCka4iOxmw787SS+PbKwL+JU3U=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=wYU+I32jnGm8cXRVPAm/2Bd4PzPu/hv/xLBB+UvXUHUlCrFWKiK8j3ahtEccyHeUK ZufnJk+kVonwZWjDKSQEXWOj+mGY5fVxXN5bdo2+jk2DCboCMV5Q/F5QZEhiVy6lpk f4YdCq182ERLROkn8omBo8hS2vuGtGGG3EzV5ZKI= 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 ESMTPS id E65A33857343 for ; Mon, 30 May 2022 13:28:06 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org E65A33857343 Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-612-bqt3mv57O1qooQtHYq9yCQ-1; Mon, 30 May 2022 09:28:05 -0400 X-MC-Unique: bqt3mv57O1qooQtHYq9yCQ-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.rdu2.redhat.com [10.11.54.1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 3A0683C0E766 for ; Mon, 30 May 2022 13:28:05 +0000 (UTC) Received: from abulafia.quesejoda.com (unknown [10.39.194.246]) by smtp.corp.redhat.com (Postfix) with ESMTPS id E138740CFD0A; Mon, 30 May 2022 13:28:04 +0000 (UTC) Received: from abulafia.quesejoda.com (localhost [127.0.0.1]) by abulafia.quesejoda.com (8.17.1/8.17.1) with ESMTPS id 24UDS2Xn1752178 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Mon, 30 May 2022 15:28:02 +0200 Received: (from aldyh@localhost) by abulafia.quesejoda.com (8.17.1/8.17.1/Submit) id 24UDS2jW1752177; Mon, 30 May 2022 15:28:02 +0200 To: GCC patches Subject: [PATCH 2/5] Implement generic range temporaries. Date: Mon, 30 May 2022 15:27:48 +0200 Message-Id: <20220530132751.1752112-2-aldyh@redhat.com> In-Reply-To: <20220530132751.1752112-1-aldyh@redhat.com> References: <20220530132751.1752112-1-aldyh@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.11.54.1 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-12.0 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_NONE, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) 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: Aldy Hernandez via Gcc-patches From: Aldy Hernandez Reply-To: Aldy Hernandez Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" Now that we have generic ranges, we need a way to define generic local temporaries on the stack for intermediate calculations in the ranger and elsewhere. We need temporaries analogous to int_range_max, but for any of the supported types (currently just integers, but soon integers, pointers, and floats). The tmp_range object is such a temporary. It is designed to be transparently used as a vrange. It shares vrange's abstract API, and implicitly casts itself to a vrange when passed around. The ultimate name will be value_range, but we need to remove legacy first for that to happen. Until then, tmp_range will do. Sample usage is as follows. Instead of: extern void foo (vrange &); int_range_max t; t.set_nonzero (type); foo (t); one does: tmp_range t (type); t.set_nonzero (type); foo (t); You can also delay initialization, for use in loops for example: tmp_range t; ... t.init (type); t.set_varying (type); Creating an supported range type, will result in an unsupported_range object being created, which will trap if anything but set_undefined() and undefined_p() are called on it. There's no size penalty for the unsupported_range, since its immutable and can be shared across instances. Since supports_type_p() is called at construction time for each temporary, I've removed the non-zero check from this function, which was mostly unneeded. I fixed the handful of callers that were passing null types, and in the process sped things up a bit. As more range types come about, the tmp_range class will be augmented to support them by adding the relevant bits in the initialization code. Tested on x86-64 & ppc64le Linux. gcc/ChangeLog: * gimple-range-fold.h (gimple_range_type): Check type before calling supports_type_p. * gimple-range-path.cc (path_range_query::range_of_stmt): Same. * value-query.cc (range_query::get_tree_range): Same. * value-range.cc (tmp_range::lower_bound): New. (tmp_range::upper_bound): New. (tmp_range::dump): New. * value-range.h (class tmp_range): New. (irange::supports_type_p): Do not check if type is non-zero. --- gcc/gimple-range-fold.h | 2 +- gcc/gimple-range-path.cc | 2 +- gcc/value-query.cc | 3 +- gcc/value-range.cc | 38 ++++++++++++ gcc/value-range.h | 130 ++++++++++++++++++++++++++++++++++++++- 5 files changed, 169 insertions(+), 6 deletions(-) diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h index 53a5bf85dd4..20cb73dabb9 100644 --- a/gcc/gimple-range-fold.h +++ b/gcc/gimple-range-fold.h @@ -81,7 +81,7 @@ gimple_range_type (const gimple *s) type = TREE_TYPE (type); } } - if (irange::supports_type_p (type)) + if (type && irange::supports_type_p (type)) return type; return NULL_TREE; } diff --git a/gcc/gimple-range-path.cc b/gcc/gimple-range-path.cc index 459d3797da7..66f433dd1d5 100644 --- a/gcc/gimple-range-path.cc +++ b/gcc/gimple-range-path.cc @@ -755,7 +755,7 @@ path_range_query::range_of_stmt (irange &r, gimple *stmt, tree) { tree type = gimple_range_type (stmt); - if (!irange::supports_type_p (type)) + if (!type || !irange::supports_type_p (type)) return false; // If resolving unknowns, fold the statement making use of any diff --git a/gcc/value-query.cc b/gcc/value-query.cc index 9ccd802457b..26e3858103b 100644 --- a/gcc/value-query.cc +++ b/gcc/value-query.cc @@ -249,7 +249,8 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt) if (UNARY_CLASS_P (expr)) { range_operator *op = range_op_handler (TREE_CODE (expr), type); - if (op) + tree op0_type = TREE_TYPE (TREE_OPERAND (expr, 0)); + if (op && irange::supports_type_p (op0_type)) { int_range_max r0; range_of_expr (r0, TREE_OPERAND (expr, 0), stmt); diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 97ff0614f48..c5f326ab479 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -30,6 +30,42 @@ along with GCC; see the file COPYING3. If not see #include "fold-const.h" #include "gimple-range.h" +// Convenience function only available for integers and pointers. + +wide_int +tmp_range::lower_bound () const +{ + if (is_a (*m_vrange)) + return as_a (*m_vrange).lower_bound (); + gcc_unreachable (); +} + +// Convenience function only available for integers and pointers. + +wide_int +tmp_range::upper_bound () const +{ + if (is_a (*m_vrange)) + return as_a (*m_vrange).upper_bound (); + gcc_unreachable (); +} + +void +tmp_range::dump (FILE *out) const +{ + if (m_vrange) + m_vrange->dump (out); + else + fprintf (out, "NULL"); +} + +DEBUG_FUNCTION void +debug (const tmp_range &r) +{ + r.dump (stderr); + fprintf (stderr, "\n"); +} + // Default implementation when none has been defined. bool @@ -186,6 +222,8 @@ unsupported_range::fits_p (const vrange &) const return false; } +unsupported_range tmp_range::m_unsupported; + // Here we copy between any two irange's. The ranges can be legacy or // multi-ranges, and copying between any combination works correctly. diff --git a/gcc/value-range.h b/gcc/value-range.h index 0061f667092..d51998145da 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -54,6 +54,7 @@ enum value_range_discriminator class vrange { template friend bool is_a (vrange &); + friend class tmp_range; public: virtual void set (tree, tree, value_range_kind = VR_RANGE) = 0; virtual tree type () const = 0; @@ -313,6 +314,131 @@ typedef int_range<1> value_range; // calculations. typedef int_range<255> int_range_max; +// This is an "infinite" precision range object for use in temporary +// calculations for any of the handled types. The object can be +// transparently used as a vrange. + +class tmp_range +{ +public: + tmp_range (); + tmp_range (const vrange &r); + tmp_range (tree type); + bool init (tree type); + vrange& operator= (const vrange &); + bool operator== (const tmp_range &r) const; + bool operator!= (const tmp_range &r) const; + operator vrange &(); + operator const vrange &() const; + void dump (FILE *out = stderr) const; + + // Convenience methods for vrange compatability. + void set (tree min, tree max, value_range_kind kind = VR_RANGE) + { return m_vrange->set (min, max, kind); } + tree type () { return m_vrange->type (); } + enum value_range_kind kind () { return m_vrange->kind (); } + bool varying_p () const { return m_vrange->varying_p (); } + bool undefined_p () const { return m_vrange->undefined_p (); } + void set_varying (tree type) { m_vrange->set_varying (type); } + void set_undefined () { m_vrange->set_undefined (); } + bool union_ (const vrange &r) { return m_vrange->union_ (r); } + bool intersect (const vrange &r) { return m_vrange->intersect (r); } + bool singleton_p (tree *result = NULL) const + { return m_vrange->singleton_p (result); } + bool zero_p () const { return m_vrange->zero_p (); } + wide_int lower_bound () const; // For irange/prange compatability. + wide_int upper_bound () const; // For irange/prange compatability. +private: + static unsupported_range m_unsupported; + vrange *m_vrange; + int_range_max m_irange; + DISABLE_COPY_AND_ASSIGN (tmp_range); +}; + +// This default constructor leaves the temporary uninitialized. Use +// init() to initialize. + +inline +tmp_range::tmp_range () +{ + m_vrange = nullptr; +} + +// Copy constructor from a vrange. + +inline +tmp_range::tmp_range (const vrange &r) +{ + *this = r; +} + +// Copy constructor from a tree TYPE. +// +// Note that unlike the similarly named int_range<> constructor which +// defaults to VARYING, this constructor defaults to UNDEFINED. +// Defaulting to VARYING had an unfortunate performance penalty. We +// could remove the int_range<> (type) constructor if this is +// confusing. + +inline +tmp_range::tmp_range (tree type) +{ + init (type); +} + +// Initialize object so it is possible to store temporaries of TYPE +// into it. The range of the temporary is undefined after this call, +// and must be explicitly set (set_varying, set_undefined, etc). + +inline bool +tmp_range::init (tree type) +{ + gcc_checking_assert (TYPE_P (type)); + + if (irange::supports_type_p (type)) + m_vrange = &m_irange; + else + m_vrange = &m_unsupported; + return true; +} + +inline vrange & +tmp_range::operator= (const vrange &r) +{ + if (is_a (r)) + { + m_irange = as_a (r); + m_vrange = &m_irange; + return *m_vrange; + } + else + gcc_unreachable (); +} + +inline bool +tmp_range::operator== (const tmp_range &r) const +{ + return *m_vrange == *r.m_vrange; +} + +inline bool +tmp_range::operator!= (const tmp_range &r) const +{ + return *m_vrange != *r.m_vrange; +} + +inline +tmp_range::operator vrange &() +{ + return *m_vrange; +} + +inline +tmp_range::operator const vrange &() const +{ + return *m_vrange; +} + // Returns true for an old-school value_range as described above. inline bool irange::legacy_mode_p () const @@ -451,9 +577,7 @@ irange::nonzero_p () const inline bool irange::supports_type_p (tree type) { - if (type && (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))) - return type; - return false; + return INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type); } inline bool