Hi Vineet.

>> On 7/2/26 3:21 PM, Jose E. Marchesi wrote:
>>>   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 outer_code,
>>>            int opno ATTRIBUTE_UNUSED,
>>> -               int *total ATTRIBUTE_UNUSED,
>>> +          int *total,
>>>            bool speed ATTRIBUTE_UNUSED)
>>>   {
>>> -  /* To be written.  */
>>> +  switch (GET_CODE (x))
>>> +    {
>>> +    case CONST_INT:
>>> +      {
>>> +   HOST_WIDE_INT val = INTVAL (x);
>>> +   /* BPF ALU instructions take a signed 32-bit immediate operand.  */
>>> +   bool imm32 = (val == (HOST_WIDE_INT) (int32_t) val);
>>> I would prefer if you would define a BPF_IMM32 macro in bpf.h and then
>>> use it as well in the imm32_operand predicate in predicates.md.
>>
>> OK.
>
> I forgot the _P in the suggested name.  It shall be BPF_IMM32_P.
>
>>
>>>> +  switch (outer_code)
>>>> +    {
>>>> +    /* Do not report a free constant when it is the operand of a
>>>> +       multiply, divide or modulo.  A zero-cost constant misleads
>>>> +       synth_mult () and expand_divmod () into implementing the
>>>> +       operation as a sequence of shifts/adds (or a magic-number
>>>> +       multiply) instead of BPF's native single-instruction mul/div,
>>>> +       which is cheaper here.  */
>
> Been looking at expand_divmod, expmed_mult_highpart, choose_mult_variant
> and friends to see why they would get misled when the cost of
> div/udiv/mod with a constant op is COSTS_N_INSNS (1), and not when the
> cost is CONSTS_N_INSNS (2).  No success yet..  Do you know what is the
> cause?  Which div/mod tests are regressing?

I used the following program, which is derived from the
divmod-libcall-1.c and divmod-libcall-2.c testcases:

  int
  foodiv (unsigned int len)
  {
    return ((unsigned long)len) * 234 / 5;
  }

  int
  foomod (unsigned int len)
  {
    return ((unsigned long)len) * 234 % 5;
  }

  long
  bardiv (long x)
  {
    return x * 234 / 5;
  }

  long
  barmod (long x)
  {
    return x * 234 % 5;
  }

With your patch as-is, which assigns cost 1 to imm32 operands in
mult/div/udiv/mod/umod instructions, i.e.

    case CONST_INT:
      {
        HOST_WIDE_INT val = INTVAL (x);
        /* BPF ALU instructions take a signed 32-bit immediate operand.  */
        bool imm32 = (val == (HOST_WIDE_INT) (int32_t) val);

        switch (outer_code)
          {
          /* Do not report a free constant when it is the operand of a
             multiply, divide or modulo.  A zero-cost constant misleads
             synth_mult () and expand_divmod () into implementing the
             operation as a sequence of shifts/adds (or a magic-number
             multiply) instead of BPF's native single-instruction mul/div,
             which is cheaper here.  */
          case MULT:
          case DIV:
          case UDIV:
          case MOD:
          case UMOD:
            *total = COSTS_N_INSNS (1);
            break;

          default:
            /* An immediate operand is free; a wider constant needs an
               extra LD_IMM64.  */
            *total = imm32 ? 0 : COSTS_N_INSNS (1);
          }

        return true;
      }

I get:


  -O2 -mcpu=v3

  foodiv:
        w0 = w1
        r0 *= 234
        r0 /= 5
        exit

  foomod:
        w0 = w1
        r0 *= 234
        r0 %= 5
        exit

  bardiv:
        r2 = 5
        r1 *= 234
        call    __divdi3
        exit

  barmod:
        r2 = 5
        r1 *= 234
        call    __moddi3
        exit


  -O2 -mcpu=v4

  foodiv:
        w0 = w1
        r0 *= 234
        r0 /= 5
        exit

  foomod:
        w0 = w1
        r0 *= 234
        r0 %= 5
        exit

  bardiv:
        r0 = r1
        r0 *= 234
        r0 s/= 5
        exit

  barmod:
        r0 = r1
        r0 *= 234
        r0 s%= 5
        exit

Which is as expected.

Then, modifying your patch so it assigns cost 0 to imm32 immediates also
in div, mod and mul instructions, i.e.

    case CONST_INT:
      {
        HOST_WIDE_INT val = INTVAL (x);
        /* BPF ALU instructions take a signed 32-bit immediate operand.  */
        bool imm32 = (val == (HOST_WIDE_INT) (int32_t) val);

        /* An immediate operand is free; a wider constant needs an
           extra LD_IMM64.  */
        *total = imm32 ? 0 : COSTS_N_INSNS (1);
        return true;
      }

I get:

  -O2 -mcpu=v3

  foodiv:
        w0 = w1
        r0 *= 234
        r0 /= 5
        exit

  foomod:
        w0 = w1
        r0 *= 234
        r0 %= 5
        exit

  bardiv:
        r2 = 5
        r1 *= 234
        call    __divdi3
        exit

  barmod:
        r2 = 5
        r1 *= 234
        call    __moddi3
        exit

  -O2 -mcpu=v4

  foodiv:
        w0 = w1
        r0 *= 234
        r0 /= 5
        exit

  foomod:
        w0 = w1
        r0 *= 234
        r0 %= 5
        exit

  bardiv:
        r0 = r1
        r0 *= 234
        r0 s/= 5
        exit

  barmod:
        r0 = r1
        r0 *= 234
        r0 s%= 5
        exit

Wich is also as expected.

Reply via email to