[PATCH] aarch64: Canonicalize halving-add builtins [PR122715]

Odysseas Georgoudis <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <FRWP195MB28641B44FA34564DF4B25BD1CCD92@FRWP195MB2864.EURP195.PROD.OUTLOOK.COM>
The first two patches for PR122715 have been committed.  This patch
handles the remaining AArch64 case.

Advanced SIMD halving-add intrinsics remain target builtins in GIMPLE,
preventing generic average simplifications from seeing them.  Canonicalize
SHADD and UHADD to IFN_AVG_FLOOR, and SRHADD and URHADD to
IFN_AVG_CEIL.

This allows equal operands to be folded by the existing match.pd rule
while retaining optab-based instruction selection for other operands.

Tested with an aarch64-linux-gnu cross compiler.  The targeted tests
pass.

Thanks,
Odysseas
PR122715-aarch64.patch (application/octet-stream, 6 KB)
From de17c2eac59fb4642f6eacac3884d8018d5dc131 Mon Sep 17 00:00:00 2001
From: Odysseas Georgoudis <[email protected]>
Date: Sat, 15 Aug 2026 01:20:17 +0100
Subject: [PATCH] aarch64: Canonicalize halving-add builtins [PR122715]

Advanced SIMD halving-add intrinsics remain target builtins in GIMPLE,
preventing generic average simplifications from seeing them.  Canonicalize
SHADD and UHADD to IFN_AVG_FLOOR, and SRHADD and URHADD to
IFN_AVG_CEIL.

This allows equal operands to be folded by the existing match.pd rule
while retaining optab-based instruction selection for other operands.

	PR target/122715

gcc/ChangeLog:

	* config/aarch64/aarch64-builtins.cc
	(aarch64_general_gimple_fold_builtin): Canonicalize halving-add
	builtins to IFN_AVG_FLOOR and IFN_AVG_CEIL.

gcc/testsuite/ChangeLog:

	* gcc.target/aarch64/avg-pr122715.c: New test.
	* gcc.target/aarch64/avg-pr122715-2.c: New test.

Signed-off-by: Odysseas Georgoudis <[email protected]>
---
 gcc/config/aarch64/aarch64-builtins.cc        |  14 ++
 .../gcc.target/aarch64/avg-pr122715-2.c       |  33 +++++
 .../gcc.target/aarch64/avg-pr122715.c         | 129 ++++++++++++++++++
 3 files changed, 176 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/avg-pr122715-2.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/avg-pr122715.c

diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc
index 8cd1bc4b1a2..bb0a1c978f2 100644
--- a/gcc/config/aarch64/aarch64-builtins.cc
+++ b/gcc/config/aarch64/aarch64-builtins.cc
@@ -5065,6 +5065,20 @@ aarch64_general_gimple_fold_builtin (unsigned int fcode, gcall *stmt,
 					       1, args[0]);
 	gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
 	break;
+      /* Lower Advanced SIMD halving-add builtins to average internal
+	 functions.  */
+      BUILTIN_VDQ_BHSI (BINOP, shadd, 0, DEFAULT)
+      BUILTIN_VDQ_BHSI (BINOPU, uhadd, 0, DEFAULT)
+	new_stmt = gimple_build_call_internal (IFN_AVG_FLOOR, 2,
+					       args[0], args[1]);
+	gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
+	break;
+      BUILTIN_VDQ_BHSI (BINOP, srhadd, 0, DEFAULT)
+      BUILTIN_VDQ_BHSI (BINOPU, urhadd, 0, DEFAULT)
+	new_stmt = gimple_build_call_internal (IFN_AVG_CEIL, 2,
+					       args[0], args[1]);
+	gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
+	break;
       BUILTIN_VSDQ_I_DI (BINOP, ashl, 3, DEFAULT)
 	if (TREE_CODE (args[1]) == INTEGER_CST
 	    && wi::ltu_p (wi::to_wide (args[1]), element_precision (args[0])))
diff --git a/gcc/testsuite/gcc.target/aarch64/avg-pr122715-2.c b/gcc/testsuite/gcc.target/aarch64/avg-pr122715-2.c
new file mode 100644
index 00000000000..c088c1327d0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/avg-pr122715-2.c
@@ -0,0 +1,33 @@
+/* PR target/122715 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+#include <arm_neon.h>
+
+int32x4_t avg_floor_s32(int32x4_t x, int32x4_t y)
+{
+  return vhaddq_s32 (x, y);
+}
+
+uint32x4_t avg_floor_u32(uint32x4_t x, uint32x4_t y)
+{
+  return vhaddq_u32 (x, y);
+}
+
+int32x4_t avg_ceil_s32(int32x4_t x, int32x4_t y)
+{
+  return vrhaddq_s32 (x, y);
+}
+
+uint32x4_t avg_ceil_u32(uint32x4_t x, uint32x4_t y)
+{
+  return vrhaddq_u32 (x, y);
+}
+
+/* { dg-final { scan-tree-dump-times {\.AVG_FLOOR} 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times {\.AVG_CEIL} 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-not {__builtin_aarch64_} "optimized" } } */
+/* { dg-final { scan-assembler-times {\tshadd\t} 1 } } */
+/* { dg-final { scan-assembler-times {\tuhadd\t} 1 } } */
+/* { dg-final { scan-assembler-times {\tsrhadd\t} 1 } } */
+/* { dg-final { scan-assembler-times {\turhadd\t} 1 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/avg-pr122715.c b/gcc/testsuite/gcc.target/aarch64/avg-pr122715.c
new file mode 100644
index 00000000000..aa46df3ffd7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/avg-pr122715.c
@@ -0,0 +1,129 @@
+/* PR target/122715 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+#include <arm_neon.h>
+
+int8x8_t avg_floor_s8_64(int8x8_t x)
+{
+  return vhadd_s8 (x, x);
+}
+
+int16x4_t avg_floor_s16_64(int16x4_t x)
+{
+  return vhadd_s16 (x, x);
+}
+
+int32x2_t avg_floor_s32_64(int32x2_t x)
+{
+  return vhadd_s32 (x, x);
+}
+
+uint8x8_t avg_floor_u8_64(uint8x8_t x)
+{
+  return vhadd_u8 (x, x);
+}
+
+uint16x4_t avg_floor_u16_64(uint16x4_t x)
+{
+  return vhadd_u16 (x, x);
+}
+
+uint32x2_t avg_floor_u32_64(uint32x2_t x)
+{
+  return vhadd_u32 (x, x);
+}
+
+int8x16_t avg_floor_s8_128(int8x16_t x)
+{
+  return vhaddq_s8 (x, x);
+}
+
+int16x8_t avg_floor_s16_128(int16x8_t x)
+{
+  return vhaddq_s16 (x, x);
+}
+
+int32x4_t avg_floor_s32_128(int32x4_t x)
+{
+  return vhaddq_s32 (x, x);
+}
+
+uint8x16_t avg_floor_u8_128(uint8x16_t x)
+{
+  return vhaddq_u8 (x, x);
+}
+
+uint16x8_t avg_floor_u16_128(uint16x8_t x)
+{
+  return vhaddq_u16 (x, x);
+}
+
+uint32x4_t avg_floor_u32_128(uint32x4_t x)
+{
+  return vhaddq_u32 (x, x);
+}
+
+int8x8_t avg_ceil_s8_64(int8x8_t x)
+{
+  return vrhadd_s8 (x, x);
+}
+
+int16x4_t avg_ceil_s16_64(int16x4_t x)
+{
+  return vrhadd_s16 (x, x);
+}
+
+int32x2_t avg_ceil_s32_64(int32x2_t x)
+{
+  return vrhadd_s32 (x, x);
+}
+
+uint8x8_t avg_ceil_u8_64(uint8x8_t x)
+{
+  return vrhadd_u8 (x, x);
+}
+
+uint16x4_t avg_ceil_u16_64(uint16x4_t x)
+{
+  return vrhadd_u16 (x, x);
+}
+
+uint32x2_t avg_ceil_u32_64(uint32x2_t x)
+{
+  return vrhadd_u32 (x, x);
+}
+
+int8x16_t avg_ceil_s8_128(int8x16_t x)
+{
+  return vrhaddq_s8 (x, x);
+}
+
+int16x8_t avg_ceil_s16_128(int16x8_t x)
+{
+  return vrhaddq_s16 (x, x);
+}
+
+int32x4_t avg_ceil_s32_128(int32x4_t x)
+{
+  return vrhaddq_s32 (x, x);
+}
+
+uint8x16_t avg_ceil_u8_128(uint8x16_t x)
+{
+  return vrhaddq_u8 (x, x);
+}
+
+uint16x8_t avg_ceil_u16_128(uint16x8_t x)
+{
+  return vrhaddq_u16 (x, x);
+}
+
+uint32x4_t avg_ceil_u32_128(uint32x4_t x)
+{
+  return vrhaddq_u32 (x, x);
+}
+
+/* { dg-final { scan-tree-dump-not {__builtin_aarch64_} "optimized" } } */
+/* { dg-final { scan-tree-dump-times {return x_} 24 "optimized" } } */
+/* { dg-final { scan-assembler-not {\t[su]r?hadd\t} } } */
-- 
2.43.5
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.