Robin Dapp <[email protected]> writes:
> From: Robin Dapp <[email protected]>
>
> Building upon Richard's register filters, this patch series introduces 
> filters 
> that can base their filtering decision on a second operand:  The constrained 
> operand (the "dependent" operand), and the "referenced" operand.
> This allows e.g. to constrain the dependent operand relative to the mode of 
> an 
> output operand.  For RISC-V, a typical example is when a source of a widening 
> vector instruction must either not overlap the destination at all or only a 
> specific subreg of the destination.
>
> A major difference to register filters is that dependent filters are dynamic 
> and can therefore be significantly heavier in compile-time.  Also, by their
> nature, they are order-dependent, influencing greedy coloring heuristics.

Just to probe the problem space a bit: how many registers does the widest
possible destination have?  The reason for asking is that, for two registers,
it's possible to arrange "no overlap of the high half" using:

#include <stdint.h>

#define TEST(X) \
    __uint128_t res; \
    asm ("foo\t%0, %1" : "=r,&r" (res) : "0,r" (X)); \
    return res;

__uint128_t f1(uint64_t x) { TEST(x); }
__uint128_t f2(uint64_t x, uint64_t y) { TEST(y); }
__uint128_t f3(uint64_t x, uint64_t y, uint64_t z) { TEST(z); }

which produces:

f1(unsigned long):
        foo     x0, x0
        ret
f2(unsigned long, unsigned long):
        mov     x2, x1
        foo     x0, x2
        ret
f3(unsigned long, unsigned long, unsigned long):
        foo     x0, x2
        ret

It sounds like the main difference here is that you want "no overlap
with the low half".  Perhaps that could be handled using a "match high"
constraint that would otherwise work similarly to the current 0-9
constraints.

If the destination is always 2 registers, an alternative approach would
be to have register filters for odd and even registers, with three
alternatives:

- odd destination, even source
- even destination, odd source
- any destination, earlyclobbered

I've no idea how well IRA would allocate that though.  (Probably not very.
It wasn't an intended use case.)

If nregs can be more than 1 in:

  unsigned int wide_nregs = riscv_hard_regno_nregs (wide_regno, wide_mode);
  unsigned int nregs = riscv_hard_regno_nregs (regno, mode);

  /* Overlap is only allowed in the highest-numbered part of the wider
     destination.  */
  if (regno == wide_regno)
    return false;

  if (regno >= wide_regno + (wide_nregs - nregs))
    return true;

  /* No overlap is OK.  */
  if (regno < wide_regno)
    return true;

  return false;

then it looks like the regno + nregs - 1 == wide_regno is OK.
Is that how it works?  Or is nregs always 1 in practice?

Another alternative would be to have something like "earlyclobber
low part", although "low part" might be difficult to define.

I'm just playing devil's advocate here, rather than objecting to the
proposal.

Thanks,
Richard

Reply via email to