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