From: Nemanja Ivanovic Date: Wed, 13 Apr 2016 09:49:45 +0000 (+0000) Subject: Enable support for __float128 in Clang X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b2ea6d9a87774e9d5a9c285927cb51ccd77f7354;p=clang Enable support for __float128 in Clang This patch corresponds to review: http://reviews.llvm.org/D15120 It adds support for the __float128 keyword, literals and a target feature to enable it. This support is disabled by default on all targets and any target that has support for this type is free to add it. Based on feedback that I've received from target maintainers, this appears to be the right thing for most targets. I have not heard from the maintainers of X86 which I believe supports this type. I will subsequently investigate the impact of enabling this on X86. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@266186 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py index 4d450eca18..dac71916d3 100644 --- a/bindings/python/clang/cindex.py +++ b/bindings/python/clang/cindex.py @@ -1685,6 +1685,7 @@ TypeKind.DEPENDENT = TypeKind(26) TypeKind.OBJCID = TypeKind(27) TypeKind.OBJCCLASS = TypeKind(28) TypeKind.OBJCSEL = TypeKind(29) +TypeKind.FLOAT128 = TypeKind(30) TypeKind.COMPLEX = TypeKind(100) TypeKind.POINTER = TypeKind(101) TypeKind.BLOCKPOINTER = TypeKind(102) diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 9c9bc7a998..e9f93364af 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -2929,6 +2929,7 @@ enum CXTypeKind { CXType_ObjCId = 27, CXType_ObjCClass = 28, CXType_ObjCSel = 29, + CXType_Float128 = 30, CXType_FirstBuiltin = CXType_Void, CXType_LastBuiltin = CXType_ObjCSel, diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index e04d976441..4e4a98d801 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -893,9 +893,10 @@ public: CanQualType SignedCharTy, ShortTy, IntTy, LongTy, LongLongTy, Int128Ty; CanQualType UnsignedCharTy, UnsignedShortTy, UnsignedIntTy, UnsignedLongTy; CanQualType UnsignedLongLongTy, UnsignedInt128Ty; - CanQualType FloatTy, DoubleTy, LongDoubleTy; + CanQualType FloatTy, DoubleTy, LongDoubleTy, Float128Ty; CanQualType HalfTy; // [OpenCL 6.1.1.1], ARM NEON CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy; + CanQualType Float128ComplexTy; CanQualType VoidPtrTy, NullPtrTy; CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy; CanQualType BuiltinFnTy; @@ -968,9 +969,6 @@ public: /// \brief Retrieve the declaration for the 128-bit unsigned integer type. TypedefDecl *getUInt128Decl() const; - /// \brief Retrieve the declaration for a 128-bit float stub type. - TypeDecl *getFloat128StubType() const; - //===--------------------------------------------------------------------===// // Type Constructors //===--------------------------------------------------------------------===// diff --git a/include/clang/AST/BuiltinTypes.def b/include/clang/AST/BuiltinTypes.def index dcca44df17..c0c6819280 100644 --- a/include/clang/AST/BuiltinTypes.def +++ b/include/clang/AST/BuiltinTypes.def @@ -133,6 +133,9 @@ FLOATING_TYPE(Double, DoubleTy) // 'long double' FLOATING_TYPE(LongDouble, LongDoubleTy) +// '__float128' +FLOATING_TYPE(Float128, Float128Ty) + //===- Language-specific types --------------------------------------------===// // This is the type of C++0x 'nullptr'. diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 1a968724ca..3e4127fa48 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -2051,7 +2051,7 @@ public: } bool isFloatingPoint() const { - return getKind() >= Half && getKind() <= LongDouble; + return getKind() >= Half && getKind() <= Float128; } /// Determines whether the given kind corresponds to a placeholder type. diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index ba3f848958..67adf4a638 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -538,7 +538,7 @@ public: bool needsExtraLocalData() const { BuiltinType::Kind bk = getTypePtr()->getKind(); return (bk >= BuiltinType::UShort && bk <= BuiltinType::UInt128) - || (bk >= BuiltinType::Short && bk <= BuiltinType::LongDouble) + || (bk >= BuiltinType::Short && bk <= BuiltinType::Float128) || bk == BuiltinType::UChar || bk == BuiltinType::SChar; } diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 822124f0dd..d5d6e874dd 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -5246,8 +5246,6 @@ def err_typecheck_pointer_arith_void_type : Error< "arithmetic on%select{ a|}0 pointer%select{|s}0 to void">; def err_typecheck_decl_incomplete_type : Error< "variable has incomplete type %0">; -def err_typecheck_decl_incomplete_type___float128 : Error< - "support for type '__float128' is not yet implemented">; def ext_typecheck_decl_incomplete_type : ExtWarn< "tentative definition of variable with internal linkage has incomplete non-array type %0">, InGroup>; @@ -7601,8 +7599,8 @@ def err_c99_array_usage_cxx : Error< "feature, not permitted in C++">; def err_type_requires_extension : Error< "use of type %0 requires %1 extension to be enabled">; -def err_int128_unsupported : Error< - "__int128 is not supported on this target">; +def err_type_unsupported : Error< + "%0 is not supported on this target">; def err_nsconsumed_attribute_mismatch : Error< "overriding method has mismatched ns_consumed attribute on its" " parameter">; diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h index 334719cd7d..b2965782de 100644 --- a/include/clang/Basic/Specifiers.h +++ b/include/clang/Basic/Specifiers.h @@ -54,6 +54,7 @@ namespace clang { TST_half, // OpenCL half, ARM NEON __fp16 TST_float, TST_double, + TST_float128, TST_bool, // _Bool TST_decimal32, // _Decimal32 TST_decimal64, // _Decimal64 diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index b98a5d6c41..008723f426 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -64,7 +64,7 @@ protected: unsigned char HalfWidth, HalfAlign; unsigned char FloatWidth, FloatAlign; unsigned char DoubleWidth, DoubleAlign; - unsigned char LongDoubleWidth, LongDoubleAlign; + unsigned char LongDoubleWidth, LongDoubleAlign, Float128Align; unsigned char LargeArrayMinWidth, LargeArrayAlign; unsigned char LongWidth, LongAlign; unsigned char LongLongWidth, LongLongAlign; @@ -78,7 +78,7 @@ protected: std::unique_ptr DataLayout; const char *MCountName; const llvm::fltSemantics *HalfFormat, *FloatFormat, *DoubleFormat, - *LongDoubleFormat; + *LongDoubleFormat, *Float128Format; unsigned char RegParmMax, SSERegParmMax; TargetCXXABI TheCXXABI; const LangAS::Map *AddrSpaceMap; @@ -136,7 +136,8 @@ public: NoFloat = 255, Float = 0, Double, - LongDouble + LongDouble, + Float128 }; /// \brief The different kinds of __builtin_va_list types defined by @@ -327,6 +328,11 @@ public: return getPointerWidth(0) >= 64; } // FIXME + /// \brief Determine whether the __float128 type is supported on this target. + virtual bool hasFloat128Type() const { + return false; + } + /// \brief Return the alignment that is suitable for storing any /// object with a fundamental alignment requirement. unsigned getSuitableAlign() const { return SuitableAlign; } @@ -379,6 +385,14 @@ public: return *LongDoubleFormat; } + /// getFloat128Width/Align/Format - Return the size/align/format of + /// '__float128'. + unsigned getFloat128Width() const { return 128; } + unsigned getFloat128Align() const { return Float128Align; } + const llvm::fltSemantics &getFloat128Format() const { + return *Float128Format; + } + /// \brief Return true if the 'long double' type should be mangled like /// __float128. virtual bool useFloat128ManglingForLongDouble() const { return false; } diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 3d0c65718f..9d97a81773 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -380,6 +380,7 @@ KEYWORD(__builtin_offsetof , KEYALL) TYPE_TRAIT_2(__builtin_types_compatible_p, TypeCompatible, KEYNOCXX) KEYWORD(__builtin_va_arg , KEYALL) KEYWORD(__extension__ , KEYALL) +KEYWORD(__float128 , KEYALL) KEYWORD(__imag , KEYALL) KEYWORD(__int128 , KEYALL) KEYWORD(__label__ , KEYALL) diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 1a8c7c606d..21bfa3a254 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -1495,6 +1495,10 @@ def minvariant_function_descriptors : def mno_invariant_function_descriptors : Flag<["-"], "mno-invariant-function-descriptors">, Group; +def mfloat128: Flag<["-"], "mfloat128">, + Group; +def mno_float128 : Flag<["-"], "mno-float128">, + Group; def faltivec : Flag<["-"], "faltivec">, Group, Flags<[CC1Option]>, HelpText<"Enable AltiVec vector initializer syntax">; diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h index 3a2e8d276e..2bbcd262a7 100644 --- a/include/clang/Lex/LiteralSupport.h +++ b/include/clang/Lex/LiteralSupport.h @@ -64,6 +64,7 @@ public: bool isHalf : 1; // 1.0h bool isFloat : 1; // 1.0f bool isImaginary : 1; // 1.0i + bool isFloat128 : 1; // 1.0q uint8_t MicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64. bool isIntegerLiteral() const { diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index b9e432b5ee..d296e74b07 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -280,6 +280,7 @@ public: 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_float128 = clang::TST_float128; static const TST TST_bool = clang::TST_bool; static const TST TST_decimal32 = clang::TST_decimal32; static const TST TST_decimal64 = clang::TST_decimal64; diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 9a0f905c24..1f7ec43787 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -798,6 +798,8 @@ namespace clang { PREDEF_TYPE_RESERVE_ID_ID = 42, /// \brief The placeholder type for OpenMP array section. PREDEF_TYPE_OMP_ARRAY_SECTION = 43, + /// \brief The '__float128' type + PREDEF_TYPE_FLOAT128_ID = 44, /// \brief OpenCL image types with auto numeration #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ PREDEF_TYPE_##Id##_ID, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index fb4c80bd7f..2b103308bb 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -58,7 +58,7 @@ unsigned ASTContext::NumImplicitDestructors; unsigned ASTContext::NumImplicitDestructorsDeclared; enum FloatingRank { - HalfRank, FloatRank, DoubleRank, LongDoubleRank + HalfRank, FloatRank, DoubleRank, LongDoubleRank, Float128Rank }; RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { @@ -967,14 +967,6 @@ TypedefDecl *ASTContext::getUInt128Decl() const { return UInt128Decl; } -TypeDecl *ASTContext::getFloat128StubType() const { - assert(LangOpts.CPlusPlus && "should only be called for c++"); - if (!Float128StubDecl) - Float128StubDecl = buildImplicitRecord("__float128"); - - return Float128StubDecl; -} - void ASTContext::InitBuiltinType(CanQualType &R, BuiltinType::Kind K) { BuiltinType *Ty = new (*this, TypeAlignment) BuiltinType(K); R = CanQualType::CreateUnsafe(QualType(Ty, 0)); @@ -1023,6 +1015,9 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target, InitBuiltinType(DoubleTy, BuiltinType::Double); InitBuiltinType(LongDoubleTy, BuiltinType::LongDouble); + // GNU extension, __float128 for IEEE quadruple precision + InitBuiltinType(Float128Ty, BuiltinType::Float128); + // GNU extension, 128-bit integers. InitBuiltinType(Int128Ty, BuiltinType::Int128); InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128); @@ -1084,6 +1079,7 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target, FloatComplexTy = getComplexType(FloatTy); DoubleComplexTy = getComplexType(DoubleTy); LongDoubleComplexTy = getComplexType(LongDoubleTy); + Float128ComplexTy = getComplexType(Float128Ty); // Builtin types for 'id', 'Class', and 'SEL'. InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId); @@ -1341,6 +1337,7 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { case BuiltinType::Float: return Target->getFloatFormat(); case BuiltinType::Double: return Target->getDoubleFormat(); case BuiltinType::LongDouble: return Target->getLongDoubleFormat(); + case BuiltinType::Float128: return Target->getFloat128Format(); } } @@ -1651,6 +1648,10 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { Width = Target->getLongDoubleWidth(); Align = Target->getLongDoubleAlign(); break; + case BuiltinType::Float128: + Width = Target->getFloat128Width(); + Align = Target->getFloat128Align(); + break; case BuiltinType::NullPtr: Width = Target->getPointerWidth(0); // C++ 3.9.1p11: sizeof(nullptr_t) Align = Target->getPointerAlign(0); // == sizeof(void*) @@ -4635,6 +4636,7 @@ static FloatingRank getFloatingRank(QualType T) { case BuiltinType::Float: return FloatRank; case BuiltinType::Double: return DoubleRank; case BuiltinType::LongDouble: return LongDoubleRank; + case BuiltinType::Float128: return Float128Rank; } } @@ -4651,6 +4653,7 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size, case FloatRank: return FloatComplexTy; case DoubleRank: return DoubleComplexTy; case LongDoubleRank: return LongDoubleComplexTy; + case Float128Rank: return Float128ComplexTy; } } @@ -4660,6 +4663,7 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size, case FloatRank: return FloatTy; case DoubleRank: return DoubleTy; case LongDoubleRank: return LongDoubleTy; + case Float128Rank: return Float128Ty; } llvm_unreachable("getFloatingRank(): illegal value for rank"); } @@ -5489,6 +5493,7 @@ static char getObjCEncodingForPrimitiveKind(const ASTContext *C, case BuiltinType::LongDouble: return 'D'; case BuiltinType::NullPtr: return '*'; // like char* + case BuiltinType::Float128: case BuiltinType::Half: // FIXME: potentially need @encodes for these! return ' '; @@ -8679,6 +8684,8 @@ QualType ASTContext::getRealTypeForBitwidth(unsigned DestWidth) const { return DoubleTy; case TargetInfo::LongDouble: return LongDoubleTy; + case TargetInfo::Float128: + return Float128Ty; case TargetInfo::NoFloat: return QualType(); } diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 7ad464e1d9..67f5a57263 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -1992,7 +1992,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { // ::= f # float // ::= d # double // ::= e # long double, __float80 - // UNSUPPORTED: ::= g # __float128 + // ::= g # __float128 // 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) @@ -2073,6 +2073,12 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { ? 'g' : 'e'); break; + case BuiltinType::Float128: + if (getASTContext().getTargetInfo().useFloat128ManglingForLongDouble()) + Out << "U10__float128"; // Match the GCC mangling + else + Out << 'g'; + break; case BuiltinType::NullPtr: Out << "Dn"; break; diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index b63b5e5651..c9caddbb6f 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -1751,6 +1751,7 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers, Out << "$$T"; break; + case BuiltinType::Float128: case BuiltinType::Half: { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID( diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp index 4c49e4c9f6..ac2a8d3542 100644 --- a/lib/AST/NSAPI.cpp +++ b/lib/AST/NSAPI.cpp @@ -441,6 +441,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const { case BuiltinType::Int128: case BuiltinType::LongDouble: case BuiltinType::UInt128: + case BuiltinType::Float128: case BuiltinType::NullPtr: case BuiltinType::ObjCClass: case BuiltinType::ObjCId: diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index cc38374092..0b3f908790 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1310,6 +1310,7 @@ static void PrintFloatingLiteral(raw_ostream &OS, FloatingLiteral *Node, case BuiltinType::Double: break; // no suffix. case BuiltinType::Float: OS << 'F'; break; case BuiltinType::LongDouble: OS << 'L'; break; + case BuiltinType::Float128: OS << 'Q'; break; } } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 1c6ae2a2b9..0262f5ba4a 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1777,7 +1777,7 @@ bool Type::hasUnsignedIntegerRepresentation() const { bool Type::isFloatingType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Half && - BT->getKind() <= BuiltinType::LongDouble; + BT->getKind() <= BuiltinType::Float128; if (const ComplexType *CT = dyn_cast(CanonicalType)) return CT->getElementType()->isFloatingType(); return false; @@ -1799,7 +1799,7 @@ bool Type::isRealFloatingType() const { bool Type::isRealType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && - BT->getKind() <= BuiltinType::LongDouble; + BT->getKind() <= BuiltinType::Float128; if (const EnumType *ET = dyn_cast(CanonicalType)) return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped(); return false; @@ -1808,7 +1808,7 @@ bool Type::isRealType() const { bool Type::isArithmeticType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && - BT->getKind() <= BuiltinType::LongDouble; + BT->getKind() <= BuiltinType::Float128; if (const EnumType *ET = dyn_cast(CanonicalType)) // GCC allows forward declaration of enum types (forbid by C99 6.7.2.3p2). // If a body isn't seen by the time we get here, return false. @@ -2552,6 +2552,8 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { return "double"; case LongDouble: return "long double"; + case Float128: + return "__float128"; case WChar_S: case WChar_U: return Policy.MSWChar ? "__wchar_t" : "wchar_t"; diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index 05e5a627b7..78947d18f9 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -320,6 +320,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { case BuiltinType::Float: case BuiltinType::Double: case BuiltinType::LongDouble: + case BuiltinType::Float128: llvm_unreachable("Builtin type needs extra local data!"); // Fall through, if the impossible happens. diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp index ff44a570de..ac6cef9d08 100644 --- a/lib/Analysis/PrintfFormatString.cpp +++ b/lib/Analysis/PrintfFormatString.cpp @@ -616,6 +616,7 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, case BuiltinType::UInt128: case BuiltinType::Int128: case BuiltinType::Half: + case BuiltinType::Float128: // Various types which are non-trivial to correct. return false; diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index 40d6001e53..c287073ead 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -46,6 +46,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) { DoubleAlign = 64; LongDoubleWidth = 64; LongDoubleAlign = 64; + Float128Align = 128; LargeArrayMinWidth = 0; LargeArrayAlign = 0; MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 0; @@ -72,6 +73,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) { FloatFormat = &llvm::APFloat::IEEEsingle; DoubleFormat = &llvm::APFloat::IEEEdouble; LongDoubleFormat = &llvm::APFloat::IEEEdouble; + Float128Format = &llvm::APFloat::IEEEquad; MCountName = "mcount"; RegParmMax = 0; SSERegParmMax = 0; @@ -223,6 +225,8 @@ TargetInfo::RealType TargetInfo::getRealTypeByWidth(unsigned BitWidth) const { if (&getLongDoubleFormat() == &llvm::APFloat::PPCDoubleDouble || &getLongDoubleFormat() == &llvm::APFloat::IEEEquad) return LongDouble; + if (hasFloat128Type()) + return Float128; break; } diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 7639b04d25..4cce9cbd8a 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -806,6 +806,7 @@ class PPCTargetInfo : public TargetInfo { bool HasHTM; bool HasBPERMD; bool HasExtDiv; + bool HasFloat128; protected: std::string ABI; @@ -814,7 +815,7 @@ public: PPCTargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple), HasVSX(false), HasP8Vector(false), HasP8Crypto(false), HasDirectMove(false), HasQPX(false), HasHTM(false), - HasBPERMD(false), HasExtDiv(false) { + HasBPERMD(false), HasExtDiv(false), HasFloat128(false) { BigEndian = (Triple.getArch() != llvm::Triple::ppc64le); SimdDefaultAlign = 128; LongDoubleWidth = LongDoubleAlign = 128; @@ -1058,6 +1059,9 @@ public: LongDoubleFormat == &llvm::APFloat::PPCDoubleDouble && getTriple().isOSBinFormatELF(); } + bool hasFloat128Type() const override { + return HasFloat128; + } }; const Builtin::Info PPCTargetInfo::BuiltinInfo[] = { @@ -1089,6 +1093,8 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector &Features, HasQPX = true; } else if (Feature == "+htm") { HasHTM = true; + } else if (Feature == "+float128") { + HasFloat128 = true; } // TODO: Finish this list and add an assert that we've handled them // all. @@ -1246,6 +1252,8 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__CRYPTO__"); if (HasHTM) Builder.defineMacro("__HTM__"); + if (HasFloat128) + Builder.defineMacro("__FLOAT128__"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); @@ -1296,6 +1304,13 @@ static bool ppcUserFeaturesCheck(DiagnosticsEngine &Diags, << "-mno-vsx"; return false; } + + if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+float128") != + FeaturesVec.end()) { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfloat128" + << "-mno-vsx"; + return false; + } } return true; @@ -1364,6 +1379,7 @@ bool PPCTargetInfo::hasFeature(StringRef Feature) const { .Case("htm", HasHTM) .Case("bpermd", HasBPERMD) .Case("extdiv", HasExtDiv) + .Case("float128", HasFloat128) .Default(false); } @@ -1373,19 +1389,19 @@ void PPCTargetInfo::setFeatureEnabled(llvm::StringMap &Features, // as well. Do the inverse if we're disabling vsx. We'll diagnose any user // incompatible options. if (Enabled) { - if (Name == "vsx") { - Features[Name] = true; - } else if (Name == "direct-move") { + if (Name == "direct-move") { Features[Name] = Features["vsx"] = true; } else if (Name == "power8-vector") { Features[Name] = Features["vsx"] = true; + } else if (Name == "float128") { + Features[Name] = Features["vsx"] = true; } else { Features[Name] = true; } } else { if (Name == "vsx") { Features[Name] = Features["direct-move"] = Features["power8-vector"] = - false; + Features["float128"] = false; } else { Features[Name] = false; } diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 13ee0fb1d9..4b7657bb35 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -528,7 +528,13 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { case BuiltinType::Half: case BuiltinType::Float: case BuiltinType::LongDouble: + case BuiltinType::Float128: case BuiltinType::Double: + // FIXME: For targets where long double and __float128 have the same size, + // they are currently indistinguishable in the debugger without some + // special treatment. However, there is currently no consensus on encoding + // and this should be updated once a DWARF encoding exists for distinct + // floating point types of the same size. Encoding = llvm::dwarf::DW_ATE_float; break; } diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 1fd79d0e0e..8f122963a1 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -1796,15 +1796,19 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, amt = llvm::ConstantFP::get(VMContext, llvm::APFloat(static_cast(amount))); else { - // Remaining types are either Half or LongDouble. Convert from float. + // Remaining types are Half, LongDouble or __float128. Convert from float. llvm::APFloat F(static_cast(amount)); bool ignored; + const llvm::fltSemantics *FS; // Don't use getFloatTypeSemantics because Half isn't // necessarily represented using the "half" LLVM type. - F.convert(value->getType()->isHalfTy() - ? CGF.getTarget().getHalfFormat() - : CGF.getTarget().getLongDoubleFormat(), - llvm::APFloat::rmTowardZero, &ignored); + if (value->getType()->isFP128Ty()) + FS = &CGF.getTarget().getFloat128Format(); + else if (value->getType()->isHalfTy()) + FS = &CGF.getTarget().getHalfFormat(); + else + FS = &CGF.getTarget().getLongDoubleFormat(); + F.convert(*FS, llvm::APFloat::rmTowardZero, &ignored); amt = llvm::ConstantFP::get(VMContext, F); } value = Builder.CreateFAdd(value, amt, isInc ? "inc" : "dec"); diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index 33e53a6cbe..ebe55c70d8 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -449,6 +449,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { case BuiltinType::Float: case BuiltinType::Double: case BuiltinType::LongDouble: + case BuiltinType::Float128: ResultType = getTypeForFormat(getLLVMContext(), Context.getFloatTypeSemantics(T), /* UseNativeHalf = */ false); diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index b44e840533..52e519f304 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -2530,6 +2530,7 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) { case BuiltinType::Float: case BuiltinType::Double: case BuiltinType::LongDouble: + case BuiltinType::Float128: case BuiltinType::Char16: case BuiltinType::Char32: case BuiltinType::Int128: @@ -3349,8 +3350,8 @@ void ItaniumCXXABI::EmitFundamentalRTTIDescriptors() { getContext().UnsignedLongLongTy, getContext().Int128Ty, getContext().UnsignedInt128Ty, getContext().HalfTy, getContext().FloatTy, getContext().DoubleTy, - getContext().LongDoubleTy, getContext().Char16Ty, - getContext().Char32Ty, + getContext().LongDoubleTy, getContext().Float128Ty, + getContext().Char16Ty, getContext().Char32Ty }; for (const QualType &FundamentalType : FundamentalTypes) EmitFundamentalRTTIDescriptor(FundamentalType); diff --git a/lib/Format/FormatToken.cpp b/lib/Format/FormatToken.cpp index d6cd450d89..2ae4ddcfd0 100644 --- a/lib/Format/FormatToken.cpp +++ b/lib/Format/FormatToken.cpp @@ -53,6 +53,7 @@ bool FormatToken::isSimpleTypeSpecifier() const { case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw___float128: case tok::kw_wchar_t: case tok::kw_bool: case tok::kw___underlying_type: diff --git a/lib/Index/USRGeneration.cpp b/lib/Index/USRGeneration.cpp index 65de75b5c4..40283dcd68 100644 --- a/lib/Index/USRGeneration.cpp +++ b/lib/Index/USRGeneration.cpp @@ -618,6 +618,8 @@ void USRGenerator::VisitType(QualType T) { c = 'd'; break; case BuiltinType::LongDouble: c = 'D'; break; + case BuiltinType::Float128: + c = 'Q'; break; case BuiltinType::NullPtr: c = 'n'; break; #define BUILTIN_TYPE(Id, SingletonId) diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp index 27c80b9301..e68b82fb49 100644 --- a/lib/Lex/LiteralSupport.cpp +++ b/lib/Lex/LiteralSupport.cpp @@ -525,6 +525,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, isHalf = false; isFloat = false; isImaginary = false; + isFloat128 = false; MicrosoftInteger = 0; hadError = false; @@ -567,9 +568,17 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, case 'f': // FP Suffix for "float" case 'F': if (!isFPConstant) break; // Error for integer constant. - if (isHalf || isFloat || isLong) break; // HF, FF, LF invalid. + if (isHalf || isFloat || isLong || isFloat128) + break; // HF, FF, LF, QF invalid. isFloat = true; continue; // Success. + case 'q': // FP Suffix for "__float128" + case 'Q': + if (!isFPConstant) break; // Error for integer constant. + if (isHalf || isFloat || isLong || isFloat128) + break; // HQ, FQ, LQ, QQ invalid. + isFloat128 = true; + continue; // Success. case 'u': case 'U': if (isFPConstant) break; // Error for floating constant. @@ -579,7 +588,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, case 'l': case 'L': if (isLong || isLongLong) break; // Cannot be repeated. - if (isHalf || isFloat) break; // LH, LF invalid. + if (isHalf || isFloat || isFloat128) break; // LH, LF, LQ invalid. // Check for long long. The L's need to be adjacent and the same case. if (s[1] == s[0]) { diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index b06eda9d23..ebe26cfb2d 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -3306,6 +3306,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID, Policy); break; + case tok::kw___float128: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float128, Loc, PrevSpec, + DiagID, Policy); + break; case tok::kw_wchar_t: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID, Policy); @@ -4300,6 +4304,7 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const { case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw___float128: case tok::kw_bool: case tok::kw__Bool: case tok::kw__Decimal32: @@ -4374,6 +4379,7 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw___float128: case tok::kw_bool: case tok::kw__Bool: case tok::kw__Decimal32: @@ -4528,6 +4534,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw___float128: case tok::kw_bool: case tok::kw__Bool: case tok::kw__Decimal32: diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 2745c33776..5b7c839454 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1166,6 +1166,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw___float128: case tok::kw_void: case tok::kw_typename: case tok::kw_typeof: diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index afed9b1ab4..b569e7aeba 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -1928,6 +1928,9 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { case tok::kw_double: DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec, DiagID, Policy); break; + case tok::kw___float128: + DS.SetTypeSpecType(DeclSpec::TST_float128, Loc, PrevSpec, DiagID, Policy); + break; case tok::kw_wchar_t: DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID, Policy); break; diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 747d0a982c..4d4bd806f3 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -946,6 +946,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw_char: case tok::kw_const: case tok::kw_double: + case tok::kw___float128: case tok::kw_enum: case tok::kw_half: case tok::kw_float: @@ -1426,6 +1427,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw___float128: case tok::kw_void: case tok::annot_decltype: if (NextToken().is(tok::l_paren)) @@ -1517,6 +1519,7 @@ bool Parser::isCXXDeclarationSpecifierAType() { case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw___float128: case tok::kw_void: case tok::kw___unknown_anytype: case tok::kw___auto_type: diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index 4bc1d3423b..ddfe6257cf 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -289,6 +289,7 @@ bool Declarator::isDeclarationOfFunction() const { case TST_decimal32: case TST_decimal64: case TST_double: + case TST_float128: case TST_enum: case TST_error: case TST_float: @@ -457,6 +458,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T, case DeclSpec::TST_half: return "half"; case DeclSpec::TST_float: return "float"; case DeclSpec::TST_double: return "double"; + case DeclSpec::TST_float128: return "__float128"; case DeclSpec::TST_bool: return Policy.Bool ? "bool" : "_Bool"; case DeclSpec::TST_decimal32: return "_Decimal32"; case DeclSpec::TST_decimal64: return "_Decimal64"; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index b0e79f6f0e..13002ba19a 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -108,6 +108,7 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const { case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw___float128: case tok::kw_wchar_t: case tok::kw_bool: case tok::kw___underlying_type: diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index a4b1525d94..fcc608fa1f 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1155,6 +1155,48 @@ static QualType handleFloatConversion(Sema &S, ExprResult &LHS, /*convertFloat=*/!IsCompAssign); } +/// \brief Diagnose attempts to convert between __float128 and long double if +/// there is no support for such conversion. Helper function of +/// UsualArithmeticConversions(). +static bool unsupportedTypeConversion(const Sema &S, QualType LHSType, + QualType RHSType) { + /* No issue converting if at least one of the types is not a floating point + type or the two types have the same rank. + */ + if (!LHSType->isFloatingType() || !RHSType->isFloatingType() || + S.Context.getFloatingTypeOrder(LHSType, RHSType) == 0) + return false; + + assert(LHSType->isFloatingType() && RHSType->isFloatingType() && + "The remaining types must be floating point types."); + + auto *LHSComplex = LHSType->getAs(); + auto *RHSComplex = RHSType->getAs(); + + QualType LHSElemType = LHSComplex ? + LHSComplex->getElementType() : LHSType; + QualType RHSElemType = RHSComplex ? + RHSComplex->getElementType() : RHSType; + + // No issue if the two types have the same representation + if (&S.Context.getFloatTypeSemantics(LHSElemType) == + &S.Context.getFloatTypeSemantics(RHSElemType)) + return false; + + bool Float128AndLongDouble = (LHSElemType == S.Context.Float128Ty && + RHSElemType == S.Context.LongDoubleTy); + Float128AndLongDouble |= (LHSElemType == S.Context.LongDoubleTy && + RHSElemType == S.Context.Float128Ty); + + /* We've handled the situation where __float128 and long double have the same + representation. The only other allowable conversion is if long double is + really just double. + */ + return Float128AndLongDouble && + (&S.Context.getFloatTypeSemantics(S.Context.LongDoubleTy) != + &llvm::APFloat::IEEEdouble); +} + typedef ExprResult PerformCastFn(Sema &S, Expr *operand, QualType toType); namespace { @@ -1318,6 +1360,11 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, // At this point, we have two different arithmetic types. + // Diagnose attempts to convert between __float128 and long double where + // such conversions currently can't be handled. + if (unsupportedTypeConversion(*this, LHSType, RHSType)) + return QualType(); + // Handle complex types first (C99 6.3.1.8p1). if (LHSType->isComplexType() || RHSType->isComplexType()) return handleComplexFloatConversion(*this, LHS, RHS, LHSType, RHSType, @@ -3325,10 +3372,12 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { } } else if (Literal.isFloat) Ty = Context.FloatTy; - else if (!Literal.isLong) - Ty = Context.DoubleTy; - else + else if (Literal.isLong) Ty = Context.LongDoubleTy; + else if (Literal.isFloat128) + Ty = Context.Float128Ty; + else + Ty = Context.DoubleTy; Res = BuildFloatingLiteral(*this, Literal, Ty, Tok.getLocation()); @@ -6602,6 +6651,15 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, QualType LHSTy = LHS.get()->getType(); QualType RHSTy = RHS.get()->getType(); + // Diagnose attempts to convert between __float128 and long double where + // such conversions currently can't be handled. + if (unsupportedTypeConversion(*this, LHSTy, RHSTy)) { + Diag(QuestionLoc, + diag::err_typecheck_cond_incompatible_operands) << LHSTy << RHSTy + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); + return QualType(); + } + // OpenCL v2.0 s6.12.5 - Blocks cannot be used as expressions of the ternary // selection operator (?:). if (getLangOpts().OpenCL && @@ -7335,6 +7393,11 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, return Incompatible; } + // Diagnose attempts to convert between __float128 and long double where + // such conversions currently can't be handled. + if (unsupportedTypeConversion(*this, LHSType, RHSType)) + return Incompatible; + // Arithmetic conversions. if (LHSType->isArithmeticType() && RHSType->isArithmeticType() && !(getLangOpts().CPlusPlus && LHSType->isEnumeralType())) { diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 87c2ded7c8..4063464c45 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -5171,6 +5171,12 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, QualType ResTy = UsualArithmeticConversions(LHS, RHS); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); + if (ResTy.isNull()) { + Diag(QuestionLoc, + diag::err_typecheck_cond_incompatible_operands) << LTy << RTy + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); + return QualType(); + } LHS = ImpCastExprToType(LHS.get(), ResTy, PrepareScalarCast(LHS, ResTy)); RHS = ImpCastExprToType(RHS.get(), ResTy, PrepareScalarCast(RHS, ResTy)); diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 08133d6889..fdf5346d92 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -681,13 +681,6 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) { NameKind == Sema::LookupRedeclarationWithLinkage) { IdentifierInfo *II = R.getLookupName().getAsIdentifierInfo(); if (II) { - if (S.getLangOpts().CPlusPlus11 && S.getLangOpts().GNUMode && - II == S.getFloat128Identifier()) { - // libstdc++4.7's type_traits expects type __float128 to exist, so - // insert a dummy type to make that header build in gnu++11 mode. - R.addDecl(S.getASTContext().getFloat128StubType()); - return true; - } if (S.getLangOpts().CPlusPlus && NameKind == Sema::LookupOrdinaryName && II == S.getASTContext().getMakeIntegerSeqName()) { R.addDecl(S.getASTContext().getMakeIntegerSeqDecl()); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 034b090fdf..e3a72c1e22 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1671,6 +1671,20 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, SCS.Second = ICK_Complex_Real; FromType = ToType.getUnqualifiedType(); } else if (FromType->isRealFloatingType() && ToType->isRealFloatingType()) { + // FIXME: disable conversions between long double and __float128 if + // their representation is different until there is back end support + // We of course allow this conversion if long double is really double. + if (&S.Context.getFloatTypeSemantics(FromType) != + &S.Context.getFloatTypeSemantics(ToType)) { + bool Float128AndLongDouble = ((FromType == S.Context.Float128Ty && + ToType == S.Context.LongDoubleTy) || + (FromType == S.Context.LongDoubleTy && + ToType == S.Context.Float128Ty)); + if (Float128AndLongDouble && + (&S.Context.getFloatTypeSemantics(S.Context.LongDoubleTy) != + &llvm::APFloat::IEEEdouble)) + return false; + } // Floating point conversions (C++ 4.8). SCS.Second = ICK_Floating_Conversion; FromType = ToType.getUnqualifiedType(); @@ -1973,7 +1987,8 @@ bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) { if (!getLangOpts().CPlusPlus && (FromBuiltin->getKind() == BuiltinType::Float || FromBuiltin->getKind() == BuiltinType::Double) && - (ToBuiltin->getKind() == BuiltinType::LongDouble)) + (ToBuiltin->getKind() == BuiltinType::LongDouble || + ToBuiltin->getKind() == BuiltinType::Float128)) return true; // Half can be promoted to float. @@ -7198,13 +7213,13 @@ class BuiltinOperatorOverloadBuilder { // provided via the getArithmeticType() method below. // The "promoted arithmetic types" are the arithmetic // types are that preserved by promotion (C++ [over.built]p2). - static const unsigned FirstIntegralType = 3; - static const unsigned LastIntegralType = 20; - static const unsigned FirstPromotedIntegralType = 3, - LastPromotedIntegralType = 11; + static const unsigned FirstIntegralType = 4; + static const unsigned LastIntegralType = 21; + static const unsigned FirstPromotedIntegralType = 4, + LastPromotedIntegralType = 12; static const unsigned FirstPromotedArithmeticType = 0, - LastPromotedArithmeticType = 11; - static const unsigned NumArithmeticTypes = 20; + LastPromotedArithmeticType = 12; + static const unsigned NumArithmeticTypes = 21; /// \brief Get the canonical type for a given arithmetic type index. CanQualType getArithmeticType(unsigned index) { @@ -7215,6 +7230,7 @@ class BuiltinOperatorOverloadBuilder { &ASTContext::FloatTy, &ASTContext::DoubleTy, &ASTContext::LongDoubleTy, + &ASTContext::Float128Ty, // Start of integral types. &ASTContext::IntTy, diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index c23b5a2adc..52a1ad545a 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -727,6 +727,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_half: case TST_float: case TST_double: + case TST_float128: case TST_bool: case TST_decimal32: case TST_decimal64: diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index cf47d867c8..4d68f4c1cf 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1355,7 +1355,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } case DeclSpec::TST_int128: if (!S.Context.getTargetInfo().hasInt128Type()) - S.Diag(DS.getTypeSpecTypeLoc(), diag::err_int128_unsupported); + S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) + << "__int128"; if (DS.getTypeSpecSign() == DeclSpec::TSS_unsigned) Result = Context.UnsignedInt128Ty; else @@ -1377,6 +1378,12 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { declarator.setInvalidType(true); } break; + case DeclSpec::TST_float128: + if (!S.Context.getTargetInfo().hasFloat128Type()) + S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) + << "__float128"; + Result = Context.Float128Ty; + break; case DeclSpec::TST_bool: Result = Context.BoolTy; break; // _Bool or bool break; case DeclSpec::TST_decimal32: // _Decimal32 @@ -6959,13 +6966,6 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, if (!Diagnoser) return true; - // We have an incomplete type. Produce a diagnostic. - if (Ident___float128 && - T == Context.getTypeDeclType(Context.getFloat128StubType())) { - Diag(Loc, diag::err_typecheck_decl_incomplete_type___float128); - return true; - } - Diagnoser->diagnose(*this, Loc, T); // If the type was a forward declaration of a class/struct/union diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp index 2382f8ea4b..792fac99e5 100644 --- a/lib/Serialization/ASTCommon.cpp +++ b/lib/Serialization/ASTCommon.cpp @@ -91,6 +91,9 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) { case BuiltinType::LongDouble: ID = PREDEF_TYPE_LONGDOUBLE_ID; break; + case BuiltinType::Float128: + ID = PREDEF_TYPE_FLOAT128_ID; + break; case BuiltinType::NullPtr: ID = PREDEF_TYPE_NULLPTR_ID; break; diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 0c2522311a..df1418649d 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -6059,6 +6059,9 @@ QualType ASTReader::GetType(TypeID ID) { case PREDEF_TYPE_LONGDOUBLE_ID: T = Context.LongDoubleTy; break; + case PREDEF_TYPE_FLOAT128_ID: + T = Context.Float128Ty; + break; case PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break; diff --git a/test/CodeGenCXX/float128-declarations.cpp b/test/CodeGenCXX/float128-declarations.cpp new file mode 100644 index 0000000000..638f56fd0d --- /dev/null +++ b/test/CodeGenCXX/float128-declarations.cpp @@ -0,0 +1,86 @@ +// RUN: %clang_cc1 -emit-llvm -triple powerpc64-unknown-unknown \ +// RUN: -target-feature +float128 -std=c++11 %s -o - | FileCheck %s +// RUN: %clang_cc1 -emit-llvm -triple powerpc64le-unknown-unknown \ +// RUN: -target-feature +float128 -std=c++11 %s -o - | FileCheck %s +// +/* Various contexts where type __float128 can appear. */ + +/* Namespace */ +namespace { + __float128 f1n; + __float128 f2n = 33.q; + __float128 arr1n[10]; + __float128 arr2n[] = { 1.2q, 3.0q, 3.e11q }; + const volatile __float128 func1n(const __float128 &arg) { + return arg + f2n + arr1n[4] - arr2n[1]; + } +} + +/* File */ +__float128 f1f; +__float128 f2f = 32.4q; +static __float128 f3f = f2f; +__float128 arr1f[10]; +__float128 arr2f[] = { -1.2q, -3.0q, -3.e11q }; +__float128 func1f(__float128 arg); + +/* Class */ +class C1 { + __float128 f1c; + static const __float128 f2c; + volatile __float128 f3c; +public: + C1(__float128 arg) : f1c(arg), f3c(arg) { } + __float128 func1c(__float128 arg ) { + return f1c + arg; + } + static __float128 func2c(__float128 arg) { + return arg * C1::f2c; + } +}; + +/* Template */ +template C func1t(C arg) { return arg * 2.q; } +template struct S1 { + C mem1; +}; +template <> struct S1<__float128> { + __float128 mem2; +}; + +/* Local */ +int main(void) { + __float128 f1l = 123e220q; + __float128 f2l = -0.q; + __float128 f3l = 1.189731495357231765085759326628007e4932q; + C1 c1(f1l); + S1<__float128> s1 = { 132.q }; + __float128 f4l = func1n(f1l) + func1f(f2l) + c1.func1c(f3l) + c1.func2c(f1l) + + func1t(f1l) + s1.mem2 - f1n + f2n; +#if (__cplusplus >= 201103L) + auto f5l = -1.q, *f6l = &f2l, f7l = func1t(f3l); +#endif + __float128 f8l = f4l++; + __float128 arr1l[] = { -1.q, -0.q, -11.q }; +} +// CHECK-DAG: @_ZN12_GLOBAL__N_13f1nE = internal global fp128 0xL00000000000000000000000000000000 +// CHECK-DAG: @_ZN12_GLOBAL__N_13f2nE = internal global fp128 0xL00000000000000004004080000000000 +// CHECK-DAG: @_ZN12_GLOBAL__N_15arr1nE = internal global [10 x fp128] +// CHECK-DAG: @_ZN12_GLOBAL__N_15arr2nE = internal global [3 x fp128] [fp128 0xL33333333333333333FFF333333333333, fp128 0xL00000000000000004000800000000000, fp128 0xL00000000000000004025176592E00000] +// CHECK-DAG: define internal fp128 @_ZN12_GLOBAL__N_16func1nERKU10__float128(fp128* +// CHECK-DAG: @f1f = global fp128 0xL00000000000000000000000000000000 +// CHECK-DAG: @f2f = global fp128 0xL33333333333333334004033333333333 +// CHECK-DAG: @arr1f = global [10 x fp128] +// CHECK-DAG: @arr2f = global [3 x fp128] [fp128 0xL3333333333333333BFFF333333333333, fp128 0xL0000000000000000C000800000000000, fp128 0xL0000000000000000C025176592E00000] +// CHECK-DAG: declare fp128 @_Z6func1fU10__float128(fp128) +// CHECK-DAG: define linkonce_odr void @_ZN2C1C2EU10__float128(%class.C1* %this, fp128 %arg) +// CHECK-DAG: define linkonce_odr fp128 @_ZN2C16func2cEU10__float128(fp128 %arg) +// CHECK-DAG: define linkonce_odr fp128 @_Z6func1tIU10__float128ET_S0_(fp128 %arg) +// CHECK-DAG: @_ZZ4mainE2s1 = private unnamed_addr constant %struct.S1 { fp128 0xL00000000000000004006080000000000 } +// CHECK-DAG: store fp128 0xLF0AFD0EBFF292DCE42E0B38CDD83F26F, fp128* %f1l, align 16 +// CHECK-DAG: store fp128 0xL00000000000000008000000000000000, fp128* %f2l, align 16 +// CHECK-DAG: store fp128 0xLFFFFFFFFFFFFFFFF7FFEFFFFFFFFFFFF, fp128* %f3l, align 16 +// CHECK-DAG: store fp128 0xL0000000000000000BFFF000000000000, fp128* %f5l, align 16 +// CHECK-DAG: [[F4L:%[a-z0-9]+]] = load fp128, fp128* %f4l +// CHECK-DAG: [[INC:%[a-z0-9]+]] = fadd fp128 [[F4L]], 0xL00000000000000003FFF000000000000 +// CHECK-DAG: store fp128 [[INC]], fp128* %f4l diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c index dbd4de605e..cc6eecc734 100644 --- a/test/Preprocessor/init.c +++ b/test/Preprocessor/init.c @@ -5819,6 +5819,9 @@ // PPCPOWER8:#define _ARCH_PWR7 1 // PPCPOWER8:#define _ARCH_PWR8 1 // +// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-none-none -target-feature +float128 -target-cpu power8 -fno-signed-char < /dev/null | FileCheck -check-prefix PPC-FLOAT128 %s +// PPC-FLOAT128:#define __FLOAT128__ 1 +// // RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-unknown-linux-gnu -fno-signed-char < /dev/null | FileCheck -match-full-lines -check-prefix PPC64-LINUX %s // // PPC64-LINUX:#define _ARCH_PPC 1 diff --git a/test/Sema/128bitfloat.cpp b/test/Sema/128bitfloat.cpp index cb76dac960..779c59dfd4 100644 --- a/test/Sema/128bitfloat.cpp +++ b/test/Sema/128bitfloat.cpp @@ -2,23 +2,23 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s #if !defined(__STRICT_ANSI__) -__float128 f; // expected-error {{support for type '__float128' is not yet implemented}} +__float128 f; // expected-error {{__float128 is not supported on this target}} // But this should work: template struct __is_floating_point_helper {}; -template<> struct __is_floating_point_helper<__float128> {}; +template<> struct __is_floating_point_helper<__float128> {}; // expected-error {{__float128 is not supported on this target}} // FIXME: This could have a better diag. -void g(int x, __float128 *y) { - x + *y; // expected-error {{invalid operands to binary expression ('int' and '__float128')}} +int g(int x, __float128 *y) { // expected-error {{__float128 is not supported on this target}} + return x + *y; } #else -__float128 f; // expected-error {{unknown type name '__float128'}} +__float128 f; // expected-error {{__float128 is not supported on this target}} template struct __is_floating_point_helper {}; -template<> struct __is_floating_point_helper<__float128> {}; // expected-error {{use of undeclared identifier '__float128'}} +template<> struct __is_floating_point_helper<__float128> {}; // expected-error {{__float128 is not supported on this target}} -void g(int x, __float128 *y) { // expected-error {{unknown type name '__float128'}} - x + *y; +int g(int x, __float128 *y) { // expected-error {{__float128 is not supported on this target}} + return x + *y; } #endif diff --git a/test/Sema/float128-ld-incompatibility.cpp b/test/Sema/float128-ld-incompatibility.cpp new file mode 100644 index 0000000000..d993ed7b08 --- /dev/null +++ b/test/Sema/float128-ld-incompatibility.cpp @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 \ +// RUN: -triple powerpc64le-unknown-linux-gnu -target-cpu pwr8 \ +// RUN: -target-feature +float128 %s + +__float128 qf(); +long double ldf(); + +// FIXME: once operations between long double and __float128 are implemented for +// targets where the types are different, these next two will change +long double ld{qf()}; // expected-error {{cannot initialize a variable of type 'long double' with an rvalue of type '__float128'}} +__float128 q{ldf()}; // expected-error {{cannot initialize a variable of type '__float128' with an rvalue of type 'long double'}} + +auto test1(__float128 q, long double ld) -> decltype(q + ld) { // expected-error {{invalid operands to binary expression ('__float128' and 'long double')}} + return q + ld; // expected-error {{invalid operands to binary expression ('__float128' and 'long double')}} +} + +auto test2(long double a, __float128 b) -> decltype(a + b) { // expected-error {{invalid operands to binary expression ('long double' and '__float128')}} + return a + b; // expected-error {{invalid operands to binary expression ('long double' and '__float128')}} +} + +void test3(bool b) { + long double ld; + __float128 q; + + ld + q; // expected-error {{invalid operands to binary expression ('long double' and '__float128')}} + q + ld; // expected-error {{invalid operands to binary expression ('__float128' and 'long double')}} + ld - q; // expected-error {{invalid operands to binary expression ('long double' and '__float128')}} + q - ld; // expected-error {{invalid operands to binary expression ('__float128' and 'long double')}} + ld * q; // expected-error {{invalid operands to binary expression ('long double' and '__float128')}} + q * ld; // expected-error {{invalid operands to binary expression ('__float128' and 'long double')}} + ld / q; // expected-error {{invalid operands to binary expression ('long double' and '__float128')}} + q / ld; // expected-error {{invalid operands to binary expression ('__float128' and 'long double')}} + ld = q; // expected-error {{assigning to 'long double' from incompatible type '__float128'}} + q = ld; // expected-error {{assigning to '__float128' from incompatible type 'long double'}} + q + b ? q : ld; // expected-error {{incompatible operand types ('__float128' and 'long double')}} +} diff --git a/test/SemaCXX/deleted-operator.cpp b/test/SemaCXX/deleted-operator.cpp index df67978a36..f71e83aa25 100644 --- a/test/SemaCXX/deleted-operator.cpp +++ b/test/SemaCXX/deleted-operator.cpp @@ -9,7 +9,7 @@ int PR10757f() { PR10757 a1; // FIXME: We get a ridiculous number of "built-in candidate" notes here... if(~a1) {} // expected-error {{overload resolution selected deleted operator}} expected-note 8 {{built-in candidate}} - if(a1==a1) {} // expected-error {{overload resolution selected deleted operator}} expected-note 121 {{built-in candidate}} + if(a1==a1) {} // expected-error {{overload resolution selected deleted operator}} expected-note 144 {{built-in candidate}} } struct DelOpDel { diff --git a/test/SemaCXX/overloaded-builtin-operators.cpp b/test/SemaCXX/overloaded-builtin-operators.cpp index 4c2953b0b3..7a99a898e2 100644 --- a/test/SemaCXX/overloaded-builtin-operators.cpp +++ b/test/SemaCXX/overloaded-builtin-operators.cpp @@ -183,7 +183,7 @@ void test_dr425(A a) { // FIXME: lots of candidates here! (void)(1.0f * a); // expected-error{{ambiguous}} \ // expected-note 4{{candidate}} \ - // expected-note {{remaining 117 candidates omitted; pass -fshow-overloads=all to show them}} + // expected-note {{remaining 140 candidates omitted; pass -fshow-overloads=all to show them}} } // pr5432 diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp index 5cde236055..ea955625aa 100644 --- a/tools/libclang/CXType.cpp +++ b/tools/libclang/CXType.cpp @@ -51,6 +51,7 @@ static CXTypeKind GetBuiltinTypeKind(const BuiltinType *BT) { BTCASE(Float); BTCASE(Double); BTCASE(LongDouble); + BTCASE(Float128); BTCASE(NullPtr); BTCASE(Overload); BTCASE(Dependent); @@ -466,6 +467,7 @@ CXString clang_getTypeKindSpelling(enum CXTypeKind K) { TKIND(Float); TKIND(Double); TKIND(LongDouble); + TKIND(Float128); TKIND(NullPtr); TKIND(Overload); TKIND(Dependent);