Hello,

On Thu, 12 Sep 2024, Stefan Schulze Frielinghaus wrote:

> > > #define call_on_stack(stack, func, asm_call, argconstr...)              \
> > > {                                                                       \
> > >          register void *tos asm("r11");                                  \
> > >                                                                          \
> > >          tos = ((void *)(stack));                                        \
> > >                                                                          \
> > >          asm_inline volatile(                                            \
> > >          "movq   %%rsp, (%[tos])                         \n"             \
> > >          "movq   %[tos], %%rsp                           \n"             \
> > >                                                                          \
> > >          asm_call                                                        \
> > >                                                                          \
> > >          "popq   %%rsp                                   \n"             \
> > >                                                                          \
> > >          : "+r" (tos), ASM_CALL_CONSTRAINT                               \
> > >          : [__func] "i" (func), [tos] "r" (tos) argconstr                \
> > >          : "cc", "rax", "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10",   \
> > >            "memory"                                                      \
> > >          );                                                              \
> > > }
> 
> I didn't find documentation how "digit references" behave in combination
> with register asm.

Because noone thought of that corner case while documenting stuff :-)

As you say: it only works because the involved inputs/outputs are the same 
expression.  If they weren't the inconsistency would be detected in 
reload/LRA when the necessary reloads would need to be generated and the 
pass would find that that's impossible.

Now, question is, what to do in this case in the light of a new feature.  
I would say that while perhaps sometimes convenient it's more likely to be 
a programmers fault, so for your new hardreg constraints it seems better 
to ...

> Anyway, I digress.  I haven't made up my mind how hard register
> constraints should behave in those cases, i.e., in cases where multiple
> inputs share the same register.  If the inputs are different or may be
> different, then we can reject those programs.
> 
> asm ("" : "={r4}" (x) : "{r5}" (42), "{r5}" (24));
> 
> Whereas if the operands are provable equal (assuming y is not volatile)
> 
> asm ("" : "={r4}" (x) : "{r5}" (y), "{r5}" (y));
> 
> we could accept those programs.  Currently, I error out even for
> programs of the latter form which may be a bit to restrictive.

... do exactly this, error out unconditionally.  I wouldn't change 
behaviour for existing features, i.e. register-asm vars plus matching 
constraints (if for inout operands, or explicit matching constraints 
doesn't matter) because there's existing usage that happens to work fine.

Why unconditionally and not just "when expressions are different"?  
Because the latter is inherently hard to see when optimizations are 
involved: is "(a + 0)" the same as "(a)"?  At which optimization levels?
What if the "0" is an expression that needs further analysis to see that 
it's actually zero?  And so on.

If it's not easily possible to error out only for the new hard-reg 
constraints, and accept whatever is there for register-asm vars and 
matching constraints, then I would opt to also _not_ error out for the new 
feature, though.  Essentially that's saying that if the user writes 
wacky code then its their responsibility that everything works out, which 
is exactly what the current implementation does: if at the end no reloads 
are required, it's fine (because it indeed adheres to all given 
constraints!), otherwise we give an error.


Ciao,
Michael.

Reply via email to