On 13/11/2026 14:59, Kyrylo Tkachov wrote:

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)
I think this function can be static.
Ok with that change.
Thanks,
Kyrill

+{
+  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

Thanks, merged

Reply via email to