On 13 Nov 2026, at 15:50, Karl Meakin <[email protected]> wrote:
The floating point variants of `vminv` and `vmaxv` were not ported to
the pragma-based framework when the integer variants were, because the
semantics AArch64's `fminv`/`fmaxv` instructions don't match the
semantics of GCC's `IFN_REDUC_MIN`/`IFN_REDUC_MAX`. This commit ports
them to the pragma framework, by expanding them to `UNSPEC_FMINV` and
`UNSPEC_FMAXV`.
There are no test changes, as tests for FP variants of vminv/vmaxv were
already included in vminv.c and vmaxv.c. The absence of any changes to
the tests does show that there were no changes in codegen (ie no
regressions).
gcc/ChangeLog:
* config/aarch64/aarch64-builtins.cc
(aarch64_general_gimple_fold_builtin): Delete cases for handling
`reduc_{u,s}{min,max}_scal_`.
* config/aarch64/aarch64-neon-builtins-base.cc (build_ifn_call):
New function.
(struct gimple_reduce_minmax): New struct.
* config/aarch64/aarch64-neon-builtins-base.def (vminv, vminvq,
vmaxv, vmaxvq): New intrinsic function declarations.
* config/aarch64/aarch64-simd-builtins.def: Delete
`reduc_{us}{min,max}{,_nan}_scal_` builtin functions.
* config/aarch64/aarch64-simd.md (reduc_<optab>_scal_<mode>):
Rename to ...
(@reduc_<optab>_scal_<mode>): ...this, so that it is callable
from `gimple_reduce_minmax::expand ()`.
* config/aarch64/arm_neon.h
(vpmaxqd_f64, vpmaxs_f32, vpmaxnmqd_f64, vpmaxnms_f32,
vpminqd_f64, vpmins_f32, vpminnmqd_f64): Call the intrinsic
(v{min,max}{,nm}v) functions rather than the now-deleted
`__builtin_aarch64_reduc_s{min,max}_scal` functions.
(vmaxv_f32, vmaxvq_f32, vmaxvq_f64, vminv_f32, vminvq_f32,
vminvq_f64, vmaxv_f16, vmaxvq_f16, vminv_f16, vminvq_f16):
Delete intrinsic function definitions.
---
gcc/config/aarch64/aarch64-builtins.cc | 12 ---
.../aarch64/aarch64-neon-builtins-base.cc | 60 +++++++++++-
.../aarch64/aarch64-neon-builtins-base.def | 12 ++-
gcc/config/aarch64/aarch64-simd-builtins.def | 8 --
gcc/config/aarch64/aarch64-simd.md | 6 +-
gcc/config/aarch64/arm_neon.h | 92 ++-----------------
6 files changed, 79 insertions(+), 111 deletions(-)
diff --git a/gcc/config/aarch64/aarch64-builtins.cc
b/gcc/config/aarch64/aarch64-builtins.cc
index 1d8baaef5c4..337ecb1088a 100644
--- a/gcc/config/aarch64/aarch64-builtins.cc
+++ b/gcc/config/aarch64/aarch64-builtins.cc
@@ -5268,18 +5268,6 @@ aarch64_general_gimple_fold_builtin (unsigned int fcode,
gcall *stmt,
break;
}
- BUILTIN_VDQIF (UNOP, reduc_smax_scal_, 10, ALL)
- BUILTIN_VDQ_BHSI (UNOPU, reduc_umax_scal_, 10, ALL)
- new_stmt = gimple_build_call_internal (IFN_REDUC_MAX,
- 1, args[0]);
- gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
- break;
- BUILTIN_VDQIF (UNOP, reduc_smin_scal_, 10, ALL)
- BUILTIN_VDQ_BHSI (UNOPU, reduc_umin_scal_, 10, ALL)
- new_stmt = gimple_build_call_internal (IFN_REDUC_MIN,
- 1, args[0]);
- 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/config/aarch64/aarch64-neon-builtins-base.cc
b/gcc/config/aarch64/aarch64-neon-builtins-base.cc
index 8c3bcc6eb74..1f5b46f216d 100644
--- a/gcc/config/aarch64/aarch64-neon-builtins-base.cc
+++ b/gcc/config/aarch64/aarch64-neon-builtins-base.cc
@@ -1176,6 +1176,62 @@ struct gimple_minmax : public gimple_function_base
}
};
+/* Build a call to the internal function IFN.
+ Handles singleton vector arguments specially: they are cast to their
+ inner element type before the function is called, and then the return value
+ is cast back to the expected singleton vector type. */
+tree
+build_ifn_call (gimple_folder &f, internal_fn ifn, tree ret_type,
+ vec<tree> &args)
+{
+ for (auto &arg : args)
+ if (one_element_vector_type_p (TREE_TYPE (arg)))
+ arg = f.force_val (build_cast (TREE_TYPE (TREE_TYPE (arg)), arg));
+
+ auto call = gimple_build_call_internal_vec (ifn, args);
+ gimple_seq_add_stmt_without_update (&f.stmts, call);
+
+ if (!one_element_vector_type_p (ret_type))
+ {
+ auto ret = is_gimple_reg_type (ret_type) ? make_ssa_name (ret_type)
+ : create_tmp_var (ret_type);
+ gimple_call_set_lhs (call, ret);
+ return ret;
+ }
+ else
+ {
+ auto ret = create_tmp_var (TREE_TYPE (ret_type));
+ gimple_call_set_lhs (call, ret);
+ return build_vec_dup (ret_type, ret);
+ }
+}
+
+template <bool min_p>
+struct gimple_reduce_minmax : public gimple_function_base
+{
+ rtx expand (function_expander &e) const override
+ {
+ auto arg_mode = e.args[0]->mode;
+ auto unspec = min_p ? UNSPEC_FMINV : UNSPEC_FMAXV;
+ auto icode = code_for_reduc_scal (unspec, arg_mode);
+ gcc_assert (icode != CODE_FOR_nothing);
+ return e.use_exact_insn (icode);
+ }
+
+ gimple *fold (gimple_folder &f) const override
+ {
+ auto arg = gimple_call_arg (f.call, 0);
+ auto ret_type = TREE_TYPE (f.lhs);
+ if (FLOAT_TYPE_P (ret_type))
+ return nullptr;
+
+ auto_vec<tree> args{};
+ args.safe_push (arg);
+ auto ifn = min_p ? IFN_REDUC_MIN : IFN_REDUC_MAX;
+ return gimple_build_assign (f.lhs, build_ifn_call (f, ifn, ret_type,
args));
+ }
+};
+
// Reinterpret
NEON_FUNCTION (vreinterpret, vreinterpretq, gimple_reinterpret,)
@@ -1218,8 +1274,8 @@ NEON_FUNCTION (vminnm, vminnmq, gimple_ifn, (IFN_FMIN))
// Reductions
NEON_FUNCTION (vaddv, vaddvq, gimple_ifn, (IFN_REDUC_PLUS))
-NEON_FUNCTION (vmaxv, vmaxvq, gimple_ifn, (IFN_REDUC_MAX))
-NEON_FUNCTION (vminv, vminvq, gimple_ifn, (IFN_REDUC_MIN))
+NEON_FUNCTION (vmaxv, vmaxvq, gimple_reduce_minmax<false>,)
+NEON_FUNCTION (vminv, vminvq, gimple_reduce_minmax<true>,)
NEON_FUNCTION (vmaxnmv, vmaxnmvq, gimple_ifn, (IFN_REDUC_FMAX))
NEON_FUNCTION (vminnmv, vminnmvq, gimple_ifn, (IFN_REDUC_FMIN))
diff --git a/gcc/config/aarch64/aarch64-neon-builtins-base.def
b/gcc/config/aarch64/aarch64-neon-builtins-base.def
index e8edb2679b9..68a8e87be3c 100644
--- a/gcc/config/aarch64/aarch64-neon-builtins-base.def
+++ b/gcc/config/aarch64/aarch64-neon-builtins-base.def
@@ -211,8 +211,12 @@ DEF_NEON_FUNCTION (vaddv, s_float_bhs_integer,
("s0,D0"))
DEF_NEON_FUNCTION (vaddvq, sd_float_all_integer, ("s0,Q0"))
DEF_NEON_FUNCTION (vmaxv, bhs_integer, ("s0,D0"))
DEF_NEON_FUNCTION (vmaxvq, bhs_integer, ("s0,Q0"))
-DEF_NEON_FUNCTION (vminv, bhs_integer, ("s0,D0"))
-DEF_NEON_FUNCTION (vminvq, bhs_integer, ("s0,Q0"))
+DEF_NEON_FUNCTION (vmaxv, sd_float, ("s0,D0"))
+DEF_NEON_FUNCTION (vmaxvq, sd_float, ("s0,Q0"))
+DEF_NEON_FUNCTION (vminv, bhs_integer, ("s0,D0"))
+DEF_NEON_FUNCTION (vminvq, bhs_integer, ("s0,Q0"))
+DEF_NEON_FUNCTION (vminv, sd_float, ("s0,D0"))
+DEF_NEON_FUNCTION (vminvq, sd_float, ("s0,Q0"))
DEF_NEON_FUNCTION (vmaxnmv, s_float, ("s0,D0"))
DEF_NEON_FUNCTION (vmaxnmvq, sd_float, ("s0,Q0"))
DEF_NEON_FUNCTION (vminnmv, s_float, ("s0,D0"))
@@ -221,6 +225,10 @@ DEF_NEON_FUNCTION (vminnmvq, sd_float,
("s0,Q0"))
// Reductions (FP16)
#define REQUIRED_EXTENSIONS nonstreaming_only (AARCH64_FL_SIMD | AARCH64_FL_F16)
+DEF_NEON_FUNCTION (vmaxv, h_float, ("s0,D0"))
+DEF_NEON_FUNCTION (vmaxvq, h_float, ("s0,Q0"))
+DEF_NEON_FUNCTION (vminv, h_float, ("s0,D0"))
+DEF_NEON_FUNCTION (vminvq, h_float, ("s0,Q0"))
DEF_NEON_FUNCTION (vmaxnmv, h_float, ("s0,D0"))
DEF_NEON_FUNCTION (vmaxnmvq, h_float, ("s0,Q0"))
DEF_NEON_FUNCTION (vminnmv, h_float, ("s0,D0"))
diff --git a/gcc/config/aarch64/aarch64-simd-builtins.def
b/gcc/config/aarch64/aarch64-simd-builtins.def
index d1a19cebe97..03d97e2265e 100644
--- a/gcc/config/aarch64/aarch64-simd-builtins.def
+++ b/gcc/config/aarch64/aarch64-simd-builtins.def
@@ -495,14 +495,6 @@
BUILTIN_VALL (UNOP, reduc_plus_scal_, 10, DEFAULT)
BUILTIN_VDQ_I (UNOPU, reduc_plus_scal_, 10, DEFAULT)
- /* Implemented by reduc_<maxmin_uns>_scal_<mode> (producing scalar). */
- BUILTIN_VDQIF_F16 (UNOP, reduc_smax_scal_, 10, DEFAULT)
- BUILTIN_VDQIF_F16 (UNOP, reduc_smin_scal_, 10, DEFAULT)
- BUILTIN_VDQ_BHSI (UNOPU, reduc_umax_scal_, 10, DEFAULT)
- BUILTIN_VDQ_BHSI (UNOPU, reduc_umin_scal_, 10, DEFAULT)
- BUILTIN_VHSDF (UNOP, reduc_smax_nan_scal_, 10, DEFAULT)
- BUILTIN_VHSDF (UNOP, reduc_smin_nan_scal_, 10, DEFAULT)
-
/* Implemented by <fmaxmin><mode>3. */
VAR1 (BINOP, fmax, 3, FP, hf)
VAR1 (BINOP, fmin, 3, FP, hf)
diff --git a/gcc/config/aarch64/aarch64-simd.md
b/gcc/config/aarch64/aarch64-simd.md
index 7691fe2fdcd..7c8bc6985a1 100644
--- a/gcc/config/aarch64/aarch64-simd.md
+++ b/gcc/config/aarch64/aarch64-simd.md
@@ -2962,9 +2962,9 @@ (define_expand "aarch64_<su>mlsl_hi_laneq<mode>"
)
;; FP vector operations.
-;; AArch64 AdvSIMD supports single-precision (32-bit) and
+;; AArch64 AdvSIMD supports single-precision (32-bit) and
;; double-precision (64-bit) floating-point data types and arithmetic as
-;; defined by the IEEE 754-2008 standard. This makes them vectorizable
+;; defined by the IEEE 754-2008 standard. This makes them vectorizable
;; without the need for -ffast-math or -funsafe-math-optimizations.
;;
;; Floating-point operations can raise an exception. Vectorizing such
@@ -4231,7 +4231,7 @@ (define_expand "popcount<mode>2"
;; Template for outputting a scalar, so we can create __builtins which can be
;; gimple_fold'd to the IFN_REDUC_(MAX|MIN) function. (This is FP smax/smin).
-(define_expand "reduc_<optab>_scal_<mode>"
+(define_expand "@reduc_<optab>_scal_<mode>"
[(match_operand:<VEL> 0 "register_operand")
(unspec:<VEL> [(match_operand:VHSDF 1 "register_operand")]
FMAXMINV)]
diff --git a/gcc/config/aarch64/arm_neon.h b/gcc/config/aarch64/arm_neon.h
index a8d1c4f61da..204e2ac47db 100644
--- a/gcc/config/aarch64/arm_neon.h
+++ b/gcc/config/aarch64/arm_neon.h
@@ -10858,14 +10858,14 @@ __extension__ extern __inline float64_t
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
vpmaxqd_f64 (float64x2_t __a)
{
- return __builtin_aarch64_reduc_smax_nan_scal_v2df (__a);
+ return vmaxvq_f64 (__a);
}
__extension__ extern __inline float32_t
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
vpmaxs_f32 (float32x2_t __a)
{
- return __builtin_aarch64_reduc_smax_nan_scal_v2sf (__a);
+ return vmaxv_f32 (__a);
}
/* vpmaxnm */
@@ -10895,14 +10895,14 @@ __extension__ extern __inline float64_t
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
vpmaxnmqd_f64 (float64x2_t __a)
{
- return __builtin_aarch64_reduc_smax_scal_v2df (__a);
+ return vmaxnmvq_f64 (__a);
}
__extension__ extern __inline float32_t
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
vpmaxnms_f32 (float32x2_t __a)
{
- return __builtin_aarch64_reduc_smax_scal_v2sf (__a);
+ return vmaxnmv_f32 (__a);
}
/* vpmin */
@@ -11022,14 +11022,14 @@ __extension__ extern __inline float64_t
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
vpminqd_f64 (float64x2_t __a)
{
- return __builtin_aarch64_reduc_smin_nan_scal_v2df (__a);
+ return vminvq_f64 (__a);
}
__extension__ extern __inline float32_t
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
vpmins_f32 (float32x2_t __a)
{
- return __builtin_aarch64_reduc_smin_nan_scal_v2sf (__a);
+ return vminv_f32 (__a);
}
/* vpminnm */
@@ -11059,60 +11059,14 @@ __extension__ extern __inline float64_t
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
vpminnmqd_f64 (float64x2_t __a)
{
- return __builtin_aarch64_reduc_smin_scal_v2df (__a);
+ return vminnmvq_f64 (__a);
}
__extension__ extern __inline float32_t
__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
vpminnms_f32 (float32x2_t __a)
{
- return __builtin_aarch64_reduc_smin_scal_v2sf (__a);
-}
-
-/* vmaxv */
-
-__extension__ extern __inline float32_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vmaxv_f32 (float32x2_t __a)
-{
- return __builtin_aarch64_reduc_smax_nan_scal_v2sf (__a);
-}
-
-__extension__ extern __inline float32_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vmaxvq_f32 (float32x4_t __a)
-{
- return __builtin_aarch64_reduc_smax_nan_scal_v4sf (__a);
-}
-
-__extension__ extern __inline float64_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vmaxvq_f64 (float64x2_t __a)
-{
- return __builtin_aarch64_reduc_smax_nan_scal_v2df (__a);
-}
-
-/* vminv */
-
-__extension__ extern __inline float32_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vminv_f32 (float32x2_t __a)
-{
- return __builtin_aarch64_reduc_smin_nan_scal_v2sf (__a);
-}
-
-__extension__ extern __inline float32_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vminvq_f32 (float32x4_t __a)
-{
- return __builtin_aarch64_reduc_smin_nan_scal_v4sf (__a);
-}
-
-__extension__ extern __inline float64_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vminvq_f64 (float64x2_t __a)
-{
- return __builtin_aarch64_reduc_smin_nan_scal_v2df (__a);
+ return vminnmv_f32 (__a);
}
/* vmla */
@@ -17430,36 +17384,6 @@ vmulxq_n_f16 (float16x8_t __a, float16_t __b)
return vmulxq_f16 (__a, vdupq_n_f16 (__b));
}
-/* ARMv8.2-A FP16 reduction vector intrinsics. */
-
-__extension__ extern __inline float16_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vmaxv_f16 (float16x4_t __a)
-{
- return __builtin_aarch64_reduc_smax_nan_scal_v4hf (__a);
-}
-
-__extension__ extern __inline float16_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vmaxvq_f16 (float16x8_t __a)
-{
- return __builtin_aarch64_reduc_smax_nan_scal_v8hf (__a);
-}
-
-__extension__ extern __inline float16_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vminv_f16 (float16x4_t __a)
-{
- return __builtin_aarch64_reduc_smin_nan_scal_v4hf (__a);
-}
-
-__extension__ extern __inline float16_t
-__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
-vminvq_f16 (float16x8_t __a)
-{
- return __builtin_aarch64_reduc_smin_nan_scal_v8hf (__a);
-}
-
#pragma GCC pop_options
/* AdvSIMD Dot Product intrinsics. */
--
2.56.0