From aa4a99b4a62615db243f7a5c433169f2fc704420 Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Fri, 14 Oct 2011 23:23:15 +0000 Subject: [PATCH] Provide half floating point support as a storage only type. Lack of half FP was a regression compared to llvm-gcc. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142016 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 1 + include/clang/AST/Type.h | 5 +- include/clang/Basic/DiagnosticSemaKinds.td | 2 + include/clang/Basic/Specifiers.h | 1 + include/clang/Basic/TargetInfo.h | 9 ++- include/clang/Basic/TokenKinds.def | 6 ++ include/clang/Sema/DeclSpec.h | 1 + include/clang/Serialization/ASTBitCodes.h | 4 +- lib/AST/ASTContext.cpp | 11 ++- lib/AST/ASTImporter.cpp | 1 + lib/AST/ItaniumMangle.cpp | 3 +- lib/AST/MicrosoftMangle.cpp | 1 + lib/AST/Type.cpp | 10 ++- lib/AST/TypeLoc.cpp | 3 +- lib/Analysis/PrintfFormatString.cpp | 1 + lib/Basic/TargetInfo.cpp | 3 + lib/CodeGen/CGDebugInfo.cpp | 1 + lib/CodeGen/CGExprConstant.cpp | 9 ++- lib/CodeGen/CGExprScalar.cpp | 79 ++++++++++++++++------ lib/CodeGen/CGRTTI.cpp | 1 + lib/CodeGen/CodeGenTypes.cpp | 10 +++ lib/Parse/ParseDecl.cpp | 10 +++ lib/Parse/ParseExpr.cpp | 1 + lib/Parse/ParseExprCXX.cpp | 4 ++ lib/Parse/ParseTentative.cpp | 2 + lib/Sema/DeclSpec.cpp | 2 + lib/Sema/SemaDecl.cpp | 5 +- lib/Sema/SemaExpr.cpp | 28 ++++++-- lib/Sema/SemaExprCXX.cpp | 6 ++ lib/Sema/SemaOverload.cpp | 9 ++- lib/Sema/SemaTemplateVariadic.cpp | 1 + lib/Sema/SemaType.cpp | 32 ++++++++- lib/Serialization/ASTCommon.cpp | 1 + lib/Serialization/ASTReader.cpp | 1 + tools/libclang/CIndex.cpp | 1 + tools/libclang/CIndexUSRs.cpp | 2 + 36 files changed, 224 insertions(+), 43 deletions(-) diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 616045c7b4..c4ffac5341 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -493,6 +493,7 @@ public: CanQualType UnsignedCharTy, UnsignedShortTy, UnsignedIntTy, UnsignedLongTy; CanQualType UnsignedLongLongTy, UnsignedInt128Ty; CanQualType FloatTy, DoubleTy, LongDoubleTy; + CanQualType HalfTy; // [OpenCL 6.1.1.1], ARM NEON CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy; CanQualType VoidPtrTy, NullPtrTy; CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy; diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 1e4b6a7402..dd9aa56ed1 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1392,6 +1392,7 @@ public: bool isComplexType() const; // C99 6.2.5p11 (complex) bool isAnyComplexType() const; // C99 6.2.5p11 (complex) + Complex Int. bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex) + bool isHalfType() const; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half) bool isRealType() const; // C99 6.2.5p17 (real floating + integer) bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating) bool isVoidType() const; // C99 6.2.5p19 @@ -1699,6 +1700,8 @@ public: LongLong, Int128, // __int128_t + Half, // This is the 'half' type in OpenCL, + // __fp16 in case of ARM NEON. Float, Double, LongDouble, NullPtr, // This is the type of C++0x 'nullptr'. @@ -1779,7 +1782,7 @@ public: } bool isFloatingPoint() const { - return getKind() >= Float && getKind() <= LongDouble; + return getKind() >= Half && getKind() <= LongDouble; } /// Determines whether this type is a placeholder type, i.e. a type diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 4051a80638..0fbf0cee0a 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -312,6 +312,8 @@ def err_statically_allocated_object : Error< def err_object_cannot_be_passed_returned_by_value : Error< "interface type %1 cannot be %select{returned|passed}0 by value" "; did you forget * in %1">; +def err_parameters_retval_cannot_have_fp16_type : Error< + "%select{parameters|function return value}0 cannot have __fp16 type; did you forget * ?">; def warn_enum_value_overflow : Warning<"overflow in enumeration value">; def warn_pragma_options_align_unsupported_option : Warning< "unsupported alignment option in '#pragma options align'">; diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h index 1e89a8c817..2a95d6165c 100644 --- a/include/clang/Basic/Specifiers.h +++ b/include/clang/Basic/Specifiers.h @@ -40,6 +40,7 @@ namespace clang { TST_char16, // C++0x char16_t TST_char32, // C++0x char32_t TST_int, + TST_half, // OpenCL half, ARM NEON __fp16 TST_float, TST_double, TST_bool, // _Bool diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index 0a7d2f1ea0..a87af2fbbc 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -69,6 +69,7 @@ protected: unsigned char PointerWidth, PointerAlign; unsigned char BoolWidth, BoolAlign; unsigned char IntWidth, IntAlign; + unsigned char HalfWidth, HalfAlign; unsigned char FloatWidth, FloatAlign; unsigned char DoubleWidth, DoubleAlign; unsigned char LongDoubleWidth, LongDoubleAlign; @@ -79,7 +80,8 @@ protected: const char *DescriptionString; const char *UserLabelPrefix; const char *MCountName; - const llvm::fltSemantics *FloatFormat, *DoubleFormat, *LongDoubleFormat; + const llvm::fltSemantics *HalfFormat, *FloatFormat, *DoubleFormat, + *LongDoubleFormat; unsigned char RegParmMax, SSERegParmMax; TargetCXXABI CXXABI; const LangAS::Map *AddrSpaceMap; @@ -224,6 +226,11 @@ public: unsigned getChar32Width() const { return getTypeWidth(Char32Type); } unsigned getChar32Align() const { return getTypeAlign(Char32Type); } + /// getHalfWidth/Align/Format - Return the size/align/format of 'half'. + unsigned getHalfWidth() const { return HalfWidth; } + unsigned getHalfAlign() const { return HalfAlign; } + const llvm::fltSemantics &getHalfFormat() const { return *HalfFormat; } + /// getFloatWidth/Align/Format - Return the size/align/format of 'float'. unsigned getFloatWidth() const { return FloatWidth; } unsigned getFloatAlign() const { return FloatAlign; } diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 151a75d1e7..35a881c660 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -441,6 +441,12 @@ KEYWORD(__pascal , KEYALL) KEYWORD(__vector , KEYALTIVEC) KEYWORD(__pixel , KEYALTIVEC) +// ARM NEON extensions. +ALIAS("__fp16", half , KEYALL) + +// OpenCL Extension. +KEYWORD(half , KEYOPENCL) + // Objective-C ARC keywords. KEYWORD(__bridge , KEYARC) KEYWORD(__bridge_transfer , KEYARC) diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index 1ed45cbf4c..3260a70ebb 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -243,6 +243,7 @@ public: static const TST TST_char16 = clang::TST_char16; static const TST TST_char32 = clang::TST_char32; static const TST TST_int = clang::TST_int; + static const TST TST_half = clang::TST_half; static const TST TST_float = clang::TST_float; static const TST TST_double = clang::TST_double; static const TST TST_bool = clang::TST_bool; diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 1efd754217..dc4d05c6f3 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -552,7 +552,9 @@ namespace clang { /// \brief The "auto" deduction type. PREDEF_TYPE_AUTO_DEDUCT = 31, /// \brief The "auto &&" deduction type. - PREDEF_TYPE_AUTO_RREF_DEDUCT = 32 + PREDEF_TYPE_AUTO_RREF_DEDUCT = 32, + /// \brief The OpenCL 'half' / ARM NEON __fp16 type. + PREDEF_TYPE_HALF_ID = 33 }; /// \brief The number of predefined type IDs that are reserved for diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index ae96dfd148..462428086d 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -50,7 +50,7 @@ unsigned ASTContext::NumImplicitDestructors; unsigned ASTContext::NumImplicitDestructorsDeclared; enum FloatingRank { - FloatRank, DoubleRank, LongDoubleRank + HalfRank, FloatRank, DoubleRank, LongDoubleRank }; void @@ -483,6 +483,9 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) { // nullptr type (C++0x 2.14.7) InitBuiltinType(NullPtrTy, BuiltinType::NullPtr); + + // half type (OpenCL 6.1.1.1) / ARM NEON __fp16 + InitBuiltinType(HalfTy, BuiltinType::Half); } DiagnosticsEngine &ASTContext::getDiagnostics() const { @@ -683,6 +686,7 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { assert(BT && "Not a floating point type!"); switch (BT->getKind()) { default: llvm_unreachable("Not a floating point type!"); + case BuiltinType::Half: return Target->getHalfFormat(); case BuiltinType::Float: return Target->getFloatFormat(); case BuiltinType::Double: return Target->getDoubleFormat(); case BuiltinType::LongDouble: return Target->getLongDoubleFormat(); @@ -905,6 +909,10 @@ ASTContext::getTypeInfo(const Type *T) const { Width = 128; Align = 128; // int128_t is 128-bit aligned on all targets. break; + case BuiltinType::Half: + Width = Target->getHalfWidth(); + Align = Target->getHalfAlign(); + break; case BuiltinType::Float: Width = Target->getFloatWidth(); Align = Target->getFloatAlign(); @@ -3483,6 +3491,7 @@ static FloatingRank getFloatingRank(QualType T) { assert(T->getAs() && "getFloatingRank(): not a floating type"); switch (T->getAs()->getKind()) { default: llvm_unreachable("getFloatingRank(): not a floating type"); + case BuiltinType::Half: return HalfRank; case BuiltinType::Float: return FloatRank; case BuiltinType::Double: return DoubleRank; case BuiltinType::LongDouble: return LongDoubleRank; diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index ab5c8cf5fe..3db75bacbf 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -1374,6 +1374,7 @@ QualType ASTNodeImporter::VisitBuiltinType(const BuiltinType *T) { case BuiltinType::Long : return Importer.getToContext().LongTy; case BuiltinType::LongLong : return Importer.getToContext().LongLongTy; case BuiltinType::Int128 : return Importer.getToContext().Int128Ty; + case BuiltinType::Half: return Importer.getToContext().HalfTy; case BuiltinType::Float: return Importer.getToContext().FloatTy; case BuiltinType::Double: return Importer.getToContext().DoubleTy; case BuiltinType::LongDouble: return Importer.getToContext().LongDoubleTy; diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index d4ac7229b2..acedf70f29 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -1704,7 +1704,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { // UNSUPPORTED: ::= Dd # IEEE 754r decimal floating point (64 bits) // UNSUPPORTED: ::= De # IEEE 754r decimal floating point (128 bits) // UNSUPPORTED: ::= Df # IEEE 754r decimal floating point (32 bits) - // UNSUPPORTED: ::= Dh # IEEE 754r half-precision floating point (16 bits) + // ::= Dh # IEEE 754r half-precision floating point (16 bits) // ::= Di # char32_t // ::= Ds # char16_t // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) @@ -1729,6 +1729,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { case BuiltinType::Long: Out << 'l'; break; case BuiltinType::LongLong: Out << 'x'; break; case BuiltinType::Int128: Out << 'n'; break; + case BuiltinType::Half: Out << "Dh"; break; case BuiltinType::Float: Out << 'f'; break; case BuiltinType::Double: Out << 'd'; break; case BuiltinType::LongDouble: Out << 'e'; break; diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index e327d8b180..1515db49fe 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -713,6 +713,7 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T) { case BuiltinType::Char16: case BuiltinType::Char32: + case BuiltinType::Half: case BuiltinType::NullPtr: llvm_unreachable("Don't know how to mangle this type"); } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 0e0548db6c..44eeec004f 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -766,9 +766,16 @@ bool Type::hasUnsignedIntegerRepresentation() const { return isUnsignedIntegerType(); } +bool Type::isHalfType() const { + if (const BuiltinType *BT = dyn_cast(CanonicalType)) + return BT->getKind() == BuiltinType::Half; + // FIXME: Should we allow complex __fp16? Probably not. + return false; +} + bool Type::isFloatingType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) - return BT->getKind() >= BuiltinType::Float && + return BT->getKind() >= BuiltinType::Half && BT->getKind() <= BuiltinType::LongDouble; if (const ComplexType *CT = dyn_cast(CanonicalType)) return CT->getElementType()->isFloatingType(); @@ -1475,6 +1482,7 @@ const char *BuiltinType::getName(const PrintingPolicy &Policy) const { case ULong: return "unsigned long"; case ULongLong: return "unsigned long long"; case UInt128: return "__uint128_t"; + case Half: return "half"; case Float: return "float"; case Double: return "double"; case LongDouble: return "long double"; diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index 34e7693e30..8e8b227e1f 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -206,7 +206,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { case BuiltinType::Char_S: return TST_char; case BuiltinType::Char16: - return TST_char16; + return TST_char16; case BuiltinType::Char32: return TST_char32; case BuiltinType::WChar_S: @@ -225,6 +225,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { case BuiltinType::Long: case BuiltinType::LongLong: case BuiltinType::Int128: + case BuiltinType::Half: case BuiltinType::Float: case BuiltinType::Double: case BuiltinType::LongDouble: diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp index 770cd37e9c..46ece65a42 100644 --- a/lib/Analysis/PrintfFormatString.cpp +++ b/lib/Analysis/PrintfFormatString.cpp @@ -387,6 +387,7 @@ bool PrintfSpecifier::fixType(QualType QT) { case BuiltinType::Char32: case BuiltinType::UInt128: case BuiltinType::Int128: + case BuiltinType::Half: // Integral types which are non-trivial to correct. return false; diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index a9285e6e2d..593db2b901 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -34,6 +34,8 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { IntWidth = IntAlign = 32; LongWidth = LongAlign = 32; LongLongWidth = LongLongAlign = 64; + HalfWidth = 16; + HalfAlign = 16; FloatWidth = 32; FloatAlign = 32; DoubleWidth = 64; @@ -57,6 +59,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { UseBitFieldTypeAlignment = true; UseZeroLengthBitfieldAlignment = false; ZeroLengthBitfieldBoundary = 0; + HalfFormat = &llvm::APFloat::IEEEhalf; FloatFormat = &llvm::APFloat::IEEEsingle; DoubleFormat = &llvm::APFloat::IEEEdouble; LongDoubleFormat = &llvm::APFloat::IEEEdouble; diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 39a9ef788f..c7a9b407d2 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -391,6 +391,7 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) { case BuiltinType::WChar_S: case BuiltinType::LongLong: Encoding = llvm::dwarf::DW_ATE_signed; break; case BuiltinType::Bool: Encoding = llvm::dwarf::DW_ATE_boolean; break; + case BuiltinType::Half: case BuiltinType::Float: case BuiltinType::LongDouble: case BuiltinType::Double: Encoding = llvm::dwarf::DW_ATE_float; break; diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 8711c1fdd5..3997866ea6 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -1026,8 +1026,13 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, NULL); return llvm::ConstantStruct::get(STy, Complex); } - case APValue::Float: - return llvm::ConstantFP::get(VMContext, Result.Val.getFloat()); + case APValue::Float: { + const llvm::APFloat &Init = Result.Val.getFloat(); + if (&Init.getSemantics() == &llvm::APFloat::IEEEhalf) + return llvm::ConstantInt::get(VMContext, Init.bitcastToAPInt()); + else + return llvm::ConstantFP::get(VMContext, Init); + } case APValue::ComplexFloat: { llvm::Constant *Complex[2]; diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 26a3e948ef..3a9fbeed9d 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -552,6 +552,16 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, if (DstType->isVoidType()) return 0; + llvm::Type *SrcTy = Src->getType(); + + // Floating casts might be a bit special: if we're doing casts to / from half + // FP, we should go via special intrinsics. + if (SrcType->isHalfType()) { + Src = Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16), Src); + SrcType = CGF.getContext().FloatTy; + SrcTy = llvm::Type::getFloatTy(VMContext); + } + // Handle conversions to bool first, they are special: comparisons against 0. if (DstType->isBooleanType()) return EmitConversionToBool(Src, SrcType); @@ -559,7 +569,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, llvm::Type *DstTy = ConvertType(DstType); // Ignore conversions like int -> uint. - if (Src->getType() == DstTy) + if (SrcTy == DstTy) return Src; // Handle pointer conversions next: pointers can only be converted to/from @@ -567,7 +577,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, // some native types (like Obj-C id) may map to a pointer type. if (isa(DstTy)) { // The source value may be an integer, or a pointer. - if (isa(Src->getType())) + if (isa(SrcTy)) return Builder.CreateBitCast(Src, DstTy, "conv"); assert(SrcType->isIntegerType() && "Not ptr->ptr or int->ptr conversion?"); @@ -581,7 +591,7 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, return Builder.CreateIntToPtr(IntResult, DstTy, "conv"); } - if (isa(Src->getType())) { + if (isa(SrcTy)) { // Must be an ptr to int cast. assert(isa(DstTy) && "not ptr->int?"); return Builder.CreatePtrToInt(Src, DstTy, "conv"); @@ -610,34 +620,47 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, } // Allow bitcast from vector to integer/fp of the same size. - if (isa(Src->getType()) || + if (isa(SrcTy) || isa(DstTy)) return Builder.CreateBitCast(Src, DstTy, "conv"); // Finally, we have the arithmetic types: real int/float. - if (isa(Src->getType())) { + Value *Res = NULL; + llvm::Type *ResTy = DstTy; + + // Cast to half via float + if (DstType->isHalfType()) + DstTy = llvm::Type::getFloatTy(VMContext); + + if (isa(SrcTy)) { bool InputSigned = SrcType->isSignedIntegerOrEnumerationType(); if (isa(DstTy)) - return Builder.CreateIntCast(Src, DstTy, InputSigned, "conv"); + Res = Builder.CreateIntCast(Src, DstTy, InputSigned, "conv"); else if (InputSigned) - return Builder.CreateSIToFP(Src, DstTy, "conv"); + Res = Builder.CreateSIToFP(Src, DstTy, "conv"); else - return Builder.CreateUIToFP(Src, DstTy, "conv"); - } - - assert(Src->getType()->isFloatingPointTy() && "Unknown real conversion"); - if (isa(DstTy)) { + Res = Builder.CreateUIToFP(Src, DstTy, "conv"); + } else if (isa(DstTy)) { + assert(SrcTy->isFloatingPointTy() && "Unknown real conversion"); if (DstType->isSignedIntegerOrEnumerationType()) - return Builder.CreateFPToSI(Src, DstTy, "conv"); + Res = Builder.CreateFPToSI(Src, DstTy, "conv"); else - return Builder.CreateFPToUI(Src, DstTy, "conv"); + Res = Builder.CreateFPToUI(Src, DstTy, "conv"); + } else { + assert(SrcTy->isFloatingPointTy() && DstTy->isFloatingPointTy() && + "Unknown real conversion"); + if (DstTy->getTypeID() < SrcTy->getTypeID()) + Res = Builder.CreateFPTrunc(Src, DstTy, "conv"); + else + Res = Builder.CreateFPExt(Src, DstTy, "conv"); } - assert(DstTy->isFloatingPointTy() && "Unknown real conversion"); - if (DstTy->getTypeID() < Src->getType()->getTypeID()) - return Builder.CreateFPTrunc(Src, DstTy, "conv"); - else - return Builder.CreateFPExt(Src, DstTy, "conv"); + if (DstTy != ResTy) { + assert(ResTy->isIntegerTy(16) && "Only half FP requires extra conversion"); + Res = Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16), Res); + } + + return Res; } /// EmitComplexToScalarConversion - Emit a conversion from the specified complex @@ -1202,7 +1225,6 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { case CK_FloatingToIntegral: case CK_FloatingCast: return EmitScalarConversion(Visit(E), E->getType(), DestTy); - case CK_IntegralToBoolean: return EmitIntToBoolConversion(Visit(E)); case CK_PointerToBoolean: @@ -1356,6 +1378,14 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, } else if (type->isRealFloatingType()) { // Add the inc/dec to the real part. llvm::Value *amt; + + if (type->isHalfType()) { + // Another special case: half FP increment should be done via float + value = + Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16), + input); + } + if (value->getType()->isFloatTy()) amt = llvm::ConstantFP::get(VMContext, llvm::APFloat(static_cast(amount))); @@ -1371,6 +1401,11 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, } value = Builder.CreateFAdd(value, amt, isInc ? "inc" : "dec"); + if (type->isHalfType()) + value = + Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16), + value); + // Objective-C pointer types. } else { const ObjCObjectPointerType *OPT = type->castAs(); @@ -1387,13 +1422,13 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, value = Builder.CreateInBoundsGEP(value, sizeValue, "incdec.objptr"); value = Builder.CreateBitCast(value, input->getType()); } - + // Store the updated result through the lvalue. if (LV.isBitField()) CGF.EmitStoreThroughBitfieldLValue(RValue::get(value), LV, &value); else CGF.EmitStoreThroughLValue(RValue::get(value), LV); - + // If this is a postinc, return the value read from memory, otherwise use the // updated value. return isPre ? value : input; diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp index dbf99fa5d7..fbdb298483 100644 --- a/lib/CodeGen/CGRTTI.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -185,6 +185,7 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) { case BuiltinType::ULong: case BuiltinType::LongLong: case BuiltinType::ULongLong: + case BuiltinType::Half: case BuiltinType::Float: case BuiltinType::Double: case BuiltinType::LongDouble: diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index 03a15ae67e..e0d9218965 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -263,6 +263,8 @@ void CodeGenTypes::UpdateCompletedType(const TagDecl *TD) { static llvm::Type *getTypeForFormat(llvm::LLVMContext &VMContext, const llvm::fltSemantics &format) { + if (&format == &llvm::APFloat::IEEEhalf) + return llvm::Type::getInt16Ty(VMContext); if (&format == &llvm::APFloat::IEEEsingle) return llvm::Type::getFloatTy(VMContext); if (&format == &llvm::APFloat::IEEEdouble) @@ -341,6 +343,14 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { static_cast(Context.getTypeSize(T))); break; + case BuiltinType::Half: + // Half is special: it might be lowered to i16 (and will be storage-only + // type),. or can be represented as a set of native operations. + + // FIXME: Ask target which kind of half FP it prefers (storage only vs + // native). + ResultType = llvm::Type::getInt16Ty(getLLVMContext()); + break; case BuiltinType::Float: case BuiltinType::Double: case BuiltinType::LongDouble: diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 228e53c4f0..2aa178f5eb 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2075,6 +2075,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID); break; + case tok::kw_half: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, + DiagID); + break; case tok::kw_float: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID); @@ -2383,6 +2387,9 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, case tok::kw_int: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID); break; + case tok::kw_half: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID); + break; case tok::kw_float: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID); break; @@ -3116,6 +3123,7 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const { case tok::kw_char16_t: case tok::kw_char32_t: case tok::kw_int: + case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw_bool: @@ -3185,6 +3193,7 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw_char16_t: case tok::kw_char32_t: case tok::kw_int: + case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw_bool: @@ -3319,6 +3328,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw_char32_t: case tok::kw_int: + case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw_bool: diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 548a599f6e..bc8bbf5640 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -920,6 +920,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___int64: case tok::kw_signed: case tok::kw_unsigned: + case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw_void: diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 6e36c91a09..60166e880c 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -1239,6 +1239,7 @@ bool Parser::isCXXSimpleTypeSpecifier() const { case tok::kw_void: case tok::kw_char: case tok::kw_int: + case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw_wchar_t: @@ -1343,6 +1344,9 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { case tok::kw_int: DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec, DiagID); break; + case tok::kw_half: + DS.SetTypeSpecType(DeclSpec::TST_half, Loc, PrevSpec, DiagID); + break; case tok::kw_float: DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec, DiagID); break; diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 0e7d288395..d53839f3cb 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -685,6 +685,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw_const: case tok::kw_double: case tok::kw_enum: + case tok::kw_half: case tok::kw_float: case tok::kw_int: case tok::kw_long: @@ -994,6 +995,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw___int64: case tok::kw_signed: case tok::kw_unsigned: + case tok::kw_half: case tok::kw_float: case tok::kw_double: case tok::kw_void: diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index 3564f2657b..f0a763e4ec 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -257,6 +257,7 @@ bool Declarator::isDeclarationOfFunction() const { case TST_enum: case TST_error: case TST_float: + case TST_half: case TST_int: case TST_struct: case TST_union: @@ -373,6 +374,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { case DeclSpec::TST_char16: return "char16_t"; case DeclSpec::TST_char32: return "char32_t"; case DeclSpec::TST_int: return "int"; + case DeclSpec::TST_half: return "half"; case DeclSpec::TST_float: return "float"; case DeclSpec::TST_double: return "double"; case DeclSpec::TST_bool: return "_Bool"; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 71b3c526a1..8d993ef610 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4729,7 +4729,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, diag::err_object_cannot_be_passed_returned_by_value) << 0 << R->getAs()->getResultType() << FixItHint::CreateInsertion(D.getIdentifierLoc(), "*"); - + QualType T = R->getAs()->getResultType(); T = Context.getObjCObjectPointerType(T); if (const FunctionProtoType *FPT = dyn_cast(R)) { @@ -4740,7 +4740,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, else if (isa(R)) R = Context.getFunctionNoProtoType(T); } - + bool isFriend = false; FunctionTemplateDecl *FunctionTemplate = 0; bool isExplicitSpecialization = false; @@ -5065,6 +5065,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, assert(R->isFunctionNoProtoType() && NewFD->getNumParams() == 0 && "Should not need args for typedef of non-prototype fn"); } + // Finally, we know we have the right number of parameters, install them. NewFD->setParams(Params); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 41fcf7299d..170097cc59 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -396,12 +396,14 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { // C99 6.3.2.1p2: // If the lvalue has qualified type, the value has the unqualified // version of the type of the lvalue; otherwise, the value has the - // type of the lvalue. + // type of the lvalue. if (T.hasQualifiers()) T = T.getUnqualifiedType(); - - return Owned(ImplicitCastExpr::Create(Context, T, CK_LValueToRValue, - E, 0, VK_RValue)); + + ExprResult Res = Owned(ImplicitCastExpr::Create(Context, T, CK_LValueToRValue, + E, 0, VK_RValue)); + + return Res; } ExprResult Sema::DefaultFunctionArrayLvalueConversion(Expr *E) { @@ -426,10 +428,15 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) { if (Res.isInvalid()) return Owned(E); E = Res.take(); - + QualType Ty = E->getType(); assert(!Ty.isNull() && "UsualUnaryConversions - missing type"); - + + // Half FP is a bit different: it's a storage-only type, meaning that any + // "use" of it should be promoted to float. + if (Ty->isHalfType()) + return ImpCastExprToType(Res.take(), Context.FloatTy, CK_FloatingCast); + // Try to perform integral promotions if the object has a theoretically // promotable type. if (Ty->isIntegralOrUnscopedEnumerationType()) { @@ -446,7 +453,7 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) { // value is converted to an int; otherwise, it is converted to an // unsigned int. These are called the integer promotions. All // other types are unchanged by the integer promotions. - + QualType PTy = Context.isPromotableBitField(E); if (!PTy.isNull()) { E = ImpCastExprToType(E, PTy, CK_IntegralCast).take(); @@ -8103,6 +8110,13 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, Input = DefaultFunctionArrayLvalueConversion(Input.take()); if (Input.isInvalid()) return ExprError(); resultType = Input.get()->getType(); + + // Though we still have to promote half FP to float... + if (resultType->isHalfType()) { + Input = ImpCastExprToType(Input.take(), Context.FloatTy, CK_FloatingCast).take(); + resultType = Context.FloatTy; + } + if (resultType->isDependentType()) break; if (resultType->isScalarType()) { diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index d3c4da8816..3300444a1c 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -2416,6 +2416,12 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, } case ICK_Boolean_Conversion: + // Perform half-to-boolean conversion via float. + if (From->getType()->isHalfType()) { + From = ImpCastExprToType(From, Context.FloatTy, CK_FloatingCast).take(); + FromType = Context.FloatTy; + } + From = ImpCastExprToType(From, Context.BoolTy, ScalarTypeToBooleanCastKind(FromType), VK_RValue, /*BasePath=*/0, CCK).take(); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 6112e0d418..b0dd5e280e 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1469,10 +1469,10 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { /// FromType to ToType is a floating point promotion (C++ 4.6). If so, /// returns true and sets PromotedType to the promoted type. bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) { - /// An rvalue of type float can be converted to an rvalue of type - /// double. (C++ 4.6p1). if (const BuiltinType *FromBuiltin = FromType->getAs()) if (const BuiltinType *ToBuiltin = ToType->getAs()) { + /// An rvalue of type float can be converted to an rvalue of type + /// double. (C++ 4.6p1). if (FromBuiltin->getKind() == BuiltinType::Float && ToBuiltin->getKind() == BuiltinType::Double) return true; @@ -1485,6 +1485,11 @@ bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) { FromBuiltin->getKind() == BuiltinType::Double) && (ToBuiltin->getKind() == BuiltinType::LongDouble)) return true; + + // Half can be promoted to float. + if (FromBuiltin->getKind() == BuiltinType::Half && + ToBuiltin->getKind() == BuiltinType::Float) + return true; } return false; diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index a2aa1b3026..e383db9350 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -641,6 +641,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_char16: case TST_char32: case TST_int: + case TST_half: case TST_float: case TST_double: case TST_bool: diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index dc08320cad..2b563a50a9 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -711,6 +711,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } 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) @@ -1434,13 +1435,26 @@ QualType Sema::BuildFunctionType(QualType T, << T->isFunctionType() << T; return QualType(); } - + + // Functions cannot return half FP. + if (T->isHalfType()) { + Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 1 << + FixItHint::CreateInsertion(Loc, "*"); + return QualType(); + } + bool Invalid = false; for (unsigned Idx = 0; Idx < NumParamTypes; ++Idx) { + // FIXME: Loc is too inprecise here, should use proper locations for args. QualType ParamType = Context.getAdjustedParameterType(ParamTypes[Idx]); if (ParamType->isVoidType()) { Diag(Loc, diag::err_param_with_void_type); Invalid = true; + } else if (ParamType->isHalfType()) { + // Disallow half FP arguments. + Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 0 << + FixItHint::CreateInsertion(Loc, "*"); + Invalid = true; } ParamTypes[Idx] = ParamType; @@ -2062,6 +2076,15 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, D.setInvalidType(true); } + // Do not allow returning half FP value. + // FIXME: This really should be in BuildFunctionType. + if (T->isHalfType()) { + S.Diag(D.getIdentifierLoc(), + diag::err_parameters_retval_cannot_have_fp16_type) << 1 + << FixItHint::CreateInsertion(D.getIdentifierLoc(), "*"); + D.setInvalidType(true); + } + // cv-qualifiers on return types are pointless except when the type is a // class type in C++. if (isa(T) && T.getLocalCVRQualifiers() && @@ -2185,6 +2208,13 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Do not add 'void' to the ArgTys list. break; } + } else if (ArgTy->isHalfType()) { + // Disallow half FP arguments. + // FIXME: This really should be in BuildFunctionType. + S.Diag(Param->getLocation(), + diag::err_parameters_retval_cannot_have_fp16_type) << 0 + << FixItHint::CreateInsertion(Param->getLocation(), "*"); + D.setInvalidType(); } else if (!FTI.hasPrototype) { if (ArgTy->isPromotableIntegerType()) { ArgTy = Context.getPromotedIntegerType(ArgTy); diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp index 782e5c6aa7..445e750834 100644 --- a/lib/Serialization/ASTCommon.cpp +++ b/lib/Serialization/ASTCommon.cpp @@ -43,6 +43,7 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) { case BuiltinType::Long: ID = PREDEF_TYPE_LONG_ID; break; case BuiltinType::LongLong: ID = PREDEF_TYPE_LONGLONG_ID; break; case BuiltinType::Int128: ID = PREDEF_TYPE_INT128_ID; break; + case BuiltinType::Half: ID = PREDEF_TYPE_HALF_ID; break; case BuiltinType::Float: ID = PREDEF_TYPE_FLOAT_ID; break; case BuiltinType::Double: ID = PREDEF_TYPE_DOUBLE_ID; break; case BuiltinType::LongDouble: ID = PREDEF_TYPE_LONGDOUBLE_ID; break; diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 361c3b79ca..fe1cc30158 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -3819,6 +3819,7 @@ QualType ASTReader::GetType(TypeID ID) { case PREDEF_TYPE_LONG_ID: T = Context.LongTy; break; case PREDEF_TYPE_LONGLONG_ID: T = Context.LongLongTy; break; case PREDEF_TYPE_INT128_ID: T = Context.Int128Ty; break; + case PREDEF_TYPE_HALF_ID: T = Context.HalfTy; break; case PREDEF_TYPE_FLOAT_ID: T = Context.FloatTy; break; case PREDEF_TYPE_DOUBLE_ID: T = Context.DoubleTy; break; case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break; diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 5748d6bdb7..46ba3d5534 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -1359,6 +1359,7 @@ bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { case BuiltinType::Long: case BuiltinType::LongLong: case BuiltinType::Int128: + case BuiltinType::Half: case BuiltinType::Float: case BuiltinType::Double: case BuiltinType::LongDouble: diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp index 416711e9d5..121d67d1d2 100644 --- a/tools/libclang/CIndexUSRs.cpp +++ b/tools/libclang/CIndexUSRs.cpp @@ -570,6 +570,8 @@ void USRGenerator::VisitType(QualType T) { c = 'K'; break; case BuiltinType::Int128: c = 'J'; break; + case BuiltinType::Half: + c = 'h'; break; case BuiltinType::Float: c = 'f'; break; case BuiltinType::Double: -- 2.40.0