Hi,
On Mon, 28 Aug 2017, Jeff Law wrote:
> > asm ("" : "=r" (x) : "r" (y+z));
> > asm ("" : "=r" (x) : "r" (z));
> > asm ("" : "=r" (x) : "r" (42));
>
> >
> > (are we still agreeing on this? I'm having a problem understanding why
> > you think the above wouldn't work)
>
> How do we represent the y+z case in particular. Isn't that shoved into
> a gimple temporary and ultimately a pseudo?
On the GIMPLE side asm operands (inputs) are generally transformed into
is_gimple_val, i.e. constants or scalar temporaries. Up to the RTL side
this usually remains, i.e. yes, y+z will be placed into a pseudo.
Since (at least) introduction of GIMPLE, also constants (actually anything
non-register_operand) will be rewritten into a pseudo already by cfgexpand
if the alternative accepts only a reg (or matches one accepting only a
reg).
But also LRA (and reload) will happily accept a constant in those operands
and reload it into a reg (in reload/lra parlance, that alternative isn't
matching as is, i.e. has loosers, but can be made matching by reloading,
i.e. it's not failing). It's generally the case that alternatives that
accept a register can accept all kinds of operands as inputs (basically
force_reg must work on it, so there are additional constraints like
impossible modes and such).
That's also true for matching constraints were the matched one accepts a
register: if the operands aren't operand_equal_p right now it merely means
the alternative has loosers currently, but as registers are acceptable
that's fine. Matching constraints do add some further constraints, but
not regarding the kinds of operands it accepts. Like in this situation:
asm("" : "=r" (op0): "2" (op1), "0" (op2));
(assuming op0/op1/op2 all don't match at the point of LRA), then to make
op0 and op2 match a reload of op2 is needed. But that'd invalidate the
reload that was created for op1 to make that one match op2 (operands are
matched/reloaded in order). LRA can't deal with this situation so it
gives up here.
All the gunk for this is in process_alt_operands(). As soon as either
badop==false or any of winreg, win or did_match is set after constraint
parsing the operand (of whatever form) is mostly acceptable (perhaps with
reloads) under still some further constraints like mode checks and such.
It's essentially the same code like in find_reloads (though I find the
latter slightly easier to read, strangely enough :) ).
> > Which is a perfectly fine rvalue. Input constraints never need lvalues
> > (or objects). Maybe you're confusing this all with one particularity that
> > _if_ the input rvalue stems from an object and that object happens to be
> > allocated to a hardreg (via an asm("regname") declaration) then this
> > hardreg will be used as input register? In that way some information
> > from lvalues also flows into input operands, but it's not generally the
> > case that they must be lvalues.
> True. I'm not thinking in terms of lvalues and rvalues, but in terms of
> allocnos and pseudos that the allocators and reloaders operate on.
For all the above cases, i.e. when non-fitting alternatives accepting
registers are involved, pseudos and hence allocnos will eventually be
created. The operands don't need to start out as pseudos.
> Going back to pshortis issue, it's interesting how the size of the input
> operand is being used to determine the mode of the matching output
> operand. That ought to be not-too-difficult to find within GCC...
> With any luck there'd be a useful comment in that code.
I think that is just a presentation problem. The printing of asms is
fairly unintuitive. What he had was these two RTL dumps of the asm in
question:
(insn 6 5 7 2 (set (reg:SI 29 [ a ])
(asm_operands:SI ("") ("=r") 0
[ (reg:HI 30) ]
[ (asm_input:HI ("0") ] ...
(with integer 0)
(insn 6 5 7 2 (set (reg:SI 29 [ a ])
(asm_operands:SI ("") ("=r") 0
[ (reg:SI 30) ]
[ (asm_input:SI ("0") ] ...
(with long 0).
What is unintuitive here is that '[ (reg:XX 30) ]' might be mistaken for
an output operand and mode, because there's that other mentioning of
'asm_input:XX'. That's not true. (reg:XX 30) is the first input, and
hence correctly reflects HI/SI mode depending on type of value. The
output operand is actually the (asm_operands:SI ("") ("=r")), which has
the correct SImode in both cases. (And the asm_input:XX is there to have
a place to store the constraint connected with the input)
Looking at asms with multiple outputs and inputs makes that more obvious.
E.g.
long a,b, i,j;
asm volatile ("XXX" : "=r" (a), "=r" (b) : "0" (i), "1" (j), "r" (j));
comes out as
(insn 12 11 7 (parallel [
(set (reg:DI 87 [ a ])
(asm_operands/v:DI ("XXX") ("=r") 0 [
(reg:DI 89)
(reg:DI 90)
(reg:DI 91)
]
[
(asm_input:DI ("0") x4.c:4)
(asm_input:DI ("1") x4.c:4)
(asm_input:DI ("r") x4.c:4)
]
[] x4.c:4))
(set (reg:DI 88 [ b ])
(asm_operands/v:DI ("XXX") ("=r") 1 [
(reg:DI 89)
(reg:DI 90)
(reg:DI 91)
]
[
(asm_input:DI ("0") x4.c:4)
(asm_input:DI ("1") x4.c:4)
(asm_input:DI ("r") x4.c:4)
]
[] x4.c:4))
(clobber (reg:CCFP 18 fpsr))
(clobber (reg:CC 17 flags))
]) "x4.c":4 -1
(nil))
See how the two vectors per asm_operands are the same, have three elements
and correspond to the three inputs, and that we have two asm_operands:DI
representing the two outputs.
So, all is as expected, there is no cross talk regarding modes between
input and output operands in the original example. (But of course it
still needs to use 0L if it expects to initialize a long lvalue from it,
there's no automatic type conversions between different operands, even if
they are requested to be matching).
Ciao,
Michael.