Date: Fri, 29 May 1998 10:50:33 +0200 (MET DST)
From: Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
To: linux-m68k@lists.linux-m68k.org
In-reply-to: <87lnrlprme.fsf@mail.usyd.edu.au> (message from Martin Mitchell
	on 29 May 1998 15:34:33 +1000)
Subject: Re: SCC_ACCESS_INIT macro problem (was L68K: SCC bug with oops)
Sender: owner-linux-m68k@phil.uni-sb.de


> #define SCC_ACCESS_INIT(info)
> 		  volatile struct PARTIAL_SCC *_SCC_p =
> 				  (volatile struct PARTIAL_SCC *)info->port;
> 		  unsigned char *_SCC_shadow = 
> 				  ({  unsigned char *_rv = (unsigned char *)SCC_shadow;
> 				  /* gcc generates suboptimal code for this, so I use an asm */
> 						  __asm__ ( "and.l #4,%1; lea %0@(%1:l:4),%0"
> 							 /* alternative: lea %za0@(%2,%1:l:4),%0 
> 											 * what's faster? */
> 											: "=&a" (_rv) 
> 											: "d" (_SCC_p), "0" (_rv) );
> 						  _rv;
> 				  })
> 
> If you look closely at the disassembly, you'll notice that d0 is assigned
> to %1 in the macro above, but that register is clobbered by the and. gcc
> (version 2.7.2.3) makes no attempt to restore its value before using it
> again in the SCCread macro.
> 
> Is there a problem with this inline assembly, or is there a compiler bug?
> How do the input/output constraints specify that the value of _SCC_p will
> be clobbered by this inline asm?

The asm is wrong here. The and insn overwrites the previous value of
%d0, but %d0 is not listed in the outputs, so gcc doesn't know this.
My fault... I've written that macro :-) The fix is to copy the value
of _SCC_p to some tmp variable and declare that it in the outputs so
gcc doesn't reuse the value.

Here is a patch:

--- linux-2.1.101/drivers/char/atari_SCC.h	Fri May  1 19:05:58 1998
+++ linux-2.1.101.my/drivers/char/atari_SCC.h	Fri May 29 10:49:43 1998
@@ -594,12 +594,13 @@
 		(volatile struct PARTIAL_SCC *)info->port;							\
 	unsigned char *_SCC_shadow =											\
 		({  unsigned char *_rv = (unsigned char *)SCC_shadow;				\
+			volatile struct PARTIAL_SCC *_tmp = _SCC_p;						\
 			/* gcc generates suboptimal code for this, so I use an asm */	\
 			__asm__ ( "and.l #4,%1; lea %0@(%1:l:4),%0"						\
 					  /* alternative: lea %za0@(%2,%1:l:4),%0				\
 					   * what's faster? */									\
-					  : "=&a" (_rv)											\
-					  : "d" (_SCC_p), "0" (_rv) );							\
+					  : "=&a" (_rv), "=&d" (_tmp)							\
+					  : "1" (_tmp), "0" (_rv) );							\
 			_rv;															\
 		})
 
Roman
