OK, thanks.

> The default cost of MULT/DIV/MOD in rtx_cost () is high: 5,7 insns
> respectively. This causes even a trivial mpy by 7 to be synthesized.
> Given these have direct equivalents in BPF ISA, fix the cost to generate
> native BPF insns.
>
> Note the existing divmod-licall-2.c test was a bit fragile as it forced
> cast signed an actual unsigned int which is provably non-negative. In
> the new cost model compiler would generate a native unsigned divide
> not available for -mcpu=v3, tripping up the test. Fix by ensuring the
> arg is actually signed.
>
> gcc/ChangeLog:
>
>       * config/bpf/bpf.cc (bpf_rtx_costs): Assign MPY/DIV/MOD cost 1.
>
> gcc/testsuite/ChangeLog:
>
>       * gcc.target/bpf/divmod-libcall-2.c: Change args/ret to signed.
>       * gcc.target/bpf/mult-large.c: New test.
>       * gcc.target/bpf/mult-small.c: New test.
>
> Signed-off-by: Vineet Gupta <[email protected]>
> ---
>  gcc/config/bpf/bpf.cc                         | 24 ++++++++++++++++---
>  .../gcc.target/bpf/divmod-libcall-2.c         | 15 +++++++-----
>  gcc/testsuite/gcc.target/bpf/mult-large.c     | 22 +++++++++++++++++
>  gcc/testsuite/gcc.target/bpf/mult-small.c     | 20 ++++++++++++++++
>  4 files changed, 72 insertions(+), 9 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.target/bpf/mult-large.c
>  create mode 100644 gcc/testsuite/gcc.target/bpf/mult-small.c
>
> diff --git a/gcc/config/bpf/bpf.cc b/gcc/config/bpf/bpf.cc
> index 89a4917cd0a0..58d2318f972b 100644
> --- a/gcc/config/bpf/bpf.cc
> +++ b/gcc/config/bpf/bpf.cc
> @@ -602,14 +602,32 @@ bpf_legitimate_address_p (machine_mode mode,
>     `rtx_cost' should recurse.  */
>  
>  static bool
> -bpf_rtx_costs (rtx x ATTRIBUTE_UNUSED,
> +bpf_rtx_costs (rtx x,
>              enum machine_mode mode ATTRIBUTE_UNUSED,
>              int outer_code ATTRIBUTE_UNUSED,
>              int opno ATTRIBUTE_UNUSED,
> -               int *total ATTRIBUTE_UNUSED,
> +            int *total,
>              bool speed ATTRIBUTE_UNUSED)
>  {
> -  /* To be written.  */
> +  switch (GET_CODE (x))
> +    {
> +    case MULT:
> +    case DIV:
> +    case UDIV:
> +    case MOD:
> +    case UMOD:
> +      /* BPF implements these as a single instruction, so keep the native
> +      operation cheaper than synthesized sequence.
> +      Only influences choice between actually available alternatives;
> +      if the operation has no insn (e.g. a 64-bit signed divide before
> +      -mcpu=v4) expand_divmod () still falls back to a libcall.
> +      Return false so caller rtx_cost keeps recursing for operands.  */
> +      *total = COSTS_N_INSNS (1);
> +      return false;
> +
> +    default:
> +      return false;
> +    }
>    return false;
>  }
>  
> diff --git a/gcc/testsuite/gcc.target/bpf/divmod-libcall-2.c 
> b/gcc/testsuite/gcc.target/bpf/divmod-libcall-2.c
> index 792d689395a2..7296579171d2 100644
> --- a/gcc/testsuite/gcc.target/bpf/divmod-libcall-2.c
> +++ b/gcc/testsuite/gcc.target/bpf/divmod-libcall-2.c
> @@ -1,16 +1,19 @@
> +/* Inverse of divmod-libcall-1.c. Ensure libcalls are generated for
> +   -mcpu=v3 due to lack of signed div/mod.  */
> +
>  /* { dg-do compile } */
>  /* { dg-options "-O2 -mcpu=v3" } */
>  /* { dg-final { scan-assembler "global\t__divdi3" } } */
>  /* { dg-final { scan-assembler "global\t__moddi3" } } */
>  
> -int
> -foo (unsigned int len)
> +long
> +foo (long len)
>  {
> -  return ((long)len) * 234 / 5;
> +  return len * 234 / 5;
>  }
>  
> -int
> -bar (unsigned int len)
> +long
> +bar (long len)
>  {
> -  return ((long)len) * 234 % 5;
> +  return len * 234 % 5;
>  }
> diff --git a/gcc/testsuite/gcc.target/bpf/mult-large.c 
> b/gcc/testsuite/gcc.target/bpf/mult-large.c
> new file mode 100644
> index 000000000000..4a5ef5da2b15
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/bpf/mult-large.c
> @@ -0,0 +1,22 @@
> +/* The multiply core of memset-4.c: a memset of a non-constant value
> +   broadcasts a byte across the word with "x * 0x01010101".  With the generic
> +   COSTS_N_INSNS (5) multiply cost this large-constant multiply was
> +   strength-reduced into a shift/add sequence; BPF has a single-instruction
> +   mul, so the native mul must be used instead.
> +
> +   Use a full 32-bit input (not 'unsigned char'): for a byte 'x * 0x01010101'
> +   equals the carry-free broadcast 'x | x<<8 | x<<16 | x<<24', which the
> +   compiler could lower without a multiply at all, weakening the test.  A
> +   32-bit input has no such equivalence, so this is a genuine multiply.  */
> +
> +/* { dg-do compile } */
> +/* { dg-options "-O2" } */
> +
> +unsigned
> +bcast (unsigned x)
> +{
> +  return x * 0x01010101u;
> +}
> +
> +/* { dg-final { scan-assembler {\*= 16843009} } } */
> +/* { dg-final { scan-assembler-not {<<=} } } */
> diff --git a/gcc/testsuite/gcc.target/bpf/mult-small.c 
> b/gcc/testsuite/gcc.target/bpf/mult-small.c
> new file mode 100644
> index 000000000000..7c82f3276266
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/bpf/mult-small.c
> @@ -0,0 +1,20 @@
> +/* Verify that a multiply by a small constant uses BPF's native single
> +   instruction mul rather than a synthesized shift/add(-sub) sequence.
> +
> +   BPF has a single-instruction multiply, so "x * 7" should be "r0 *= 7",
> +   not the strength-reduced "(x << 3) - x".  synth_mult () only avoids the
> +   native multiply when it finds a cheaper sequence, so the rtx_cost hook
> +   must report MULT as a single instruction (rather than the generic
> +   COSTS_N_INSNS (5) schoolbook default) for the native op to win.  */
> +
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -mcpu=v4" } */
> +
> +unsigned
> +mul7 (unsigned x)
> +{
> +  return x * 7;
> +}
> +
> +/* { dg-final { scan-assembler {\*= 7} } } */
> +/* { dg-final { scan-assembler-not {<<=} } } */

Reply via email to