On 2000-Jul-19 19:31:12 -0700, John Polstra <[EMAIL PROTECTED]> wrote: >In article <[EMAIL PROTECTED]>, >Hellmuth Michaelis <[EMAIL PROTECTED]> wrote: >> >> In the process of tracing down the problem of the kernel panic when booting >> a kernel with pcvt enabled, i tried to compile a kernel without the -O >> option to gcc and got this compile failure (sources from 18.7.2000 9:00 MET): >> >> cc -c -pipe -Wall -Wredundant-decls -Wnested-externs -Wstrict-prototypes >> -Wmissing-prototypes -Wpointer-arith -Winline -Wcast-qual >> -fformat-extensions -ansi -nostdinc -I- -I. -I../.. -I../../../include >> -D_KERNEL -include opt_global.h -elf -mpreferred-stack-boundary=2 >> -fomit-frame-pointer ../../i386/i386/atomic.c >> In file included from ../../i386/i386/atomic.c:47: >> machine/atomic.h: In function `atomic_set_char': >> machine/atomic.h:106: inconsistent operand constraints in an `asm' >> machine/atomic.h: In function `atomic_clear_char': >> machine/atomic.h:107: inconsistent operand constraints in an `asm' >[...] > >I have seen that same problem recently in a slightly different >context. After staring at the code for a very long time, I could >only conclude that the problem was a bug in gcc. Last year I did some testing of atomic.h with a variety of gcc versions (and, following a prod from bde, at a variety of optimisation levels). At the time, I had great difficulty finding a set of constraints that would work with both gcc 2.7.2 and egcs, with and without optimisation. Attached is a patch to /sys/i386/include/atomic.h,v 1.11 that I believe solves the problem. This is an adaption of what I did last year, to include some of Bruce's comments. At this stage, I've only checked it against gcc version 2.95.2 19991024 (release) - at it appears in 4.0 and the latest -current, with -O0, -O1 and -O2. An earlier version[1] worked with 2.7.2, 2.8.1 and ecgs 1.?. I hope to be able to check it on gcc 2.7.2 and maybe gcc 2.8.1 tonight. Note that in theory, gcc 2.7.2 needs a second read-only argument with a "0" constraint. In practice, this doesn't seem to be necessary since the write-only argument is volatile memory and therefore the compiler can't optimize out any preceeding read. This shouldn't be required for later compiler versions since the first argument is explicitly read-write. [1] This was sent to Bruce early last October. The changes since then are: - Correct `char' case to specify "q" constraint - Cast result of not (~) to ensure correct operand type. - Specify `w' in `short' case to correctly print the 16-bit register. Peter
--- /3.0/cvs/src/sys/i386/include/atomic.h Thu May 11 01:27:24 2000 +++ atomic.h Mon Jul 24 08:02:16 2000 @@ -62,7 +62,7 @@ * This allows kernel modules to be portable between UP and SMP systems. */ #if defined(KLD_MODULE) -#define ATOMIC_ASM(NAME, TYPE, OP, V) \ +#define ATOMIC_ASM(NAME, TYPE, OP, V, CLASS) \ extern void atomic_##NAME##_##TYPE(volatile u_##TYPE *p, u_##TYPE v); #else /* !KLD_MODULE */ @@ -75,77 +75,61 @@ /* * The assembly is volatilized to demark potential before-and-after side * effects if an interrupt or SMP collision were to occur. + * + * GCC 2.8 and later (including EGCS) support read/write operands + * using '+' as a constraint modifier. + * + * Earlier versions of gcc don't allow the '+' and recommend the use + * of separate, matching read-only and write-only operands. + * Unfortunately, this doesn't appear to work in all cases. On + * the assumption that the memory operand is always volatile, it + * seems safe to tell gcc that it is write-only. The `volatile' + * attribute on the memory operand prohibits any optimization + * away of the reference. + * + * The constraint class for the read operand is passed as a parameter + * to the macro because it needs to be different in the char case. + * (In theory, it should also be different in the short case, but + * gcc doesn't have any constraint classes to specify 16-bit registers). + * + * Note that gcc doesn't support string glueing for the constraint + * expressions, so the common "m" or "i" bits cannot be pulled out. */ -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 9) -/* egcs 1.1.2+ version */ -#define ATOMIC_ASM(NAME, TYPE, OP, V) \ +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) +#define ATOMIC_ASM(NAME, TYPE, OP, V, CLASS) \ static __inline void \ atomic_##NAME##_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\ { \ - __asm __volatile(MPLOCKED OP \ - : "=m" (*p) \ - : "0" (*p), "ir" (V)); \ + __asm __volatile(MPLOCKED OP : "+m" (*p) : CLASS (V) : "cc"); \ } - -#else -/* gcc <= 2.8 version */ -#define ATOMIC_ASM(NAME, TYPE, OP, V) \ +#else /* gcc < 2.8 version */ +#define ATOMIC_ASM(NAME, TYPE, OP, V, CLASS) \ static __inline void \ atomic_##NAME##_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\ { \ - __asm __volatile(MPLOCKED OP \ - : "=m" (*p) \ - : "ir" (V)); \ + __asm __volatile(MPLOCKED OP : "=m" (*p) : CLASS (V) : "cc"); \ } #endif #endif /* KLD_MODULE */ -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 9) - -/* egcs 1.1.2+ version */ -ATOMIC_ASM(set, char, "orb %b2,%0", v) -ATOMIC_ASM(clear, char, "andb %b2,%0", ~v) -ATOMIC_ASM(add, char, "addb %b2,%0", v) -ATOMIC_ASM(subtract, char, "subb %b2,%0", v) - -ATOMIC_ASM(set, short, "orw %w2,%0", v) -ATOMIC_ASM(clear, short, "andw %w2,%0", ~v) -ATOMIC_ASM(add, short, "addw %w2,%0", v) -ATOMIC_ASM(subtract, short, "subw %w2,%0", v) - -ATOMIC_ASM(set, int, "orl %2,%0", v) -ATOMIC_ASM(clear, int, "andl %2,%0", ~v) -ATOMIC_ASM(add, int, "addl %2,%0", v) -ATOMIC_ASM(subtract, int, "subl %2,%0", v) - -ATOMIC_ASM(set, long, "orl %2,%0", v) -ATOMIC_ASM(clear, long, "andl %2,%0", ~v) -ATOMIC_ASM(add, long, "addl %2,%0", v) -ATOMIC_ASM(subtract, long, "subl %2,%0", v) - -#else - -/* gcc <= 2.8 version */ -ATOMIC_ASM(set, char, "orb %1,%0", v) -ATOMIC_ASM(clear, char, "andb %1,%0", ~v) -ATOMIC_ASM(add, char, "addb %1,%0", v) -ATOMIC_ASM(subtract, char, "subb %1,%0", v) - -ATOMIC_ASM(set, short, "orw %1,%0", v) -ATOMIC_ASM(clear, short, "andw %1,%0", ~v) -ATOMIC_ASM(add, short, "addw %1,%0", v) -ATOMIC_ASM(subtract, short, "subw %1,%0", v) - -ATOMIC_ASM(set, int, "orl %1,%0", v) -ATOMIC_ASM(clear, int, "andl %1,%0", ~v) -ATOMIC_ASM(add, int, "addl %1,%0", v) -ATOMIC_ASM(subtract, int, "subl %1,%0", v) - -ATOMIC_ASM(set, long, "orl %1,%0", v) -ATOMIC_ASM(clear, long, "andl %1,%0", ~v) -ATOMIC_ASM(add, long, "addl %1,%0", v) -ATOMIC_ASM(subtract, long, "subl %1,%0", v) - -#endif +ATOMIC_ASM(set, char, "orb %1,%0", v, "iq") +ATOMIC_ASM(clear, char, "andb %1,%0", (char)~v, "iq") +ATOMIC_ASM(add, char, "addb %1,%0", v, "iq") +ATOMIC_ASM(subtract, char, "subb %1,%0", v, "iq") + +ATOMIC_ASM(set, short, "orw %w1,%0", v, "ir") +ATOMIC_ASM(clear, short, "andw %w1,%0", (short)~v, "ir") +ATOMIC_ASM(add, short, "addw %w1,%0", v, "ir") +ATOMIC_ASM(subtract, short, "subw %w1,%0", v, "ir") + +ATOMIC_ASM(set, int, "orl %1,%0", v, "ir") +ATOMIC_ASM(clear, int, "andl %1,%0", ~v, "ir") +ATOMIC_ASM(add, int, "addl %1,%0", v, "ir") +ATOMIC_ASM(subtract, int, "subl %1,%0", v, "ir") + +ATOMIC_ASM(set, long, "orl %1,%0", v, "ir") +ATOMIC_ASM(clear, long, "andl %1,%0", ~v, "ir") +ATOMIC_ASM(add, long, "addl %1,%0", v, "ir") +ATOMIC_ASM(subtract, long, "subl %1,%0", v, "ir") #endif /* ! _MACHINE_ATOMIC_H_ */