On Wed, Sep 18, 2024 at 03:53:37PM +0200, Michael Matz wrote:
> 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.
Thanks for sharing this. I also tend to error out in those cases as it
rather looks like a programming error. I came up with an updated
version just a few minutes ago where I added some documentation which
also discusses this. I also added some discussion for output operands
where I also tend to error out because those look like programming
errors.
>
> 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.
I will have a look and try to distinguish between both mechanisms during
error checking.
Thanks!
Stefan