From patchwork Mon Oct 7 14:17:16 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marc Glisse X-Patchwork-Id: 281112 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 406A52C00AA for ; Tue, 8 Oct 2013 01:17:40 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=ahm1+j3T3Vz8tYiuFEDjK16KVZpI17wmqTJFN4Wd8wPfxWjZQAmd7 gUv22fylEwmiqDyYBejovwI7O6veNmRoKcrx0vtqMC7U50c0Cbzh/zTAZN+RFmMw 8he7N2cQ1NiFMhz9Q4YeAKCSJQyC//0BY7rf1HlD4ffu59/C9knXZw= 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:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=qs5gWzfuX16oSbDahiM32KOQw6g=; b=mug0cjF1ICFW7r2LnYTC mJrMlybmv0ecVdDyOdoXilSgFjS0Yd5xk1rlgvH63LlVfHUrvyvoBqgexFxLSpm1 60bZdwMA9CbzSyjWV0NnogGxwWxDRP3edq/Bk2BDTvC+sQwVOwtI6+rsfgsMga4e xWv1BP46g8hiju+4q66TvPA= Received: (qmail 16981 invoked by alias); 7 Oct 2013 14:17:34 -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 16965 invoked by uid 89); 7 Oct 2013 14:17:33 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-4.1 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mail3-relais-sop.national.inria.fr Received: from mail3-relais-sop.national.inria.fr (HELO mail3-relais-sop.national.inria.fr) (192.134.164.104) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (CAMELLIA256-SHA encrypted) ESMTPS; Mon, 07 Oct 2013 14:17:32 +0000 Received: from stedding.saclay.inria.fr ([193.55.250.194]) by mail3-relais-sop.national.inria.fr with ESMTP/TLS/DHE-RSA-AES128-SHA; 07 Oct 2013 16:17:17 +0200 Received: from glisse (helo=localhost) by stedding.saclay.inria.fr with local-esmtp (Exim 4.80) (envelope-from ) id 1VTBca-00062g-QE for gcc-patches@gcc.gnu.org; Mon, 07 Oct 2013 16:17:16 +0200 Date: Mon, 7 Oct 2013 16:17:16 +0200 (CEST) From: Marc Glisse To: gcc-patches@gcc.gnu.org Subject: New attribute: returns_nonnull Message-ID: User-Agent: Alpine 2.02 (DEB 1266 2009-07-14) MIME-Version: 1.0 Hello, this patch adds an attribute to let the compiler know that a function never returns NULL. I saw some ECF_* flags, but the attribute seems sufficient. I considered using nonnull(0), but then it would have been confusing that the version of nonnull without arguments applies only to parameters and not the return value. 2013-10-08 Marc Glisse PR tree-optimization/20318 gcc/c-family/ * c-common.c (handle_returns_nonnull_attribute): New function. (c_common_attribute_table): Add returns_nonnull. gcc/ * doc/extend.texi (returns_nonnull): New function attribute. * fold-const.c (tree_expr_nonzero_warnv_p): Look for returns_nonnull attribute. * tree-vrp.c (gimple_stmt_nonzero_warnv_p): Likewise. (stmt_interesting_for_vrp): Accept all GIMPLE_CALL. gcc/testsuite/ * c-c++-common/pr20318.c: New file. * gcc.dg/tree-ssa/pr20318.c: New file. Index: c-family/c-common.c =================================================================== --- c-family/c-common.c (revision 203241) +++ c-family/c-common.c (working copy) @@ -364,20 +364,21 @@ static tree handle_warn_unused_result_at bool *); static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *); static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *); static tree handle_alloc_size_attribute (tree *, tree, tree, int, bool *); static tree handle_target_attribute (tree *, tree, tree, int, bool *); static tree handle_optimize_attribute (tree *, tree, tree, int, bool *); static tree ignore_attribute (tree *, tree, tree, int, bool *); static tree handle_no_split_stack_attribute (tree *, tree, tree, int, bool *); static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *); static tree handle_warn_unused_attribute (tree *, tree, tree, int, bool *); +static tree handle_returns_nonnull_attribute (tree *, tree, tree, int, bool *); static void check_function_nonnull (tree, int, tree *); static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT); static bool nonnull_check_p (tree, unsigned HOST_WIDE_INT); static bool get_nonnull_operand (tree, unsigned HOST_WIDE_INT *); static int resort_field_decl_cmp (const void *, const void *); /* Reserved words. The third field is a mask: keywords are disabled if they match the mask. @@ -740,20 +741,22 @@ const struct attribute_spec c_common_att { "*tm regparm", 0, 0, false, true, true, ignore_attribute, false }, { "no_split_stack", 0, 0, true, false, false, handle_no_split_stack_attribute, false }, /* For internal use (marking of builtins and runtime functions) only. The name contains space to prevent its usage in source code. */ { "fn spec", 1, 1, false, true, true, handle_fnspec_attribute, false }, { "warn_unused", 0, 0, false, false, false, handle_warn_unused_attribute, false }, + { "returns_nonnull", 0, 0, false, true, true, + handle_returns_nonnull_attribute, false }, { NULL, 0, 0, false, false, false, NULL, false } }; /* Give the specifications for the format attributes, used by C and all descendants. */ const struct attribute_spec c_common_format_attribute_table[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, affects_type_identity } */ @@ -9041,20 +9044,37 @@ handle_no_split_stack_attribute (tree *n } else if (DECL_INITIAL (decl)) { error_at (DECL_SOURCE_LOCATION (decl), "can%'t set %qE attribute after definition", name); *no_add_attrs = true; } return NULL_TREE; } + +/* Handle a "returns_nonnull" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_returns_nonnull_attribute (tree *node, tree, tree, int, + bool *no_add_attrs) +{ + // Even without a prototype we still have a return type we can check. + if (TREE_CODE (TREE_TYPE (*node)) != POINTER_TYPE) + { + error ("returns_nonnull attribute on a function not returning a pointer"); + *no_add_attrs = true; + } + return NULL_TREE; +} + /* Check for valid arguments being passed to a function with FNTYPE. There are NARGS arguments in the array ARGARRAY. */ void check_function_arguments (const_tree fntype, int nargs, tree *argarray) { /* Check for null being passed in a pointer argument that must be non-null. We also need to do this if format checking is enabled. */ if (warn_nonnull) Index: doc/extend.texi =================================================================== --- doc/extend.texi (revision 203241) +++ doc/extend.texi (working copy) @@ -2126,21 +2126,22 @@ attributes when making a declaration. T attribute specification inside double parentheses. The following attributes are currently defined for functions on all targets: @code{aligned}, @code{alloc_size}, @code{noreturn}, @code{returns_twice}, @code{noinline}, @code{noclone}, @code{always_inline}, @code{flatten}, @code{pure}, @code{const}, @code{nothrow}, @code{sentinel}, @code{format}, @code{format_arg}, @code{no_instrument_function}, @code{no_split_stack}, @code{section}, @code{constructor}, @code{destructor}, @code{used}, @code{unused}, @code{deprecated}, @code{weak}, @code{malloc}, @code{alias}, @code{ifunc}, -@code{warn_unused_result}, @code{nonnull}, @code{gnu_inline}, +@code{warn_unused_result}, @code{nonnull}, +@code{returns_nonnull}, @code{gnu_inline}, @code{externally_visible}, @code{hot}, @code{cold}, @code{artificial}, @code{no_sanitize_address}, @code{no_address_safety_analysis}, @code{no_sanitize_undefined}, @code{error} and @code{warning}. Several other attributes are defined for functions on particular target systems. Other attributes, including @code{section} are supported for variables declarations (@pxref{Variable Attributes}) and for types (@pxref{Type Attributes}). GCC plugins may provide their own attributes. @@ -3302,20 +3303,34 @@ on the knowledge that certain function a If no argument index list is given to the @code{nonnull} attribute, all pointer arguments are marked as non-null. To illustrate, the following declaration is equivalent to the previous example: @smallexample extern void * my_memcpy (void *dest, const void *src, size_t len) __attribute__((nonnull)); @end smallexample +@item returns_nonnull (@var{arg-index}, @dots{}) +@cindex @code{returns_nonnull} function attribute +The @code{returns_nonnull} attribute specifies that the function +return value should be a non-null pointer. For instance, the declaration: + +@smallexample +extern void * +mymalloc (size_t len) __attribute__((returns_nonnull)); +@end smallexample + +@noindent +lets the compiler optimize callers based on the knowledge +that the return value will never be null. + @item noreturn @cindex @code{noreturn} function attribute A few standard library functions, such as @code{abort} and @code{exit}, cannot return. GCC knows this automatically. Some programs define their own functions that never return. You can declare them @code{noreturn} to tell the compiler this fact. For example, @smallexample @group void fatal () __attribute__ ((noreturn)); Index: fold-const.c =================================================================== --- fold-const.c (revision 203241) +++ fold-const.c (working copy) @@ -16222,20 +16222,24 @@ tree_expr_nonzero_warnv_p (tree t, bool strict_overflow_p); case CALL_EXPR: { tree fndecl = get_callee_fndecl (t); if (!fndecl) return false; if (flag_delete_null_pointer_checks && !flag_check_new && DECL_IS_OPERATOR_NEW (fndecl) && !TREE_NOTHROW (fndecl)) return true; + if (flag_delete_null_pointer_checks + && lookup_attribute ("returns_nonnull", + TYPE_ATTRIBUTES (TREE_TYPE (fndecl)))) + return true; return alloca_call_p (t); } default: break; } return false; } /* Return true when T is an address and is known to be nonzero. Index: testsuite/c-c++-common/pr20318.c =================================================================== --- testsuite/c-c++-common/pr20318.c (revision 0) +++ testsuite/c-c++-common/pr20318.c (working copy) @@ -0,0 +1,3 @@ +/* { dg-do compile } */ + +extern int f() __attribute__((returns_nonnull)); /* { dg-error "not returning a pointer" } */ Property changes on: testsuite/c-c++-common/pr20318.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision URL \ No newline at end of property Index: testsuite/gcc.dg/tree-ssa/pr20318.c =================================================================== --- testsuite/gcc.dg/tree-ssa/pr20318.c (revision 0) +++ testsuite/gcc.dg/tree-ssa/pr20318.c (working copy) @@ -0,0 +1,19 @@ +/* { dg-do compile { target { ! keeps_null_pointer_checks } } } */ +/* { dg-options "-O2 -fdump-tree-original -fdump-tree-vrp1" } */ + +extern int* f(int) __attribute__((returns_nonnull)); +extern void eliminate (); +void g () { + if (f (2) == 0) + eliminate (); +} +void h () { + int *p = f (2); + if (p == 0) + eliminate (); +} + +/* { dg-final { scan-tree-dump-times "== 0" 1 "original" } } */ +/* { dg-final { scan-tree-dump-times "Folding predicate\[^\\n\]*to 0" 1 "vrp1" } } */ +/* { dg-final { cleanup-tree-dump "original" } } */ +/* { dg-final { cleanup-tree-dump "vrp1" } } */ Property changes on: testsuite/gcc.dg/tree-ssa/pr20318.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision URL \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: tree-vrp.c =================================================================== --- tree-vrp.c (revision 203241) +++ tree-vrp.c (working copy) @@ -1031,40 +1031,44 @@ gimple_assign_nonzero_warnv_p (gimple st case GIMPLE_SINGLE_RHS: return tree_single_nonzero_warnv_p (gimple_assign_rhs1 (stmt), strict_overflow_p); case GIMPLE_INVALID_RHS: gcc_unreachable (); default: gcc_unreachable (); } } -/* Return true if STMT is know to to compute a non-zero value. +/* Return true if STMT is known to compute a non-zero value. If the return value is based on the assumption that signed overflow is undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change *STRICT_OVERFLOW_P.*/ static bool gimple_stmt_nonzero_warnv_p (gimple stmt, bool *strict_overflow_p) { switch (gimple_code (stmt)) { case GIMPLE_ASSIGN: return gimple_assign_nonzero_warnv_p (stmt, strict_overflow_p); case GIMPLE_CALL: { tree fndecl = gimple_call_fndecl (stmt); if (!fndecl) return false; if (flag_delete_null_pointer_checks && !flag_check_new && DECL_IS_OPERATOR_NEW (fndecl) && !TREE_NOTHROW (fndecl)) return true; + if (flag_delete_null_pointer_checks && + lookup_attribute ("returns_nonnull", + TYPE_ATTRIBUTES (gimple_call_fntype (stmt)))) + return true; return gimple_alloca_call_p (stmt); } default: gcc_unreachable (); } } /* Like tree_expr_nonzero_warnv_p, but this function uses value ranges obtained so far. */ @@ -6489,24 +6493,21 @@ stmt_interesting_for_vrp (gimple stmt) else if (is_gimple_assign (stmt) || is_gimple_call (stmt)) { tree lhs = gimple_get_lhs (stmt); /* In general, assignments with virtual operands are not useful for deriving ranges, with the obvious exception of calls to builtin functions. */ if (lhs && TREE_CODE (lhs) == SSA_NAME && (INTEGRAL_TYPE_P (TREE_TYPE (lhs)) || POINTER_TYPE_P (TREE_TYPE (lhs))) - && ((is_gimple_call (stmt) - && gimple_call_fndecl (stmt) != NULL_TREE - && (DECL_BUILT_IN (gimple_call_fndecl (stmt)) - || DECL_IS_OPERATOR_NEW (gimple_call_fndecl (stmt)))) + && (is_gimple_call (stmt) || !gimple_vuse (stmt))) return true; } else if (gimple_code (stmt) == GIMPLE_COND || gimple_code (stmt) == GIMPLE_SWITCH) return true; return false; }