diff --git a/gcc/cfgexpand.cc b/gcc/cfgexpand.cc index d51af2e..c377f16 100644 --- a/gcc/cfgexpand.cc +++ b/gcc/cfgexpand.cc @@ -3715,7 +3715,22 @@ expand_value_return (rtx val) mode = promote_function_mode (type, old_mode, &unsignedp, funtype, 1); if (mode != old_mode) - val = convert_modes (mode, old_mode, val, unsignedp); + { + /* Some ABIs require scalar floating point modes to be returned + in a wider scalar integer mode. We need to explicitly + reinterpret to an integer mode of the correct precision + before extending to the desired result. */ + if (SCALAR_INT_MODE_P (mode) + && SCALAR_FLOAT_MODE_P (old_mode) + && known_gt (GET_MODE_SIZE (mode), GET_MODE_SIZE (old_mode))) + { + scalar_int_mode imode = int_mode_for_mode (old_mode).require (); + val = force_reg (imode, gen_lowpart (imode, val)); + val = convert_modes (mode, imode, val, 1); + } + else + val = convert_modes (mode, old_mode, val, unsignedp); + } if (GET_CODE (return_reg) == PARALLEL) emit_group_load (return_reg, val, type, int_size_in_bytes (type)); diff --git a/gcc/expr.cc b/gcc/expr.cc index 35e4029..e4efdcd 100644 --- a/gcc/expr.cc +++ b/gcc/expr.cc @@ -10674,6 +10674,19 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, pmode = promote_ssa_mode (ssa_name, &unsignedp); gcc_assert (GET_MODE (decl_rtl) == pmode); + /* Some ABIs require scalar floating point modes to be passed + in a wider scalar integer mode. We need to explicitly + truncate to an integer mode of the correct precision before + using a SUBREG to reinterpret as a floating point value. */ + if (SCALAR_FLOAT_MODE_P (mode) + && SCALAR_INT_MODE_P (pmode) + && known_lt (GET_MODE_SIZE (mode), GET_MODE_SIZE (pmode))) + { + scalar_int_mode imode = int_mode_for_mode (mode).require (); + temp = force_reg (imode, gen_lowpart (imode, decl_rtl)); + return gen_lowpart_SUBREG (mode, temp); + } + temp = gen_lowpart_SUBREG (mode, decl_rtl); SUBREG_PROMOTED_VAR_P (temp) = 1; SUBREG_PROMOTED_SET (temp, unsignedp);