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]

RFD: asm-register-declared local variables and asm clobber overlap


Summary:
When asm-register-declared local variables (using the feature
"Explicit Reg Vars") are used as operands in an asm, what should
happen if the asm clobber list mention those registers?

I think that GCC should detect the overlap and emit an error.
Alternatively, the register allocator should allocate a
temporary register to avoid the clobber list (with the usual
error if it can't find any register to satisfy constraints).
I'd prefer the first to happen (least unintuitive, least
surprising), but currently neither happens.  I'm willing to
implement either.  Are there other useful alternatives?  See end
for tests either way.

Non-summary:
On some ports, such as for the i386 family, you can effectively
force the input operands of asms to a certain register by
specifying a register class with a single register member as
input or output constraint.  It's harder on machines with only
multi-register classes; you don't want to introduce extra move
instructions for the case when you don't get input in the wanted
register.  You'd rather want to direct register allocation to use
a specific register.  A solution is to declare input and output
variables asm-register-declared, and the manual says that TRT
will happen; those registers will be used in the asm.  Though it
doesn't explicitly mention what the effect is of asm clobber
lists mentioning such operands (don't confuse this case with
clobbers contradicting asm operand *constraints*).  It's
ambiguous AFAICT.  There be bugs there.

Related quotes from the manual (Extended Asm::Assembler
Instructions with C Expression Operands):

  You may not write a clobber description in a way that overlaps
  with an input or output operand.
...
  The input operands are guaranteed not to use any of the
  clobbered registers

Related quotes from (Explicit Reg Vars::Variables in Specified
Registers):

  References to local register variables may be deleted or moved
  or simplified.

  These local variables are sometimes convenient for use with the
  extended asm feature (see Extended Asm), if you want to write
  one output of the assembler instruction directly into a
  particular register. (This will work provided the register you
  specify fits the constraints specified for that operand in the asm.)

Like before a constraint/clobber-list overlap started to get
compilation errors (see discussion just afterwards, three or
four years ago), you can currently silently get bad code with
multi-register classes when clobbering registers declared as
asm-register-declared for input of output operands.  The
real-world example _dl_stat in 20020918-1.c below is in error
(loses either way).  It mentions its combined input and output
operand (in register r10) as being clobbered.  When inlined in a
larger context, the output for *some* inlined instances are
currently ignored (seemingly due to the clobber), effectively
always returning -1.  That's the event triggering this rant.
Hence to emit error for such clobber overlap is *not* to barf on
something that currently works.  I suggest this error wording on
the line with the asm: "asm-specifier for variable %s conflicts
with asm clobber list".

If instead it is judged that the register allocator should
handle overlap between clobber list and asm-register-declared
operands silently, then there would be a hard-to-find bug in
_dl_stat since r10 would silently not be used as expected for
input and output.  That would be less intuitive than an clean
error and also surprising, given current wording in the manual.

If clobber list and asm-register-declared operand overlap is to
be an error, the first patch, intended for gcc.dg/20020918-1.c
would serve as a test:

*** /dev/null	Wed Jan 17 20:56:11 2001
--- /tmp/20020918-1.c	Wed Sep 18 16:45:07 2002
***************
*** 0 ****
--- 1,62 ----
+ /* Copyright (C) 2002  Free Software Foundation.
+    by Hans-Peter Nilsson  <hp@axis.com>
+ 
+    Making sure that asm clobbers conflicting with asm-declared input
+    operands are detected: ``You may not write a clobber description in a
+    way that overlaps with an input or output operand''.  */
+ 
+ /* { dg-do compile { target cris-*-* } } */
+ /* { dg-options "-O2" } */
+ 
+ /* Constructed examples; input/output (same register), output, input, and
+    input and output (different registers).  */
+ 
+ void *
+ foo (void *p)
+ {
+   register void *q asm ("r10") = p;
+   asm ("foo1 %0" : "=r" (q) : "0" (q) : "r10"); /* { dg-error "conflict" } */
+   return q;
+ }
+ 
+ void *
+ bar (void *p)
+ {
+   register void *q asm ("r10") = p;
+   register void *w asm ("r11") = p;
+   asm ("bar1 %1,%0" : "=r" (q) : "r" (w) : "r10"); /* { dg-error "conflict" } */
+   return q;
+ }
+ 
+ void *
+ foobar (void *p)
+ {
+   register void *q asm ("r10") = p;
+   register void *w asm ("r11") = p;
+   asm ("foobar1 %1,%0" : "=r" (q) : "r" (w) : "r11"); /* { dg-error "conflict" } */
+   return q;
+ }
+ 
+ void *
+ baz (void *p)
+ {
+   register void *q asm ("r10") = p;
+   register void *w asm ("r11") = p;
+   asm ("baz1 %1,%0" : "=r" (q) : "r" (w) : "r10", "r11"); /* { dg-error "conflict" } */
+   return q;
+ }
+ 
+ /* Real-world example of bug.  */
+ 
+ struct stat;
+ int
+ _dl_stat (const char *file_name, struct stat *buf)
+ {
+   register long a asm ("r10") = (long) file_name;
+   register long b asm ("r11") = (long) buf;
+ 
+   asm volatile ("movu.w %1,$r9\n\tbreak 13" : "=r" (a) : "g" (106), "0" (a), "r" (b) : "r10", "r9"); /* { dg-error "conflict" } */
+   if (a >= 0)
+     return (int) a;
+   return (int) -1;
+ }

If the register allocator should instead allocate an extra
register to avoid collision, the following test, named
gcc.dg/20020918-2.c, would serve for input operands.  That
specific bug currently contradicts the manual that says "the
input operands are guaranteed not to use any of the clobbered
registers".  GCC will actually not move the input operand to a
non-clobbered register; it does move the output register when it
likes to.

*** /dev/null	Wed Jan 17 20:56:11 2001
--- /tmp/20020918-2.c	Wed Sep 18 19:33:51 2002
***************
*** 0 ****
--- 1,57 ----
+ /* Copyright (C) 2002  Free Software Foundation.
+    by Hans-Peter Nilsson  <hp@axis.com>
+ 
+    Making sure that an asm-declared input variable with a register
+    explicitly clobbered in the asm is moved to a non-clobbered register.  */
+ 
+ /* { dg-do compile { target cris-*-* } } */
+ /* { dg-options "-O2" } */
+ /* { dg-final { scan-assembler-not "frobr10 .*r10" } } */
+ /* { dg-final { scan-assembler-not "frobr9 .*r9" } } */
+ 
+ /* Constraining input to same as output, but not asm-declaring the output
+    to the same as the clobber (which would be an error).  */
+ 
+ void *
+ foo (void *p)
+ {
+   register void *q asm ("r10") = p;
+   void *w;
+   asm ("frobr10 %0" : "=r" (w) : "0" (q) : "r10");
+   return w;
+ }
+ 
+ /* A variant on the above, using a register other than the ABI-mandated
+    register for the p parameter and return-value.  */
+ 
+ void *
+ foobar (void *p)
+ {
+   register void *q asm ("r9") = p;
+   void *w;
+   asm ("frobr9 %0" : "=r" (w) : "0" (q) : "r9");
+   return w;
+ }
+ 
+ /* No input=output constraint; still, r10 should not be used due to the
+    clobber.  */
+ 
+ void *
+ bar (void *p)
+ {
+   register void *q asm ("r10") = p;
+   void *w;
+   asm ("frobr10 %0 %1" : "=r" (w) : "r" (q) : "r10");
+   return w;
+ }
+ 
+ /* A variant like with foobar.  */
+ 
+ void *
+ barfoo (void *p)
+ {
+   register void *q asm ("r9") = p;
+   void *w;
+   asm ("frobr9 %0 %1" : "=r" (w) : "r" (q) : "r9");
+   return w;
+ }

brgds, H-P


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