From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 17446 invoked by alias); 25 Nov 2001 23:46:01 -0000 Mailing-List: contact gcc-prs-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Archive: List-Post: List-Help: Sender: gcc-prs-owner@gcc.gnu.org Received: (qmail 17415 invoked by uid 71); 25 Nov 2001 23:46:00 -0000 Resent-Date: 25 Nov 2001 23:46:00 -0000 Resent-Message-ID: <20011125234600.17413.qmail@sourceware.cygnus.com> Resent-From: gcc-gnats@gcc.gnu.org (GNATS Filer) Resent-To: nobody@gcc.gnu.org Resent-Cc: gcc-prs@gcc.gnu.org, gcc-bugs@gcc.gnu.org Resent-Reply-To: gcc-gnats@gcc.gnu.org, Urs Thuermann Received:(qmail 16655 invoked from network); 25 Nov 2001 23:40:06 -0000 Received: from unknown (HELO oker.escape.de) (194.120.234.254) by sourceware.cygnus.com with SMTP; 25 Nov 2001 23:40:06 -0000 Received: from isnogud.escape.de (uucp@localhost) by oker.escape.de (8.11.6/8.11.6/$Revision: 1.29 $) with UUCP-isnogud id fAPNe5O26820 for gcc-gnats@gcc.gnu.org; Mon, 26 Nov 2001 00:40:05 +0100 Received: (from urs@localhost) by isnogud.escape.de (8.11.5/8.11.5) id fAPNc2222557; Mon, 26 Nov 2001 00:38:02 +0100 Message-Id: Date: Tue, 20 Nov 2001 19:46:00 -0000 From: Urs Thuermann To: gcc-gnats@gcc.gnu.org X-Send-Pr-Version:3.113 Subject: optimization/4946: gcc-3.0.x fails to compile Linux-2.4.15 X-SW-Source: 2001-11/txt/msg00616.txt.bz2 List-Id: >Number: 4946 >Category: optimization >Synopsis: gcc-3.0.x fails to compile Linux-2.4.15 >Confidential: no >Severity: serious >Priority: medium >Responsible: unassigned >State: open >Class: ice-on-legal-code >Submitter-Id: net >Arrival-Date: Sun Nov 25 15:46:00 PST 2001 >Closed-Date: >Last-Modified: >Originator: Urs Thuermann >Release: 3.0.2 >Organization: >Environment: System: Linux isnogud 2.4.7-ut #27 Sun Aug 19 15:30:29 CEST 2001 i686 unknown Architecture: i686 host: i686-pc-linux-gnu build: i686-pc-linux-gnu target: i686-pc-linux-gnu configured with: /usr/src/gcc-3.0.2/configure --prefix=/usr/local/gnu --enable-shared --disable-nls --enable-languages=c++,f77 >Description: gcc-3.0.x exits with an internal compiler error, when using inline assembly very massively and compiling with -O2 -fomit-frame-pointer. >How-To-Repeat: The C code causing the error is appended. It has been taken from linux-2.4.15/drivers/net/8139too.c and has been stripped down very much. The normal build process of the Linux-2.4.15 kernel fails with gcc-3.0.x due to this bug. Compile it with gcc -O2 -fomit-frame-pointer -c gcc-3-inline-asm-bug.c I've found five lines in the C code which, when deleted, cause the error to disappear, i.e. compiling with -DDEL1 or -DDEL2 or -DDEL3 or -DDEL4 or -DDEL5 will not cause the error. Also, leaving out -O2 or -fomit-frame-pointer or both makes the error disappear. >Fix: ------ gcc-3-inline-asm-bug.c -------------------------------------- typedef unsigned int size_t; static inline char * strcpy(char * dest,const char *src) { int d0, d1, d2; __asm__ __volatile__( "1:\tlodsb\n\t" "stosb\n\t" "testb %%al,%%al\n\t" "jne 1b" : "=&S" (d0), "=&D" (d1), "=&a" (d2) :"0" (src),"1" (dest) : "memory"); return dest; } static inline void * __memset_generic(void * s, char c,size_t count) { int d0, d1; __asm__ __volatile__( "rep\n\t" "stosb" : "=&c" (d0), "=&D" (d1) :"a" (c),"1" (s),"0" (count) :"memory"); return s; } /* we might want to write optimized versions of these later */ #define __constant_count_memset(s,c,count) __memset_generic((s),(c),(count)) /* * memset(x,0,y) is a reasonably common thing to do, so we want to fill * things 32 bits at a time even when we don't know the size of the * area at compile-time.. */ static inline void * __constant_c_memset(void * s, unsigned long c, size_t count) { int d0, d1; __asm__ __volatile__( "rep ; stosl\n\t" "testb $2,%b3\n\t" "je 1f\n\t" "stosw\n" "1:\ttestb $1,%b3\n\t" "je 2f\n\t" "stosb\n" "2:" : "=&c" (d0), "=&D" (d1) :"a" (c), "q" (count), "0" (count/4), "1" ((long) s) :"memory"); return (s); } /* * This looks horribly ugly, but the compiler can optimize it totally, * as we by now know that both pattern and count is constant.. */ static inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count) { switch (count) { case 0: return s; case 1: *(unsigned char *)s = pattern; return s; case 2: *(unsigned short *)s = pattern; return s; case 3: *(unsigned short *)s = pattern; *(2+(unsigned char *)s) = pattern; return s; case 4: *(unsigned long *)s = pattern; return s; } #define COMMON(x) \ __asm__ __volatile__( \ "rep ; stosl" \ x \ : "=&c" (d0), "=&D" (d1) \ : "a" (pattern),"0" (count/4),"1" ((long) s) \ : "memory") { int d0, d1; switch (count % 4) { case 0: COMMON(""); return s; case 1: COMMON("\n\tstosb"); return s; case 2: COMMON("\n\tstosw"); return s; default: COMMON("\n\tstosw\n\tstosb"); return s; } } #undef COMMON } #define __constant_c_x_memset(s, c, count) \ (__builtin_constant_p(count) ? \ __constant_c_and_count_memset((s),(c),(count)) : \ __constant_c_memset((s),(c),(count))) #define __memset(s, c, count) \ (__builtin_constant_p(count) ? \ __constant_count_memset((s),(c),(count)) : \ __memset_generic((s),(c),(count))) #define memset(s, c, count) \ (__builtin_constant_p(c) ? \ __constant_c_x_memset((s),(0x01010101UL*(unsigned char)(c)),(count)) : \ __memset((s),(c),(count))) typedef struct { unsigned long seg; } mm_segment_t; struct task_struct { mm_segment_t addr_limit; }; static inline struct task_struct * get_current(void) { struct task_struct *current; __asm__("andl %%esp,%0; ":"=r" (current) : "0" (~8191UL)); return current; } #define current get_current() #define __range_ok(addr,size) ({ \ unsigned long flag,sum; \ asm("addl %3,%1 ; sbbl %0,%0; cmpl %1,%4; sbbl $0,%0" \ :"=&r" (flag), "=r" (sum) \ :"1" (addr),"g" ((int)(size)),"g" (current->addr_limit.seg)); \ flag; }) #define access_ok(type,addr,size) (__range_ok(addr,size) == 0) /* Generic arbitrary sized copy. */ #define __copy_user(to,from,size) \ do { \ int __d0, __d1; \ __asm__ __volatile__( \ "0: rep; movsl\n" \ " movl %3,%0\n" \ "1: rep; movsb\n" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ "3: lea 0(%3,%0,4),%0\n" \ " jmp 2b\n" \ ".previous\n" \ ".section __ex_table,\"a\"\n" \ " .align 4\n" \ " .long 0b,3b\n" \ " .long 1b,2b\n" \ ".previous" \ : "=&c"(size), "=&D" (__d0), "=&S" (__d1) \ : "r"(size & 3), "0"(size / 4), "1"(to), "2"(from) \ : "memory"); \ } while (0) #define __copy_user_zeroing(to,from,size) \ do { \ int __d0, __d1; \ __asm__ __volatile__( \ "0: rep; movsl\n" \ " movl %3,%0\n" \ "1: rep; movsb\n" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ "3: lea 0(%3,%0,4),%0\n" \ "4: pushl %0\n" \ " pushl %%eax\n" \ " xorl %%eax,%%eax\n" \ " rep; stosb\n" \ " popl %%eax\n" \ " popl %0\n" \ " jmp 2b\n" \ ".previous\n" \ ".section __ex_table,\"a\"\n" \ " .align 4\n" \ " .long 0b,3b\n" \ " .long 1b,4b\n" \ ".previous" \ : "=&c"(size), "=&D" (__d0), "=&S" (__d1) \ : "r"(size & 3), "0"(size / 4), "1"(to), "2"(from) \ : "memory"); \ } while (0) /* We let the __ versions of copy_from/to_user inline, because they're often * used in fast paths and have only a small space overhead. */ static inline unsigned long __generic_copy_from_user_nocheck(void *to, const void *from, unsigned long n) { __copy_user_zeroing(to,from,n); return n; } static inline unsigned long __generic_copy_to_user_nocheck(void *to, const void *from, unsigned long n) { __copy_user(to,from,n); return n; } /* Optimize just a little bit when we know the size of the move. */ #define __constant_copy_user(to, from, size) \ do { \ int __d0, __d1; \ switch (size & 3) { \ default: \ __asm__ __volatile__( \ "0: rep; movsl\n" \ "1:\n" \ ".section .fixup,\"ax\"\n" \ "2: shl $2,%0\n" \ " jmp 1b\n" \ ".previous\n" \ ".section __ex_table,\"a\"\n" \ " .align 4\n" \ " .long 0b,2b\n" \ ".previous" \ : "=c"(size), "=&S" (__d0), "=&D" (__d1)\ : "1"(from), "2"(to), "0"(size/4) \ : "memory"); \ break; \ case 1: \ __asm__ __volatile__( \ "0: rep; movsl\n" \ "1: movsb\n" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ "3: shl $2,%0\n" \ "4: incl %0\n" \ " jmp 2b\n" \ ".previous\n" \ ".section __ex_table,\"a\"\n" \ " .align 4\n" \ " .long 0b,3b\n" \ " .long 1b,4b\n" \ ".previous" \ : "=c"(size), "=&S" (__d0), "=&D" (__d1)\ : "1"(from), "2"(to), "0"(size/4) \ : "memory"); \ break; \ case 2: \ __asm__ __volatile__( \ "0: rep; movsl\n" \ "1: movsw\n" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ "3: shl $2,%0\n" \ "4: addl $2,%0\n" \ " jmp 2b\n" \ ".previous\n" \ ".section __ex_table,\"a\"\n" \ " .align 4\n" \ " .long 0b,3b\n" \ " .long 1b,4b\n" \ ".previous" \ : "=c"(size), "=&S" (__d0), "=&D" (__d1)\ : "1"(from), "2"(to), "0"(size/4) \ : "memory"); \ break; \ case 3: \ __asm__ __volatile__( \ "0: rep; movsl\n" \ "1: movsw\n" \ "2: movsb\n" \ "3:\n" \ ".section .fixup,\"ax\"\n" \ "4: shl $2,%0\n" \ "5: addl $2,%0\n" \ "6: incl %0\n" \ " jmp 3b\n" \ ".previous\n" \ ".section __ex_table,\"a\"\n" \ " .align 4\n" \ " .long 0b,4b\n" \ " .long 1b,5b\n" \ " .long 2b,6b\n" \ ".previous" \ : "=c"(size), "=&S" (__d0), "=&D" (__d1)\ : "1"(from), "2"(to), "0"(size/4) \ : "memory"); \ break; \ } \ } while (0) /* Optimize just a little bit when we know the size of the move. */ #define __constant_copy_user_zeroing(to, from, size) \ do { \ int __d0, __d1; \ switch (size & 3) { \ default: \ __asm__ __volatile__( \ "0: rep; movsl\n" \ "1:\n" \ ".section .fixup,\"ax\"\n" \ "2: pushl %0\n" \ " pushl %%eax\n" \ " xorl %%eax,%%eax\n" \ " rep; stosl\n" \ " popl %%eax\n" \ " popl %0\n" \ " shl $2,%0\n" \ " jmp 1b\n" \ ".previous\n" \ ".section __ex_table,\"a\"\n" \ " .align 4\n" \ " .long 0b,2b\n" \ ".previous" \ : "=c"(size), "=&S" (__d0), "=&D" (__d1)\ : "1"(from), "2"(to), "0"(size/4) \ : "memory"); \ break; \ case 1: \ __asm__ __volatile__( \ "0: rep; movsl\n" \ "1: movsb\n" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ "3: pushl %0\n" \ " pushl %%eax\n" \ " xorl %%eax,%%eax\n" \ " rep; stosl\n" \ " stosb\n" \ " popl %%eax\n" \ " popl %0\n" \ " shl $2,%0\n" \ " incl %0\n" \ " jmp 2b\n" \ "4: pushl %%eax\n" \ " xorl %%eax,%%eax\n" \ " stosb\n" \ " popl %%eax\n" \ " incl %0\n" \ " jmp 2b\n" \ ".previous\n" \ ".section __ex_table,\"a\"\n" \ " .align 4\n" \ " .long 0b,3b\n" \ " .long 1b,4b\n" \ ".previous" \ : "=c"(size), "=&S" (__d0), "=&D" (__d1)\ : "1"(from), "2"(to), "0"(size/4) \ : "memory"); \ break; \ case 2: \ __asm__ __volatile__( \ "0: rep; movsl\n" \ "1: movsw\n" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ "3: pushl %0\n" \ " pushl %%eax\n" \ " xorl %%eax,%%eax\n" \ " rep; stosl\n" \ " stosw\n" \ " popl %%eax\n" \ " popl %0\n" \ " shl $2,%0\n" \ " addl $2,%0\n" \ " jmp 2b\n" \ "4: pushl %%eax\n" \ " xorl %%eax,%%eax\n" \ " stosw\n" \ " popl %%eax\n" \ " addl $2,%0\n" \ " jmp 2b\n" \ ".previous\n" \ ".section __ex_table,\"a\"\n" \ " .align 4\n" \ " .long 0b,3b\n" \ " .long 1b,4b\n" \ ".previous" \ : "=c"(size), "=&S" (__d0), "=&D" (__d1)\ : "1"(from), "2"(to), "0"(size/4) \ : "memory"); \ break; \ case 3: \ __asm__ __volatile__( \ "0: rep; movsl\n" \ "1: movsw\n" \ "2: movsb\n" \ "3:\n" \ ".section .fixup,\"ax\"\n" \ "4: pushl %0\n" \ " pushl %%eax\n" \ " xorl %%eax,%%eax\n" \ " rep; stosl\n" \ " stosw\n" \ " stosb\n" \ " popl %%eax\n" \ " popl %0\n" \ " shl $2,%0\n" \ " addl $3,%0\n" \ " jmp 2b\n" \ "5: pushl %%eax\n" \ " xorl %%eax,%%eax\n" \ " stosw\n" \ " stosb\n" \ " popl %%eax\n" \ " addl $3,%0\n" \ " jmp 2b\n" \ "6: pushl %%eax\n" \ " xorl %%eax,%%eax\n" \ " stosb\n" \ " popl %%eax\n" \ " incl %0\n" \ " jmp 3b\n" \ ".previous\n" \ ".section __ex_table,\"a\"\n" \ " .align 4\n" \ " .long 0b,4b\n" \ " .long 1b,5b\n" \ " .long 2b,6b\n" \ ".previous" \ : "=c"(size), "=&S" (__d0), "=&D" (__d1)\ : "1"(from), "2"(to), "0"(size/4) \ : "memory"); \ break; \ } \ } while (0) unsigned long __generic_copy_to_user(void *, const void *, unsigned long); unsigned long __generic_copy_from_user(void *, const void *, unsigned long); static inline void prefetch(const void *x) {;} static inline unsigned long __constant_copy_to_user(void *to, const void *from, unsigned long n) { prefetch(from); if (access_ok(VERIFY_WRITE, to, n)) __constant_copy_user(to,from,n); return n; } static inline unsigned long __constant_copy_from_user(void *to, const void *from, unsigned long n) { if (access_ok(VERIFY_READ, from, n)) __constant_copy_user_zeroing(to,from,n); else memset(to, 0, n); return n; } static inline unsigned long __constant_copy_to_user_nocheck(void *to, const void *from, unsigned long n) { __constant_copy_user(to,from,n); return n; } static inline unsigned long __constant_copy_from_user_nocheck(void *to, const void *from, unsigned long n) { __constant_copy_user_zeroing(to,from,n); return n; } #define copy_to_user(to,from,n) \ (__builtin_constant_p(n) ? \ __constant_copy_to_user((to),(from),(n)) : \ __generic_copy_to_user((to),(from),(n))) #define copy_from_user(to,from,n) \ (__builtin_constant_p(n) ? \ __constant_copy_from_user((to),(from),(n)) : \ __generic_copy_from_user((to),(from),(n))) #define __copy_to_user(to,from,n) \ (__builtin_constant_p(n) ? \ __constant_copy_to_user_nocheck((to),(from),(n)) : \ __generic_copy_to_user_nocheck((to),(from),(n))) #define __copy_from_user(to,from,n) \ (__builtin_constant_p(n) ? \ __constant_copy_from_user_nocheck((to),(from),(n)) : \ __generic_copy_from_user_nocheck((to),(from),(n))) typedef unsigned char u8; typedef unsigned int u32; struct pci_dev { char slot_name[8]; }; struct net_device { void *priv; }; #define ETHTOOL_GSET 0x00000001 #define ETHTOOL_GDRVINFO 0x00000003 #define ETHTOOL_GWOL 0x00000005 #define ETHTOOL_SWOL 0x00000006 struct ethtool_cmd { u8 autoneg; }; #define ETHTOOL_BUSINFO_LEN 32 struct ethtool_drvinfo { char driver[32]; char version[32]; char bus_info[ETHTOOL_BUSINFO_LEN]; }; #define SOPASS_MAX 6 struct ethtool_wolinfo { // removing any one of the following lines // avoids the internal gcc bug. #ifndef DEL1 u32 cmd; #endif #ifndef DEL2 u32 supported; #endif #ifndef DEL3 u32 wolopts; #endif #ifndef DEL4 u8 sopass[SOPASS_MAX]; #endif }; struct rtl8139_private { struct pci_dev *pci_dev; }; #define DRV_NAME "8139too" #define DRV_VERSION "0.9.22" static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) { struct rtl8139_private *np = dev->priv; u32 ethcmd; if (copy_from_user (ðcmd, useraddr, sizeof (ethcmd))) return -14; switch (ethcmd) { case ETHTOOL_GSET: { struct ethtool_cmd eset = { ETHTOOL_GSET }; if (copy_to_user (useraddr, &eset, sizeof (eset))) return -14; return 0; } /* TODO: ETHTOOL_SSET */ case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; strcpy (info.driver, DRV_NAME); strcpy (info.version, DRV_VERSION); strcpy (info.bus_info, np->pci_dev->slot_name); if (copy_to_user (useraddr, &info, sizeof (info))) return -14; return 0; } case ETHTOOL_GWOL: { struct ethtool_wolinfo wol = { ETHTOOL_GWOL }; #ifndef DEL5 // removing the following avoids the internal gcc bug. netdev_get_wol (dev, &wol); #endif if (copy_to_user (useraddr, &wol, sizeof (wol))) return -14; return 0; } case ETHTOOL_SWOL: { struct ethtool_wolinfo wol; int rc; if (copy_from_user (&wol, useraddr, sizeof (wol))) return -14; rc = netdev_set_wol (dev, &wol); return rc; } default: break; } return -95; } -------------------------------------------------------------------- >Release-Note: >Audit-Trail: >Unformatted: