The AArch64 AdvSIMD backend lacks SAD expanders for halfword vectors.

Add signed and unsigned expanders for V8HI and V4HI SAD operations.
Expand them into UABD/SABD followed by UADALP using UADALP for both forms
because absolute differences are non-negative. This enables vectorization
of loops accumulating 16-bit absolute differences into 32-bit costs.
The pattern improved the SPECCPU-2017 benchmarking around 1 -2%.

Bootstrapped and regression tested on Aarch64 with no extra failures.

gcc/ChangeLog:
        * config/aarch64/aarch64-simd.md (<su>sadv8hi): New define_expand.
        (<su>sadv4hi): Likewise.

gcc/testsuite/ChangeLog:
        * gcc.target/aarch64/sadv8hi.c: New test.

Signed-off-by: Naveen <[email protected]>
---
 gcc/config/aarch64/aarch64-simd.md         | 32 ++++++++++++++++++
 gcc/testsuite/gcc.target/aarch64/sadv8hi.c | 38 ++++++++++++++++++++++
 2 files changed, 70 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/sadv8hi.c

diff --git a/gcc/config/aarch64/aarch64-simd.md 
b/gcc/config/aarch64/aarch64-simd.md
index f9b2fd6b2db..e1ec520c8dc 100644
--- a/gcc/config/aarch64/aarch64-simd.md
+++ b/gcc/config/aarch64/aarch64-simd.md
@@ -1284,6 +1284,38 @@
   }
 )
 
+;; Sum-of-absolute-differences for eight 16-bit lanes, accumulating into
+;; four 32-bit lanes.  The absolute difference is always non-negative, so
+;; UADALP is used for both signed and unsigned input interpretations.
+(define_expand "<su>sadv8hi"
+  [(use (match_operand:V4SI 0 "register_operand"))
+   (USMAX:V8HI (match_operand:V8HI 1 "register_operand")
+               (match_operand:V8HI 2 "register_operand"))
+   (use (match_operand:V4SI 3 "register_operand"))]
+  "TARGET_SIMD"
+  {
+    rtx abd = gen_reg_rtx (V8HImode);
+    emit_insn (gen_aarch64_<su>abdv8hi (abd, operands[1], operands[2]));
+    emit_insn (gen_aarch64_uadalpv8hi (operands[0], operands[3], abd));
+    DONE;
+  }
+)
+
+;; D-register variant for four 16-bit lanes.
+(define_expand "<su>sadv4hi"
+  [(use (match_operand:V2SI 0 "register_operand"))
+   (USMAX:V4HI (match_operand:V4HI 1 "register_operand")
+               (match_operand:V4HI 2 "register_operand"))
+   (use (match_operand:V2SI 3 "register_operand"))]
+  "TARGET_SIMD"
+  {
+    rtx abd = gen_reg_rtx (V4HImode);
+    emit_insn (gen_aarch64_<su>abdv4hi (abd, operands[1], operands[2]));
+    emit_insn (gen_aarch64_uadalpv4hi (operands[0], operands[3], abd));
+    DONE;
+  }
+)
+
 (define_insn "aarch64_<su>aba<mode><vczle><vczbe>"
   [(set (match_operand:VDQ_BHSI 0 "register_operand" "=w")
        (plus:VDQ_BHSI (minus:VDQ_BHSI
diff --git a/gcc/testsuite/gcc.target/aarch64/sadv8hi.c 
b/gcc/testsuite/gcc.target/aarch64/sadv8hi.c
new file mode 100644
index 00000000000..c1dc068e93c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sadv8hi.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=armv8-a -fno-vect-cost-model -fno-unroll-loops" } 
*/
+
+#pragma GCC target "+nosve"
+
+#include <stdint.h>
+
+#define N 1024
+
+uint16_t ua[N], ub[N];
+int16_t sa[N], sb[N];
+
+unsigned int
+usad16 (void)
+{
+  unsigned int sum = 0;
+  for (int i = 0; i < N; ++i)
+    {
+      sum += __builtin_abs ((int) ua[i] - (int) ub[i]);
+    }
+  return sum;
+}
+
+unsigned int
+ssad16 (void)
+{
+  unsigned int sum = 0;
+  for (int i = 0; i < N; ++i)
+    {
+      int d = (int) sa[i] - (int) sb[i];
+      sum += __builtin_abs (d);
+    }
+  return sum;
+}
+
+/* { dg-final { scan-assembler {\tuabd\tv[0-9]+\.8h, v[0-9]+\.8h, v[0-9]+\.8h} 
} } */
+/* { dg-final { scan-assembler {\tsabd\tv[0-9]+\.8h, v[0-9]+\.8h, v[0-9]+\.8h} 
} } */
+/* { dg-final { scan-assembler-times {\tuadalp\tv[0-9]+\.4s, v[0-9]+\.8h} 2 } 
} */
-- 
2.34.1

Reply via email to