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 {<<=} } } */
--
2.55.0