Disable _Float16 for non ARM/SPIR Targets
As Discussed here: http://lists.llvm.org/pipermail/llvm-dev/2019-January/129543.html There are problems exposing the _Float16 type on architectures that haven't defined the ABI/ISel for the type yet, so we're temporarily disabling the type and making it opt-in. Differential Revision: https://reviews.llvm.org/D57188 Change-Id: I5db7366dedf1deb9485adb8948b1deb7e612a736 llvm-svn: 352221
This commit is contained in:
parent
a04584b095
commit
1d1d438e8e
|
@ -474,44 +474,58 @@ Half-Precision Floating Point
|
||||||
=============================
|
=============================
|
||||||
|
|
||||||
Clang supports two half-precision (16-bit) floating point types: ``__fp16`` and
|
Clang supports two half-precision (16-bit) floating point types: ``__fp16`` and
|
||||||
``_Float16``. ``__fp16`` is defined in the ARM C Language Extensions (`ACLE
|
``_Float16``. These types are supported in all language modes.
|
||||||
<http://infocenter.arm.com/help/topic/com.arm.doc.ihi0053d/IHI0053D_acle_2_1.pdf>`_)
|
|
||||||
and ``_Float16`` in ISO/IEC TS 18661-3:2015.
|
|
||||||
|
|
||||||
``__fp16`` is a storage and interchange format only. This means that values of
|
``__fp16`` is supported on every target, as it is purely a storage format; see below.
|
||||||
``__fp16`` promote to (at least) float when used in arithmetic operations.
|
``_Float16`` is currently only supported on the following targets, with further
|
||||||
There are two ``__fp16`` formats. Clang supports the IEEE 754-2008 format and
|
targets pending ABI standardization:
|
||||||
not the ARM alternative format.
|
- 32-bit ARM
|
||||||
|
- 64-bit ARM (AArch64)
|
||||||
|
- SPIR
|
||||||
|
``_Float16`` will be supported on more targets as they define ABIs for it.
|
||||||
|
|
||||||
ISO/IEC TS 18661-3:2015 defines C support for additional floating point types.
|
``__fp16`` is a storage and interchange format only. This means that values of
|
||||||
``_FloatN`` is defined as a binary floating type, where the N suffix denotes
|
``__fp16`` are immediately promoted to (at least) ``float`` when used in arithmetic
|
||||||
the number of bits and is 16, 32, 64, or greater and equal to 128 and a
|
operations, so that e.g. the result of adding two ``__fp16`` values has type ``float``.
|
||||||
multiple of 32. Clang supports ``_Float16``. The difference from ``__fp16`` is
|
The behavior of ``__fp16`` is specified by the ARM C Language Extensions (`ACLE <http://infocenter.arm.com/help/topic/com.arm.doc.ihi0053d/IHI0053D_acle_2_1.pdf>`_).
|
||||||
that arithmetic on ``_Float16`` is performed in half-precision, thus it is not
|
Clang uses the ``binary16`` format from IEEE 754-2008 for ``__fp16``, not the ARM
|
||||||
a storage-only format. ``_Float16`` is available as a source language type in
|
alternative format.
|
||||||
both C and C++ mode.
|
|
||||||
|
|
||||||
It is recommended that portable code use the ``_Float16`` type because
|
``_Float16`` is an extended floating-point type. This means that, just like arithmetic on
|
||||||
``__fp16`` is an ARM C-Language Extension (ACLE), whereas ``_Float16`` is
|
``float`` or ``double``, arithmetic on ``_Float16`` operands is formally performed in the
|
||||||
defined by the C standards committee, so using ``_Float16`` will not prevent
|
``_Float16`` type, so that e.g. the result of adding two ``_Float16`` values has type
|
||||||
code from being ported to architectures other than Arm. Also, ``_Float16``
|
``_Float16``. The behavior of ``_Float16`` is specified by ISO/IEC TS 18661-3:2015
|
||||||
arithmetic and operations will directly map on half-precision instructions when
|
("Floating-point extensions for C"). As with ``__fp16``, Clang uses the ``binary16``
|
||||||
they are available (e.g. Armv8.2-A), avoiding conversions to/from
|
format from IEEE 754-2008 for ``_Float16``.
|
||||||
single-precision, and thus will result in more performant code. If
|
|
||||||
half-precision instructions are unavailable, values will be promoted to
|
|
||||||
single-precision, similar to the semantics of ``__fp16`` except that the
|
|
||||||
results will be stored in single-precision.
|
|
||||||
|
|
||||||
In an arithmetic operation where one operand is of ``__fp16`` type and the
|
``_Float16`` arithmetic will be performed using native half-precision support
|
||||||
other is of ``_Float16`` type, the ``_Float16`` type is first converted to
|
when available on the target (e.g. on ARMv8.2a); otherwise it will be performed
|
||||||
``__fp16`` type and then the operation is completed as if both operands were of
|
at a higher precision (currently always ``float``) and then truncated down to
|
||||||
``__fp16`` type.
|
``_Float16``. Note that C and C++ allow intermediate floating-point operands
|
||||||
|
of an expression to be computed with greater precision than is expressible in
|
||||||
|
their type, so Clang may avoid intermediate truncations in certain cases; this may
|
||||||
|
lead to results that are inconsistent with native arithmetic.
|
||||||
|
|
||||||
To define a ``_Float16`` literal, suffix ``f16`` can be appended to the compile-time
|
It is recommended that portable code use ``_Float16`` instead of ``__fp16``,
|
||||||
constant declaration. There is no default argument promotion for ``_Float16``; this
|
as it has been defined by the C standards committee and has behavior that is
|
||||||
applies to the standard floating types only. As a consequence, for example, an
|
more familiar to most programmers.
|
||||||
explicit cast is required for printing a ``_Float16`` value (there is no string
|
|
||||||
format specifier for ``_Float16``).
|
Because ``__fp16`` operands are always immediately promoted to ``float``, the
|
||||||
|
common real type of ``__fp16`` and ``_Float16`` for the purposes of the usual
|
||||||
|
arithmetic conversions is ``float``.
|
||||||
|
|
||||||
|
A literal can be given ``_Float16`` type using the suffix ``f16``; for example:
|
||||||
|
```
|
||||||
|
3.14f16
|
||||||
|
```
|
||||||
|
|
||||||
|
Because default argument promotion only applies to the standard floating-point
|
||||||
|
types, ``_Float16`` values are not promoted to ``double`` when passed as variadic
|
||||||
|
or untyped arguments. As a consequence, some caution must be taken when using
|
||||||
|
certain library facilities with ``_Float16``; for example, there is no ``printf`` format
|
||||||
|
specifier for ``_Float16``, and (unlike ``float``) it will not be implicitly promoted to
|
||||||
|
``double`` when passed to ``printf``, so the programmer must explicitly cast it to
|
||||||
|
``double`` before using it with an ``%f`` or similar specifier.
|
||||||
|
|
||||||
Messages on ``deprecated`` and ``unavailable`` Attributes
|
Messages on ``deprecated`` and ``unavailable`` Attributes
|
||||||
=========================================================
|
=========================================================
|
||||||
|
|
|
@ -63,6 +63,7 @@ protected:
|
||||||
bool HasLegalHalfType; // True if the backend supports operations on the half
|
bool HasLegalHalfType; // True if the backend supports operations on the half
|
||||||
// LLVM IR type.
|
// LLVM IR type.
|
||||||
bool HasFloat128;
|
bool HasFloat128;
|
||||||
|
bool HasFloat16;
|
||||||
unsigned char PointerWidth, PointerAlign;
|
unsigned char PointerWidth, PointerAlign;
|
||||||
unsigned char BoolWidth, BoolAlign;
|
unsigned char BoolWidth, BoolAlign;
|
||||||
unsigned char IntWidth, IntAlign;
|
unsigned char IntWidth, IntAlign;
|
||||||
|
@ -516,6 +517,9 @@ public:
|
||||||
/// Determine whether the __float128 type is supported on this target.
|
/// Determine whether the __float128 type is supported on this target.
|
||||||
virtual bool hasFloat128Type() const { return HasFloat128; }
|
virtual bool hasFloat128Type() const { return HasFloat128; }
|
||||||
|
|
||||||
|
/// Determine whether the _Float16 type is supported on this target.
|
||||||
|
virtual bool hasFloat16Type() const { return HasFloat16; }
|
||||||
|
|
||||||
/// Return the alignment that is suitable for storing any
|
/// Return the alignment that is suitable for storing any
|
||||||
/// object with a fundamental alignment requirement.
|
/// object with a fundamental alignment requirement.
|
||||||
unsigned getSuitableAlign() const { return SuitableAlign; }
|
unsigned getSuitableAlign() const { return SuitableAlign; }
|
||||||
|
|
|
@ -34,6 +34,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) {
|
||||||
NoAsmVariants = false;
|
NoAsmVariants = false;
|
||||||
HasLegalHalfType = false;
|
HasLegalHalfType = false;
|
||||||
HasFloat128 = false;
|
HasFloat128 = false;
|
||||||
|
HasFloat16 = false;
|
||||||
PointerWidth = PointerAlign = 32;
|
PointerWidth = PointerAlign = 32;
|
||||||
BoolWidth = BoolAlign = 8;
|
BoolWidth = BoolAlign = 8;
|
||||||
IntWidth = IntAlign = 32;
|
IntWidth = IntAlign = 32;
|
||||||
|
|
|
@ -49,6 +49,7 @@ AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple,
|
||||||
|
|
||||||
// All AArch64 implementations support ARMv8 FP, which makes half a legal type.
|
// All AArch64 implementations support ARMv8 FP, which makes half a legal type.
|
||||||
HasLegalHalfType = true;
|
HasLegalHalfType = true;
|
||||||
|
HasFloat16 = true;
|
||||||
|
|
||||||
LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
|
LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
|
||||||
MaxVectorAlign = 128;
|
MaxVectorAlign = 128;
|
||||||
|
|
|
@ -396,6 +396,7 @@ bool ARMTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
|
||||||
SoftFloat = SoftFloatABI = false;
|
SoftFloat = SoftFloatABI = false;
|
||||||
HWDiv = 0;
|
HWDiv = 0;
|
||||||
DotProd = 0;
|
DotProd = 0;
|
||||||
|
HasFloat16 = true;
|
||||||
|
|
||||||
// This does not diagnose illegal cases like having both
|
// This does not diagnose illegal cases like having both
|
||||||
// "+vfpv2" and "+vfpv3" or having "+neon" and "+fp-only-sp".
|
// "+vfpv2" and "+vfpv3" or having "+neon" and "+fp-only-sp".
|
||||||
|
|
|
@ -47,6 +47,7 @@ public:
|
||||||
AddrSpaceMap = &SPIRAddrSpaceMap;
|
AddrSpaceMap = &SPIRAddrSpaceMap;
|
||||||
UseAddrSpaceMapMangling = true;
|
UseAddrSpaceMapMangling = true;
|
||||||
HasLegalHalfType = true;
|
HasLegalHalfType = true;
|
||||||
|
HasFloat16 = true;
|
||||||
// Define available target features
|
// Define available target features
|
||||||
// These must be defined in sorted order!
|
// These must be defined in sorted order!
|
||||||
NoAsmVariants = true;
|
NoAsmVariants = true;
|
||||||
|
|
|
@ -1441,7 +1441,12 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
|
||||||
else
|
else
|
||||||
Result = Context.Int128Ty;
|
Result = Context.Int128Ty;
|
||||||
break;
|
break;
|
||||||
case DeclSpec::TST_float16: Result = Context.Float16Ty; break;
|
case DeclSpec::TST_float16:
|
||||||
|
if (!S.Context.getTargetInfo().hasFloat16Type())
|
||||||
|
S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported)
|
||||||
|
<< "_Float16";
|
||||||
|
Result = Context.Float16Ty;
|
||||||
|
break;
|
||||||
case DeclSpec::TST_half: Result = Context.HalfTy; break;
|
case DeclSpec::TST_half: Result = Context.HalfTy; break;
|
||||||
case DeclSpec::TST_float: Result = Context.FloatTy; break;
|
case DeclSpec::TST_float: Result = Context.FloatTy; break;
|
||||||
case DeclSpec::TST_double:
|
case DeclSpec::TST_double:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// RUN: %clang_cc1 -std=c++11 -ast-dump %s | FileCheck %s --strict-whitespace
|
// RUN: %clang_cc1 -std=c++11 -ast-dump -triple aarch64-linux-gnu %s | FileCheck %s --strict-whitespace
|
||||||
// RUN: %clang_cc1 -std=c++11 -ast-dump -fnative-half-type %s | FileCheck %s --check-prefix=CHECK-NATIVE --strict-whitespace
|
// RUN: %clang_cc1 -std=c++11 -ast-dump -triple aarch64-linux-gnu -fnative-half-type %s | FileCheck %s --check-prefix=CHECK-NATIVE --strict-whitespace
|
||||||
|
|
||||||
/* Various contexts where type _Float16 can appear. */
|
/* Various contexts where type _Float16 can appear. */
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
// RUN: %clang -std=c++11 --target=aarch64-arm--eabi -S -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-AARCH64
|
// RUN: %clang -std=c++11 --target=aarch64-arm--eabi -S -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-AARCH64
|
||||||
// RUN: %clang -std=c++11 --target=x86_64 -S -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-X86
|
|
||||||
|
|
||||||
/* Various contexts where type _Float16 can appear. */
|
/* Various contexts where type _Float16 can appear. */
|
||||||
|
|
||||||
|
@ -15,7 +14,6 @@ namespace {
|
||||||
|
|
||||||
_Float16 arr1n[10];
|
_Float16 arr1n[10];
|
||||||
// CHECK-AARCH64-DAG: @_ZN12_GLOBAL__N_15arr1nE = internal global [10 x half] zeroinitializer, align 2
|
// CHECK-AARCH64-DAG: @_ZN12_GLOBAL__N_15arr1nE = internal global [10 x half] zeroinitializer, align 2
|
||||||
// CHECK-X86-DAG: @_ZN12_GLOBAL__N_15arr1nE = internal global [10 x half] zeroinitializer, align 16
|
|
||||||
|
|
||||||
_Float16 arr2n[] = { 1.2, 3.0, 3.e4 };
|
_Float16 arr2n[] = { 1.2, 3.0, 3.e4 };
|
||||||
// CHECK-DAG: @_ZN12_GLOBAL__N_15arr2nE = internal global [3 x half] [half 0xH3CCD, half 0xH4200, half 0xH7753], align 2
|
// CHECK-DAG: @_ZN12_GLOBAL__N_15arr2nE = internal global [3 x half] [half 0xH3CCD, half 0xH4200, half 0xH7753], align 2
|
||||||
|
@ -30,14 +28,12 @@ namespace {
|
||||||
|
|
||||||
_Float16 f1f;
|
_Float16 f1f;
|
||||||
// CHECK-AARCH64-DAG: @f1f = dso_local global half 0xH0000, align 2
|
// CHECK-AARCH64-DAG: @f1f = dso_local global half 0xH0000, align 2
|
||||||
// CHECK-X86-DAG: @f1f = dso_local global half 0xH0000, align 2
|
|
||||||
|
|
||||||
_Float16 f2f = 32.4;
|
_Float16 f2f = 32.4;
|
||||||
// CHECK-DAG: @f2f = dso_local global half 0xH500D, align 2
|
// CHECK-DAG: @f2f = dso_local global half 0xH500D, align 2
|
||||||
|
|
||||||
_Float16 arr1f[10];
|
_Float16 arr1f[10];
|
||||||
// CHECK-AARCH64-DAG: @arr1f = dso_local global [10 x half] zeroinitializer, align 2
|
// CHECK-AARCH64-DAG: @arr1f = dso_local global [10 x half] zeroinitializer, align 2
|
||||||
// CHECK-X86-DAG: @arr1f = dso_local global [10 x half] zeroinitializer, align 16
|
|
||||||
|
|
||||||
_Float16 arr2f[] = { -1.2, -3.0, -3.e4 };
|
_Float16 arr2f[] = { -1.2, -3.0, -3.e4 };
|
||||||
// CHECK-DAG: @arr2f = dso_local global [3 x half] [half 0xHBCCD, half 0xHC200, half 0xHF753], align 2
|
// CHECK-DAG: @arr2f = dso_local global [3 x half] [half 0xHBCCD, half 0xHC200, half 0xHF753], align 2
|
||||||
|
@ -137,8 +133,6 @@ int main(void) {
|
||||||
long double cvtld = f2n;
|
long double cvtld = f2n;
|
||||||
//CHECK-AARCh64-DAG: [[H2LD:%[a-z0-9]+]] = fpext half {{%[0-9]+}} to fp128
|
//CHECK-AARCh64-DAG: [[H2LD:%[a-z0-9]+]] = fpext half {{%[0-9]+}} to fp128
|
||||||
//CHECK-AARCh64-DAG: store fp128 [[H2LD]], fp128* %{{.*}}, align 16
|
//CHECK-AARCh64-DAG: store fp128 [[H2LD]], fp128* %{{.*}}, align 16
|
||||||
//CHECK-X86-DAG: [[H2LD:%[a-z0-9]+]] = fpext half {{%[0-9]+}} to x86_fp80
|
|
||||||
//CHECK-X86-DAG: store x86_fp80 [[H2LD]], x86_fp80* %{{.*}}, align 16
|
|
||||||
|
|
||||||
_Float16 f2h = 42.0f;
|
_Float16 f2h = 42.0f;
|
||||||
//CHECK-DAG: store half 0xH5140, half* %{{.*}}, align 2
|
//CHECK-DAG: store half 0xH5140, half* %{{.*}}, align 2
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// RUN: %clang_cc1 -fblocks -emit-llvm %s -o - -triple=i386-pc-win32 -std=c++98 | FileCheck %s
|
// RUN: %clang_cc1 -fblocks -emit-llvm %s -o - -triple=i386-pc-win32 -std=c++98 | FileCheck %s
|
||||||
// RUN: %clang_cc1 -fblocks -emit-llvm %s -o - -triple=x86_64-pc-win32 -std=c++98| FileCheck -check-prefix X64 %s
|
// RUN: %clang_cc1 -fblocks -emit-llvm %s -o - -triple=x86_64-pc-win32 -std=c++98| FileCheck -check-prefix X64 %s
|
||||||
|
// RUN: %clang_cc1 -fblocks -emit-llvm %s -o - -triple=aarch64-pc-win32 -std=c++98 -DARM | FileCheck -check-prefixes=X64,ARM %s
|
||||||
|
|
||||||
int a;
|
int a;
|
||||||
// CHECK-DAG: @"?a@@3HA"
|
// CHECK-DAG: @"?a@@3HA"
|
||||||
|
@ -466,10 +467,12 @@ namespace Complex {
|
||||||
// CHECK-DAG: define dso_local void @"?f@Complex@@YAXU?$_Complex@H@__clang@@@Z"(
|
// CHECK-DAG: define dso_local void @"?f@Complex@@YAXU?$_Complex@H@__clang@@@Z"(
|
||||||
void f(_Complex int) {}
|
void f(_Complex int) {}
|
||||||
}
|
}
|
||||||
|
#ifdef ARM
|
||||||
namespace Float16 {
|
namespace Float16 {
|
||||||
// CHECK-DAG: define dso_local void @"?f@Float16@@YAXU_Float16@__clang@@@Z"(
|
// ARM-DAG: define dso_local void @"?f@Float16@@YAXU_Float16@__clang@@@Z"(
|
||||||
void f(_Float16) {}
|
void f(_Float16) {}
|
||||||
}
|
}
|
||||||
|
#endif // ARM
|
||||||
|
|
||||||
namespace PR26029 {
|
namespace PR26029 {
|
||||||
template <class>
|
template <class>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
|
// RUN: %clang_cc1 -fsyntax-only -verify -pedantic -triple aarch64-linux-gnu %s
|
||||||
float a = 1.0h; // expected-error{{no matching literal operator for call to 'operator""h' with argument of type 'long double' or 'const char *', and no matching literal operator template}}
|
float a = 1.0h; // expected-error{{no matching literal operator for call to 'operator""h' with argument of type 'long double' or 'const char *', and no matching literal operator template}}
|
||||||
float b = 1.0H; // expected-error{{invalid suffix 'H' on floating constant}}
|
float b = 1.0H; // expected-error{{invalid suffix 'H' on floating constant}}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-linux-pc %s
|
||||||
|
// RUN: %clang_cc1 -fsyntax-only -verify -triple spir-unknown-unknown %s -DHAVE
|
||||||
|
// RUN: %clang_cc1 -fsyntax-only -verify -triple armv7a-linux-gnu %s -DHAVE
|
||||||
|
// RUN: %clang_cc1 -fsyntax-only -verify -triple aarch64-linux-gnu %s -DHAVE
|
||||||
|
|
||||||
|
#ifdef HAVE
|
||||||
|
// expected-no-diagnostics
|
||||||
|
#else
|
||||||
|
// expected-error@+2{{_Float16 is not supported on this target}}
|
||||||
|
#endif // HAVE
|
||||||
|
_Float16 f;
|
Loading…
Reference in New Issue