> On 13 Nov 2026, at 15:50, Karl Meakin <[email protected]> wrote:
>
> The floating point variants of `vmin` and `vmax` were not ported to the
> pragma-based framework when the integer variants were, because the
> semantics AArch64's `fmin`/`fmax` instructions don't match the semantics
> of GCC's `MIN_EXPR`/`MAX_EXPR`. This commit ports them to the pragma
> framework, by expanding them to `UNSPEC_FMIN` and `UNSPEC_FMAX`.
>
> There are no test changes, as tests for FP variants of vmin/vmax were
> already included in vmin.c and vmax.c. The absence of any changes to the
> tests does show that there were no changes in codegen (ie no
> regressions).
>
> Also delete the `__builtin_aarch64_{u,s}{min,max}` functions which were
> mistakenly left behind when the integer min/max intrinsics were ported.
>
Ok.
Thanks,
Kyrill
> gcc/ChangeLog:
>
> * config/aarch64/aarch64-neon-builtins-base.cc (struct
> gimple_minmax): New struct.
> * config/aarch64/aarch64-neon-builtins-base.def (vmax, vmaxq,
> vmin, vminq): New intrinsic function definitions.
> * config/aarch64/aarch64-simd-builtins.def (smax, smin, umax,
> umin, fmax, fmin): Delete now-unused builtin function declarations.
> (fmax_nan, fmin_nan): Only define for float16_t, as they are
> only now called from `arm_fp16.h`.
> * config/aarch64/arm_fp16.h (vmaxh_f16, vminh_f16): Call the
> correct `_nan` variant of the `__aarch64_builtin` functions.
> (vmaxnmh_f16, vminnmh_f16): Use the platform-agnostic
> `__builtin_f{min,max}f16` functions rather than the now-deleted
> aarch64-specific builtins.
> * config/aarch64/arm_neon.h (vmax_f32, vmax_f64, vmaxq_f32,
> vmaxq_f64, vmin_f32, vmin_f64, vminq_f32, vminq_f64, vmax_f16,
> vmaxq_f16, vmin_f16, vminq_f16): Delete intrinsic function
> definitions.
> ---
> .../aarch64/aarch64-neon-builtins-base.cc | 40 +++++++-
> .../aarch64/aarch64-neon-builtins-base.def | 8 ++
> gcc/config/aarch64/aarch64-simd-builtins.def | 14 +--
> gcc/config/aarch64/arm_fp16.h | 4 +-
> gcc/config/aarch64/arm_neon.h | 92 -------------------
> 5 files changed, 52 insertions(+), 106 deletions(-)
>
> diff --git a/gcc/config/aarch64/aarch64-neon-builtins-base.cc
> b/gcc/config/aarch64/aarch64-neon-builtins-base.cc
> index 4b66a93d0f0..8c3bcc6eb74 100644
> --- a/gcc/config/aarch64/aarch64-neon-builtins-base.cc
> +++ b/gcc/config/aarch64/aarch64-neon-builtins-base.cc
> @@ -1140,6 +1140,42 @@ public:
> }
> };
>
> +template <bool min_p>
> +struct gimple_minmax : public gimple_function_base
> +{
> + rtx expand (function_expander &e) const override
> + {
> + auto ret_mode = e.result_mode ();
> + auto singleton_p = (ret_mode == V1DFmode);
> + auto unspec = min_p ? UNSPEC_FMIN : UNSPEC_FMAX;
> +
> + if (singleton_p)
> + {
> + for (int i = 0; i < 2; i++)
> + e.args[i] = simplify_gen_subreg (DFmode, e.args[i], V1DFmode, 0);
> + ret_mode = DFmode;
> + }
> +
> + auto ret = gen_reg_rtx (ret_mode);
> + auto args = gen_rtvec_v (e.args.length (), e.args.address ());
> + emit_insn (gen_rtx_SET (ret, gen_rtx_UNSPEC (ret_mode, args, unspec)));
> +
> + if (singleton_p)
> + ret = simplify_gen_subreg (V1DFmode, ret, DFmode, 0);
> +
> + return ret;
> + }
> +
> + gimple *fold (gimple_folder &f) const override {
> + auto lhs = gimple_call_arg (f.call, 0);
> + auto rhs = gimple_call_arg (f.call, 1);
> + auto ret_type = TREE_TYPE (f.lhs);
> + if (FLOAT_TYPE_P (ret_type))
> + return nullptr;
> + return gimple_build_assign (f.lhs, min_p ? MIN_EXPR : MAX_EXPR, lhs,
> rhs);
> + }
> +};
> +
> // Reinterpret
> NEON_FUNCTION (vreinterpret, vreinterpretq, gimple_reinterpret,)
>
> @@ -1175,8 +1211,8 @@ NEON_FUNCTION (vqaddb, vqaddh, vqadds, vqaddd, vqadd,
> vqaddq, gimple_ifn, (IFN_S
> NEON_FUNCTION (vqsubb, vqsubh, vqsubs, vqsubd, vqsub, vqsubq, gimple_ifn,
> (IFN_SAT_SUB))
>
> // Max/min
> -NEON_FUNCTION (vmax, vmaxq, gimple_expr, (MAX_EXPR))
> -NEON_FUNCTION (vmin, vminq, gimple_expr, (MIN_EXPR))
> +NEON_FUNCTION (vmax, vmaxq, gimple_minmax<false>,)
> +NEON_FUNCTION (vmin, vminq, gimple_minmax<true>,)
> NEON_FUNCTION (vmaxnm, vmaxnmq, gimple_ifn, (IFN_FMAX))
> NEON_FUNCTION (vminnm, vminnmq, gimple_ifn, (IFN_FMIN))
>
> diff --git a/gcc/config/aarch64/aarch64-neon-builtins-base.def
> b/gcc/config/aarch64/aarch64-neon-builtins-base.def
> index db9defc454c..e8edb2679b9 100644
> --- a/gcc/config/aarch64/aarch64-neon-builtins-base.def
> +++ b/gcc/config/aarch64/aarch64-neon-builtins-base.def
> @@ -180,9 +180,13 @@ DEF_NEON_FUNCTION (vqsubq, all_integer, ("Q0,Q0,Q0"))
> // Max/min
> #define REQUIRED_EXTENSIONS nonstreaming_only (AARCH64_FL_SIMD)
> DEF_NEON_FUNCTION (vmax, bhs_integer, ("D0,D0,D0"))
> +DEF_NEON_FUNCTION (vmax, sd_float, ("D0,D0,D0"))
> DEF_NEON_FUNCTION (vmaxq, bhs_integer, ("Q0,Q0,Q0"))
> +DEF_NEON_FUNCTION (vmaxq, sd_float, ("Q0,Q0,Q0"))
> DEF_NEON_FUNCTION (vmin, bhs_integer, ("D0,D0,D0"))
> +DEF_NEON_FUNCTION (vmin, sd_float, ("D0,D0,D0"))
> DEF_NEON_FUNCTION (vminq, bhs_integer, ("Q0,Q0,Q0"))
> +DEF_NEON_FUNCTION (vminq, sd_float, ("Q0,Q0,Q0"))
> DEF_NEON_FUNCTION (vmaxnm, sd_float, ("D0,D0,D0"))
> DEF_NEON_FUNCTION (vmaxnmq, sd_float, ("Q0,Q0,Q0"))
> DEF_NEON_FUNCTION (vminnm, sd_float, ("D0,D0,D0"))
> @@ -191,6 +195,10 @@ DEF_NEON_FUNCTION (vminnmq, sd_float, ("Q0,Q0,Q0"))
>
> // Max/min (FP16)
> #define REQUIRED_EXTENSIONS nonstreaming_only (AARCH64_FL_SIMD |
> AARCH64_FL_F16)
> +DEF_NEON_FUNCTION (vmax, h_float, ("D0,D0,D0"))
> +DEF_NEON_FUNCTION (vmaxq, h_float, ("Q0,Q0,Q0"))
> +DEF_NEON_FUNCTION (vmin, h_float, ("D0,D0,D0"))
> +DEF_NEON_FUNCTION (vminq, h_float, ("Q0,Q0,Q0"))
> DEF_NEON_FUNCTION (vmaxnm, h_float, ("D0,D0,D0"))
> DEF_NEON_FUNCTION (vmaxnmq, h_float, ("Q0,Q0,Q0"))
> DEF_NEON_FUNCTION (vminnm, h_float, ("D0,D0,D0"))
> diff --git a/gcc/config/aarch64/aarch64-simd-builtins.def
> b/gcc/config/aarch64/aarch64-simd-builtins.def
> index 0a84dfd459d..d1a19cebe97 100644
> --- a/gcc/config/aarch64/aarch64-simd-builtins.def
> +++ b/gcc/config/aarch64/aarch64-simd-builtins.def
> @@ -503,17 +503,11 @@
> BUILTIN_VHSDF (UNOP, reduc_smax_nan_scal_, 10, DEFAULT)
> BUILTIN_VHSDF (UNOP, reduc_smin_nan_scal_, 10, DEFAULT)
>
> - /* Implemented by <optab><mode>3. */
> - BUILTIN_VDQ_BHSI (BINOP, smax, 3, DEFAULT)
> - BUILTIN_VDQ_BHSI (BINOP, smin, 3, DEFAULT)
> - BUILTIN_VDQ_BHSI (BINOP, umax, 3, DEFAULT)
> - BUILTIN_VDQ_BHSI (BINOP, umin, 3, DEFAULT)
> -
> /* Implemented by <fmaxmin><mode>3. */
> - BUILTIN_VHSDF_HSDF (BINOP, fmax, 3, FP)
> - BUILTIN_VHSDF_HSDF (BINOP, fmin, 3, FP)
> - BUILTIN_VHSDF_DF (BINOP, fmax_nan, 3, FP)
> - BUILTIN_VHSDF_DF (BINOP, fmin_nan, 3, FP)
> + VAR1 (BINOP, fmax, 3, FP, hf)
> + VAR1 (BINOP, fmin, 3, FP, hf)
> + VAR1 (BINOP, fmax_nan, 3, FP, hf)
> + VAR1 (BINOP, fmin_nan, 3, FP, hf)
>
> /* Implemented by aarch64_<optab>p<mode>. */
> BUILTIN_VDQ_BHSI (BINOP, smaxp, 0, DEFAULT)
> diff --git a/gcc/config/aarch64/arm_fp16.h b/gcc/config/aarch64/arm_fp16.h
> index d932d8ab1c9..d353eea65ab 100644
> --- a/gcc/config/aarch64/arm_fp16.h
> +++ b/gcc/config/aarch64/arm_fp16.h
> @@ -588,7 +588,7 @@ __extension__ extern __inline float16_t
> __attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
> vmaxh_f16 (float16_t __a, float16_t __b)
> {
> - return __builtin_aarch64_fmaxhf (__a, __b);
> + return __builtin_aarch64_fmax_nanhf (__a, __b);
> }
>
> __extension__ extern __inline float16_t
> @@ -602,7 +602,7 @@ __extension__ extern __inline float16_t
> __attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
> vminh_f16 (float16_t __a, float16_t __b)
> {
> - return __builtin_aarch64_fminhf (__a, __b);
> + return __builtin_aarch64_fmin_nanhf (__a, __b);
> }
>
> __extension__ extern __inline float16_t
> diff --git a/gcc/config/aarch64/arm_neon.h b/gcc/config/aarch64/arm_neon.h
> index a0dca5e8da9..a8d1c4f61da 100644
> --- a/gcc/config/aarch64/arm_neon.h
> +++ b/gcc/config/aarch64/arm_neon.h
> @@ -10613,38 +10613,6 @@ vld4q_lane_p64 (const poly64_t * __ptr, poly64x2x4_t
> __b, const int __c)
> (__builtin_aarch64_simd_di *) __ptr, __b, __c);
> }
>
> -/* vmax */
> -
> -__extension__ extern __inline float32x2_t
> -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
> -vmax_f32 (float32x2_t __a, float32x2_t __b)
> -{
> - return __builtin_aarch64_fmax_nanv2sf (__a, __b);
> -}
> -
> -__extension__ extern __inline float64x1_t
> -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
> -vmax_f64 (float64x1_t __a, float64x1_t __b)
> -{
> - return (float64x1_t)
> - { __builtin_aarch64_fmax_nandf (vget_lane_f64 (__a, 0),
> - vget_lane_f64 (__b, 0)) };
> -}
> -
> -__extension__ extern __inline float32x4_t
> -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
> -vmaxq_f32 (float32x4_t __a, float32x4_t __b)
> -{
> - return __builtin_aarch64_fmax_nanv4sf (__a, __b);
> -}
> -
> -__extension__ extern __inline float64x2_t
> -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
> -vmaxq_f64 (float64x2_t __a, float64x2_t __b)
> -{
> - return __builtin_aarch64_fmax_nanv2df (__a, __b);
> -}
> -
> /* vmulx */
>
> __extension__ extern __inline float32x2_t
> @@ -11124,38 +11092,6 @@ vmaxvq_f64 (float64x2_t __a)
> return __builtin_aarch64_reduc_smax_nan_scal_v2df (__a);
> }
>
> -/* vmin */
> -
> -__extension__ extern __inline float32x2_t
> -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
> -vmin_f32 (float32x2_t __a, float32x2_t __b)
> -{
> - return __builtin_aarch64_fmin_nanv2sf (__a, __b);
> -}
> -
> -__extension__ extern __inline float64x1_t
> -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
> -vmin_f64 (float64x1_t __a, float64x1_t __b)
> -{
> - return (float64x1_t)
> - { __builtin_aarch64_fmin_nandf (vget_lane_f64 (__a, 0),
> - vget_lane_f64 (__b, 0)) };
> -}
> -
> -__extension__ extern __inline float32x4_t
> -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
> -vminq_f32 (float32x4_t __a, float32x4_t __b)
> -{
> - return __builtin_aarch64_fmin_nanv4sf (__a, __b);
> -}
> -
> -__extension__ extern __inline float64x2_t
> -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
> -vminq_f64 (float64x2_t __a, float64x2_t __b)
> -{
> - return __builtin_aarch64_fmin_nanv2df (__a, __b);
> -}
> -
> /* vminv */
>
> __extension__ extern __inline float32_t
> @@ -17170,34 +17106,6 @@ vcvtq_n_u16_f16 (float16x8_t __a, const int __b)
> return __builtin_aarch64_fcvtzuv8hf_uss (__a, __b);
> }
>
> -__extension__ extern __inline float16x4_t
> -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
> -vmax_f16 (float16x4_t __a, float16x4_t __b)
> -{
> - return __builtin_aarch64_fmax_nanv4hf (__a, __b);
> -}
> -
> -__extension__ extern __inline float16x8_t
> -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
> -vmaxq_f16 (float16x8_t __a, float16x8_t __b)
> -{
> - return __builtin_aarch64_fmax_nanv8hf (__a, __b);
> -}
> -
> -__extension__ extern __inline float16x4_t
> -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
> -vmin_f16 (float16x4_t __a, float16x4_t __b)
> -{
> - return __builtin_aarch64_fmin_nanv4hf (__a, __b);
> -}
> -
> -__extension__ extern __inline float16x8_t
> -__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
> -vminq_f16 (float16x8_t __a, float16x8_t __b)
> -{
> - return __builtin_aarch64_fmin_nanv8hf (__a, __b);
> -}
> -
> __extension__ extern __inline float16x4_t
> __attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
> vmulx_f16 (float16x4_t __a, float16x4_t __b)
> --
> 2.56.0
>