This is the mail archive of the gcc-patches@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: 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 */
+}


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