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.