From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 16490 invoked by alias); 2 Oct 2007 11:51:11 -0000 Received: (qmail 16477 invoked by uid 22791); 2 Oct 2007 11:51:10 -0000 X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (66.187.233.31) by sourceware.org (qpsmtpd/0.31) with ESMTP; Tue, 02 Oct 2007 11:51:03 +0000 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.13.1/8.13.1) with ESMTP id l92Bnt1e025466 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Tue, 2 Oct 2007 07:49:55 -0400 Received: from devserv.devel.redhat.com (devserv.devel.redhat.com [10.10.36.72]) by int-mx1.corp.redhat.com (8.13.1/8.13.1) with ESMTP id l92BntRn021601; Tue, 2 Oct 2007 07:49:55 -0400 Received: from devserv.devel.redhat.com (localhost.localdomain [127.0.0.1]) by devserv.devel.redhat.com (8.12.11.20060308/8.12.11) with ESMTP id l92BnsDS018003; Tue, 2 Oct 2007 07:49:54 -0400 Received: (from jakub@localhost) by devserv.devel.redhat.com (8.12.11.20060308/8.12.11/Submit) id l92BnsUd018001; Tue, 2 Oct 2007 07:49:54 -0400 Date: Tue, 02 Oct 2007 11:51:00 -0000 From: Jakub Jelinek To: Jason Merrill , Mark Mitchell , Alexandre Oliva Cc: gcc-patches@gcc.gnu.org Subject: [C++ PATCH] Don't clear DECL_BUILT_IN_CLASS/DECL_FUNCTION_CODE when redeclaring a builtin if types match Message-ID: <20071002114954.GC2625@devserv.devel.redhat.com> Reply-To: Jakub Jelinek Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="qftxBdZWiueWNAVY" Content-Disposition: inline User-Agent: Mutt/1.4.1i X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org X-SW-Source: 2007-10/txt/msg00119.txt.bz2 --qftxBdZWiueWNAVY Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 2103 Hi! The C FE always keeps DECL_BUILT_IN_CLASS when types match, even when newdecl defines a function. if (DECL_BUILT_IN (olddecl)) { /* If redeclaring a builtin function, it stays built in. But it gets tagged as having been declared. */ DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl); DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl); C_DECL_DECLARED_BUILTIN (newdecl) = 1; if (new_is_prototype) C_DECL_BUILTIN_PROTOTYPE (newdecl) = 0; else C_DECL_BUILTIN_PROTOTYPE (newdecl) = C_DECL_BUILTIN_PROTOTYPE (olddecl); } But the C++ FE doesn't do this: if (new_defines_function) ... else if (types_match) { /* If redeclaring a builtin function, and not a definition, it stays built in. */ if (DECL_BUILT_IN (olddecl)) { DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl); DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl); /* If we're keeping the built-in definition, keep the rtl, regardless of declaration matches. */ COPY_DECL_RTL (olddecl, newdecl); } ... This causes quite undesirable behavior e.g. on glibc headers on ppc with -mlong-double-64 (as shown on the testcase). Attached are two different patches, one does what the C FE does and copies DECL_BUILT_IN_CLASS etc. whenever types_match (bootstrapped/regtested on x86_64-linux). IMHO when you define memcpy in current CU (or some other builtins), there is no reason why any calls to that builtin from within other functions in the CU shouldn't be suddenly optimized as builtins. The second alternative patch only does that for gnu_inline wrappers - especially if the function is just extern inline __attribute__((gnu_inline)) without always_inline attribute, it might not be inlined in some places. Still they should be treated as builtin calls. I very much prefer the first patch though. Ok for trunk? Jakub --qftxBdZWiueWNAVY Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=E2 Content-length: 3658 2007-10-02 Jakub Jelinek * decl.c (duplicate_decls): When redeclaring a builtin function, keep the merged decl builtin whenever types match, even if new decl defines a function. * gcc.dg/builtins-65.c: New test. * g++.dg/ext/builtin10.C: New test. --- gcc/cp/decl.c.jj 2007-10-01 22:11:09.000000000 +0200 +++ gcc/cp/decl.c 2007-10-02 11:39:46.000000000 +0200 @@ -1988,23 +1988,21 @@ duplicate_decls (tree newdecl, tree oldd DECL_ARGUMENTS (olddecl) = DECL_ARGUMENTS (newdecl); DECL_RESULT (olddecl) = DECL_RESULT (newdecl); } + /* If redeclaring a builtin function, it stays built in. */ + if (types_match && DECL_BUILT_IN (olddecl)) + { + DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl); + DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl); + /* If we're keeping the built-in definition, keep the rtl, + regardless of declaration matches. */ + COPY_DECL_RTL (olddecl, newdecl); + } if (new_defines_function) /* If defining a function declared with other language linkage, use the previously declared language linkage. */ SET_DECL_LANGUAGE (newdecl, DECL_LANGUAGE (olddecl)); else if (types_match) { - /* If redeclaring a builtin function, and not a definition, - it stays built in. */ - if (DECL_BUILT_IN (olddecl)) - { - DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl); - DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl); - /* If we're keeping the built-in definition, keep the rtl, - regardless of declaration matches. */ - COPY_DECL_RTL (olddecl, newdecl); - } - DECL_RESULT (newdecl) = DECL_RESULT (olddecl); /* Don't clear out the arguments if we're redefining a function. */ if (DECL_ARGUMENTS (olddecl)) --- gcc/testsuite/gcc.dg/builtins-65.c.jj 2007-10-02 11:23:51.000000000 +0200 +++ gcc/testsuite/gcc.dg/builtins-65.c 2007-10-02 11:24:12.000000000 +0200 @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +typedef __SIZE_TYPE__ size_t; +extern void __chk_fail (void); +extern int snprintf (char *, size_t, const char *, ...); +extern inline __attribute__((gnu_inline, always_inline)) int snprintf (char *a, size_t b, const char *fmt, ...) +{ + if (__builtin_object_size (a, 0) != -1UL && __builtin_object_size (a, 0) < b) + __chk_fail (); + return __builtin_snprintf (a, b, fmt, __builtin_va_arg_pack ()); +} +extern int snprintf (char *, size_t, const char *, ...) __asm ("mysnprintf"); + +char buf[10]; + +int +main (void) +{ + snprintf (buf, 10, "%d%d\n", 10, 10); + return 0; +} + +/* { dg-final { scan-assembler "mysnprintf" } } */ +/* { dg-final { scan-assembler-not "__chk_fail" } } */ --- gcc/testsuite/g++.dg/ext/builtin10.C.jj 2007-10-02 11:19:45.000000000 +0200 +++ gcc/testsuite/g++.dg/ext/builtin10.C 2007-10-02 11:23:26.000000000 +0200 @@ -0,0 +1,27 @@ +// { dg-do compile } +// { dg-options "-O2" } + +typedef __SIZE_TYPE__ size_t; +extern "C" { +extern void __chk_fail (void); +extern int snprintf (char *, size_t, const char *, ...); +extern inline __attribute__((gnu_inline, always_inline)) int snprintf (char *a, size_t b, const char *fmt, ...) +{ + if (__builtin_object_size (a, 0) != -1UL && __builtin_object_size (a, 0) < b) + __chk_fail (); + return __builtin_snprintf (a, b, fmt, __builtin_va_arg_pack ()); +} +extern int snprintf (char *, size_t, const char *, ...) __asm ("mysnprintf"); +} + +char buf[10]; + +int +main (void) +{ + snprintf (buf, 10, "%d%d\n", 10, 10); + return 0; +} + +// { dg-final { scan-assembler "mysnprintf" } } +// { dg-final { scan-assembler-not "__chk_fail" } } --qftxBdZWiueWNAVY Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=E Content-length: 3337 2007-10-02 Jakub Jelinek * decl.c (duplicate_decls): When redeclaring a builtin function, keep the merged decl builtin also when new decl defines a gnu_inline function and types match. * gcc.dg/builtins-65.c: New test. * g++.dg/ext/builtin10.C: New test. --- gcc/cp/decl.c.jj 2007-10-01 22:11:09.000000000 +0200 +++ gcc/cp/decl.c 2007-10-02 11:16:40.000000000 +0200 @@ -1989,9 +1989,21 @@ duplicate_decls (tree newdecl, tree oldd DECL_RESULT (olddecl) = DECL_RESULT (newdecl); } if (new_defines_function) - /* If defining a function declared with other language - linkage, use the previously declared language linkage. */ - SET_DECL_LANGUAGE (newdecl, DECL_LANGUAGE (olddecl)); + { + /* If defining a function declared with other language + linkage, use the previously declared language linkage. */ + SET_DECL_LANGUAGE (newdecl, DECL_LANGUAGE (olddecl)); + /* If redeclaring a builtin function as gnu_inline wrapper, + it stays built in. */ + if (DECL_BUILT_IN (olddecl) && types_match && GNU_INLINE_P (newdecl)) + { + DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl); + DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl); + /* If we're keeping the built-in definition, keep the rtl, + regardless of declaration matches. */ + COPY_DECL_RTL (olddecl, newdecl); + } + } else if (types_match) { /* If redeclaring a builtin function, and not a definition, --- gcc/testsuite/gcc.dg/builtins-65.c.jj 2007-10-02 11:23:51.000000000 +0200 +++ gcc/testsuite/gcc.dg/builtins-65.c 2007-10-02 11:24:12.000000000 +0200 @@ -0,0 +1,25 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +typedef __SIZE_TYPE__ size_t; +extern void __chk_fail (void); +extern int snprintf (char *, size_t, const char *, ...); +extern inline __attribute__((gnu_inline, always_inline)) int snprintf (char *a, size_t b, const char *fmt, ...) +{ + if (__builtin_object_size (a, 0) != -1UL && __builtin_object_size (a, 0) < b) + __chk_fail (); + return __builtin_snprintf (a, b, fmt, __builtin_va_arg_pack ()); +} +extern int snprintf (char *, size_t, const char *, ...) __asm ("mysnprintf"); + +char buf[10]; + +int +main (void) +{ + snprintf (buf, 10, "%d%d\n", 10, 10); + return 0; +} + +/* { dg-final { scan-assembler "mysnprintf" } } */ +/* { dg-final { scan-assembler-not "__chk_fail" } } */ --- gcc/testsuite/g++.dg/ext/builtin10.C.jj 2007-10-02 11:19:45.000000000 +0200 +++ gcc/testsuite/g++.dg/ext/builtin10.C 2007-10-02 11:23:26.000000000 +0200 @@ -0,0 +1,27 @@ +// { dg-do compile } +// { dg-options "-O2" } + +typedef __SIZE_TYPE__ size_t; +extern "C" { +extern void __chk_fail (void); +extern int snprintf (char *, size_t, const char *, ...); +extern inline __attribute__((gnu_inline, always_inline)) int snprintf (char *a, size_t b, const char *fmt, ...) +{ + if (__builtin_object_size (a, 0) != -1UL && __builtin_object_size (a, 0) < b) + __chk_fail (); + return __builtin_snprintf (a, b, fmt, __builtin_va_arg_pack ()); +} +extern int snprintf (char *, size_t, const char *, ...) __asm ("mysnprintf"); +} + +char buf[10]; + +int +main (void) +{ + snprintf (buf, 10, "%d%d\n", 10, 10); + return 0; +} + +// { dg-final { scan-assembler "mysnprintf" } } +// { dg-final { scan-assembler-not "__chk_fail" } } --qftxBdZWiueWNAVY--