This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

optimization/4946: gcc-3.0.x fails to compile Linux-2.4.15

[Get raw message]

>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 (&ethcmd, 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:


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]