[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