https://gcc.gnu.org/g:c743ce6b75543fadea31ab8d518bba363bf5e44e

commit r17-2570-gc743ce6b75543fadea31ab8d518bba363bf5e44e
Author: Vineet Gupta <[email protected]>
Date:   Mon Jul 20 10:58:31 2026 -0700

    bpf: TARGET_RTX_COSTS: avoid multiply synthesis
    
    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
    even though it 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]>

Diff:
---
 gcc/config/bpf/bpf.cc                           | 24 +++++++++++++++++++++---
 gcc/testsuite/gcc.target/bpf/divmod-libcall-2.c | 15 +++++++++------
 gcc/testsuite/gcc.target/bpf/mult-large.c       | 17 +++++++++++++++++
 gcc/testsuite/gcc.target/bpf/mult-small.c       | 14 ++++++++++++++
 4 files changed, 61 insertions(+), 9 deletions(-)

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..cc0efb8bb523
--- /dev/null
+++ b/gcc/testsuite/gcc.target/bpf/mult-large.c
@@ -0,0 +1,17 @@
+/* Verify that a multiply by a complex constant uses BPF's native single
+   instruction mul rather than a synthesized shift/add(-sub) sequence.
+   This is extracted from memset-4.c but with 32-bit multiplicand vs. byte
+   as the constant multiplier could genuinely trigger a mpy synthesis as
+      'x | x<<8 | x<<16 | x<<24'.  */
+
+/* { 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..3cebb1fdc1f0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/bpf/mult-small.c
@@ -0,0 +1,14 @@
+/* Verify that a multiply by a small constant uses BPF's native single
+   instruction mul rather than a synthesized shift/add(-sub) sequence.  */
+
+/* { 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