[Bug inline-asm/81890] New: asm memory constraints are difficult and not well documented

amodra at gmail dot com gcc-bugzilla@gcc.gnu.org
Fri Aug 18 16:02:00 GMT 2017


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81890

            Bug ID: 81890
           Summary: asm memory constraints are difficult and not well
                    documented
           Product: gcc
           Version: 8.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: inline-asm
          Assignee: unassigned at gcc dot gnu.org
          Reporter: amodra at gmail dot com
  Target Milestone: ---

gcc doesn't have a simple way to say that a pointer passed to an inline asm is
used to address an array.  "m" (*p) unfortunately only makes the asm depend on
the first element of an array.

The following came about from a discussion starting at
https://gcc.gnu.org/ml/gcc/2017-08/msg00116.html

Compiling with -DTRY=4 or -DTRY=6 give good results, and I believe are
reasonable to extend to types other than char without falling foul of aliasing
rules, but these tricks are a little contrived and not documented.  

-DTRY=5 is no doubt what should be used but this does not appear to be
documented.


/* -O3 */
#include <stdio.h>

#if TRY == 1
int get_string_length (const char *p)
{
  int count;

  /* Unfortunately the "m" here only makes the asm depend on p[0], so
     this is not safe.  The initialization of buff in main can be
     partly moved past the get_string_length call.  */
  __asm__ ("repne scasb"
           : "=c" (count), "+D" (p)
           : "m" (*p), "0" (-1), "a" (0)
           );
  return -2 - count;
}
#elif TRY == 2
/* No better than the above.  */
int get_string_length (const char p[])
{
  int count;

  __asm__ ("repne scasb"
           : "=c" (count), "+D" (p)
           : "m" (*p), "0" (-1), "a" (0)
           );
  return -2 - count;
}
#elif TRY == 3
int get_string_length (const char *p)
{
  int count;

  /* Warns unfortunately, but works, at least on some versions of gcc.  */
  __asm__ ("repne scasb"
           : "=c" (count), "+D" (p)
           : "m" (*(const void *)p), "0" (-1), "a" (0)
           );
  return -2 - count;
}
#elif TRY == 4
int get_string_length (const char *p)
{
  int count;

  /* A way of saying that p points to an array of indeterminate
     length, near enough.  */
  __asm__ ("repne scasb"
           : "=c" (count), "+D" (p)
           : "m" (*(const struct {char a; char x[];} *) p), "0" (-1), "a" (0)
           );
  return -2 - count;
}
#elif TRY == 5
int get_string_length (const char *p)
{
  int count;

  /* The right way to say that p points to an array of char of
     indeterminate length.  */
  __asm__ ("repne scasb"
           : "=c" (count), "+D" (p)
           : "m" (*(const char (*)[]) p), "0" (-1), "a" (0)
           );
  return -2 - count;
}
#elif TRY == 6
int get_string_length (const char *p)
{
  int count;

  /* Make gcc lose detailed information regarding the memory pointed
     to by p.  This, in conjuction with "m" (*p) as an input below
     will act similarly to a "memory" clobber, but is more precise in
     that it doesn't say all memory may be written.  */
  __asm__ ("#%0" : "+X" (p));

  __asm__ ("repne scasb"
           : "=c" (count), "+D" (p)
           : "m" (*p), "0" (-1), "a" (0)
           );
  return -2 - count;
}
#elif TRY == 7
int get_string_length (const char *p)
{
  int count;

  /* As recommended by the gcc info doc.  Suffers from needing to know
     the size of the array.  */
  __asm__ ("repne scasb"
           : "=c" (count), "+D" (p)
           : "m" (*(const struct {char x[48];} *) p), "0" (-1), "a" (0)
           );
  return -2 - count;
}
#else
int get_string_length (const char *p)
{
  int count;

  /* Bog standard, but unfortunately says to gcc that memory might be
     written by the asm.  As can be seen by inspecting the code
     produced, this means "expected" below must be read before calling
     get_string_length, using an extra register.  This may result in
     less optimized code in real-world examples.  */
  __asm__ ("repne scasb"
           : "=c" (count), "+D" (p)
           : "0" (-1), "a" (0)
           : "memory"
           );
  return -2 - count;
}
#endif

int expected = 4;

int
main ()
{
  char buff[48] = "hello world";
  buff[4] = 0;
  int b = expected;
  int a = get_string_length (buff);
  printf ("%s: %d %d\n", buff, a, b);
  return 0;
}


More information about the Gcc-bugs mailing list