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.

Reply via email to