This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: PR 27528: Expanding constant asm operands
Ian Lance Taylor <iant@google.com> writes:
> Richard Sandiford <richard@codesourcery.com> writes:
>> Note that EXPAND_INITIALIZER doesn't actually cause non-initialisers
>> to be rejected, so we still deal gracefully with bogus code like:
>>
>> int x;
>> asm volatile ("..." :: "i" (x));
>
> But note that this is valid and actually used:
>
> static inline void my_favorite_insn(int x) __attribute__ ((always_inline));
> static inline void my_favorite_insn(int x)
> {
> asm volatile ("insn %0" :: "i" (x));
> }
> int
> foo()
> {
> my_favorite_insn (1);
> my_favorite_insn (2);
> }
>
> Here we can count on the inliner to give the asm a constant. In some
> cases this may require compiling with optimization, but that is
> acceptable for some embedded targets which is where this kind of thing
> is typically used.
>
> I don't think your patch will break this, but let's be sure.
Yeah, this still works. In this particular example, the optimisation
will be done by the tree optimisers before expand, but I think it should
work even in cases where (for whatever reason) only the rtl optimisers
can reduce the expression to a constant.
> If you add a test case for this, and confirm that it still works with
> your patch, then your patch is OK.
Thanks. Here's what I committed to trunk and 4.2. It adds the extra
tests you mentioned and adds a comment above the changed code explaining
why EXPAND_INITIALIZER is being used.
I also added a comment to the testcase about &x[1] not being treated as
a constant at -O0. This surprised me, but it isn't a regression from
either before the patch or from gcc 3.4, which behaved in the same way.
Richard
gcc/
PR middle-end/27528
* stmt.c (expand_asm_operands): Use EXPAND_INITIALIZER if the
constraints accept neither registers or memories.
gcc/testsuite/
PR middle-end/27528
* gcc.c-torture/compile/pr27528.c: New test.
* gcc.dg/pr27528.c: Likewise.
Index: gcc/stmt.c
===================================================================
--- gcc/stmt.c (revision 118688)
+++ gcc/stmt.c (working copy)
@@ -885,9 +885,13 @@ expand_asm_operands (tree string, tree o
val = TREE_VALUE (tail);
type = TREE_TYPE (val);
+ /* EXPAND_INITIALIZER will not generate code for valid initializer
+ constants, but will still generate code for other types of operand.
+ This is the behavior we want for constant constraints. */
op = expand_expr (val, NULL_RTX, VOIDmode,
- (allows_mem && !allows_reg
- ? EXPAND_MEMORY : EXPAND_NORMAL));
+ allows_reg ? EXPAND_NORMAL
+ : allows_mem ? EXPAND_MEMORY
+ : EXPAND_INITIALIZER);
/* Never pass a CONCAT to an ASM. */
if (GET_CODE (op) == CONCAT)
Index: gcc/testsuite/gcc.c-torture/compile/pr27528.c
===================================================================
--- gcc/testsuite/gcc.c-torture/compile/pr27528.c (revision 0)
+++ gcc/testsuite/gcc.c-torture/compile/pr27528.c (revision 0)
@@ -0,0 +1,38 @@
+/* Check that constant constraints like "i", "n" and "s" can be used in
+ cases where the operand is an initializer constant. */
+int x[2] = { 1, 2 };
+
+#ifdef __OPTIMIZE__
+static inline void __attribute__((__always_inline__))
+insn1 (int x)
+{
+ asm volatile ("# %0 %1" :: "n" (x), "i" (x));
+}
+
+static inline void __attribute__((__always_inline__))
+insn2 (const void *x)
+{
+ asm volatile ("# %0 %1" :: "s" (x), "i" (x));
+}
+#endif
+
+void
+foo (void)
+{
+#ifdef __OPTIMIZE__
+ insn1 (2);
+ insn1 (2);
+ insn1 (400);
+ insn1 (__LINE__);
+ insn2 (x);
+ insn2 (x);
+ insn2 (&x[1]);
+ insn2 ("string");
+#endif
+ asm volatile ("# %0 %1" :: "s" (x), "i" (x));
+ /* At the time of writing, &x[1] is decomposed before reaching expand
+ when compiling with -O0. */
+ asm volatile ("# %0 %1" :: "s" ("string"), "i" ("string"));
+ asm volatile ("# %0 %1" :: "s" (__FILE__), "i" (__FILE__));
+ asm volatile ("# %0 %1" :: "s" (__FUNCTION__), "i" (__FUNCTION__));
+}
Index: gcc/testsuite/gcc.dg/pr27528.c
===================================================================
--- gcc/testsuite/gcc.dg/pr27528.c (revision 0)
+++ gcc/testsuite/gcc.dg/pr27528.c (revision 0)
@@ -0,0 +1,18 @@
+/* Check the warnings and errors generated for asm operands that aren't
+ obviously constant but that are constrained to be constants. */
+/* { dg-options "" } */
+/* { dg-error "impossible constraint" "" { target *-*-* } 13 } */
+/* { dg-error "impossible constraint" "" { target *-*-* } 14 } */
+/* { dg-error "impossible constraint" "" { target *-*-* } 15 } */
+/* { dg-error "impossible constraint" "" { target *-*-* } 16 } */
+int bar (int);
+void
+foo (int *x, int y)
+{
+ int constant = 0;
+ asm ("# %0" :: "i" (x)); /* { dg-warning "probably doesn't match" } */
+ asm ("# %0" :: "i" (bar (*x))); /* { dg-warning "probably doesn't match" } */
+ asm ("# %0" :: "i" (*x + 0x11)); /* { dg-warning "probably doesn't match" } */
+ asm ("# %0" :: "i" (constant)); /* { dg-warning "probably doesn't match" } */
+ asm ("# %0" :: "i" (y * 0)); /* folded */
+}