diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -657,7 +657,7 @@ /// getRealTypeForBitwidth - /// sets floating point QualTy according to specified bitwidth. /// Returns empty type if there is no appropriate target types. - QualType getRealTypeForBitwidth(unsigned DestWidth) const; + QualType getRealTypeForBitwidth(unsigned DestWidth, bool ExplicitIEEE) const; bool AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const; diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -368,8 +368,13 @@ virtual IntType getLeastIntTypeByWidth(unsigned BitWidth, bool IsSigned) const; - /// Return floating point type with specified width. - RealType getRealTypeByWidth(unsigned BitWidth) const; + /// Return floating point type with specified width. On PPC, there are + /// three possible types for 128-bit floating point: "PPC double-double", + /// IEEE 754R quad precision, and "long double" (which under the covers + /// is represented as one of those two). At this time, there is no support + /// for an explicit "PPC double-double" type (i.e. __ibm128) so we only + /// need to differentiate between "long double" and IEEE quad precision. + RealType getRealTypeByWidth(unsigned BitWidth, bool ExplicitIEEE) const; /// Return the alignment (in bits) of the specified integer type enum. /// diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -10644,8 +10644,10 @@ /// getRealTypeForBitwidth - /// sets floating point QualTy according to specified bitwidth. /// Returns empty type if there is no appropriate target types. -QualType ASTContext::getRealTypeForBitwidth(unsigned DestWidth) const { - TargetInfo::RealType Ty = getTargetInfo().getRealTypeByWidth(DestWidth); +QualType ASTContext::getRealTypeForBitwidth(unsigned DestWidth, + bool ExplicitIEEE) const { + TargetInfo::RealType Ty = + getTargetInfo().getRealTypeByWidth(DestWidth, ExplicitIEEE); switch (Ty) { case TargetInfo::Float: return FloatTy; diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -265,7 +265,8 @@ return NoInt; } -TargetInfo::RealType TargetInfo::getRealTypeByWidth(unsigned BitWidth) const { +TargetInfo::RealType TargetInfo::getRealTypeByWidth(unsigned BitWidth, + bool ExplicitIEEE) const { if (getFloatWidth() == BitWidth) return Float; if (getDoubleWidth() == BitWidth) @@ -277,6 +278,10 @@ return LongDouble; break; case 128: + // The caller explicitly asked for an IEEE compliant type but we still + // have to check if the target supports it. + if (ExplicitIEEE) + return hasFloat128Type() ? Float128 : NoFloat; if (&getLongDoubleFormat() == &llvm::APFloat::PPCDoubleDouble() || &getLongDoubleFormat() == &llvm::APFloat::IEEEquad()) return LongDouble; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3942,7 +3942,8 @@ /// parseModeAttrArg - Parses attribute mode string and returns parsed type /// attribute. static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth, - bool &IntegerMode, bool &ComplexMode) { + bool &IntegerMode, bool &ComplexMode, + bool &ExplicitIEEE) { IntegerMode = true; ComplexMode = false; switch (Str.size()) { @@ -3963,7 +3964,12 @@ case 'X': DestWidth = 96; break; + case 'K': // KFmode - IEEE quad precision (__float128) + ExplicitIEEE = true; + DestWidth = Str[1] == 'I' ? 0 : 128; + break; case 'T': + ExplicitIEEE = false; DestWidth = 128; break; } @@ -4024,6 +4030,7 @@ unsigned DestWidth = 0; bool IntegerMode = true; bool ComplexMode = false; + bool ExplicitIEEE = false; llvm::APInt VectorSize(64, 0); if (Str.size() >= 4 && Str[0] == 'V') { // Minimal length of vector mode is 4: 'V' + NUMBER(>=1) + TYPE(>=2). @@ -4036,7 +4043,7 @@ !Str.substr(1, VectorStringLength).getAsInteger(10, VectorSize) && VectorSize.isPowerOf2()) { parseModeAttrArg(*this, Str.substr(VectorStringLength + 1), DestWidth, - IntegerMode, ComplexMode); + IntegerMode, ComplexMode, ExplicitIEEE); // Avoid duplicate warning from template instantiation. if (!InInstantiation) Diag(AttrLoc, diag::warn_vector_mode_deprecated); @@ -4046,7 +4053,8 @@ } if (!VectorSize) - parseModeAttrArg(*this, Str, DestWidth, IntegerMode, ComplexMode); + parseModeAttrArg(*this, Str, DestWidth, IntegerMode, ComplexMode, + ExplicitIEEE); // FIXME: Sync this with InitializePredefinedMacros; we need to match int8_t // and friends, at least with glibc. @@ -4112,7 +4120,7 @@ NewElemTy = Context.getIntTypeForBitwidth(DestWidth, OldElemTy->isSignedIntegerType()); else - NewElemTy = Context.getRealTypeForBitwidth(DestWidth); + NewElemTy = Context.getRealTypeForBitwidth(DestWidth, ExplicitIEEE); if (NewElemTy.isNull()) { Diag(AttrLoc, diag::err_machine_mode) << 1 /*Unsupported*/ << Name; diff --git a/clang/test/Sema/attr-mode.c b/clang/test/Sema/attr-mode.c --- a/clang/test/Sema/attr-mode.c +++ b/clang/test/Sema/attr-mode.c @@ -4,6 +4,8 @@ // RUN: -verify %s // RUN: %clang_cc1 -triple powerpc64-pc-linux-gnu -DTEST_64BIT_PPC64 -fsyntax-only \ // RUN: -verify %s +// RUN: %clang_cc1 -triple powerpc64-pc-linux-gnu -DTEST_F128_PPC64 -fsyntax-only \ +// RUN: -verify -target-feature +float128 %s // RUN: %clang_cc1 -triple x86_64-pc-linux-gnux32 -DTEST_64BIT_X86 -fsyntax-only \ // RUN: -verify %s // RUN: %clang_cc1 -triple mips-linux-gnu -DTEST_MIPS_32 -fsyntax-only \ @@ -90,6 +92,15 @@ void f_ft128_complex_arg(_Complex long double *x); void test_TFtype(f128ibm *a) { f_ft128_arg (a); } void test_TCtype(c128ibm *a) { f_ft128_complex_arg (a); } +#elif TEST_F128_PPC64 +typedef int invalid_7 __attribute((mode(KF))); // expected-error{{type of machine mode does not match type of base type}} +typedef int invalid_8 __attribute((mode(KI))); // expected-error{{unknown machine mode}} +typedef _Complex float cf128 __attribute__((mode(KC))); +typedef float f128 __attribute__((mode(KF))); +void f_f128_arg(__float128 *x); +void f_f128_complex_arg(_Complex __float128 *x); +void test_KFtype(f128 *a) { f_f128_arg(a); } +void test_KCtype(cf128 *a) { f_f128_complex_arg(a); } #elif TEST_MIPS_32 typedef unsigned int gcc_unwind_word __attribute__((mode(unwind_word))); int foo[sizeof(gcc_unwind_word) == 4 ? 1 : -1];