Hello,
On 28/04/16 16:49, Joseph Myers wrote:
On Thu, 28 Apr 2016, Matthew Wahab wrote:
The ARM target supports the half-precision floating point type __fp16 but does
not allow its use as a function return or parameter type. This patch removes
that restriction and defines the ACLE macro __ARM_FP16_ARGS to indicate this.
The code generated for passing __fp16 values into and out of functions depends
on the level of hardware support but conforms to the AAPCS (see
http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042f/IHI0042F_aapcs.pdf).
The sole use of the TARGET_INVALID_PARAMETER_TYPE and TARGET_INVALID_RETURN_TYPE
hooks was to disallow __fp16 use as a function return or parameter type. Thus,
I
think this patch should completely remove those hooks and poison them in
system.h.
This touches the C and C++ front-ends so I'll send a separate patch to do this.
This patch addresses one incompatibility of the original __fp16 specification
with
the more recent ACLE specification and the specification in ISO/IEC TS 18661-3
for
how such types should work. Another such incompatibility is the peculiar rule in
the original specification that conversions from double to __fp16 go via float,
with double rounding. Do you have plans to eliminate that and move to the
single-rounding semantics that are in current specifications?
The patch aims to preserve the __fp16 semantics currently used by GCC, except
for the
obvious argument/return value in registers change. This is to avoid any changes
to
the values calculated by existing __fp16 code that might be introduced if
things like
the conversion rules are changed.
I note that that AAPCS revision says for __fp16, in 7.1.1 Arithmetic Types, "In
a
variadic function call this will be passed as a double-precision value.". I
haven't checked what this patch implements, but that could be problematic, and
different from what's said under 7.2, "For variadic functions, float arguments
that match the ellipsis (...) are converted to type double.".
The patch keeps the current GCC behaviour (conversion to double). (There's an
existing test for this in gcc.target/arm/fp16-variadic-1.c.)
In TS 18661-3, _Float16 is *not* affected by default argument promotions; only
float is. This reflects how the default conversion of float to double is a
legacy
feature; note for example how in C99 and C11 float _Imaginary is not promoted to
double _Imaginary, and float _Complex is not promoted to double _Complex.
Thus it would be better for compatibility with TS 18661-3 to pass __fp16 values
to
variadic functions as themselves, unpromoted. (Formally of course the lack of
promotion is a language feature not an ABI feature; as long as va_arg for
_Float16
named works correctly, you could promote at the ABI level and then convert back,
and the only effect would be that sNaNs get quieted, so passing a _Float16 sNaN
through variable arguments would act as a convertFormat operation instead of a
copy operation. It's not clear that having such an ABI-level promotion is a
good
idea, however.)
Now, in the context of the current implementation and current ACLE arithmetic on
__fp16 values produces float results - the operands are promoted at the C
language
level. This is different from TS 18661-3, where _Float16 arithmetic produces
results whose semantics type is _Float16 but which, if FLT_EVAL_METHOD is 0, are
evaluated with excess range and precision to the range and precision of float.
So
if __fp16 and float are differently passed to variadic functions, you have the
issue that if the argument is an expression resulting from __fp16 arithmetic,
the
way it is passed depends on whether current ACLE or TS 18661-3 are followed.
But
if the eventual aim is for __fp16 (when using the IEEE format rather than the
alternative format) to become just a typedef for _Float16, then these issues
will
need to be addressed.
When _Float16 support is added, the relationship between __fp16 and _FLoat16 is
something that will need to be considered. At the moment though, there's only the
__fp16 type and the intention with this patch is to avoid doing anything that changes
the behaviour of existing code.
Matthew