Hi everyone,

as promised in
https://gcc.gnu.org/pipermail/gcc/2025-October/246854.html I would like
to add _Float16 support to s390.  I went for
targetm.c.excess_precision(EXCESS_PRECISION_TYPE_FLOAT16) to return
FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16 in order to stay for as long as
possible in _Float16.  Any feedback is very welcome.  If there are no
further comments I will commit this by the coming week.

Cheers,
Stefan

-- 8< --

This patch adds support for _Float16.  As time of writing this, there is
no hardware _Float16 support on s390.  Therefore, _Float16 operations
have to be extended and truncated which is supported via soft-fp.

The ABI demands that _Float16 values are left aligned in FP registers
similar as it is already the case for 32-bit FP values.  If vector
extensions are available, copying between left-aligned FPRs and
right-aligned GPRs is natively supported.  Without vector extensions,
the alignment has to be taken care of manually.  For target z10,
instructions lgdr/ldgr can be used in conjunction with shifts.  Copying
via lgdr from an FPR into a GPR is the easy case since for the shift the
target GPR can be utilized.  However, copying via ldgr from a GPR into a
FPR requires a secondary reload register which is used for the shift
result and is then copied into the FPR.  Prior z10, there is no hardware
support in order to copy directly between FPRs and GPRs.  Therefore, in
order to copy from a GPR into an FPR we would require a secondary reload
register for the shift and secondary memory for copying the aligned
value.  Since this is not supported, _Float16 support starts with z10.
As a consequence, for all targets older than z10 test
libstdc++-abi/abi_check fails.

gcc/ChangeLog:

        * config/s390/s390-modes.def (FLOAT_MODE): Add HF mode.
        * config/s390/s390.cc (s390_scalar_mode_supported_p): For 64-bit
        targets z10 and newer support HF mode.
        (s390_register_move_cost): Keep HF mode operands in registers.
        (s390_legitimate_constant_p): Support zero constant.
        (s390_secondary_reload): For GPR to FPR moves a secondary reload
        register is required.
        (s390_secondary_memory_needed): GPR<->FPR moves don't require
        secondary memory.
        (s390_libgcc_floating_mode_supported_p): For 64-bit targets z10
        and newer support HF mode.
        (s390_hard_regno_mode_ok): Allow HF mode for FPRs and VRs.
        (s390_function_arg_float): Consider HF mode, too.
        (s390_excess_precision): For EXCESS_PRECISION_TYPE_FLOAT16
        return FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16.
        (TARGET_LIBGCC_FLOATING_MODE_SUPPORTED_P): Define.
        * config/s390/s390.md (movhf): Define.
        (reload_half_gprtofpr_z10): Define.
        (signbithf2): Define.

libgcc/ChangeLog:

        * config.host: Include s390/t-float16.
        * config/s390/libgcc-glibc.ver: Export symbols
        __trunc{sf,df,tf}hf2, __extendhf{sf,df,tf}2, __fix{,uns}hfti,
        __float{,un}tihf.
        * config/s390/t-softfp: Add to softfp_extras instead of setting
        it.
        * configure: Regenerate.
        * configure.ac: Support float16 only for 64-bit targets z10 and
        newer.
        * config/s390/_dpd_dd_to_hf.c: New file.
        * config/s390/_dpd_hf_to_dd.c: New file.
        * config/s390/_dpd_hf_to_sd.c: New file.
        * config/s390/_dpd_hf_to_td.c: New file.
        * config/s390/_dpd_sd_to_hf.c: New file.
        * config/s390/_dpd_td_to_hf.c: New file.
        * config/s390/t-float16: New file.

libstdc++-v3/ChangeLog:

        * config/abi/post/s390x-linux-gnu/baseline_symbols.txt: Add
        names {,P,K}DF16.

gcc/testsuite/ChangeLog:

        * g++.target/s390/float16-1.C: New test.
        * g++.target/s390/float16-2.C: New test.
        * gcc.target/s390/float16-1-2.h: New test.
        * gcc.target/s390/float16-1.c: New test.
        * gcc.target/s390/float16-10.c: New test.
        * gcc.target/s390/float16-2.c: New test.
        * gcc.target/s390/float16-3.c: New test.
        * gcc.target/s390/float16-4.c: New test.
        * gcc.target/s390/float16-5.c: New test.
        * gcc.target/s390/float16-6.c: New test.
        * gcc.target/s390/float16-7.c: New test.
        * gcc.target/s390/float16-8.c: New test.
        * gcc.target/s390/float16-9.c: New test.
        * gcc.target/s390/float16-signbit.h: New test.
---
 gcc/config/s390/s390-modes.def                |   2 +
 gcc/config/s390/s390.cc                       |  81 +++++++-
 gcc/config/s390/s390.md                       | 126 ++++++++++--
 gcc/testsuite/g++.target/s390/float16-1.C     |   9 +
 gcc/testsuite/g++.target/s390/float16-2.C     |  11 +
 gcc/testsuite/gcc.target/s390/float16-1-2.h   |  36 ++++
 gcc/testsuite/gcc.target/s390/float16-1.c     |  42 ++++
 gcc/testsuite/gcc.target/s390/float16-10.c    |  30 +++
 gcc/testsuite/gcc.target/s390/float16-2.c     |  36 ++++
 gcc/testsuite/gcc.target/s390/float16-3.c     |  68 ++++++
 gcc/testsuite/gcc.target/s390/float16-4.c     | 104 ++++++++++
 gcc/testsuite/gcc.target/s390/float16-5.c     | 105 ++++++++++
 gcc/testsuite/gcc.target/s390/float16-6.c     |  71 +++++++
 gcc/testsuite/gcc.target/s390/float16-7.c     | 194 ++++++++++++++++++
 gcc/testsuite/gcc.target/s390/float16-8.c     |  22 ++
 gcc/testsuite/gcc.target/s390/float16-9.c     |  20 ++
 .../gcc.target/s390/float16-signbit.h         |  56 +++++
 libgcc/config.host                            |   3 +
 libgcc/config/s390/_dpd_dd_to_hf.c            |  39 ++++
 libgcc/config/s390/_dpd_hf_to_dd.c            |  39 ++++
 libgcc/config/s390/_dpd_hf_to_sd.c            |  39 ++++
 libgcc/config/s390/_dpd_hf_to_td.c            |  39 ++++
 libgcc/config/s390/_dpd_sd_to_hf.c            |  39 ++++
 libgcc/config/s390/_dpd_td_to_hf.c            |  39 ++++
 libgcc/config/s390/libgcc-glibc.ver           |  10 +
 libgcc/config/s390/t-float16                  |  11 +
 libgcc/config/s390/t-softfp                   |   2 +-
 libgcc/configure                              |  26 +++
 libgcc/configure.ac                           |  14 ++
 .../post/s390x-linux-gnu/baseline_symbols.txt |   3 +
 30 files changed, 1291 insertions(+), 25 deletions(-)
 create mode 100644 gcc/testsuite/g++.target/s390/float16-1.C
 create mode 100644 gcc/testsuite/g++.target/s390/float16-2.C
 create mode 100644 gcc/testsuite/gcc.target/s390/float16-1-2.h
 create mode 100644 gcc/testsuite/gcc.target/s390/float16-1.c
 create mode 100644 gcc/testsuite/gcc.target/s390/float16-10.c
 create mode 100644 gcc/testsuite/gcc.target/s390/float16-2.c
 create mode 100644 gcc/testsuite/gcc.target/s390/float16-3.c
 create mode 100644 gcc/testsuite/gcc.target/s390/float16-4.c
 create mode 100644 gcc/testsuite/gcc.target/s390/float16-5.c
 create mode 100644 gcc/testsuite/gcc.target/s390/float16-6.c
 create mode 100644 gcc/testsuite/gcc.target/s390/float16-7.c
 create mode 100644 gcc/testsuite/gcc.target/s390/float16-8.c
 create mode 100644 gcc/testsuite/gcc.target/s390/float16-9.c
 create mode 100644 gcc/testsuite/gcc.target/s390/float16-signbit.h
 create mode 100644 libgcc/config/s390/_dpd_dd_to_hf.c
 create mode 100644 libgcc/config/s390/_dpd_hf_to_dd.c
 create mode 100644 libgcc/config/s390/_dpd_hf_to_sd.c
 create mode 100644 libgcc/config/s390/_dpd_hf_to_td.c
 create mode 100644 libgcc/config/s390/_dpd_sd_to_hf.c
 create mode 100644 libgcc/config/s390/_dpd_td_to_hf.c
 create mode 100644 libgcc/config/s390/t-float16

diff --git a/gcc/config/s390/s390-modes.def b/gcc/config/s390/s390-modes.def
index e135d66fffb..d43f20afa72 100644
--- a/gcc/config/s390/s390-modes.def
+++ b/gcc/config/s390/s390-modes.def
@@ -28,6 +28,8 @@ FLOAT_MODE (TF, 16, ieee_quad_format);
 /* 128-bit float stored in a FPR pair.  */
 FLOAT_MODE (FPRX2, 16, ieee_quad_format);
 
+FLOAT_MODE (HF, 2, ieee_half_format);
+
 /* Add any extra modes needed to represent the condition code.  */
 
 /*
diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc
index d65109026f2..b077f9f2f10 100644
--- a/gcc/config/s390/s390.cc
+++ b/gcc/config/s390/s390.cc
@@ -1384,6 +1384,9 @@ s390_scalar_mode_supported_p (scalar_mode mode)
   if (DECIMAL_FLOAT_MODE_P (mode))
     return default_decimal_float_supported_p ();
 
+  if (TARGET_64BIT && TARGET_Z10 && mode == HFmode)
+    return true;
+
   return default_scalar_mode_supported_p (mode);
 }
 
@@ -3876,8 +3879,12 @@ s390_register_move_cost (machine_mode mode,
     }
 
   /* Without vector extensions it still becomes somewhat faster having
-     ldgr/lgdr.  */
-  if (TARGET_Z10 && GET_MODE_SIZE (mode) == 8)
+     ldgr/lgdr.
+
+     Although, a GPR<->FPR load for 16-bit values involves a shift, use lower
+     costs since otherwise unnecessarily many reloads via memory are emitted.
+     Limit this quirk to HF mode only.  */
+  if (TARGET_Z10 && (GET_MODE_SIZE (mode) == 8 || mode == HFmode))
     {
       /* ldgr is single cycle. */
       if (reg_classes_intersect_p (from, GENERAL_REGS)
@@ -4498,6 +4505,9 @@ s390_legitimate_constant_p (machine_mode mode, rtx op)
        return 0;
     }
 
+  if (mode == HFmode)
+    return satisfies_constraint_j00 (op);
+
   /* Accept all non-symbolic constants.  */
   if (!SYMBOLIC_CONST (op))
     return 1;
@@ -4912,6 +4922,22 @@ s390_secondary_reload (bool in_p, rtx x, reg_class_t 
rclass_i,
   if (reg_classes_intersect_p (CC_REGS, rclass))
     return GENERAL_REGS;
 
+  /* A 2-byte GPR-to-FPR move requires a scratch register if no vector
+     extensions are available but instruction ldgr.  */
+  if (TARGET_Z10 && !TARGET_VX && GET_MODE_SIZE (mode) == 2
+      && ((in_p && true_regnum (x) >= 0
+          && reg_classes_intersect_p (rclass, FP_REGS))
+         || (!in_p && FP_REGNO_P (true_regnum (x))
+             && reg_classes_intersect_p (rclass, GENERAL_REGS))))
+    {
+      sri->icode = CODE_FOR_reload_half_gprtofpr_z10;
+      return NO_REGS;
+    }
+
+  if (TARGET_Z10 && !TARGET_VX && GET_MODE_SIZE (mode) == 2
+      && MEM_P (x) && reg_classes_intersect_p (rclass, FP_REGS))
+    return GENERAL_REGS;
+
   if (TARGET_VX)
     {
       /* The vst/vl vector move instructions allow only for short
@@ -4978,6 +5004,7 @@ s390_secondary_reload (bool in_p, rtx x, reg_class_t 
rclass_i,
              __SECONDARY_RELOAD_CASE (SI, si);
              __SECONDARY_RELOAD_CASE (DI, di);
              __SECONDARY_RELOAD_CASE (TI, ti);
+             __SECONDARY_RELOAD_CASE (HF, hf);
              __SECONDARY_RELOAD_CASE (SF, sf);
              __SECONDARY_RELOAD_CASE (DF, df);
              __SECONDARY_RELOAD_CASE (TF, tf);
@@ -5084,6 +5111,16 @@ static bool
 s390_secondary_memory_needed (machine_mode mode,
                              reg_class_t class1, reg_class_t class2)
 {
+  /* A 2-byte GPR<->FPR move is implemented for 64-bit targets and z10 which is
+     realized via ldgr/lgdr in conjunction with shifts in order satisfy
+     alignment requirements, or via vector loads.  Thus, there is no secondary
+     memory needed.  */
+  if (TARGET_64BIT && TARGET_Z10 && GET_MODE_SIZE (mode) == 2
+      && ((reg_classes_intersect_p (class1, VEC_REGS)
+          && reg_classes_intersect_p (class2, GENERAL_REGS))
+         || (reg_classes_intersect_p (class2, VEC_REGS)
+             && reg_classes_intersect_p (class1, GENERAL_REGS))))
+    return false;
   return (((reg_classes_intersect_p (class1, VEC_REGS)
            && reg_classes_intersect_p (class2, GENERAL_REGS))
           || (reg_classes_intersect_p (class1, GENERAL_REGS)
@@ -8440,6 +8477,13 @@ s390_mangle_type (const_tree type)
 }
 #endif
 
+static bool
+s390_libgcc_floating_mode_supported_p (scalar_float_mode mode)
+{
+  return (TARGET_64BIT && TARGET_Z10 && mode == HFmode)
+        || default_libgcc_floating_mode_supported_p (mode);
+}
+
 /* In the name of slightly smaller debug output, and to cater to
    general assembler lossage, recognize various UNSPEC sequences
    and turn them back into a direct symbol reference.  */
@@ -9691,7 +9735,7 @@ static machine_mode constant_modes[] =
   V8QImode, V4HImode, V2SImode, V1DImode, V2SFmode, V1DFmode,
   SFmode, SImode, SDmode,
   V4QImode, V2HImode, V1SImode,  V1SFmode,
-  HImode,
+  HImode, HFmode,
   V2QImode, V1HImode,
   QImode,
   V1QImode
@@ -11396,6 +11440,7 @@ s390_hard_regno_mode_ok (unsigned int regno, 
machine_mode mode)
               && s390_class_max_nregs (VEC_REGS, mode) == 1)
              || mode == DFmode
              || (TARGET_VXE && mode == SFmode)
+             || mode == HFmode
              || s390_vector_mode_supported_p (mode));
       break;
     case FP_REGS:
@@ -13297,7 +13342,8 @@ s390_function_arg_float (machine_mode mode, const_tree 
type)
 
   /* No type info available for some library calls ...  */
   if (!type)
-    return mode == SFmode || mode == DFmode || mode == SDmode || mode == 
DDmode;
+    return mode == HFmode || mode == SFmode || mode == DFmode
+          || mode == SDmode || mode == DDmode;
 
   if (!s390_single_field_struct_p (REAL_TYPE, type, false))
     return false;
@@ -17680,13 +17726,28 @@ s390_excess_precision (enum excess_precision_type 
type)
           float is evaluated to the range and precision of double.  */
        return FLT_EVAL_METHOD_PROMOTE_TO_DOUBLE;
       case EXCESS_PRECISION_TYPE_FLOAT16:
-       error ("%<-fexcess-precision=16%> is not supported on this target");
-       break;
+       return FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16;
       default:
        gcc_unreachable ();
     }
   return FLT_EVAL_METHOD_UNPREDICTABLE;
 }
+#else
+static enum flt_eval_method
+s390_excess_precision (enum excess_precision_type type)
+{
+  /* As time of writing this, there is no hardware support for _Float16 on
+     s390.  Therefore, operations have to be extended and truncated.  In case
+     of EXCESS_PRECISION_TYPE_FLOAT16, this can happen on tree or rtl level.
+     The former might lead to cases were _Float16 operations cannot be folded
+     anymore by tree passes as e.g. FRE due to extends/truncates.  Therefore,
+     return FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16 in this case in order to stay in
+     _Float16 for as long as possible.  */
+  if (type == EXCESS_PRECISION_TYPE_FLOAT16)
+    return FLT_EVAL_METHOD_PROMOTE_TO_FLOAT16;
+
+  return default_excess_precision (type);
+}
 #endif
 
 void
@@ -18845,12 +18906,8 @@ s390_bitint_type_info (int n, struct bitint_info *info)
 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK 
hook_bool_const_tree_hwi_hwi_const_tree_true
 
-#if ENABLE_S390_EXCESS_FLOAT_PRECISION == 1
-/* This hook is only needed to maintain the historic behavior with glibc
-   versions that typedef float_t to double. */
 #undef TARGET_C_EXCESS_PRECISION
 #define TARGET_C_EXCESS_PRECISION s390_excess_precision
-#endif
 
 #undef  TARGET_SCHED_ADJUST_PRIORITY
 #define TARGET_SCHED_ADJUST_PRIORITY s390_adjust_priority
@@ -19109,6 +19166,10 @@ s390_bitint_type_info (int n, struct bitint_info *info)
 #undef TARGET_C_BITINT_TYPE_INFO
 #define TARGET_C_BITINT_TYPE_INFO s390_bitint_type_info
 
+#undef TARGET_LIBGCC_FLOATING_MODE_SUPPORTED_P
+#define TARGET_LIBGCC_FLOATING_MODE_SUPPORTED_P        \
+  s390_libgcc_floating_mode_supported_p
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-s390.h"
diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index 06876a5563a..9b1232bee47 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -121,6 +121,7 @@
 
    ; Test Data Class (TDC)
    UNSPEC_TDC_INSN
+   UNSPEC_TDC_SIGNBIT_HF
    UNSPEC_SIGNBIT
 
    ; Byte-wise Population Count
@@ -254,6 +255,8 @@
 
    UNSPEC_FMAX
    UNSPEC_FMIN
+
+   UNSPEC_HALF_GPRTOFPR
 ])
 
 ;;
@@ -532,7 +535,7 @@
 (define_attr "type" "none,integer,load,lr,la,larl,lm,stm,
                     cs,vs,store,sem,idiv,
                      imulhi,imulsi,imuldi,
-                    branch,jsr,fsimptf,fsimpdf,fsimpsf,fhex,
+                    branch,jsr,fsimptf,fsimpdf,fsimpsf,fsimphf,fhex,
                     floadtf,floaddf,floadsf,fstoredf,fstoresf,
                     fmultf,fmuldf,fmulsf,fdivtf,fdivdf,fdivsf,
                     ftoi,fsqrttf,fsqrtdf,fsqrtsf,
@@ -743,7 +746,7 @@
 
 ;; Iterators
 
-(define_mode_iterator ALL [TI DI SI HI QI TF FPRX2 DF SF TD DD SD V1QI V2QI
+(define_mode_iterator ALL [TI DI SI HI QI TF FPRX2 DF SF HF TD DD SD V1QI V2QI
                           V4QI V8QI V16QI V1HI V2HI V4HI V8HI V1SI V2SI V4SI
                           V1DI V2DI V1SF V2SF V4SF V1TI V1DF V2DF V1TF])
 
@@ -877,7 +880,7 @@
 ;; sign bit instructions only handle single source and target fp registers
 ;; these instructions can only be used for TFmode values if the source and
 ;; target operand uses the same fp register.
-(define_mode_attr fT0 [(TF "0") (FPRX2 "0") (DF "f") (SF "f")])
+(define_mode_attr fT0 [(TF "0") (FPRX2 "0") (DF "f") (SF "f") (HF "f")])
 
 ;; This attribute adds b for bfp instructions and t for dfp instructions and 
is used
 ;; within instruction mnemonics.
@@ -981,12 +984,12 @@
 (define_code_iterator ANY_RETURN [return simple_return])
 
 ;; Facilitate dispatching TFmode expanders on z14+.
-(define_mode_attr tf_fpr [(TF "_fpr") (FPRX2 "") (DF "") (SF "") (TD "")
-                         (DD "") (SD "")])
+(define_mode_attr tf_fpr [(TF "_fpr") (FPRX2 "") (DF "") (SF "") (HF "")
+                         (TD "") (DD "") (SD "")])
 
 ;; Mode names as seen in type mode_attr values.
-(define_mode_attr type [(TF "tf") (FPRX2 "tf") (DF "df") (SF "sf") (TD "td")
-                       (DD "dd") (SD "sd")])
+(define_mode_attr type [(TF "tf") (FPRX2 "tf") (DF "df") (SF "sf") (HF "hf")
+                       (TD "td") (DD "dd") (SD "sd")])
 
 
 ; Condition code modes generated by vector fp comparisons.  These will
@@ -3105,6 +3108,67 @@
    (set_attr "cpu_facility" 
"z196,vx,*,vx,*,longdisp,*,longdisp,*,*,z10,*,longdisp,z10,*,longdisp,vx,vx,vx,vx,vx,vx")
    (set_attr "relative_long" 
"*,*,*,*,*,*,*,*,*,*,yes,*,*,yes,*,*,*,*,*,*,*,*")])
 
+;
+; movhf instruction pattern
+;
+
+(define_insn "movhf"
+  [(set (match_operand:HF 0 "nonimmediate_operand")
+       (match_operand:HF 1 "general_operand"))]
+  "TARGET_64BIT"
+  {@ [ cons: =0, 1; attrs: op_type, cpu_facility ]
+     [ v , v   ; VRR , vx       ] vlr\t%v0,%v1
+     [ v , d   ; VRS , vx       ] vlvgh\t%v0,%1,0
+     [ d , v   ; VRS , vx       ] vlgvh\t%0,%v1,0
+     [ v , R   ; VRX , vx       ] vleh\t%v0,%1,0
+     [ R , v   ; VRX , vx       ] vsteh\t%v1,%0,0
+     [ v , j00 ; VRI , vx       ] vzero\t%v0
+     [ v , jm1 ; VRI , vx       ] vone\t%v0
+     [ f , G   ; RRE , *        ] lzdr\t%0
+     [ f , f   ; RR  , *        ] ldr\t%0,%1
+     [ d , f   ; *   , z10      ] #
+     [ d , d   ; RR  , *        ] lr\t%0,%1
+     [ d , R   ; RX  , *        ] lh\t%0,%1
+     [ d , T   ; RXY , longdisp ] lhy\t%0,%1
+     [ d , b   ; RIL , z10      ] lhrl\t%0,%1
+     [ R , d   ; RX  , *        ] sth\t%1,%0
+     [ T , d   ; RXY , longdisp ] sthy\t%1,%0
+     [ b , d   ; RIL , z10      ] sthrl\t%1,%0
+  })
+
+; exploit instruction lgdr
+(define_split
+  [(set (match_operand:HF 0 "register_operand")
+       (match_operand:HF 1 "register_operand"))]
+  "TARGET_Z10 && !TARGET_VX && reload_completed && GENERAL_REG_P (operands[0]) 
&& FP_REG_P (operands[1])"
+  [(const_int 0)]
+{
+  operands[0] = gen_rtx_REG (DImode, REGNO (operands[0]));
+  operands[1] = gen_rtx_REG (DImode, REGNO (operands[1]));
+  emit_insn (gen_rtx_SET (operands[0], operands[1]));
+  emit_insn (gen_rtx_SET (operands[0], gen_rtx_LSHIFTRT (DImode, operands[0], 
GEN_INT (48))));
+  DONE;
+})
+
+; exploit instruction ldgr
+(define_insn_and_split "reload_half_gprtofpr_z10"
+  [(set (match_operand          0 "register_operand" "=f")
+       (unspec [(match_operand 1 "register_operand"  "d")]
+               UNSPEC_HALF_GPRTOFPR))
+   (clobber (match_operand:DI   2 "register_operand" "=d"))]
+  "TARGET_Z10 && !TARGET_VX"
+  "#"
+  "&& reload_completed"
+  [(const_int 0)]
+{
+  operands[0] = gen_rtx_REG (DImode, REGNO (operands[0]));
+  operands[1] = gen_rtx_REG (DImode, REGNO (operands[1]));
+  emit_insn (gen_rtx_SET (operands[2], gen_rtx_ASHIFT (DImode, operands[1], 
GEN_INT (48))));
+  emit_insn (gen_rtx_SET (operands[0], operands[2]));
+  DONE;
+})
+
+
 ;
 ; movcc instruction pattern
 ;
@@ -3804,8 +3868,26 @@
        (unspec:SI [(reg:CCZ CC_REGNUM)] UNSPEC_CC_TO_INT))]
   "TARGET_HARD_DFP")
 
+(define_expand "signbithf2"
+  [(match_operand:SI 0 "register_operand")
+   (match_operand:HF 1 "nonimmediate_operand")]
+  "TARGET_HARD_FLOAT && TARGET_Z10 && TARGET_64BIT"
+{
+  if (TARGET_VX)
+    {
+      rtx tmp = gen_reg_rtx (HImode);
+      emit_insn (gen_rtx_SET (tmp, simplify_gen_subreg (HImode, operands[1], 
HFmode, 0)));
+      emit_insn (gen_rtx_SET (operands[0], simplify_gen_unary (ZERO_EXTEND, 
SImode, tmp, HImode)));
+      emit_insn (gen_rtx_SET (operands[0], gen_rtx_LSHIFTRT (SImode, 
operands[0], GEN_INT (15))));
+    }
+  else
+    emit_insn (gen_signbithf2_z10 (operands[0], operands[1]));
+  DONE;
+})
+
 (define_mode_iterator SIGNBIT_SINGLE [(SF "TARGET_HARD_FLOAT")
                                      (SD "TARGET_HARD_DFP")])
+
 (define_expand "signbit<mode>2"
   [(match_operand:SI 0 "register_operand")
    (match_operand:SIGNBIT_SINGLE 1 "nonimmediate_operand")]
@@ -3823,16 +3905,20 @@
   DONE;
 })
 
+(define_mode_iterator SIGNBIT_HALF_SINGLE [(HF "TARGET_HARD_FLOAT")
+                                          (SF "TARGET_HARD_FLOAT")
+                                          (SD "TARGET_HARD_DFP")])
+
 (define_insn "signbit<mode>2_z10"
   [(set (match_operand:SI 0 "register_operand" "=d")
-       (unspec:SI [(match_operand:SIGNBIT_SINGLE 1 "nonimmediate_operand" 
"fRT")]
+       (unspec:SI [(match_operand:SIGNBIT_HALF_SINGLE 1 "nonimmediate_operand" 
"fRT")]
                   UNSPEC_SIGNBIT))]
   "TARGET_Z10 && TARGET_64BIT"
   "#")
 
 (define_split
   [(set (match_operand:SI 0 "register_operand")
-       (unspec:SI [(match_operand:SIGNBIT_SINGLE 1 "register_operand")]
+       (unspec:SI [(match_operand:SIGNBIT_HALF_SINGLE 1 "register_operand")]
                   UNSPEC_SIGNBIT))]
   "TARGET_Z10 && TARGET_64BIT && reload_completed"
   [(set (match_dup 0) (match_dup 1))
@@ -3844,13 +3930,23 @@
 
 (define_split
   [(set (match_operand:SI 0 "register_operand")
-       (unspec:SI [(match_operand:SIGNBIT_SINGLE 1 "memory_operand")]
+       (unspec:SI [(match_operand:SIGNBIT_HALF_SINGLE 1 "memory_operand")]
                   UNSPEC_SIGNBIT))]
   "TARGET_Z10 && TARGET_64BIT && reload_completed"
   [(set (match_dup 0) (match_dup 1))
    (set (match_dup 0) (lshiftrt:SI (match_dup 0) (const_int 31)))]
 {
-  operands[1] = change_address (operands[1], SImode, 0);
+  if (<MODE>mode == HFmode)
+    {
+      rtx op0_hi = gen_rtx_REG (HImode, REGNO (operands[0]));
+      rtx op1_hi = change_address (operands[1], HImode, 0);
+      emit_insn (gen_rtx_SET (op0_hi, op1_hi));
+      emit_insn (gen_rtx_SET (operands[0], simplify_gen_unary (ZERO_EXTEND, 
SImode, op0_hi, HImode)));
+      emit_insn (gen_rtx_SET (operands[0], gen_rtx_LSHIFTRT (SImode, 
operands[0], GEN_INT (15))));
+      DONE;
+    }
+  else
+    operands[1] = change_address (operands[1], SImode, 0);
 })
 
 (define_mode_iterator SIGNBIT_DBL_TETRA [(DF "TARGET_HARD_FLOAT")
@@ -12435,10 +12531,12 @@
 ;;- Copy sign instructions
 ;;
 
+(define_mode_iterator FP_COPYSIGN [(TF "!TARGET_VXE") (FPRX2 "TARGET_VXE") DF 
SF HF
+                                  (TD "TARGET_HARD_DFP") (DD 
"TARGET_HARD_DFP")])
 (define_insn "copysign<mode>3<tf_fpr>"
-  [(set (match_operand:FP 0 "register_operand" "=f")
-       (copysign:FP (match_operand:FP 1 "register_operand" "<fT0>")
-                    (match_operand:FP 2 "register_operand" "f")))]
+  [(set (match_operand:FP_COPYSIGN 0 "register_operand" "=f")
+       (copysign:FP_COPYSIGN (match_operand:FP_COPYSIGN 1 "register_operand" 
"<fT0>")
+                             (match_operand:FP_COPYSIGN 2 "register_operand" 
"f")))]
   "TARGET_Z196"
   "cpsdr\t%0,%2,%1"
   [(set_attr "op_type"  "RRF")
diff --git a/gcc/testsuite/g++.target/s390/float16-1.C 
b/gcc/testsuite/g++.target/s390/float16-1.C
new file mode 100644
index 00000000000..172b264696a
--- /dev/null
+++ b/gcc/testsuite/g++.target/s390/float16-1.C
@@ -0,0 +1,9 @@
+// { dg-do compile { target float16 } }
+// { dg-options "-std=c++23" }
+
+// Ensure that macro __STDCPP_FLOAT16_T__ evaluates to 1 since this in turn
+// ensures that common tests for float16_t are executed.
+
+#if __STDCPP_FLOAT16_T__ != 1
+# error "Type float16_t is supported for 64-bit targets starting with z10"
+#endif
diff --git a/gcc/testsuite/g++.target/s390/float16-2.C 
b/gcc/testsuite/g++.target/s390/float16-2.C
new file mode 100644
index 00000000000..8db99bb996c
--- /dev/null
+++ b/gcc/testsuite/g++.target/s390/float16-2.C
@@ -0,0 +1,11 @@
+// { dg-do compile { target float16 } }
+
+// Test name mangling
+
+void f1 (_Float16) {}
+void f2 (_Float16 *) {}
+void f3 (_Float16 const *) {}
+
+// { dg-final { scan-assembler "_Z2f1DF16_:" } }
+// { dg-final { scan-assembler "_Z2f2PDF16_:" } }
+// { dg-final { scan-assembler "_Z2f3PKDF16_:" } }
diff --git a/gcc/testsuite/gcc.target/s390/float16-1-2.h 
b/gcc/testsuite/gcc.target/s390/float16-1-2.h
new file mode 100644
index 00000000000..54250e2a72e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/float16-1-2.h
@@ -0,0 +1,36 @@
+unsigned short
+fpr_to_gpr (_Float16 x)
+{
+  unsigned short y;
+  __builtin_memcpy (&y, &x, 2);
+  return y;
+}
+
+_Float16
+gpr_to_fpr (unsigned short x)
+{
+  _Float16 y;
+  __builtin_memcpy (&y, &x, 2);
+  return y;
+}
+
+_Float16
+load_into_fpr (_Float16 *x)
+{
+  return *x;
+}
+
+unsigned short
+load_into_gpr (_Float16 *x)
+{
+  _Float16 xx = *x;
+  unsigned short y;
+  __builtin_memcpy (&y, &xx, 2);
+  return y;
+}
+
+void
+store (_Float16 *x, _Float16 y)
+{
+  *x = y;
+}
diff --git a/gcc/testsuite/gcc.target/s390/float16-1.c 
b/gcc/testsuite/gcc.target/s390/float16-1.c
new file mode 100644
index 00000000000..ac8c0d85bd9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/float16-1.c
@@ -0,0 +1,42 @@
+/* { dg-do compile { target float16 } } */
+/* { dg-options "-O2 -march=z10" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+/*
+** fpr_to_gpr:
+**     lgdr    (%r[0-9]+),%f0
+**     srlg    (%r[0-9]+),\1,48
+**     llghr   %r2,\2
+**     br      %r14
+*/
+
+/*
+** gpr_to_fpr:
+**     sllg    (%r[0-9]+),%r2,48
+**     ldgr    %f0,\1
+**     br      %r14
+*/
+
+/*
+** load_into_fpr:
+**     lh      (%r[0-9]+),0\(%r2\)
+**     sllg    (%r[0-9]+),\1,48
+**     ldgr    %f0,\2
+**     br      %r14
+*/
+
+/*
+** load_into_gpr:
+**     llgh    %r2,0\(%r2\)
+**     br      %r14
+*/
+
+/*
+** store:
+**     lgdr    (%r[0-9]+),%f0
+**     srlg    (%r[0-9]+),\1,48
+**     sth     \2,0\(%r2\)
+**     br      %r14
+*/
+
+#include "float16-1-2.h"
diff --git a/gcc/testsuite/gcc.target/s390/float16-10.c 
b/gcc/testsuite/gcc.target/s390/float16-10.c
new file mode 100644
index 00000000000..051f83b3580
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/float16-10.c
@@ -0,0 +1,30 @@
+/* { dg-do compile { target float16 } } */
+/* { dg-require-effective-target s390_mvx } */
+/* { dg-options "-O2" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+/*
+** copysign_reg:
+**     cpsdr   %f0,%f2,%f0
+**     br      %r14
+*/
+
+_Float16
+copysign_reg (_Float16 x, _Float16 y)
+{
+  return __builtin_copysignf16 (x, y);
+}
+
+/*
+** copysign_mem:
+**     vleh    %v([0-9]+),0\(%r2\),0
+**     vleh    %v([0-9]+),0\(%r3\),0
+**     cpsdr   %f0,%f\2,%f\1
+**     br      %r14
+*/
+
+_Float16
+copysign_mem (_Float16 *x, _Float16 *y)
+{
+  return __builtin_copysignf16 (*x, *y);
+}
diff --git a/gcc/testsuite/gcc.target/s390/float16-2.c 
b/gcc/testsuite/gcc.target/s390/float16-2.c
new file mode 100644
index 00000000000..4a2e6ea043d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/float16-2.c
@@ -0,0 +1,36 @@
+/* { dg-do compile { target float16 } } */
+/* { dg-options "-O2" } */
+/* { dg-require-effective-target s390_mvx } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+/*
+** fpr_to_gpr:
+**     vlgvh   %r2,%v0,0
+**     br      %r14
+*/
+
+/*
+** gpr_to_fpr:
+**     vlvgh   %v0,%r2,0
+**     br      %r14
+*/
+
+/*
+** load_into_fpr:
+**     vleh    %v0,0\(%r2\),0
+**     br      %r14
+*/
+
+/*
+** load_into_gpr:
+**     llgh    %r2,0\(%r2\)
+**     br      %r14
+*/
+
+/*
+** store:
+**     vsteh   %v0,0\(%r2\),0
+**     br      %r14
+*/
+
+#include "float16-1-2.h"
diff --git a/gcc/testsuite/gcc.target/s390/float16-3.c 
b/gcc/testsuite/gcc.target/s390/float16-3.c
new file mode 100644
index 00000000000..e39ea36fef3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/float16-3.c
@@ -0,0 +1,68 @@
+/* { dg-do compile { target float16 } } */
+/* { dg-require-effective-target s390_mvx } */
+/* { dg-options "-O2" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+/* Calling Convention Tests */
+
+/* Parameters of type _Float16 are passed via FPRs, if possible.  Return values
+   are passed via FPR f2.  */
+
+/*
+** test_arg:
+**     vlr     %v0,%v2
+**     br      %r14
+*/
+
+_Float16
+test_arg (double unused, _Float16 x)
+{
+  return x;
+}
+
+/* Test passing a struct with a single member.  */
+
+struct s { _Float16 x; };
+
+/*
+** test:
+**     br      %r14
+*/
+
+_Float16
+test (struct s y)
+{
+  return y.x;
+}
+
+/* Test _Float16 _Complex which must be returned via reference.  */
+
+/*
+** test_complex_return:
+**     vsteh   %v0,0\(%r2\),0
+**     vsteh   %v2,2\(%r2\),0
+**     br      %r14
+*/
+
+_Float16 _Complex
+test_complex_return (_Float16 a, _Float16 b)
+{
+  _Float16 _Complex x;
+  __real__ x = a;
+  __imag__ x = b;
+  return x;
+}
+
+/* Likewise, an argument of type _Float16 _Complex is passed via reference.  */
+
+/*
+** test_complex_arg:
+**     vleh    %v0,0\(%r2\),0
+**     br      %r14
+*/
+
+_Float16
+test_complex_arg (_Float16 _Complex x)
+{
+  return __real__ x;
+}
diff --git a/gcc/testsuite/gcc.target/s390/float16-4.c 
b/gcc/testsuite/gcc.target/s390/float16-4.c
new file mode 100644
index 00000000000..df25777e4ac
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/float16-4.c
@@ -0,0 +1,104 @@
+/* { dg-do run { target float16 } } */
+/* { dg-options "-O2 -fsignaling-nans -save-temps" } */
+/* { dg-final { scan-assembler-times "brasl\t%r14,__truncsfhf2@PLT" 1 } } */
+/* { dg-final { scan-assembler-times "brasl\t%r14,__truncdfhf2@PLT" 1 } } */
+/* { dg-final { scan-assembler-times "brasl\t%r14,__trunctfhf2@PLT" 1 } } */
+/* { dg-final { scan-assembler-times "brasl\t%r14,__extendhfsf2@PLT" 1 } } */
+/* { dg-final { scan-assembler-times "brasl\t%r14,__extendhfdf2@PLT" 1 } } */
+/* { dg-final { scan-assembler-times "brasl\t%r14,__extendhftf2@PLT" 1 } } */
+
+#define _GNU_SOURCE
+
+#include <assert.h>
+#include <fenv.h>
+#include <math.h>
+
+#pragma STDC FENV_ACCESS ON
+
+#define fn_truncate(mode, type) \
+  [[gnu::noipa]] _Float16 \
+  truncate##mode##hf (type x) { return x; }
+
+fn_truncate (sf, float)
+fn_truncate (df, double)
+fn_truncate (tf, long double)
+
+#define fn_extend(mode, type) \
+  [[gnu::noipa]] type \
+  extendhf##mode (_Float16 x) { return x; }
+
+fn_extend (sf, float)
+fn_extend (df, double)
+fn_extend (tf, long double)
+
+int
+main (void)
+{
+  feclearexcept (FE_ALL_EXCEPT);
+
+  /* Don't use isnan() but rather check manually since otherwise values of type
+     _Float16 would be extended before being passed to isnan() and we really
+     want to verify type _Float16 here.  */
+#define test_truncate_nan(mode, fn) \
+  { \
+    unsigned short tmp; \
+    _Float16 x; \
+    x = truncate##mode##hf (__builtin_nans##fn ("42")); \
+    assert (fetestexcept (FE_ALL_EXCEPT) == FE_INVALID); \
+    __builtin_memcpy (&tmp, &x, 2); \
+    assert (tmp == 0x7E00); \
+    feclearexcept (FE_ALL_EXCEPT); \
+    x = truncate##mode##hf (__builtin_nan##fn ("42")); \
+    assert (fetestexcept (FE_ALL_EXCEPT) == 0); \
+    __builtin_memcpy (&tmp, &x, 2); \
+    assert (tmp == 0x7E00); \
+  }
+
+  test_truncate_nan (sf, f)
+  test_truncate_nan (df,  )
+  test_truncate_nan (tf, l)
+
+#define test_truncate_inexact_overflow(mode) \
+  { \
+    truncate##mode##hf (__FLT_MAX__); \
+    assert (fetestexcept (FE_ALL_EXCEPT) == (FE_INEXACT | FE_OVERFLOW)); \
+    feclearexcept (FE_ALL_EXCEPT); \
+    truncate##mode##hf (42.f); \
+    assert (fetestexcept (FE_ALL_EXCEPT) == 0); \
+  }
+
+  test_truncate_inexact_overflow (sf)
+  test_truncate_inexact_overflow (df)
+  test_truncate_inexact_overflow (tf)
+
+#define test_truncate_inexact_underflow(mode) \
+  { \
+    truncate##mode##hf (__FLT_MIN__); \
+    assert (fetestexcept (FE_ALL_EXCEPT) == (FE_INEXACT | FE_UNDERFLOW)); \
+    feclearexcept (FE_ALL_EXCEPT); \
+    truncate##mode##hf (-42.f); \
+    assert (fetestexcept (FE_ALL_EXCEPT) == 0); \
+  }
+
+  test_truncate_inexact_underflow (sf)
+  test_truncate_inexact_underflow (df)
+  test_truncate_inexact_underflow (tf)
+
+#define test_extend(type, mode) \
+  { \
+    type x; \
+    x = extendhf##mode (__builtin_nansf16 ("42")); \
+    assert (fetestexcept (FE_ALL_EXCEPT) == FE_INVALID); \
+    assert (isnan (x)); \
+    feclearexcept (FE_ALL_EXCEPT); \
+    x = extendhf##mode (__builtin_nanf16 ("42")); \
+    assert (fetestexcept (FE_ALL_EXCEPT) == 0); \
+    assert (isnan (x)); \
+  }
+
+  test_extend (float, sf)
+  test_extend (double, df)
+  test_extend (long double, tf)
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/s390/float16-5.c 
b/gcc/testsuite/gcc.target/s390/float16-5.c
new file mode 100644
index 00000000000..1d9b6fe6954
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/float16-5.c
@@ -0,0 +1,105 @@
+/* { dg-do run { target float16 } } */
+/* { dg-options "-O2 -fsignaling-nans -save-temps" } */
+/* { dg-final { scan-assembler-times "brasl\t%r14,__dpd_truncsdhf@PLT" 1 } } */
+/* { dg-final { scan-assembler-times "brasl\t%r14,__dpd_truncddhf@PLT" 1 } } */
+/* { dg-final { scan-assembler-times "brasl\t%r14,__dpd_trunctdhf@PLT" 1 } } */
+/* { dg-final { scan-assembler-times "brasl\t%r14,__dpd_extendhfsd@PLT" 1 } } 
*/
+/* { dg-final { scan-assembler-times "brasl\t%r14,__dpd_extendhfdd@PLT" 1 } } 
*/
+/* { dg-final { scan-assembler-times "brasl\t%r14,__dpd_extendhftd@PLT" 1 } } 
*/
+
+#define _GNU_SOURCE
+
+#include <assert.h>
+#include <fenv.h>
+#include <math.h>
+
+#pragma STDC FENV_ACCESS ON
+
+#define fn_truncate(mode, type) \
+  [[gnu::noipa]] _Float16 \
+  truncate##mode##hf (type x) { return x; }
+
+fn_truncate (sd, _Decimal32)
+fn_truncate (dd, _Decimal64)
+fn_truncate (td, _Decimal128)
+
+#define fn_extend(mode, type) \
+  [[gnu::noipa]] type \
+  extendhf##mode (_Float16 x) { return x; }
+
+fn_extend (sd, _Decimal32)
+fn_extend (dd, _Decimal64)
+fn_extend (td, _Decimal128)
+
+int
+main (void)
+{
+  feclearexcept (FE_ALL_EXCEPT);
+
+  /* Don't use isnan() but rather check manually since otherwise values of type
+     _Float16 would be extended before being passed to isnan() and we really
+     want to verify type _Float16 here.  */
+#define test_truncate_nan(mode, fn) \
+  { \
+    unsigned short tmp; \
+    _Float16 x; \
+    x = truncate##mode##hf (__builtin_nans##fn ("42")); \
+    assert (fetestexcept (FE_ALL_EXCEPT) == FE_INVALID); \
+    __builtin_printf ("%u\n", tmp); \
+    __builtin_memcpy (&tmp, &x, 2); \
+    assert (tmp == 0x7E00); \
+    feclearexcept (FE_ALL_EXCEPT); \
+    x = truncate##mode##hf (__builtin_nan##fn ("42")); \
+    assert (fetestexcept (FE_ALL_EXCEPT) == 0); \
+    __builtin_memcpy (&tmp, &x, 2); \
+    assert (tmp == 0x7E00); \
+  }
+
+  test_truncate_nan (sd, d32)
+  test_truncate_nan (dd, d64)
+  test_truncate_nan (td, d128)
+
+#define test_truncate_inexact_overflow(mode) \
+  { \
+    truncate##mode##hf (__FLT_MAX__); \
+    assert (fetestexcept (FE_ALL_EXCEPT) == (FE_INEXACT | FE_OVERFLOW)); \
+    feclearexcept (FE_ALL_EXCEPT); \
+    truncate##mode##hf (42.f); \
+    assert (fetestexcept (FE_ALL_EXCEPT) == 0); \
+  }
+
+  test_truncate_inexact_overflow (sd)
+  test_truncate_inexact_overflow (dd)
+  test_truncate_inexact_overflow (td)
+
+#define test_truncate_inexact_underflow(mode) \
+  { \
+    truncate##mode##hf (__FLT_MIN__); \
+    assert (fetestexcept (FE_ALL_EXCEPT) == (FE_INEXACT | FE_UNDERFLOW)); \
+    feclearexcept (FE_ALL_EXCEPT); \
+    truncate##mode##hf (-42.f); \
+    assert (fetestexcept (FE_ALL_EXCEPT) == 0); \
+  }
+
+  test_truncate_inexact_underflow (sd)
+  test_truncate_inexact_underflow (dd)
+  test_truncate_inexact_underflow (td)
+
+#define test_extend(type, mode) \
+  { \
+    type x; \
+    x = extendhf##mode (__builtin_nansf16 ("42")); \
+    assert (fetestexcept (FE_ALL_EXCEPT) == FE_INVALID); \
+    assert (isnan (x)); \
+    feclearexcept (FE_ALL_EXCEPT); \
+    x = extendhf##mode (__builtin_nanf16 ("42")); \
+    assert (fetestexcept (FE_ALL_EXCEPT) == 0); \
+    assert (isnan (x)); \
+  }
+
+  test_extend (_Decimal32, sd)
+  test_extend (_Decimal64, dd)
+  test_extend (_Decimal128, td)
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/s390/float16-6.c 
b/gcc/testsuite/gcc.target/s390/float16-6.c
new file mode 100644
index 00000000000..012285d20fa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/float16-6.c
@@ -0,0 +1,71 @@
+/* { dg-do run { target float16 } } */
+/* { dg-options "-O2 -save-temps" } */
+/* { dg-final { scan-assembler-times "brasl\t%r14,__truncsfhf2@PLT" 1 } } */
+/* { dg-final { scan-assembler-times "brasl\t%r14,__truncdfhf2@PLT" 1 } } */
+/* { dg-final { scan-assembler-times "brasl\t%r14,__trunctfhf2@PLT" 1 } } */
+
+#include <assert.h>
+#include <fenv.h>
+
+#define fn_truncate(mode, type) \
+  [[gnu::noipa]] _Float16 \
+  truncate##mode##hf (type x) { return x; }
+
+fn_truncate (sf, float)
+fn_truncate (df, double)
+fn_truncate (tf, long double)
+
+#define fn_test_truncate(mode, type) \
+void \
+test_truncate##mode (type x, unsigned short a, unsigned short b, \
+                     unsigned short c, unsigned short d) \
+{ \
+  _Float16 y; \
+  unsigned short z; \
+\
+  fesetround (FE_TONEAREST); \
+  y = truncate##mode##hf (x); \
+  __builtin_memcpy (&z, &y, sizeof (z)); \
+  assert (z == a); \
+\
+  fesetround (FE_TOWARDZERO); \
+  y = truncate##mode##hf (x); \
+  __builtin_memcpy (&z, &y, sizeof (z)); \
+  assert (z == b); \
+\
+  fesetround (FE_DOWNWARD); \
+  y = truncate##mode##hf (x); \
+  __builtin_memcpy (&z, &y, sizeof (z)); \
+  assert (z == c); \
+\
+  fesetround (FE_UPWARD); \
+  y = truncate##mode##hf (x); \
+  __builtin_memcpy (&z, &y, sizeof (z)); \
+  assert (z == d); \
+}
+
+fn_test_truncate (sf, float)
+fn_test_truncate (df, double)
+fn_test_truncate (tf, long double)
+
+int
+main (void)
+{
+  test_truncatesf (__FLT_MAX__, 0x7c00, 0x7bff, 0x7bff, 0x7c00);
+  test_truncatesf (__FLT_MIN__, 0, 0, 0, 1);
+  test_truncatesf (0.5f, 0x3800, 0x3800, 0x3800, 0x3800);
+  test_truncatesf (-0.0000001f, 0x8002, 0x8001, 0x8002, 0x8001);
+  test_truncatesf (0.0000001f, 2, 1, 1, 2);
+
+  test_truncatedf (__DBL_MAX__, 0x7c00, 0x7bff, 0x7bff, 0x7c00);
+  test_truncatedf (__DBL_MIN__, 0, 0, 0, 1);
+  test_truncatedf (0.5f, 0x3800, 0x3800, 0x3800, 0x3800);
+  test_truncatedf (-0.0000001f, 0x8002, 0x8001, 0x8002, 0x8001);
+  test_truncatedf (0.0000001f, 2, 1, 1, 2);
+
+  test_truncatetf (__LDBL_MAX__, 0x7c00, 0x7bff, 0x7bff, 0x7c00);
+  test_truncatetf (__LDBL_MIN__, 0, 0, 0, 1);
+  test_truncatetf (0.5f, 0x3800, 0x3800, 0x3800, 0x3800);
+  test_truncatetf (-0.0000001f, 0x8002, 0x8001, 0x8002, 0x8001);
+  test_truncatetf (0.0000001f, 2, 1, 1, 2);
+}
diff --git a/gcc/testsuite/gcc.target/s390/float16-7.c 
b/gcc/testsuite/gcc.target/s390/float16-7.c
new file mode 100644
index 00000000000..f82150ca56a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/float16-7.c
@@ -0,0 +1,194 @@
+/* { dg-do compile { target float16 } } */
+/* { dg-require-effective-target s390_mvx } */
+/* { dg-options "-O2" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+/*
+** test_asm_constant_zero_via_f:
+**     vzero   %v([0-9]+)
+**     foo     %f\1
+**     br      %r14
+*/
+
+void
+test_asm_constant_zero_via_f (void)
+{
+  __asm__ __volatile__ ("foo\t%0" :: "f" (0.f16));
+}
+
+/*
+** test_asm_constant_zero_via_v:
+**     vzero   %v([0-9]+)
+**     foo     %f\1
+**     br      %r14
+*/
+
+void
+test_asm_constant_zero_via_v (void)
+{
+  __asm__ __volatile__ ("foo\t%0" :: "v" (0.f16));
+}
+
+/*
+** test_asm_constant_via_f:
+**     larl    (%r[0-9]+),\.L[0-9]+
+**     vleh    %v([0-9]+),\.L[0-9]+-\.L[0-9]+\(\1\),0
+**     foo     %f\2
+**     br      %r14
+*/
+
+void
+test_asm_constant_via_f (void)
+{
+  __asm__ __volatile__ ("foo\t%0" :: "f" (42.f16));
+}
+
+/*
+** test_asm_constant_via_v:
+**     larl    (%r[0-9]+),\.L[0-9]+
+**     vleh    %v([0-9]+),\.L[0-9]+-\.L[0-9]+\(\1\),0
+**     foo     %f\2
+**     br      %r14
+*/
+
+void
+test_asm_constant_via_v (void)
+{
+  __asm__ __volatile__ ("foo\t%0" :: "v" (42.f16));
+}
+
+/*
+** test_asm_in_float16_via_f:
+**     foo     %f0
+**     br      %r14
+*/
+
+void
+test_asm_in_float16_via_f (_Float16 x)
+{
+  __asm__ __volatile__ ("foo\t%0" :: "f" (x));
+}
+
+/*
+** test_asm_in_float16_via_v:
+**     foo     %f0
+**     br      %r14
+*/
+
+void
+test_asm_in_float16_via_v (_Float16 x)
+{
+  __asm__ __volatile__ ("foo\t%0" :: "v" (x));
+}
+
+/*
+** test_asm_in_float16_via_r:
+**     vlgvh   (%r[0-9]+),%v0,0
+**     foo     \1
+**     br      %r14
+*/
+
+void
+test_asm_in_float16_via_r (_Float16 x)
+{
+  __asm__ __volatile__ ("foo\t%0" :: "r" (x));
+}
+
+/*
+** test_asm_in_ushort_via_f:
+**     vlvgh   %v([0-9]+),%r2,0
+**     foo     %f\1
+**     br      %r14
+*/
+
+void
+test_asm_in_ushort_via_f (unsigned short x)
+{
+  __asm__ __volatile__ ("foo\t%0" :: "f" (x));
+}
+
+/*
+** test_asm_in_ushort_via_v:
+**     vlvgh   %v([0-9]+),%r2,0
+**     foo     %f\1
+**     br      %r14
+*/
+
+void
+test_asm_in_ushort_via_v (unsigned short x)
+{
+  __asm__ __volatile__ ("foo\t%0" :: "v" (x));
+}
+
+/*
+** test_asm_out_float16_via_f:
+**     foo     %f0
+**     br      %r14
+*/
+
+_Float16
+test_asm_out_float16_via_f (void)
+{
+  _Float16 x;
+  __asm__ ("foo\t%0" : "=f" (x));
+  return x;
+}
+
+/*
+** test_asm_out_float16_via_v:
+**     foo     %f0
+**     br      %r14
+*/
+
+_Float16
+test_asm_out_float16_via_v (void)
+{
+  _Float16 x;
+  __asm__ ("foo\t%0" : "=v" (x));
+  return x;
+}
+
+/*
+** test_asm_out_float16_via_r:
+**     foo     (%r[0-9]+)
+**     vlvgh   %v0,\1,0
+**     br      %r14
+*/
+
+_Float16
+test_asm_out_float16_via_r (void)
+{
+  _Float16 x;
+  __asm__ ("foo\t%0" : "=r" (x));
+  return x;
+}
+
+/*
+** test_asm_out_ushort_via_f:
+**     foo     %f([0-9]+)
+**     vlgvh   %r2,%v\1,0
+**     br      %r14
+*/
+
+unsigned short
+test_asm_out_ushort_via_f (void)
+{
+  unsigned short x;
+  __asm__ ("foo\t%0" : "=f" (x));
+  return x;
+}
+
+/*
+** test_asm_out_ushort_via_v:
+**     foo     %f([0-9]+)
+**     vlgvh   %r2,%v\1,0
+**     br      %r14
+*/
+
+unsigned short
+test_asm_out_ushort_via_v (void)
+{
+  unsigned short x;
+  __asm__ ("foo\t%0" : "=v" (x));
+  return x;
+}
diff --git a/gcc/testsuite/gcc.target/s390/float16-8.c 
b/gcc/testsuite/gcc.target/s390/float16-8.c
new file mode 100644
index 00000000000..ae37b771ec3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/float16-8.c
@@ -0,0 +1,22 @@
+/* { dg-do run { target float16 } } */
+/* { dg-options "-O2 -march=z10 -save-temps" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+/*
+** signbit_reg:
+**     lgdr    (%r[0-9]+),%f0
+**     srlg    (%r[0-9]+),\1,63
+**     lgfr    %r2,\2
+**     br      %r14
+*/
+
+/*
+** signbit_mem:
+**     lh      (%r[0-9]+),0\(%r2\)
+**     llhr    (%r[0-9]+),\1
+**     srl     \2,15
+**     lgfr    %r2,\2
+**     br      %r14
+*/
+
+#include "float16-signbit.h"
diff --git a/gcc/testsuite/gcc.target/s390/float16-9.c 
b/gcc/testsuite/gcc.target/s390/float16-9.c
new file mode 100644
index 00000000000..1d02a3f5da8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/float16-9.c
@@ -0,0 +1,20 @@
+/* { dg-do run { target float16 } } */
+/* { dg-require-effective-target s390_mvx } */
+/* { dg-options "-O2 -save-temps" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+/*
+** signbit_reg:
+**     vlgvh   (%r[0-9]+),%v0,0
+**     risbgn  %r2,\1,64-1,128\+63,48\+1
+**     br      %r14
+*/
+
+/*
+** signbit_mem:
+**     llh     (%r[0-9]+),0\(%r2\)
+**     risbgn  %r2,\1,64-1,128\+63,48\+1
+**     br      %r14
+*/
+
+#include "float16-signbit.h"
diff --git a/gcc/testsuite/gcc.target/s390/float16-signbit.h 
b/gcc/testsuite/gcc.target/s390/float16-signbit.h
new file mode 100644
index 00000000000..137bc247383
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/float16-signbit.h
@@ -0,0 +1,56 @@
+[[gnu::noipa]] int
+signbit_reg (_Float16 x)
+{
+  return __builtin_signbit (x);
+}
+
+[[gnu::noipa]] int
+signbit_mem (_Float16 *x)
+{
+  return __builtin_signbit (*x);
+}
+
+int
+main (void)
+{
+  _Float16 x;
+  int res = 0;
+
+  x = __builtin_nanf16 ("42");
+  res += signbit_reg (x);
+  res += signbit_mem (&x);
+
+  x = __builtin_inff16 ();
+  res += signbit_reg (x);
+  res += signbit_mem (&x);
+
+  x = 0.f16;
+  res += signbit_reg (x);
+  res += signbit_mem (&x);
+
+  x = 42.42f16;
+  res += signbit_reg (x);
+  res += signbit_mem (&x);
+
+  if (res != 0)
+    __builtin_abort ();
+
+  x = -__builtin_nanf16 ("42");
+  res += signbit_reg (x);
+  res += signbit_mem (&x);
+
+  x = -__builtin_inff16 ();
+  res += signbit_reg (x);
+  res += signbit_mem (&x);
+
+  x = -0.f16;
+  res += signbit_reg (x);
+  res += signbit_mem (&x);
+
+  x = -42.42f16;
+  res += signbit_reg (x);
+  res += signbit_mem (&x);
+
+  if (res != 8)
+    __builtin_abort ();
+}
diff --git a/libgcc/config.host b/libgcc/config.host
index 82ea1772f51..fdb47b240be 100644
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -1391,6 +1391,9 @@ s390x-*-linux*)
        if test "${host_address}" = 32; then
           tmake_file="${tmake_file} s390/32/t-floattodi"
        else
+          if test "$libgcc_cv_s390_float16" = "yes"; then
+               tmake_file="${tmake_file} s390/t-float16"
+          fi
           tmake_file="${tmake_file} s390/t-softfp t-softfp"
        fi
        md_unwind_header=s390/linux-unwind.h
diff --git a/libgcc/config/s390/_dpd_dd_to_hf.c 
b/libgcc/config/s390/_dpd_dd_to_hf.c
new file mode 100644
index 00000000000..d2b7a347847
--- /dev/null
+++ b/libgcc/config/s390/_dpd_dd_to_hf.c
@@ -0,0 +1,39 @@
+/* Copyright (C) 2001-2025 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+typedef float HFtype __attribute__ ((mode (HF)));
+typedef float DFtype __attribute__ ((mode (DF)));
+
+HFtype __dpd_truncddhf (_Decimal64);
+
+__attribute__ ((noinline))
+static DFtype
+force_convert (_Decimal32 x)
+{ return x; }
+
+HFtype
+__dpd_truncddhf (_Decimal64 x)
+{
+  DFtype xdf = force_convert (x);
+  return xdf;
+}
diff --git a/libgcc/config/s390/_dpd_hf_to_dd.c 
b/libgcc/config/s390/_dpd_hf_to_dd.c
new file mode 100644
index 00000000000..00d2f3fd8e1
--- /dev/null
+++ b/libgcc/config/s390/_dpd_hf_to_dd.c
@@ -0,0 +1,39 @@
+/* Copyright (C) 2001-2025 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+typedef float HFtype __attribute__ ((mode (HF)));
+typedef float DFtype __attribute__ ((mode (DF)));
+
+_Decimal64 __dpd_extendhfdd (HFtype);
+
+__attribute__ ((noinline))
+static DFtype
+force_bfp_extend (HFtype x)
+{ return x; }
+
+_Decimal64
+__dpd_extendhfdd (HFtype x)
+{
+  DFtype xdf = force_bfp_extend (x);
+  return xdf;
+}
diff --git a/libgcc/config/s390/_dpd_hf_to_sd.c 
b/libgcc/config/s390/_dpd_hf_to_sd.c
new file mode 100644
index 00000000000..3e0dede6805
--- /dev/null
+++ b/libgcc/config/s390/_dpd_hf_to_sd.c
@@ -0,0 +1,39 @@
+/* Copyright (C) 2001-2025 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+typedef float HFtype __attribute__ ((mode (HF)));
+typedef float SFtype __attribute__ ((mode (SF)));
+
+_Decimal32 __dpd_extendhfsd (HFtype);
+
+__attribute__ ((noinline))
+static SFtype
+force_bfp_extend (HFtype x)
+{ return x; }
+
+_Decimal32
+__dpd_extendhfsd (HFtype x)
+{
+  SFtype xsf = force_bfp_extend (x);
+  return xsf;
+}
diff --git a/libgcc/config/s390/_dpd_hf_to_td.c 
b/libgcc/config/s390/_dpd_hf_to_td.c
new file mode 100644
index 00000000000..37eece8667b
--- /dev/null
+++ b/libgcc/config/s390/_dpd_hf_to_td.c
@@ -0,0 +1,39 @@
+/* Copyright (C) 2001-2025 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+typedef float HFtype __attribute__ ((mode (HF)));
+typedef float TFtype __attribute__ ((mode (TF)));
+
+_Decimal128 __dpd_extendhftd (HFtype);
+
+__attribute__ ((noinline))
+static TFtype
+force_bfp_extend (HFtype x)
+{ return x; }
+
+_Decimal128
+__dpd_extendhftd (HFtype x)
+{
+  TFtype xtf = force_bfp_extend (x);
+  return xtf;
+}
diff --git a/libgcc/config/s390/_dpd_sd_to_hf.c 
b/libgcc/config/s390/_dpd_sd_to_hf.c
new file mode 100644
index 00000000000..b93d053d3c9
--- /dev/null
+++ b/libgcc/config/s390/_dpd_sd_to_hf.c
@@ -0,0 +1,39 @@
+/* Copyright (C) 2001-2025 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+typedef float HFtype __attribute__ ((mode (HF)));
+typedef float SFtype __attribute__ ((mode (SF)));
+
+HFtype __dpd_truncsdhf (_Decimal32);
+
+__attribute__ ((noinline))
+static SFtype
+force_convert (_Decimal32 x)
+{ return x; }
+
+HFtype
+__dpd_truncsdhf (_Decimal32 x)
+{
+  SFtype xsf = force_convert (x);
+  return xsf;
+}
diff --git a/libgcc/config/s390/_dpd_td_to_hf.c 
b/libgcc/config/s390/_dpd_td_to_hf.c
new file mode 100644
index 00000000000..8f9e2586849
--- /dev/null
+++ b/libgcc/config/s390/_dpd_td_to_hf.c
@@ -0,0 +1,39 @@
+/* Copyright (C) 2001-2025 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+typedef float HFtype __attribute__ ((mode (HF)));
+typedef float TFtype __attribute__ ((mode (TF)));
+
+HFtype __dpd_trunctdhf (_Decimal128);
+
+__attribute__ ((noinline))
+static TFtype
+force_convert (_Decimal128 x)
+{ return x; }
+
+HFtype
+__dpd_trunctdhf (_Decimal128 x)
+{
+  TFtype xtf = force_convert (x);
+  return xtf;
+}
diff --git a/libgcc/config/s390/libgcc-glibc.ver 
b/libgcc/config/s390/libgcc-glibc.ver
index 00375b3df0e..6fcc24630a6 100644
--- a/libgcc/config/s390/libgcc-glibc.ver
+++ b/libgcc/config/s390/libgcc-glibc.ver
@@ -126,5 +126,15 @@ GCC_16.0.0 {
   __floatbitintsf
   __floatbitintdf
   __floatbitinttf
+  __truncsfhf2
+  __truncdfhf2
+  __trunctfhf2
+  __extendhfsf2
+  __extendhfdf2
+  __extendhftf2
+  __fixhfti
+  __fixunshfti
+  __floattihf
+  __floatuntihf
 }
 %endif
diff --git a/libgcc/config/s390/t-float16 b/libgcc/config/s390/t-float16
new file mode 100644
index 00000000000..0be04413d1f
--- /dev/null
+++ b/libgcc/config/s390/t-float16
@@ -0,0 +1,11 @@
+LIB2ADD += $(addprefix $(srcdir)/config/s390/, \
+               _dpd_hf_to_sd.c \
+               _dpd_hf_to_dd.c \
+               _dpd_hf_to_td.c \
+               _dpd_sd_to_hf.c \
+               _dpd_dd_to_hf.c \
+               _dpd_td_to_hf.c)
+
+softfp_extensions += hfsf hfdf hftf
+softfp_truncations += sfhf dfhf tfhf
+softfp_extras += fixhfti fixunshfti floattihf floatuntihf
diff --git a/libgcc/config/s390/t-softfp b/libgcc/config/s390/t-softfp
index 724b15e83ba..0614fefbd23 100644
--- a/libgcc/config/s390/t-softfp
+++ b/libgcc/config/s390/t-softfp
@@ -1,2 +1,2 @@
 LIB2ADD += $(srcdir)/config/s390/sfp-exceptions.c
-softfp_extras := fixtfbitint floatbitinttf
+softfp_extras += fixtfbitint floatbitinttf
diff --git a/libgcc/configure b/libgcc/configure
index d5e80d227ff..6ff14f6ceac 100755
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -5284,6 +5284,32 @@ $as_echo "$libgcc_cv_powerpc_3_1_float128_hw" >&6; }
   CFLAGS="$saved_CFLAGS"
 esac
 
+case ${host} in
+s390*-*-linux*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking Support float16 on s390" 
>&5
+$as_echo_n "checking Support float16 on s390... " >&6; }
+if ${libgcc_cv_s390_float16+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#if ! __s390x__ || __ARCH__ < 8
+     # error "HF not supported"
+     #endif
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  libgcc_cv_s390_float16=yes
+else
+  libgcc_cv_s390_float16=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_s390_float16" >&5
+$as_echo "$libgcc_cv_s390_float16" >&6; }
+  ;;
+esac
+
 # Collect host-machine-specific information.
 . ${srcdir}/config.host
 
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index 65cd3c6aa1a..7a06cc43dc6 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -467,6 +467,20 @@ powerpc*-*-linux*)
   CFLAGS="$saved_CFLAGS"
 esac
 
+case ${host} in
+s390*-*-linux*)
+  AC_CACHE_CHECK([Support float16 on s390],
+                [libgcc_cv_s390_float16],
+                [AC_COMPILE_IFELSE(
+    [AC_LANG_SOURCE([#if ! __s390x__ || __ARCH__ < 8
+     # error "HF not supported"
+     #endif
+     ])],
+    [libgcc_cv_s390_float16=yes],
+    [libgcc_cv_s390_float16=no])])
+  ;;
+esac
+
 # Collect host-machine-specific information.
 . ${srcdir}/config.host
 
diff --git a/libstdc++-v3/config/abi/post/s390x-linux-gnu/baseline_symbols.txt 
b/libstdc++-v3/config/abi/post/s390x-linux-gnu/baseline_symbols.txt
index 8c204af66fc..b29c71a0753 100644
--- a/libstdc++-v3/config/abi/post/s390x-linux-gnu/baseline_symbols.txt
+++ b/libstdc++-v3/config/abi/post/s390x-linux-gnu/baseline_symbols.txt
@@ -4951,6 +4951,7 @@ OBJECT:15:_ZTSSt8messagesIwE@@GLIBCXX_3.4
 OBJECT:15:_ZTSSt8numpunctIcE@@GLIBCXX_3.4
 OBJECT:15:_ZTSSt8numpunctIwE@@GLIBCXX_3.4
 OBJECT:16:_ZTIDF128_@@CXXABI_1.3.14
+OBJECT:16:_ZTIDF16_@@CXXABI_1.3.14
 OBJECT:16:_ZTIDF32_@@CXXABI_1.3.14
 OBJECT:16:_ZTIDF32x@@CXXABI_1.3.14
 OBJECT:16:_ZTIDF64_@@CXXABI_1.3.14
@@ -5615,6 +5616,7 @@ 
OBJECT:30:_ZTSSt7codecvtIDsDu11__mbstate_tE@@GLIBCXX_3.4.26
 
OBJECT:32:_ZNSbIwSt11char_traitsIwESaIwEE4_Rep20_S_empty_rep_storageE@@GLIBCXX_3.4
 OBJECT:32:_ZNSs4_Rep20_S_empty_rep_storageE@@GLIBCXX_3.4
 OBJECT:32:_ZTIPDF128_@@CXXABI_1.3.14
+OBJECT:32:_ZTIPDF16_@@CXXABI_1.3.14
 OBJECT:32:_ZTIPDF32_@@CXXABI_1.3.14
 OBJECT:32:_ZTIPDF32x@@CXXABI_1.3.14
 OBJECT:32:_ZTIPDF64_@@CXXABI_1.3.14
@@ -5627,6 +5629,7 @@ OBJECT:32:_ZTIPDn@@CXXABI_1.3.5
 OBJECT:32:_ZTIPDs@@CXXABI_1.3.3
 OBJECT:32:_ZTIPDu@@CXXABI_1.3.12
 OBJECT:32:_ZTIPKDF128_@@CXXABI_1.3.14
+OBJECT:32:_ZTIPKDF16_@@CXXABI_1.3.14
 OBJECT:32:_ZTIPKDF32_@@CXXABI_1.3.14
 OBJECT:32:_ZTIPKDF32x@@CXXABI_1.3.14
 OBJECT:32:_ZTIPKDF64_@@CXXABI_1.3.14
-- 
2.49.0

Reply via email to