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.