From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 6526 invoked by alias); 6 Nov 2007 15:47:43 -0000 Received: (qmail 6504 invoked by uid 22791); 6 Nov 2007 15:47:41 -0000 X-Spam-Check-By: sourceware.org Received: from mail.gnu.org (HELO mx10.gnu.org) (199.232.76.166) by sourceware.org (qpsmtpd/0.31) with ESMTP; Tue, 06 Nov 2007 15:47:34 +0000 Received: from mx1.redhat.com ([66.187.233.31]) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1IpQeK-0005hA-Pi for gcc-patches@gcc.gnu.org; Tue, 06 Nov 2007 10:47:33 -0500 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.13.8/8.13.1) with ESMTP id lA6FgPDd014188 for ; Tue, 6 Nov 2007 10:42:25 -0500 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 lA6FgPpk020172 for ; Tue, 6 Nov 2007 10:42:25 -0500 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 lA6FgP35025449 for ; Tue, 6 Nov 2007 10:42:25 -0500 Received: (from jakub@localhost) by devserv.devel.redhat.com (8.12.11.20060308/8.12.11/Submit) id lA6FgPZl025447 for gcc-patches@gcc.gnu.org; Tue, 6 Nov 2007 10:42:25 -0500 Date: Tue, 06 Nov 2007 15:47:00 -0000 From: Jakub Jelinek To: gcc-patches@gcc.gnu.org Subject: [PATCH] Don't emit diagnostic about redefined extern inline always_inline functions (PR tree-optimization/33763) Message-ID: <20071106154224.GI5451@devserv.devel.redhat.com> Reply-To: Jakub Jelinek Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4.1i X-detected-kernel: by monty-python.gnu.org: Linux 2.6 (newer, 3) 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-11/txt/msg00269.txt.bz2 Hi! No GCC so far has been able to inline extern inline functions when they are redefined, because that means have two different bodies for a function, one for the out of line copy and one for inlining. While this is now technically possible with current cgraph stuff, it is a lot of work, something unlikely to happen in time for 4.3. So for now redefined extern inline function implies no inlining of that function, something people are able to live with for now. Then there is always_inline attribute, which says that the function must be inlined, or diagnostic issued. But we never actually documented what happens if you redefine extern always_inline inline function. Older GCCs silently didn't inline it, 4.[123] issue diagnostic and fail. I don't argue that the best thing to do is just to have two bodies and allow inlining the body from inline fn while use the separately defined non-inline body for the out of line copy. But before then I'd strongly prefer to just do what older GCCs have done in the past, i.e. silently not inline it. Otherwise, e.g. libraries couldn't use almost at all always_inline extern inline functions, because if some user decides to redefine that function (e.g. for interposition), the compile will fail unless using some extremely ugly hacks (e.g. #define __always_inline__ /**/ before including system headers or something similarly horrible). But the fact that the implementation uses always_inline extern inline (gnu_inline) functions is really an implementation detail. glibc 2.7 now uses always_inline functions heavily and e.g. a bunch of apps don't compile any longer, whenever they e.g. define their own open for symbol interposition purposes. Bootstrapped/regtested on x86_64-linux, ok for trunk/4.2/4.1? 2007-11-06 Jakub Jelinek PR tree-optimization/33763 * gcc.dg/pr33763.c: New test. * g++.dg/opt/inline13.C: New test. 2007-11-06 Jan Hubicka PR tree-optimization/33763 * tree-inline.c (expand_call_inline): Silently ignore always_inline attribute for redefined extern inline functions. --- gcc/tree-inline.c.jj 2007-11-06 09:29:04.000000000 +0100 +++ gcc/tree-inline.c 2007-11-06 16:19:12.000000000 +0100 @@ -2582,6 +2582,12 @@ expand_call_inline (basic_block bb, tree if (!cgraph_inline_p (cg_edge, &reason)) { if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)) + /* For extern inline functions that get redefined we always + silently ignored alway_inline flag. Better behaviour would + be to be able to keep both bodies and use extern inline body + for inlining, but we can't do that because frontends overwrite + the body. */ + && !cg_edge->callee->local.redefined_extern_inline /* Avoid warnings during early inline pass. */ && (!flag_unit_at_a_time || cgraph_global_info_ready)) { --- gcc/testsuite/gcc.dg/pr33763.c.jj 2007-11-06 16:19:12.000000000 +0100 +++ gcc/testsuite/gcc.dg/pr33763.c 2007-11-06 16:19:12.000000000 +0100 @@ -0,0 +1,60 @@ +/* PR tree-optimization/33763 */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +typedef struct +{ + void *a; + void *b; +} T; +extern void *foo (const char *, const char *); +extern void *bar (void *, const char *, T); +extern int baz (const char *, int); + +extern inline __attribute__ ((always_inline, gnu_inline)) int +baz (const char *x, int y) +{ + return 2; +} + +int +baz (const char *x, int y) +{ + return 1; +} + +int xa, xb; + +static void * +inl (const char *x, const char *y) +{ + T t = { &xa, &xb }; + int *f = (int *) __builtin_malloc (sizeof (int)); + const char *z; + int o = 0; + void *r = 0; + + for (z = y; *z; z++) + { + if (*z == 'r') + o |= 1; + if (*z == 'w') + o |= 2; + } + if (o == 1) + *f = baz (x, 0); + if (o == 2) + *f = baz (x, 1); + if (o == 3) + *f = baz (x, 2); + + if (o && *f > 0) + r = bar (f, "w", t); + return r; +} + +void * +foo (const char *x, const char *y) +{ + return inl (x, y); +} --- gcc/testsuite/g++.dg/opt/inline13.C.jj 2007-11-06 16:20:20.000000000 +0100 +++ gcc/testsuite/g++.dg/opt/inline13.C 2007-11-06 16:21:30.000000000 +0100 @@ -0,0 +1,60 @@ +// PR tree-optimization/33763 +// { dg-do compile } +// { dg-options "-O2" } + +typedef struct +{ + void *a; + void *b; +} T; +extern void *foo (const char *, const char *); +extern void *bar (void *, const char *, T); +extern int baz (const char *, int); + +extern inline __attribute__ ((always_inline, gnu_inline)) int +baz (const char *x, int y) +{ + return 2; +} + +int +baz (const char *x, int y) +{ + return 1; +} + +int xa, xb; + +static void * +inl (const char *x, const char *y) +{ + T t = { &xa, &xb }; + int *f = (int *) __builtin_malloc (sizeof (int)); + const char *z; + int o = 0; + void *r = 0; + + for (z = y; *z; z++) + { + if (*z == 'r') + o |= 1; + if (*z == 'w') + o |= 2; + } + if (o == 1) + *f = baz (x, 0); + if (o == 2) + *f = baz (x, 1); + if (o == 3) + *f = baz (x, 2); + + if (o && *f > 0) + r = bar (f, "w", t); + return r; +} + +void * +foo (const char *x, const char *y) +{ + return inl (x, y); +} Jakub