diff mbox

[RFA:] fix PR55030, wrong code from __builtin_setjmp_receiver

Message ID 20121127120347.GU2315@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Nov. 27, 2012, 12:03 p.m. UTC
On Tue, Nov 27, 2012 at 06:44:23AM -0500, Hans-Peter Nilsson wrote:
> > We apparently have a small conflict between the meaning of volatile asms with
> > operands at the source level and volatile_insn_p.  However, I think that the
> > latter interpretation is the correct one: if your asm statements have effects
> > that can be described, then you should use output constraints instead of
> > volatile; otherwise, you should use volatile and the output constraints have
> > essentially no meaning.

I strongly disagree with this.  Outputs and clobbers have significant
meaning even on volatile asms, asm volatile doesn't mean all registers and
all memory are supposed to be considered clobbered.  For memory you have
"memory" clobber for that, for registers it is users responsibility to
describe exactly what changes, either in clobbers or in outputs.
The difference between non-volatile and volatile asm is, as the
documentation states:

The `volatile' keyword indicates that the instruction has important
side-effects.  GCC will not delete a volatile `asm' if it is reachable.

Volatile asm acts as an optimization barrier to some extent, but it really
can't modify registers or memory that aren't described as modified in the
asm pattern.  The important side-effects are of some other kind than
modifying registers or memory visible from the current function.
Ditto for UNSPEC_VOLATILE.

So, at least from var-tracking POV which doesn't attempt to perform any
optimizations across any insn, just tries to track where values live, IMHO a
volatile asm acts exactly the same as non-volatile, that is why I'm testing
following patch right now.

But the question is also what effects your patch can have e.g. on RTL DSE.

2012-11-26  Jakub Jelinek  <jakub@redhat.com>

	PR debug/36728
	PR debug/55467
	* cselib.c (cselib_process_insn): If cselib_preserve_constants,
	don't reset table and exit early on volatile insns and setjmp.
	Reset table afterwards on setjmp.

	* gcc.dg/guality/pr36728-1.c: Include "../nop.h", make sure the asm
	are non-empty and add dependency between the first and second asm.
	* gcc.dg/guality/pr36728-2.c: Likewise.
	* gcc.dg/guality/pr36728-3.c: New test.
	* gcc.dg/guality/pr36728-4.c: New test.



	Jakub

Comments

Hans-Peter Nilsson Nov. 27, 2012, 12:27 p.m. UTC | #1
On Tue, 27 Nov 2012, Jakub Jelinek wrote:
> On Tue, Nov 27, 2012 at 06:44:23AM -0500, Hans-Peter Nilsson wrote:

JFTR: No I didn't, Eric wrote the below.  But, it made sense to me. :)

> > > We apparently have a small conflict between the meaning of volatile asms with
> > > operands at the source level and volatile_insn_p.  However, I think that the
> > > latter interpretation is the correct one: if your asm statements have effects
> > > that can be described, then you should use output constraints instead of
> > > volatile; otherwise, you should use volatile and the output constraints have
> > > essentially no meaning.
>
> I strongly disagree with this.
> [...]

As long as volatile asms and UNSPEC_VOLATILE insns (aka.
barriers) are handled the same way and consistently throughout
gcc, I'm fine.  It seems your patch does that, so thanks!

> But the question is also what effects your patch can have e.g. on RTL DSE.

Looks like the patch caused a bootstrap for s390x.

Eagerly awaiting a PR for that, but whoever is interested
on that, please try Jakub's patch first...

> 2012-11-26  Jakub Jelinek  <jakub@redhat.com>
>
> 	PR debug/36728
> 	PR debug/55467
> 	* cselib.c (cselib_process_insn): If cselib_preserve_constants,
> 	don't reset table and exit early on volatile insns and setjmp.
> 	Reset table afterwards on setjmp.
>
> 	* gcc.dg/guality/pr36728-1.c: Include "../nop.h", make sure the asm
> 	are non-empty and add dependency between the first and second asm.
> 	* gcc.dg/guality/pr36728-2.c: Likewise.
> 	* gcc.dg/guality/pr36728-3.c: New test.
> 	* gcc.dg/guality/pr36728-4.c: New test.

brgds, H-P
Jakub Jelinek Nov. 27, 2012, 1:32 p.m. UTC | #2
On Tue, Nov 27, 2012 at 01:03:47PM +0100, Jakub Jelinek wrote:
> So, at least from var-tracking POV which doesn't attempt to perform any
> optimizations across any insn, just tries to track where values live, IMHO a
> volatile asm acts exactly the same as non-volatile, that is why I'm testing
> following patch right now.
> 
> 2012-11-26  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR debug/36728
> 	PR debug/55467
> 	* cselib.c (cselib_process_insn): If cselib_preserve_constants,
> 	don't reset table and exit early on volatile insns and setjmp.
> 	Reset table afterwards on setjmp.
> 
> 	* gcc.dg/guality/pr36728-1.c: Include "../nop.h", make sure the asm
> 	are non-empty and add dependency between the first and second asm.
> 	* gcc.dg/guality/pr36728-2.c: Likewise.
> 	* gcc.dg/guality/pr36728-3.c: New test.
> 	* gcc.dg/guality/pr36728-4.c: New test.

Bootstrapped/regtested fine on x86_64-linux and i686-linux (and fixes the
pr36728-[34].c failures that appear without the patch, which are of the
wrong debug kind).

	Jakub
Eric Botcazou Nov. 27, 2012, 5:35 p.m. UTC | #3
> I strongly disagree with this.  Outputs and clobbers have significant
> meaning even on volatile asms, asm volatile doesn't mean all registers and
> all memory are supposed to be considered clobbered.  For memory you have
> "memory" clobber for that, for registers it is users responsibility to
> describe exactly what changes, either in clobbers or in outputs.
> The difference between non-volatile and volatile asm is, as the
> documentation states:
> 
> The `volatile' keyword indicates that the instruction has important
> side-effects.  GCC will not delete a volatile `asm' if it is reachable.
> 
> Volatile asm acts as an optimization barrier to some extent, but it really
> can't modify registers or memory that aren't described as modified in the
> asm pattern.  The important side-effects are of some other kind than
> modifying registers or memory visible from the current function.
> Ditto for UNSPEC_VOLATILE.

Well, the last sentence would essentially void the entire argument I think.  
It's well established in the RTL middle-end that UNSPEC_VOLATILE can do pretty 
much everything behind the back of the compiler.

Now I agree that the discussion exists for volatile asms.  But you have for 
example in the unmodified cse.c:

  /* A volatile ASM invalidates everything.  */
  if (NONJUMP_INSN_P (insn)
      && GET_CODE (PATTERN (insn)) == ASM_OPERANDS
      && MEM_VOLATILE_P (PATTERN (insn)))
    flush_hash_table ();

and the comment of volatile_insn_p is rather explicit:

/* Nonzero if X contains any volatile instructions.  These are instructions
   which may cause unpredictable machine state instructions, and thus no
   instructions should be moved or combined across them.  This includes
   only volatile asms and UNSPEC_VOLATILE instructions.  */

The problem is that the various RTL passes don't have a consistent view on 
that so the patch attempts to tidy this up in a conservative manner.

I think that a compromise could be to say that volatile asms without outputs 
are full barriers (like UNSPEC_VOLATILE) but other volatile asms aren't.
That's what the unmodified cse.c, cselib.c and dse.c currently implement.
But implementing it consistently would mean weakening volatile_insn_p.

> So, at least from var-tracking POV which doesn't attempt to perform any
> optimizations across any insn, just tries to track where values live, IMHO a
> volatile asm acts exactly the same as non-volatile, that is why I'm testing
> following patch right now.
> 
> But the question is also what effects your patch can have e.g. on RTL DSE.

It will make all volatile asms be treated as volatile asms without outputs.
Jakub Jelinek Nov. 27, 2012, 6:20 p.m. UTC | #4
On Tue, Nov 27, 2012 at 06:35:52PM +0100, Eric Botcazou wrote:
> Now I agree that the discussion exists for volatile asms.  But you have for 
> example in the unmodified cse.c:
> 
>   /* A volatile ASM invalidates everything.  */
>   if (NONJUMP_INSN_P (insn)
>       && GET_CODE (PATTERN (insn)) == ASM_OPERANDS
>       && MEM_VOLATILE_P (PATTERN (insn)))
>     flush_hash_table ();

That was weird indeed, because
  asm volatile ("" : : "r" (x));
flushed (for targets that don't add any implicit clobbers) but e.g.
  asm volatile ("" : : "r" (x) : "r23");
wouldn't (then the pattern is a parallel with ASM_OPERANDS and some
CLOBBERs).  The effect of that is that it never triggered on i?86/x86_64,
because those have the implicit fprs/flags clobbers.

I was mainly arguing with the sentence that for asm volatile, the output
constraints (did you mean outputs and clobbers?) have essentially no
meaning.  While for some optimizations perhaps it might be desirable
to treat asm volatile as full optimization barrier, I'm not sure about all
of them (i.e. it would be important to look for performance degradations
caused by that change), and for var-tracking I'd argue that asm vs. asm
volatile is completely unimportant, if the asm volatile pattern (or even
UNSPEC_VOLATILE) doesn't say it clobbers or sets hard register XYZ, then it
can't change it (well, it could but is responsible of restoring it),
similarly for memory, if it doesn't clobber "memory" and doesn't set some
memory, it can't do that.

So, do you object even to the var-tracking change (which would mean if
var-tracking found that say some variable's value lives in hard register 12, when
encountering asm volatile it would mean to forget about that even when
hard register 12 isn't clobbered by the asm, nor set)?  For now var-tracking
seems to be the most important issue, as we generate invalid debug info
there (latent before, but never hit on inline asm on x86_64/i686 except
on setjmp calls).

As for other passes, the r193802 change e.g. regresses slightly modified
pr44194-1.c testcase on x86_64,
struct ints { int a, b, c; } foo();
void bar(int a, int b);

void func() {
  struct ints s = foo();
  int x;
  asm volatile ("" : "=r" (x));
  bar(s.a, s.b);
}

 func:
 .LFB0:
-	xorl	%eax, %eax
 	subq	$24, %rsp
 .LCFI0:
+	xorl	%eax, %eax
 	call	foo
-	movq	%rax, %rcx
-	shrq	$32, %rcx
-	movq	%rcx, %rsi
-	movl	%eax, %edi
+	movq	%rax, (%rsp)
+	movl	%edx, 8(%rsp)
+	movl	4(%rsp), %esi
+	movl	(%rsp), %edi
 	addq	$24, %rsp
 .LCFI1:
 	jmp	bar

To me it looks like an unnecessary pessimization, the volatile there
I understand that just it doesn't want to be moved around (e.g. scheduled
before the foo call or after bar), that it can't be DCEd, but as it doesn't
mention it modifies memory, I don't understand why it should force some
registers to stack and back when it has no way to know the compiler would be
emitting anything like that at all.
Compare that to
  asm volatile ("" : "=r" (x) : : "memory");
in the testcase, where the r193802 commit makes no difference, the
stores/loads are done in both cases.

For CSE, I'd agree it should treat asm volatile as barriers, so for cselib.c
we probably need some additional cselib_init flag how we want to treat
volatile asms...  For UNSPEC_VOLATILE, perhaps even DSE should stay
conservative, but for var-tracking.c I still don't see a reason for that.

	Jakub
Hans-Peter Nilsson Nov. 28, 2012, 1:44 p.m. UTC | #5
On Tue, 27 Nov 2012, Jakub Jelinek wrote:
> 2012-11-26  Jakub Jelinek  <jakub@redhat.com>
>
> 	PR debug/36728
> 	PR debug/55467
> 	* cselib.c (cselib_process_insn): If cselib_preserve_constants,
> 	don't reset table and exit early on volatile insns and setjmp.
> 	Reset table afterwards on setjmp.

It seems this also fixes the s390x-linux bootstrap; at least the
test-case in PR bootstrap/55511.  Thanks again.

(N.B. there may also be a bug in var-tracking, covered up by the
patch above.)

brgds, H-P
Jakub Jelinek Nov. 28, 2012, 1:56 p.m. UTC | #6
On Wed, Nov 28, 2012 at 08:44:18AM -0500, Hans-Peter Nilsson wrote:
> On Tue, 27 Nov 2012, Jakub Jelinek wrote:
> > 2012-11-26  Jakub Jelinek  <jakub@redhat.com>
> >
> > 	PR debug/36728
> > 	PR debug/55467
> > 	* cselib.c (cselib_process_insn): If cselib_preserve_constants,
> > 	don't reset table and exit early on volatile insns and setjmp.
> > 	Reset table afterwards on setjmp.
> 
> It seems this also fixes the s390x-linux bootstrap; at least the
> test-case in PR bootstrap/55511.  Thanks again.
> 
> (N.B. there may also be a bug in var-tracking, covered up by the
> patch above.)

The patch is actually a fix for that.  The thing is that
both cselib was doing the wrong thing for the resets (not calling
cselib_preserve_only_constants () before cselib_reset_table resp.
cselib_reset_table not prepared to the thing that it would need
to flush all regs/mems, not just from the VALUEs that are kept in the hash
table, but also from those that are dropped), and also not adding some
special magic microoperation for the volatile insns (unclear what exactly
it would have to do).  By never handling the volatile insns specially during
var-tracking all those issues are gone.

	Jakub
Richard Sandiford Nov. 28, 2012, 8:09 p.m. UTC | #7
Eric Botcazou <ebotcazou@adacore.com> writes:
>> I strongly disagree with this.  Outputs and clobbers have significant
>> meaning even on volatile asms, asm volatile doesn't mean all registers and
>> all memory are supposed to be considered clobbered.  For memory you have
>> "memory" clobber for that, for registers it is users responsibility to
>> describe exactly what changes, either in clobbers or in outputs.
>> The difference between non-volatile and volatile asm is, as the
>> documentation states:
>> 
>> The `volatile' keyword indicates that the instruction has important
>> side-effects.  GCC will not delete a volatile `asm' if it is reachable.
>> 
>> Volatile asm acts as an optimization barrier to some extent, but it really
>> can't modify registers or memory that aren't described as modified in the
>> asm pattern.  The important side-effects are of some other kind than
>> modifying registers or memory visible from the current function.
>> Ditto for UNSPEC_VOLATILE.
>
> Well, the last sentence would essentially void the entire argument I
> think.  It's well established in the RTL middle-end that
> UNSPEC_VOLATILE can do pretty much everything behind the back of the
> compiler.

As always when jumping in the middle of thread, I might well be missing
the point sorry, but this sounded a bit extreme if taken literally.
An UNSPEC_VOLATILE doesn't in itself force the function to save all
call-saved registers, so an UNSPEC_VOLATILE that modifies those registers
behind the back of the compiler would lead to us generating wrong code.
And I thought UNSPEC_VOLATILEs that also clobber visible memory in an
unpredictable way had to have something like (clobber (mem:BLK (scratch))).

I thought Jakub's "the important side-effects are of some other
kind than modifying registers or memory visible from the current
function" applied to UNSPEC_VOLATILE too.

Richard
Richard Henderson Nov. 28, 2012, 8:45 p.m. UTC | #8
On 11/27/2012 09:35 AM, Eric Botcazou wrote:
> It's well established in the RTL middle-end that UNSPEC_VOLATILE can do pretty 
> much everything behind the back of the compiler.

This is false.  U_V is a scheduling barrier, and is never deleted as
dead (as opposed to unreachable) code.  Certainly we don't do anything
so complete as invalidate all registers, nor do we invalidate memory.


r~
Richard Henderson Nov. 28, 2012, 8:53 p.m. UTC | #9
On 11/27/2012 04:03 AM, Jakub Jelinek wrote:
> 2012-11-26  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR debug/36728
> 	PR debug/55467
> 	* cselib.c (cselib_process_insn): If cselib_preserve_constants,
> 	don't reset table and exit early on volatile insns and setjmp.
> 	Reset table afterwards on setjmp.
> 
> 	* gcc.dg/guality/pr36728-1.c: Include "../nop.h", make sure the asm
> 	are non-empty and add dependency between the first and second asm.
> 	* gcc.dg/guality/pr36728-2.c: Likewise.
> 	* gcc.dg/guality/pr36728-3.c: New test.
> 	* gcc.dg/guality/pr36728-4.c: New test.

Ok.

It appears that PRs 55507 and 55511 are also fixed.


r~
Eric Botcazou Nov. 30, 2012, 11:58 p.m. UTC | #10
> I was mainly arguing with the sentence that for asm volatile, the output
> constraints (did you mean outputs and clobbers?) have essentially no
> meaning.  While for some optimizations perhaps it might be desirable
> to treat asm volatile as full optimization barrier, I'm not sure about all
> of them (i.e. it would be important to look for performance degradations
> caused by that change), and for var-tracking I'd argue that asm vs. asm
> volatile is completely unimportant, if the asm volatile pattern (or even
> UNSPEC_VOLATILE) doesn't say it clobbers or sets hard register XYZ, then it
> can't change it (well, it could but is responsible of restoring it),
> similarly for memory, if it doesn't clobber "memory" and doesn't set some
> memory, it can't do that.

Yes, I meant outputs and clobbers.  The origin of all this is:

`blockage'
     This pattern defines a pseudo insn that prevents the instruction
     scheduler and other passes from moving instructions and using
     register equivalences across the boundary defined by the blockage
     insn.  This needs to be an UNSPEC_VOLATILE pattern or a volatile
     ASM.

Now the typical blockage insn is that of the x86:

;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
;; all of memory.  This blocks insns from being moved across this point.

(define_insn "blockage"
  [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)]
  ""
  ""
  [(set_attr "length" "0")])

[Note the pretty adamant comment about UNSPEC_VOLATILE here...]

So, if UNSPEC_VOLATILE is not treated specially, the blockage insn of most 
ports won't block hard register equivalences.  And blockages are precisely 
used to do that, see e.g. the untyped_call pattern of the x86:

  /* The optimizer does not know that the call sets the function value
     registers we stored in the result block.  We avoid problems by
     claiming that all hard registers are used and clobbered at this
     point.  */
  emit_insn (gen_blockage ());

That being said, I agree that volatile asms are a separate discussion.

> So, do you object even to the var-tracking change (which would mean if
> var-tracking found that say some variable's value lives in hard register 12,
> when encountering asm volatile it would mean to forget about that even when
> hard register 12 isn't clobbered by the asm, nor set)?  For now
> var-tracking seems to be the most important issue, as we generate invalid
> debug info there (latent before, but never hit on inline asm on x86_64/i686
> except on setjmp calls).

For volatile asms, no, thanks for fixing the fallout on this side.

> As for other passes, the r193802 change e.g. regresses slightly modified
> pr44194-1.c testcase on x86_64,
> struct ints { int a, b, c; } foo();
> void bar(int a, int b);
> 
> void func() {
>   struct ints s = foo();
>   int x;
>   asm volatile ("" : "=r" (x));
>   bar(s.a, s.b);
> }
> 
>  func:
>  .LFB0:
> -	xorl	%eax, %eax
>  	subq	$24, %rsp
>  .LCFI0:
> +	xorl	%eax, %eax
>  	call	foo
> -	movq	%rax, %rcx
> -	shrq	$32, %rcx
> -	movq	%rcx, %rsi
> -	movl	%eax, %edi
> +	movq	%rax, (%rsp)
> +	movl	%edx, 8(%rsp)
> +	movl	4(%rsp), %esi
> +	movl	(%rsp), %edi
>  	addq	$24, %rsp
>  .LCFI1:
>  	jmp	bar
> 
> To me it looks like an unnecessary pessimization, the volatile there
> I understand that just it doesn't want to be moved around (e.g. scheduled
> before the foo call or after bar), that it can't be DCEd, but as it doesn't
> mention it modifies memory, I don't understand why it should force some
> registers to stack and back when it has no way to know the compiler would be
> emitting anything like that at all.
> Compare that to
>   asm volatile ("" : "=r" (x) : : "memory");
> in the testcase, where the r193802 commit makes no difference, the
> stores/loads are done in both cases.

OK, I agree that the fallout for DSE, and the effect on memory in general, is 
undesirable, especially for volatile asms.

> For CSE, I'd agree it should treat asm volatile as barriers, so for cselib.c
> we probably need some additional cselib_init flag how we want to treat
> volatile asms...  For UNSPEC_VOLATILE, perhaps even DSE should stay
> conservative, but for var-tracking.c I still don't see a reason for that.

Thank you (as well as the others) for the detailed feedback.  Clearly my 
initial stance on this was a bit extreme and needs to be watered down.
I'll ponder about this over the week-end and propose something next week.
diff mbox

Patch

--- gcc/cselib.c.jj	2012-11-26 10:14:26.000000000 +0100
+++ gcc/cselib.c	2012-11-26 20:01:10.488304558 +0100
@@ -2626,11 +2626,12 @@  cselib_process_insn (rtx insn)
   cselib_current_insn = insn;
 
   /* Forget everything at a CODE_LABEL, a volatile insn, or a setjmp.  */
-  if (LABEL_P (insn)
-      || (CALL_P (insn)
-	  && find_reg_note (insn, REG_SETJMP, NULL))
-      || (NONJUMP_INSN_P (insn)
-	  && volatile_insn_p (PATTERN (insn))))
+  if ((LABEL_P (insn)
+       || (CALL_P (insn)
+	   && find_reg_note (insn, REG_SETJMP, NULL))
+       || (NONJUMP_INSN_P (insn)
+	   && volatile_insn_p (PATTERN (insn))))
+      && !cselib_preserve_constants)
     {
       cselib_reset_table (next_uid);
       cselib_current_insn = NULL_RTX;
@@ -2668,9 +2669,18 @@  cselib_process_insn (rtx insn)
   /* Look for any CLOBBERs in CALL_INSN_FUNCTION_USAGE, but only
      after we have processed the insn.  */
   if (CALL_P (insn))
-    for (x = CALL_INSN_FUNCTION_USAGE (insn); x; x = XEXP (x, 1))
-      if (GET_CODE (XEXP (x, 0)) == CLOBBER)
-	cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0));
+    {
+      for (x = CALL_INSN_FUNCTION_USAGE (insn); x; x = XEXP (x, 1))
+	if (GET_CODE (XEXP (x, 0)) == CLOBBER)
+	  cselib_invalidate_rtx (XEXP (XEXP (x, 0), 0));
+      /* Flush evertything on setjmp.  */
+      if (cselib_preserve_constants
+	  && find_reg_note (insn, REG_SETJMP, NULL))
+	{
+	  cselib_preserve_only_values ();
+	  cselib_reset_table (next_uid);
+	}
+    }
 
   /* On setter of the hard frame pointer if frame_pointer_needed,
      invalidate stack_pointer_rtx, so that sp and {,h}fp based
--- gcc/testsuite/gcc.dg/guality/pr36728-1.c.jj	2012-11-26 10:14:25.000000000 +0100
+++ gcc/testsuite/gcc.dg/guality/pr36728-1.c	2012-11-27 10:01:14.517080157 +0100
@@ -1,7 +1,11 @@ 
 /* PR debug/36728 */
 /* { dg-do run } */
 /* { dg-options "-g" } */
-int a;
+
+#include "../nop.h"
+
+int a, b;
+
 int __attribute__((noinline))
 foo (int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7)
 {
@@ -9,9 +13,9 @@  foo (int arg1, int arg2, int arg3, int a
   int __attribute__ ((aligned(32))) y;
 
   y = 2;
-  asm ("" : "=m" (y) : "m" (y));
+  asm (NOP : "=m" (y), "=m" (b) : "m" (y));
   x[0] = 25;
-  asm ("" : "=m" (x[0]), "=m" (a) : "m" (x[0]));
+  asm (NOP : "=m" (x[0]), "=m" (a) : "m" (x[0]), "m" (b));
   return y;
 }
 
@@ -21,23 +25,23 @@  foo (int arg1, int arg2, int arg3, int a
    and arg2.  So it is expected that these values are unavailable in
    some of these tests.  */
 
-/* { dg-final { gdb-test 12 "arg1" "1" { target { ! "s390*-*-*" } } } }*/
-/* { dg-final { gdb-test 12 "arg2" "2" { target { ! "s390*-*-*" } } } }*/
-/* { dg-final { gdb-test 12 "arg3" "3" } } */
-/* { dg-final { gdb-test 12 "arg4" "4" } } */
-/* { dg-final { gdb-test 12 "arg5" "5" } } */
-/* { dg-final { gdb-test 12 "arg6" "6" } } */
-/* { dg-final { gdb-test 12 "arg7" "30" } } */
-/* { dg-final { gdb-test 12 "y" "2" } } */
-/* { dg-final { gdb-test 14 "arg1" "1" { target { ! "s390*-*-*" } } } }*/
-/* { dg-final { gdb-test 14 "arg2" "2" { target { ! "s390*-*-*" } } } }*/
-/* { dg-final { gdb-test 14 "arg3" "3" } } */
-/* { dg-final { gdb-test 14 "arg4" "4" } } */
-/* { dg-final { gdb-test 14 "arg5" "5" } } */
-/* { dg-final { gdb-test 14 "arg6" "6" } } */
-/* { dg-final { gdb-test 14 "arg7" "30" } } */
-/* { dg-final { gdb-test 14 "*x" "(char) 25" } } */
-/* { dg-final { gdb-test 14 "y" "2" } } */
+/* { dg-final { gdb-test 16 "arg1" "1" { target { ! "s390*-*-*" } } } } */
+/* { dg-final { gdb-test 16 "arg2" "2" { target { ! "s390*-*-*" } } } } */
+/* { dg-final { gdb-test 16 "arg3" "3" } } */
+/* { dg-final { gdb-test 16 "arg4" "4" } } */
+/* { dg-final { gdb-test 16 "arg5" "5" } } */
+/* { dg-final { gdb-test 16 "arg6" "6" } } */
+/* { dg-final { gdb-test 16 "arg7" "30" } } */
+/* { dg-final { gdb-test 16 "y" "2" } } */
+/* { dg-final { gdb-test 18 "arg1" "1" { target { ! "s390*-*-*" } } } } */
+/* { dg-final { gdb-test 18 "arg2" "2" { target { ! "s390*-*-*" } } } } */
+/* { dg-final { gdb-test 18 "arg3" "3" } } */
+/* { dg-final { gdb-test 18 "arg4" "4" } } */
+/* { dg-final { gdb-test 18 "arg5" "5" } } */
+/* { dg-final { gdb-test 18 "arg6" "6" } } */
+/* { dg-final { gdb-test 18 "arg7" "30" } } */
+/* { dg-final { gdb-test 18 "*x" "(char) 25" } } */
+/* { dg-final { gdb-test 18 "y" "2" } } */
 
 int
 main ()
--- gcc/testsuite/gcc.dg/guality/pr36728-2.c.jj	2012-11-26 10:14:25.000000000 +0100
+++ gcc/testsuite/gcc.dg/guality/pr36728-2.c	2012-11-27 10:00:46.237254022 +0100
@@ -1,7 +1,11 @@ 
 /* PR debug/36728 */
 /* { dg-do run } */
 /* { dg-options "-g" } */
-int a;
+
+#include "../nop.h"
+
+int a, b;
+
 int __attribute__((noinline))
 foo (int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7)
 {
@@ -9,9 +13,9 @@  foo (int arg1, int arg2, int arg3, int a
   int __attribute__ ((aligned(32))) y;
 
   y = 2;
-  asm ("" : "=m" (y) : "m" (y));
+  asm (NOP : "=m" (y), "=m" (b) : "m" (y));
   x[0] = 25;
-  asm ("" : "=m" (x[0]), "=m" (a) : "m" (x[0]));
+  asm (NOP : "=m" (x[0]), "=m" (a) : "m" (x[0]), "m" (b));
   return y;
 }
 
@@ -21,23 +25,23 @@  foo (int arg1, int arg2, int arg3, int a
    and arg2.  So it is expected that these values are unavailable in
    some of these tests.  */
 
-/* { dg-final { gdb-test 12 "arg1" "1" { target { ! "s390*-*-*" } } } } */
-/* { dg-final { gdb-test 12 "arg2" "2" { target { ! "s390*-*-*" } } } } */
-/* { dg-final { gdb-test 12 "arg3" "3" } } */
-/* { dg-final { gdb-test 12 "arg4" "4" } } */
-/* { dg-final { gdb-test 12 "arg5" "5" } } */
-/* { dg-final { gdb-test 12 "arg6" "6" } } */
-/* { dg-final { gdb-test 12 "arg7" "30" } } */
-/* { dg-final { gdb-test 12 "y" "2" } } */
-/* { dg-final { gdb-test 14 "arg1" "1" { target { ! "s390*-*-*" } } } } */
-/* { dg-final { gdb-test 14 "arg2" "2" { target { ! "s390*-*-*" } } } } */
-/* { dg-final { gdb-test 14 "arg3" "3" } } */
-/* { dg-final { gdb-test 14 "arg4" "4" } } */
-/* { dg-final { gdb-test 14 "arg5" "5" } } */
-/* { dg-final { gdb-test 14 "arg6" "6" } } */
-/* { dg-final { gdb-test 14 "arg7" "30" } } */
-/* { dg-final { gdb-test 14 "*x" "(char) 25" } } */
-/* { dg-final { gdb-test 14 "y" "2" } } */
+/* { dg-final { gdb-test 16 "arg1" "1" { target { ! "s390*-*-*" } } } } */
+/* { dg-final { gdb-test 16 "arg2" "2" { target { ! "s390*-*-*" } } } } */
+/* { dg-final { gdb-test 16 "arg3" "3" } } */
+/* { dg-final { gdb-test 16 "arg4" "4" } } */
+/* { dg-final { gdb-test 16 "arg5" "5" } } */
+/* { dg-final { gdb-test 16 "arg6" "6" } } */
+/* { dg-final { gdb-test 16 "arg7" "30" } } */
+/* { dg-final { gdb-test 16 "y" "2" } } */
+/* { dg-final { gdb-test 18 "arg1" "1" { target { ! "s390*-*-*" } } } } */
+/* { dg-final { gdb-test 18 "arg2" "2" { target { ! "s390*-*-*" } } } } */
+/* { dg-final { gdb-test 18 "arg3" "3" } } */
+/* { dg-final { gdb-test 18 "arg4" "4" } } */
+/* { dg-final { gdb-test 18 "arg5" "5" } } */
+/* { dg-final { gdb-test 18 "arg6" "6" } } */
+/* { dg-final { gdb-test 18 "arg7" "30" } } */
+/* { dg-final { gdb-test 18 "*x" "(char) 25" } } */
+/* { dg-final { gdb-test 18 "y" "2" } } */
 
 int
 main ()
--- gcc/testsuite/gcc.dg/guality/pr36728-3.c.jj	2012-11-26 18:58:40.896599886 +0100
+++ gcc/testsuite/gcc.dg/guality/pr36728-3.c	2012-11-27 10:01:45.455892012 +0100
@@ -0,0 +1,51 @@ 
+/* PR debug/36728 */
+/* { dg-do run } */
+/* { dg-options "-g" } */
+
+#include "../nop.h"
+
+int __attribute__((noinline))
+foo (int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7)
+{
+  char *x = __builtin_alloca (arg7);
+  int __attribute__ ((aligned(32))) y;
+
+  y = 2;
+  asm (NOP : "=m" (y) : "m" (y));
+  x[0] = 25;
+  asm volatile (NOP : "=m" (x[0]) : "m" (x[0]));
+  return y;
+}
+
+/* On s390(x) r2 and r3 are (depending on the optimization level) used
+   when adjusting the addresses in order to meet the alignment
+   requirements above.  They usually hold the function arguments arg1
+   and arg2.  So it is expected that these values are unavailable in
+   some of these tests.  */
+
+/* { dg-final { gdb-test 14 "arg1" "1" { target { ! "s390*-*-*" } } } } */
+/* { dg-final { gdb-test 14 "arg2" "2" { target { ! "s390*-*-*" } } } } */
+/* { dg-final { gdb-test 14 "arg3" "3" } } */
+/* { dg-final { gdb-test 14 "arg4" "4" } } */
+/* { dg-final { gdb-test 14 "arg5" "5" } } */
+/* { dg-final { gdb-test 14 "arg6" "6" } } */
+/* { dg-final { gdb-test 14 "arg7" "30" } } */
+/* { dg-final { gdb-test 14 "y" "2" } } */
+/* { dg-final { gdb-test 16 "arg1" "1" { target { ! "s390*-*-*" } } } } */
+/* { dg-final { gdb-test 16 "arg2" "2" { target { ! "s390*-*-*" } } } } */
+/* { dg-final { gdb-test 16 "arg3" "3" } } */
+/* { dg-final { gdb-test 16 "arg4" "4" } } */
+/* { dg-final { gdb-test 16 "arg5" "5" } } */
+/* { dg-final { gdb-test 16 "arg6" "6" } } */
+/* { dg-final { gdb-test 16 "arg7" "30" } } */
+/* { dg-final { gdb-test 16 "*x" "(char) 25" } } */
+/* { dg-final { gdb-test 16 "y" "2" } } */
+
+int
+main ()
+{
+  int l = 0;
+  asm volatile ("" : "=r" (l) : "0" (l));
+  foo (l + 1, l + 2, l + 3, l + 4, l + 5, l + 6, l + 30);
+  return 0;
+}
--- gcc/testsuite/gcc.dg/guality/pr36728-4.c.jj	2012-11-26 18:58:44.624580656 +0100
+++ gcc/testsuite/gcc.dg/guality/pr36728-4.c	2012-11-26 14:56:12.000000000 +0100
@@ -0,0 +1,51 @@ 
+/* PR debug/36728 */
+/* { dg-do run } */
+/* { dg-options "-g" } */
+
+#include "../nop.h"
+
+int __attribute__((noinline))
+foo (int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7)
+{
+  char x[30];
+  int __attribute__ ((aligned(32))) y;
+
+  y = 2;
+  asm (NOP : "=m" (y) : "m" (y));
+  x[0] = 25;
+  asm volatile (NOP : "=m" (x[0]) : "m" (x[0]));
+  return y;
+}
+
+/* On s390(x) r2 and r3 are (depending on the optimization level) used
+   when adjusting the addresses in order to meet the alignment
+   requirements above.  They usually hold the function arguments arg1
+   and arg2.  So it is expected that these values are unavailable in
+   some of these tests.  */
+
+/* { dg-final { gdb-test 14 "arg1" "1" { target { ! "s390*-*-*" } } } } */
+/* { dg-final { gdb-test 14 "arg2" "2" { target { ! "s390*-*-*" } } } } */
+/* { dg-final { gdb-test 14 "arg3" "3" } } */
+/* { dg-final { gdb-test 14 "arg4" "4" } } */
+/* { dg-final { gdb-test 14 "arg5" "5" } } */
+/* { dg-final { gdb-test 14 "arg6" "6" } } */
+/* { dg-final { gdb-test 14 "arg7" "30" } } */
+/* { dg-final { gdb-test 14 "y" "2" } } */
+/* { dg-final { gdb-test 16 "arg1" "1" { target { ! "s390*-*-*" } } } } */
+/* { dg-final { gdb-test 16 "arg2" "2" { target { ! "s390*-*-*" } } } } */
+/* { dg-final { gdb-test 16 "arg3" "3" } } */
+/* { dg-final { gdb-test 16 "arg4" "4" } } */
+/* { dg-final { gdb-test 16 "arg5" "5" } } */
+/* { dg-final { gdb-test 16 "arg6" "6" } } */
+/* { dg-final { gdb-test 16 "arg7" "30" } } */
+/* { dg-final { gdb-test 16 "*x" "(char) 25" } } */
+/* { dg-final { gdb-test 16 "y" "2" } } */
+
+int
+main ()
+{
+  int l = 0;
+  asm volatile ("" : "=r" (l) : "0" (l));
+  foo (l + 1, l + 2, l + 3, l + 4, l + 5, l + 6, l + 30);
+  return 0;
+}