Hello!

The _FloatN patch uncovers a problem on alpha OSF/1 ABI when _Float32
variable arguments are passed to a function. As seen from the source,
32bit _Float32 arguments (SFmode) are *not* promoted to 64bit DFmode
when passing to as variable arguments, and this uncovers following
limitation:

Values, passed in FP registers are pushed to a pretend-args area of
called va-arg function in their 64-bit full word mode, so they are
stored as their bit-exact copy from the reg to the memory using STT
instruction. However, when this memory is later accessed as SFmode
value using LDS instruction, this doesn't load SFmode value (as it was
passed in the FP register), since LDS reorders bits on the way from/to
memory. To make things worse, the value can be moved from pretend-args
area as a DImode value and stored as a SImode subreg of this value.

Float arguments, passed to va-arg function work OK, since default c
promoting rules always promote float variable arguments to double.
This is not the case with _Float32.

To illustrate the problem, consider following source:

--cut here--
volatile _Float32 a = 1.0f32, b = 2.5F32, c = -2.5f32;

_Float32
vafn (_Float32 arg1, ...)
{
  __builtin_va_list ap;
  _Float32 ret;

 __builtin_va_start (ap, arg1);
  ret = arg1 + __builtin_va_arg (ap, _Float32);
 __builtin_va_end (ap);
  return ret;
}

int
main (void)
{
  volatile _Float32 r;
  r = vafn (a, c);
  if (r != -1.5f32)
    __builtin_abort ();
  return 0;
}
--cut here--

Please note the lack of promotion in __builtin_va_arg.

This is compiled to following assembly:

vafn:
        ...
        stt $f17,24($30) <- store DFmode to pretend args area and ...
        ldq $1,24($30) <- ... load it as DImode value
        ...
        stl $1,16($30) <- store SImode subreg to stack and ...
        lds $f10,16($30) <- ... load it as SFmode value
        stq $1,40($30) <- (dead DImode store)
        adds $f16,$f10,$f0 <- use SFmode value in $f10
        ...

main:
        ...
        lda $1,a
        lds $f16,0($1)
        lda $1,c
        lds $f17,0($1)
        jsr $26,vafn
        ...

SFmode values are stored in the FP registers in canonical form, as
subset of DFmode values, with 11-bit exponents restricted to the
corresponding single-precision range, and with the 29 low-order
fraction bits restricted to be all zero. IOW, it is not possible to
load SFmode value from the location where the full 64bit value was
stored from the FP register.

I didn't find a way around this limitation, so I propose to disable
_FloatN on alpha with the attached patch.

Uros.
diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c
index 702cd27..1bf27ca 100644
--- a/gcc/config/alpha/alpha.c
+++ b/gcc/config/alpha/alpha.c
@@ -736,6 +736,20 @@ alpha_vector_mode_supported_p (machine_mode mode)
   return mode == V8QImode || mode == V4HImode || mode == V2SImode;
 }
 
+/* Target hook for floatn_mode.  */
+
+static machine_mode
+alpha_floatn_mode (int n ATTRIBUTE_UNUSED, bool extended ATTRIBUTE_UNUSED)
+{
+  /* Alpha can't pass _Float32 variable arguments.  The function that is
+     receiving a variable number of arguments pushes floating-point values
+     in the remaining incoming registers to the stack as DFmode 64-bit values.
+     These stores are not compatible with SFmode loads due to implicit
+     reordering of bits during SFmode load.  Disable all _Floatn types.  */
+
+  return VOIDmode;
+}
+
 /* Return 1 if this function can directly return via $26.  */
 
 int
@@ -9978,8 +9992,6 @@ alpha_atomic_assign_expand_fenv (tree *hold, tree *clear, 
tree *update)
 
 #undef TARGET_PROMOTE_FUNCTION_MODE
 #define TARGET_PROMOTE_FUNCTION_MODE 
default_promote_function_mode_always_promote
-#undef TARGET_PROMOTE_PROTOTYPES
-#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false
 
 #undef TARGET_FUNCTION_VALUE
 #define TARGET_FUNCTION_VALUE alpha_function_value
@@ -10020,6 +10032,8 @@ alpha_atomic_assign_expand_fenv (tree *hold, tree 
*clear, tree *update)
 #define TARGET_SCALAR_MODE_SUPPORTED_P alpha_scalar_mode_supported_p
 #undef TARGET_VECTOR_MODE_SUPPORTED_P
 #define TARGET_VECTOR_MODE_SUPPORTED_P alpha_vector_mode_supported_p
+#undef TARGET_FLOATN_MODE
+#define TARGET_FLOATN_MODE alpha_floatn_mode
 
 #undef TARGET_BUILD_BUILTIN_VA_LIST
 #define TARGET_BUILD_BUILTIN_VA_LIST alpha_build_builtin_va_list

Reply via email to