8 changes: 6 additions & 2 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -714,8 +714,10 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
return ExprError();
E = Res.get();

// If this is a 'float' or '__fp16' (CVR qualified or typedef) promote to
// double.
// If this is a 'float' or '__fp16' (CVR qualified or typedef)
// promote to double.
// Note that default argument promotion applies only to float (and
// half/fp16); it does not apply to _Float16.
const BuiltinType *BTy = Ty->getAs<BuiltinType>();
if (BTy && (BTy->getKind() == BuiltinType::Half ||
BTy->getKind() == BuiltinType::Float)) {
Expand Down Expand Up @@ -3321,6 +3323,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
Ty = Context.FloatTy;
else if (Literal.isLong)
Ty = Context.LongDoubleTy;
else if (Literal.isFloat16)
Ty = Context.Float16Ty;
else if (Literal.isFloat128)
Ty = Context.Float128Ty;
else
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/SemaTemplateVariadic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
case TST_half:
case TST_float:
case TST_double:
case TST_Float16:
case TST_float128:
case TST_bool:
case TST_decimal32:
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1392,8 +1392,9 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
else
Result = Context.Int128Ty;
break;
case DeclSpec::TST_half: Result = Context.HalfTy; break;
case DeclSpec::TST_float: Result = Context.FloatTy; break;
case DeclSpec::TST_float16: Result = Context.Float16Ty; break;
case DeclSpec::TST_half: Result = Context.HalfTy; break;
case DeclSpec::TST_float: Result = Context.FloatTy; break;
case DeclSpec::TST_double:
if (DS.getTypeSpecWidth() == DeclSpec::TSW_long)
Result = Context.LongDoubleTy;
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Serialization/ASTCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) {
case BuiltinType::LongDouble:
ID = PREDEF_TYPE_LONGDOUBLE_ID;
break;
case BuiltinType::Float16:
ID = PREDEF_TYPE_FLOAT16_ID;
break;
case BuiltinType::Float128:
ID = PREDEF_TYPE_FLOAT128_ID;
break;
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6683,6 +6683,9 @@ QualType ASTReader::GetType(TypeID ID) {
case PREDEF_TYPE_LONGDOUBLE_ID:
T = Context.LongDoubleTy;
break;
case PREDEF_TYPE_FLOAT16_ID:
T = Context.Float16Ty;
break;
case PREDEF_TYPE_FLOAT128_ID:
T = Context.Float128Ty;
break;
Expand Down
156 changes: 156 additions & 0 deletions clang/test/CodeGenCXX/float16-declarations.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// 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. */


/* Namespace */

namespace {
_Float16 f1n;
// CHECK-DAG: @_ZN12_GLOBAL__N_13f1nE = internal global half 0xH0000, align 2

_Float16 f2n = 33.f16;
// CHECK-AARCH64-DAG: @_ZN12_GLOBAL__N_13f2nE = internal global half 0xH5020, align 2
// CHECK-X86-DAG: @_ZN12_GLOBAL__N_13f2nE = internal global i16 20512, align 2

_Float16 arr1n[10];
// 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 };
// CHECK-AARCH64-DAG: @_ZN12_GLOBAL__N_15arr2nE = internal global [3 x half] [half 0xH3CCD, half 0xH4200, half 0xH7753], align 2
// CHECK-X86-DAG: @_ZN12_GLOBAL__N_15arr2nE = internal global [3 x i16] [i16 15565, i16 16896, i16 30547], align 2

const volatile _Float16 func1n(const _Float16 &arg) {
return arg + f2n + arr1n[4] - arr2n[1];
}
}


/* File */

_Float16 f1f;
// CHECK-AARCH64-DAG: @f1f = global half 0xH0000, align 2
// CHECK-X86-DAG: @f1f = global half 0xH0000, align 2

_Float16 f2f = 32.4;
// CHECK-AARCH64-DAG: @f2f = global half 0xH500D, align 2
// CHECK-X86-DAG: @f2f = global i16 20493, align 2

_Float16 arr1f[10];
// CHECK-AARCH64-DAG: @arr1f = global [10 x half] zeroinitializer, align 2
// CHECK-X86-DAG: @arr1f = global [10 x half] zeroinitializer, align 16

_Float16 arr2f[] = { -1.2, -3.0, -3.e4 };
// CHECK-AARCH64-DAG: @arr2f = global [3 x half] [half 0xHBCCD, half 0xHC200, half 0xHF753], align 2
// CHECK-X86-DAG: @arr2f = global [3 x i16] [i16 -17203, i16 -15872, i16 -2221], align 2

_Float16 func1f(_Float16 arg);


/* Class */

class C1 {
_Float16 f1c;

static const _Float16 f2c;
// CHECK-DAG: @_ZN2C13f2cE = external constant half, align 2

volatile _Float16 f3c;

public:
C1(_Float16 arg) : f1c(arg), f3c(arg) { }
// Check that we mangle _Float16 to DF16_
// CHECK-DAG: define linkonce_odr void @_ZN2C1C2EDF16_(%class.C1* %this, half %arg)

_Float16 func1c(_Float16 arg ) {
return f1c + arg;
}
// CHECK-DAG: define linkonce_odr half @_ZN2C16func1cEDF16_(%class.C1* %this, half %arg)

static _Float16 func2c(_Float16 arg) {
return arg * C1::f2c;
}
// CHECK-DAG: define linkonce_odr half @_ZN2C16func2cEDF16_(half %arg)
};

/* Template */

template <class C> C func1t(C arg) {
return arg * 2.f16;
}
// CHECK-DAG: define linkonce_odr half @_Z6func1tIDF16_ET_S0_(half %arg)

template <class C> struct S1 {
C mem1;
};

template <> struct S1<_Float16> {
_Float16 mem2;
};


/* Local */

extern int printf (const char *__restrict __format, ...);

int main(void) {
_Float16 f1l = 1e3f16;
// CHECK-DAG: store half 0xH63D0, half* %f1l, align 2

_Float16 f2l = -0.f16;
// CHECK-DAG: store half 0xH8000, half* %f2l, align 2

_Float16 f3l = 1.000976562;
// CHECK-DAG: store half 0xH3C01, half* %f3l, align 2

C1 c1(f1l);
// CHECK-DAG: [[F1L:%[a-z0-9]+]] = load half, half* %f1l, align 2
// CHECK-DAG: call void @_ZN2C1C2EDF16_(%class.C1* %c1, half [[F1L]])

S1<_Float16> s1 = { 132.f16 };
// CHECK-AARCH64-DAG: @_ZZ4mainE2s1 = private unnamed_addr constant %struct.S1 { half 0xH5820 }, align 2
// CHECK-X86-DAG: @_ZZ4mainE2s1 = private unnamed_addr constant { i16 } { i16 22560 }, align 2
// CHECK-DAG: [[S1:%[0-9]+]] = bitcast %struct.S1* %s1 to i8*
// CHECK-AARCH64-DAG: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[S1]], i8* bitcast (%struct.S1* @_ZZ4mainE2s1 to i8*), i64 2, i32 2, i1 false)
// CHECK-X86-DAG: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* bitcast ({ i16 }* @_ZZ4mainE2s1 to i8*), i64 2, i32 2, i1 false)

_Float16 f4l = func1n(f1l) + func1f(f2l) + c1.func1c(f3l) + c1.func2c(f1l) +
func1t(f1l) + s1.mem2 - f1n + f2n;

auto f5l = -1.f16, *f6l = &f2l, f7l = func1t(f3l);
// CHECK-DAG: store half 0xHBC00, half* %f5l, align 2
// CHECK-DAG: store half* %f2l, half** %f6l, align 8

_Float16 f8l = f4l++;
// CHECK-DAG: [[F4L:%[a-z0-9]+]] = load half, half* %f4l, align 2
// CHECK-DAG: [[INC:%inc[0-9]*]] = fadd half [[F4L]], 0xH3C00
// CHECK-DAG: store half [[INC]], half* %f4l, align 2

_Float16 arr1l[] = { -1.f16, -0.f16, -11.f16 };
// CHECK-AARCH64-DAG: @_ZZ4mainE5arr1l = private unnamed_addr constant [3 x half] [half 0xHBC00, half 0xH8000, half 0xHC980], align 2
// CHECK-X86-DAG: @_ZZ4mainE5arr1l = private unnamed_addr constant [3 x i16] [i16 -17408, i16 -32768, i16 -13952], align 2

float cvtf = f2n;
//CHECK-DAG: [[H2F:%conv[0-9]*]] = fpext half {{%[0-9]+}} to float
//CHECK-DAG: store float [[H2F]], float* %cvtf, align 4

double cvtd = f2n;
//CHECK-DAG: [[H2D:%conv[0-9]*]] = fpext half {{%[0-9]+}} to double
//CHECK-DAG: store double [[H2D]], double* %cvtd, align 8


long double cvtld = f2n;
//CHECK-AARCh64-DAG: [[H2LD:%conv[0-9]*]] = fpext half {{%[0-9]+}} to fp128
//CHECK-AARCh64-DAG: store fp128 [[H2LD]], fp128* %cvtld, align 16
//CHECK-X86-DAG: [[H2LD:%conv[0-9]+]] = fpext half {{%[0-9]+}} to x86_fp80
//CHECK-X86-DAG: store x86_fp80 [[H2LD]], x86_fp80* %cvtld, align 16

_Float16 f2h = 42.0f;
//CHECK-DAG: store half 0xH5140, half* %f2h, align 2
_Float16 d2h = 42.0;
//CHECK-DAG: store half 0xH5140, half* %d2h, align 2
_Float16 ld2h = 42.0l;
//CHECK-DAG:store half 0xH5140, half* %ld2h, align 2
}
326 changes: 326 additions & 0 deletions clang/test/Frontend/float16.cpp

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions clang/test/Lexer/half-literal.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
float a = 1.0h; // expected-error{{invalid suffix 'h' on floating constant}}
float b = 1.0H; // expected-error{{invalid suffix 'H' on floating constant}}

_Float16 c = 1.f166; // expected-error{{invalid suffix 'f166' on floating constant}}
_Float16 d = 1.f1; // expected-error{{invalid suffix 'f1' on floating constant}}
4 changes: 3 additions & 1 deletion clang/tools/libclang/CXType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ static CXTypeKind GetBuiltinTypeKind(const BuiltinType *BT) {
BTCASE(Float);
BTCASE(Double);
BTCASE(LongDouble);
BTCASE(Float16);
BTCASE(Float128);
BTCASE(NullPtr);
BTCASE(Overload);
Expand Down Expand Up @@ -520,7 +521,7 @@ CXString clang_getTypeKindSpelling(enum CXTypeKind K) {
TKIND(Char_U);
TKIND(UChar);
TKIND(Char16);
TKIND(Char32);
TKIND(Char32);
TKIND(UShort);
TKIND(UInt);
TKIND(ULong);
Expand All @@ -538,6 +539,7 @@ CXString clang_getTypeKindSpelling(enum CXTypeKind K) {
TKIND(Float);
TKIND(Double);
TKIND(LongDouble);
TKIND(Float16);
TKIND(Float128);
TKIND(NullPtr);
TKIND(Overload);
Expand Down