This is the mail archive of the gcc@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]

Re: decl_conflicts_with_clobbers_p problem


> Date: Thu, 13 Mar 2003 10:17:32 +0100
> From: Gunther Nikl <gni at gecko dot de>

> I am using a port (not the repository) that uses asm() statements to
> access system functions. This is an example how its done (its for m68k):

> #define LP1NR(offs, name, t1, v1, r1, bt, bn)			\
> ({								\
>    t1 _##name##_v1 = (v1);					\
>    {								\
>       register void *const _##name##_bn __asm("a6") = (bn);	\
>       register t1 _n1 __asm(#r1) = _##name##_v1;		\
>       __asm volatile ("jsr a6@(-"#offs":W)"			\
>       : /* no output */						\
>       : "r" (_##name##_bn), "rf"(_n1)				\
>       : "d0", "d1", "a0", "a1", "fp0", "fp1", "cc", "memory");	\
>    }								\
> })
> 
> #define SendIO(ioRequest) \
> 	LP1NR(0x1ce, SendIO, struct IORequest *, ioRequest, a1, \
> 	, EXEC_BASE_NAME)

If you have control over the system, I suggest consider passing
all parameters in the same register to avoid confusion, for
programmers more than for GCC. ;-)  But I assume you don't.
Still, consider a solution where you do not need to specify
matching register name *and* system call in the macro.  It's a
recipe for bugs.  Instead parametrize the register name on the
syscall name.

> The clobber list contains all registers that can be changed by a system
> function as defined by the system ABI.

The clobber list must not contain inputs nor outputs.

> In this example the system function
> expects its argument in register "a1". Thus the value for _n1 is bound to
> register "a1" and passed as an input to the asm() statement.

With the actual register name *as a parameter*, it seems.  No,
you can't parametrize it simply like that.  Why not use
different macros, since you list the register at the point of
the macro call anyway?  Or without code changes elsewhere than
the macro definition, use a trick like
 #define LP1NR(offs, name, t1, v1, r1, bt, bn) LP1NR_##r1 (offs, name, t1, v1, bt, bn)
and define different
 #define LP1NR_a1(offs, name, t1, v1, r1, bt, bn) ...
 #define LP1NR_d0(offs, name, t1, v1, r1, bt, bn) ...
with contents where each different "r1" is listed as output and
not in the clobber list?  Or just parametrize the clobber list?
See below for examples.

> With GCC 3.3
> the asm statement is rejected because of overlapping inputs and clobbers :-(
> For me the asm statememt looks fine because I must pass the argument in
> register "a1" and its correct that the contents of register "a1" cannot be
> relied on after the call anymore.

The manual (Node "Extended Asm", "Assembler Instructions with C
Expression Operands") says: "you may not write a clobber
description in a way that overlaps with an input or output
operand" and "there is no way for you to specify that an input
operand is modified without also specifying it as an output
operand".  It said this *before* the decl_conflicts_with_clobbers_p
change.

So the asm doesn't look "fine" to me.

> Is the example asm statement wrong

Yes.

> or is decl_conflicts_with_clobbers_p()
> wrong?

No; the declaration *does* conflict with the clobbers, so the
function does its job.

You *have* to list the register that is changed as output.  This
is not really a change; your asm was in error before too, GCC
just didn't notice; it'd silently generated wrong code instead.
See <URL:http://gcc.gnu.org/ml/gcc/2002-09/msg00741.html>.  See
also discussion some years ago about the corresponding i386
construct (where the constraint letters were the cause of the
overlap).


In your later email, you listed your "inputs" *only* as asm
outputs.  That is also wrong.  Here's an example LP1NR_a1, which
I hope is right.  I removed the "name" parameter since it seemed
unnecessary and just confusing:

#define LP1NR_a1(offs, name, t1, v1, bt, bn)			\
({								\
   t1 _v1 = (v1);						\
   {								\
      register void *const _bn __asm("a6") = (bn);		\
      register t1 _n1 __asm("a1") = _v1;			\
      __asm volatile ("jsr a6@(-"#offs":W)"			\
      : "=r" (_n1)						\
      : "r" (_bn), "0" (_n1)					\
      : "d0", "d1", "a0", "fp0", "fp1", "cc", "memory");	\
   }								\
})

Or perhaps it would be sufficient to just change the clobber
list into a macro:

#define LP1NR(offs, name, t1, v1, r1, bt, bn)			\
({								\
   t1 _##name##_v1 = (v1);					\
   {								\
      register void *const _##name##_bn __asm("a6") = (bn);	\
      register t1 _n1 __asm(#r1) = _##name##_v1;		\
      __asm volatile ("jsr a6@(-"#offs":W)"			\
      : /* no output */						\
      : "r" (_##name##_bn), "rf"(_n1)				\
      : CLOBBER_LIST_EXCLUDING_##r1;				\
   }								\
})

with
#define CLOBBER_LIST_EXCLUDING_a1 \
 "d0", "d1", "a0", "fp0", "fp1", "cc", "memory"
etc.

brgds, H-P


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