From patchwork Wed Aug 29 10:54:57 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aldy Hernandez X-Patchwork-Id: 963386 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-484679-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="eWCYtOe0"; 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 420jFY58hKz9rvt for ; Wed, 29 Aug 2018 20:55:12 +1000 (AEST) 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=YqxwGK3aL/4P+IFdnTFIAYXPYnhXrAGIurPIsgZJyXWLLTvrFiPgF md9p+6rs+MYbvPbvf+bspfA9UQZaIztAls+RNVNS1jsgUFcfs9Rl6B4m5gnJvdEM UKhU+B7mJhmhRBkIbyju5Wn8/qWYenFTHMfV2SwkxwH6KKUbv0tVTw= 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=ZDp4n4oZcjsOTJPrhQYuUOXLgAY=; b=eWCYtOe0uwgwYwJvnEmY W8qPVhVRlJs3xg6BZh1awzaGCLWAk6zvBBNt+8sppGPGYIXW752nY9ivCszxVJHr nPAxvF/CDNZispLtTz+5nV9lHDSypUabC9hh4d+G6AedAYtTKj1M8dE8fH7p7Gwn hkNk6LInhPLXWnPNTtoJ/zw= Received: (qmail 95050 invoked by alias); 29 Aug 2018 10:55:04 -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 95041 invoked by uid 89); 29 Aug 2018 10:55:04 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.6 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.2 spammy=HX-Received:sk:v1-v6mr, H*r:sk:dynamic, U*aldyh, aldyhredhatcom X-HELO: mail-wr1-f45.google.com Received: from mail-wr1-f45.google.com (HELO mail-wr1-f45.google.com) (209.85.221.45) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 29 Aug 2018 10:55:02 +0000 Received: by mail-wr1-f45.google.com with SMTP id 20-v6so4353539wrb.12 for ; Wed, 29 Aug 2018 03:55:01 -0700 (PDT) Received: from abulafia.quesejoda.com (131.107.133.37.dynamic.jazztel.es. [37.133.107.131]) by smtp.gmail.com with ESMTPSA id d10-v6sm7971665wrv.70.2018.08.29.03.54.58 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 29 Aug 2018 03:54:58 -0700 (PDT) From: Aldy Hernandez Subject: VRP: abstract out POINTER_TYPE_P handling To: gcc-patches Message-ID: <5db8448c-3822-35ad-016d-274fcfdc90a5@redhat.com> Date: Wed, 29 Aug 2018 06:54:57 -0400 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.8.0 MIME-Version: 1.0 X-IsSubscribed: yes Never say never. Just when I thought I was done... It looks like I need the special casing we do for pointer types in extract_range_from_binary_expr_1. The code is simple enough that we could just duplicate it anywhere we need it, but I hate code duplication and keeping track of multiple versions of the same thing. No change in functionality. Tested on x86-64 Linux with all languages. OK? commit 32a423e3ab5a75eee6de59b1a235a2892dc8ca38 Author: Aldy Hernandez Date: Tue Aug 28 17:27:26 2018 +0200 * tree-vrp.c (vrp_range_pointer): New. (extract_range_from_binary_expr_1): Call vrp_range_pointer. * wide-int-range.cc (wide_int_range_pointer): New. * wide-int-range.h (enum wide_int_range_nullness): New. (wide_int_range_pointer): New. diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index f20730a85ba..228f20b5203 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -1275,6 +1275,32 @@ set_value_range_with_overflow (value_range &vr, } } +/* Value range wrapper for wide_int_range_pointer. */ + +static void +vrp_range_pointer (value_range *vr, + enum tree_code code, tree type, + value_range *vr0, value_range *vr1) +{ + signop sign = TYPE_SIGN (type); + unsigned prec = TYPE_PRECISION (type); + wide_int vr0_min, vr0_max; + wide_int vr1_min, vr1_max; + + extract_range_into_wide_ints (vr0, sign, prec, vr0_min, vr0_max); + extract_range_into_wide_ints (vr1, sign, prec, vr1_min, vr1_max); + wide_int_range_nullness n; + n = wide_int_range_pointer (code, sign, vr0_min, vr0_max, vr1_min, vr1_max); + if (n == WIDE_INT_RANGE_UNKNOWN) + set_value_range_to_varying (vr); + else if (n == WIDE_INT_RANGE_NULL) + set_value_range_to_null (vr, type); + else if (n == WIDE_INT_RANGE_NONNULL) + set_value_range_to_nonnull (vr, type); + else + gcc_unreachable (); +} + /* Extract range information from a binary operation CODE based on the ranges of each of its operands *VR0 and *VR1 with resulting type EXPR_TYPE. The resulting range is stored in *VR. */ @@ -1416,47 +1442,10 @@ extract_range_from_binary_expr_1 (value_range *vr, } /* Now evaluate the expression to determine the new range. */ + if (POINTER_TYPE_P (expr_type)) { - if (code == MIN_EXPR || code == MAX_EXPR) - { - /* For MIN/MAX expressions with pointers, we only care about - nullness, if both are non null, then the result is nonnull. - If both are null, then the result is null. Otherwise they - are varying. */ - if (!range_includes_zero_p (&vr0) && !range_includes_zero_p (&vr1)) - set_value_range_to_nonnull (vr, expr_type); - else if (range_is_null (&vr0) && range_is_null (&vr1)) - set_value_range_to_null (vr, expr_type); - else - set_value_range_to_varying (vr); - } - else if (code == POINTER_PLUS_EXPR) - { - /* For pointer types, we are really only interested in asserting - whether the expression evaluates to non-NULL. */ - if (!range_includes_zero_p (&vr0) - || !range_includes_zero_p (&vr1)) - set_value_range_to_nonnull (vr, expr_type); - else if (range_is_null (&vr0) && range_is_null (&vr1)) - set_value_range_to_null (vr, expr_type); - else - set_value_range_to_varying (vr); - } - else if (code == BIT_AND_EXPR) - { - /* For pointer types, we are really only interested in asserting - whether the expression evaluates to non-NULL. */ - if (!range_includes_zero_p (&vr0) && !range_includes_zero_p (&vr1)) - set_value_range_to_nonnull (vr, expr_type); - else if (range_is_null (&vr0) || range_is_null (&vr1)) - set_value_range_to_null (vr, expr_type); - else - set_value_range_to_varying (vr); - } - else - set_value_range_to_varying (vr); - + vrp_range_pointer (vr, code, expr_type, &vr0, &vr1); return; } diff --git a/gcc/wide-int-range.cc b/gcc/wide-int-range.cc index 3cdcede04cd..9ab1b04c4dd 100644 --- a/gcc/wide-int-range.cc +++ b/gcc/wide-int-range.cc @@ -733,3 +733,60 @@ wide_int_range_div (wide_int &wmin, wide_int &wmax, extra_range_p = false; return true; } + +/* Given a binary operator (CODE) on two pointer ranges, return if the + result will be zero, non-zero, or unknown. */ + +enum wide_int_range_nullness +wide_int_range_pointer (enum tree_code code, + signop sign, + const wide_int &vr0_min, + const wide_int &vr0_max, + const wide_int &vr1_min, + const wide_int &vr1_max) +{ + unsigned prec = vr0_min.get_precision (); + if (code == MIN_EXPR || code == MAX_EXPR) + { + /* For MIN/MAX expressions with pointers, we only care about + nullness, if both are non null, then the result is nonnull. + If both are null, then the result is null. Otherwise they + are varying. */ + if (!wide_int_range_includes_zero_p (vr0_min, vr0_max, sign) + && !wide_int_range_includes_zero_p (vr1_min, vr1_max, sign)) + return WIDE_INT_RANGE_NONNULL; + else if (wide_int_range_zero_p (vr0_min, vr0_max, prec) + && wide_int_range_zero_p (vr1_min, vr1_max, prec)) + return WIDE_INT_RANGE_NULL; + else + return WIDE_INT_RANGE_UNKNOWN; + } + else if (code == POINTER_PLUS_EXPR) + { + /* For pointer types, we are really only interested in asserting + whether the expression evaluates to non-NULL. */ + if (!wide_int_range_includes_zero_p (vr0_min, vr0_max, sign) + || !wide_int_range_includes_zero_p (vr1_min, vr1_max, sign)) + return WIDE_INT_RANGE_NONNULL; + else if (wide_int_range_zero_p (vr0_min, vr0_max, prec) + && wide_int_range_zero_p (vr1_min, vr1_max, prec)) + return WIDE_INT_RANGE_NULL; + else + return WIDE_INT_RANGE_UNKNOWN; + } + else if (code == BIT_AND_EXPR) + { + /* For pointer types, we are really only interested in asserting + whether the expression evaluates to non-NULL. */ + if (!wide_int_range_includes_zero_p (vr0_min, vr0_max, sign) + && !wide_int_range_includes_zero_p (vr1_min, vr1_max, sign)) + return WIDE_INT_RANGE_NONNULL; + else if (wide_int_range_zero_p (vr0_min, vr0_max, prec) + || wide_int_range_zero_p (vr1_min, vr1_max, prec)) + return WIDE_INT_RANGE_NULL; + else + return WIDE_INT_RANGE_UNKNOWN; + } + else + return WIDE_INT_RANGE_UNKNOWN; +} diff --git a/gcc/wide-int-range.h b/gcc/wide-int-range.h index 427ef34c6b4..ecdd961df36 100644 --- a/gcc/wide-int-range.h +++ b/gcc/wide-int-range.h @@ -20,6 +20,14 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_WIDE_INT_RANGE_H #define GCC_WIDE_INT_RANGE_H +/* For an operation on pointers, this specifies whether the resulting + operation is null, non-null, or unknown. */ +enum wide_int_range_nullness { + WIDE_INT_RANGE_UNKNOWN = 0, + WIDE_INT_RANGE_NULL, + WIDE_INT_RANGE_NONNULL +}; + extern bool wide_int_range_cross_product (wide_int &res_lb, wide_int &res_ub, enum tree_code code, signop sign, const wide_int &, const wide_int &, @@ -110,6 +118,12 @@ extern bool wide_int_range_div (wide_int &wmin, wide_int &wmax, bool overflow_wraps, bool &extra_range_p, wide_int &extra_min, wide_int &extra_max); +enum wide_int_range_nullness wide_int_range_pointer (enum tree_code code, + signop sign, + const wide_int &vr0_min, + const wide_int &vr0_max, + const wide_int &vr1_min, + const wide_int &vr1_max); /* Return TRUE if shifting by range [MIN, MAX] is undefined behavior. */