public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
* Register conflicts between output memory address and output register
@ 2018-04-17 13:55 Matthew Fortune
  2018-04-19 15:50 ` Ulrich Weigand
  0 siblings, 1 reply; 2+ messages in thread
From: Matthew Fortune @ 2018-04-17 13:55 UTC (permalink / raw)
  To: gcc, Vladimir Makarov

Hi,

I've been investigating some quirks of register allocation when handling
some inline asm. The behaviour is non-intuitive but I am not sure if it
is a bug or not. This is back on GCC 6 so I'm still reviewing to see if
anything changed in this area since then.

The inline asm in question is:

int bar;
int my_mem;

void foo()
{
  asm volatile ("%0, %1, %2" : "=m"(my_mem), "=r"(bar)
                             : "m"(my_mem)
                             : "memory");
}

What I see is that if the address of my_mem is lowered prior to IRA then
there is a pseudo register for the output memory address (and perhaps an
offset) and a pseudo register for the output register. These two registers
are seen as a conflict in IRA so get different registers allocated. This is
good.

If however the address of my_mem is lowered after IRA i.e. when validating
constraints in LRA then IRA has nothing to do as the address is just a
symbol_ref. When LRA resolves the constraint for the address it introduces
a register for the output memory address but does not seem to acknowledge
any conflict with the output register (bar) it can therefore end up
using the same register for the output memory address as the output register.
This leads to the obvious problem if the ASM updates %1 before %0 as it will
corrupt the address.

This can of course be worked around by making (bar) an early clobber or an
in/out but this does seem unnecessary.

The question is... Should LRA recognise a conflict between the registers
involved in the address portion of an output memory operand and any output
register operands or is this a case where you strictly have to use early
clobber.

Any advice welcome!

Thanks,
Matthew

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: Register conflicts between output memory address and output register
  2018-04-17 13:55 Register conflicts between output memory address and output register Matthew Fortune
@ 2018-04-19 15:50 ` Ulrich Weigand
  0 siblings, 0 replies; 2+ messages in thread
From: Ulrich Weigand @ 2018-04-19 15:50 UTC (permalink / raw)
  To: Matthew Fortune; +Cc: gcc, Vladimir Makarov

Matthew Fortune wrote:

> If however the address of my_mem is lowered after IRA i.e. when validating
> constraints in LRA then IRA has nothing to do as the address is just a
> symbol_ref. When LRA resolves the constraint for the address it introduces
> a register for the output memory address but does not seem to acknowledge
> any conflict with the output register (bar) it can therefore end up
> using the same register for the output memory address as the output registe=
> r.
> This leads to the obvious problem if the ASM updates %1 before %0 as it will
> corrupt the address.
> 
> This can of course be worked around by making (bar) an early clobber or an
> in/out but this does seem unnecessary.
> 
> The question is... Should LRA recognise a conflict between the registers
> involved in the address portion of an output memory operand and any output
> register operands or is this a case where you strictly have to use early
> clobber.

Usually, the constraints are interpreted under the assumption that inputs
and output are used atomically, as if by a single target instruction.

If you consider an instruction that both updates memory and sets a register,
then most architectures will indeed allow for the output register to be the
same as one of the address registers for the memory operand, and therefore
GCC should allow this allocation.

In those cases where this is not true, e.g. because your inline asm does
in fact use multiple instructions which set the two outputs at different
times, then you should indeed use the earlyclobber flag -- that is
exactly what this flag is intended for.

The GCC documentation of the earlyclobber flag says:

  Means (in a particular alternative) that this operand is an
  earlyclobber operand, which is written before the instruction is
  finished using the input operands.  Therefore, this operand may not lie
  in a register that is read by the instruction or as part of any memory
  address.

Note in particular "... as part of any memory address."

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2018-04-19 15:45 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-17 13:55 Register conflicts between output memory address and output register Matthew Fortune
2018-04-19 15:50 ` Ulrich Weigand

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).