diff --git a/clang/include/clang/Basic/Builtins.h b/clang/include/clang/Basic/Builtins.h --- a/clang/include/clang/Basic/Builtins.h +++ b/clang/include/clang/Basic/Builtins.h @@ -76,7 +76,8 @@ /// Mark the identifiers for all the builtins with their /// appropriate builtin ID # and mark any non-portable builtin identifiers as /// such. - void initializeBuiltins(IdentifierTable &Table, const LangOptions& LangOpts); + void initializeBuiltins(IdentifierTable &Table, const LangOptions &LangOpts, + const TargetInfo &Target); /// Return the identifier name for the specified builtin, /// e.g. "__builtin_abs". @@ -178,6 +179,12 @@ strchr(getRecord(ID).Type, 'A') != nullptr; } + /// Return true if this builtin has a result or any arguments which are + /// long double types (or long long double, or __float128). + bool hasLongDouble(unsigned ID) const { + return strstr(getRecord(ID).Type, "Ld") != nullptr; + } + /// Completely forget that the given ID was ever considered a builtin, /// e.g., because the user provided a conflicting signature. void forgetBuiltin(unsigned ID, IdentifierTable &Table); @@ -240,7 +247,8 @@ /// Is this builtin supported according to the given language options? bool builtinIsSupported(const Builtin::Info &BuiltinInfo, - const LangOptions &LangOpts); + const LangOptions &LangOpts, + const TargetInfo &Target); /// Helper function for isPrintfLike and isScanfLike. bool isLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg, 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 @@ -193,6 +193,7 @@ bool HasFloat16; bool HasBFloat16; bool HasStrictFP; + bool HasLongDouble; unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth; unsigned short SimdDefaultAlign; @@ -571,6 +572,9 @@ /// Determine whether _Float16 is supported on this target. virtual bool hasLegalHalfType() const { return HasLegalHalfType; } + /// Determine whether `long double` type is supported on this target. + virtual bool hasLongDouble() const { return HasLongDouble; } + /// Determine whether the __float128 type is supported on this target. virtual bool hasFloat128Type() const { return HasFloat128; } diff --git a/clang/lib/Basic/Builtins.cpp b/clang/lib/Basic/Builtins.cpp --- a/clang/lib/Basic/Builtins.cpp +++ b/clang/lib/Basic/Builtins.cpp @@ -56,7 +56,8 @@ } bool Builtin::Context::builtinIsSupported(const Builtin::Info &BuiltinInfo, - const LangOptions &LangOpts) { + const LangOptions &LangOpts, + const TargetInfo &Target) { bool BuiltinsUnsupported = (LangOpts.NoBuiltin || LangOpts.isNoBuiltinFunc(BuiltinInfo.Name)) && strchr(BuiltinInfo.Attributes, 'f'); @@ -77,26 +78,29 @@ bool OpenMPUnsupported = !LangOpts.OpenMP && BuiltinInfo.Langs == OMP_LANG; bool CPlusPlusUnsupported = !LangOpts.CPlusPlus && BuiltinInfo.Langs == CXX_LANG; + bool LongDoubleUnsupported = + !Target.hasLongDouble() && strstr(BuiltinInfo.Type, "Ld") != nullptr; return !BuiltinsUnsupported && !MathBuiltinsUnsupported && !OclCUnsupported && !OclC1Unsupported && !OclC2Unsupported && !OpenMPUnsupported && !GnuModeUnsupported && !MSModeUnsupported && !ObjCUnsupported && - !CPlusPlusUnsupported; + !CPlusPlusUnsupported && !LongDoubleUnsupported; } /// initializeBuiltins - Mark the identifiers for all the builtins with their /// appropriate builtin ID # and mark any non-portable builtin identifiers as /// such. void Builtin::Context::initializeBuiltins(IdentifierTable &Table, - const LangOptions& LangOpts) { + const LangOptions &LangOpts, + const TargetInfo &Target) { // Step #1: mark all target-independent builtins with their ID's. for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) - if (builtinIsSupported(BuiltinInfo[i], LangOpts)) { + if (builtinIsSupported(BuiltinInfo[i], LangOpts, Target)) { Table.get(BuiltinInfo[i].Name).setBuiltinID(i); } // Step #2: Register target-specific builtins. for (unsigned i = 0, e = TSRecords.size(); i != e; ++i) - if (builtinIsSupported(TSRecords[i], LangOpts)) + if (builtinIsSupported(TSRecords[i], LangOpts, Target)) Table.get(TSRecords[i].Name).setBuiltinID(i + Builtin::FirstTSBuiltin); // Step #3: Register target-specific builtins for AuxTarget. 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 @@ -38,6 +38,7 @@ HasFloat16 = false; HasBFloat16 = false; HasStrictFP = false; + HasLongDouble = true; PointerWidth = PointerAlign = 32; BoolWidth = BoolAlign = 8; IntWidth = IntAlign = 32; diff --git a/clang/lib/Basic/Targets/AMDGPU.cpp b/clang/lib/Basic/Targets/AMDGPU.cpp --- a/clang/lib/Basic/Targets/AMDGPU.cpp +++ b/clang/lib/Basic/Targets/AMDGPU.cpp @@ -322,6 +322,7 @@ HasLegalHalfType = true; HasFloat16 = true; + HasLongDouble = false; WavefrontSize = GPUFeatures & llvm::AMDGPU::FEATURE_WAVE32 ? 32 : 64; AllowAMDGPUUnsafeFPAtomics = Opts.AllowAMDGPUUnsafeFPAtomics; diff --git a/clang/lib/Basic/Targets/NVPTX.cpp b/clang/lib/Basic/Targets/NVPTX.cpp --- a/clang/lib/Basic/Targets/NVPTX.cpp +++ b/clang/lib/Basic/Targets/NVPTX.cpp @@ -62,6 +62,7 @@ TLSSupported = false; VLASupported = false; + HasLongDouble = false; AddrSpaceMap = &NVPTXAddrSpaceMap; GridValues = llvm::omp::NVPTXGpuGridValues; UseAddrSpaceMapMangling = true; diff --git a/clang/lib/Frontend/ChainedIncludesSource.cpp b/clang/lib/Frontend/ChainedIncludesSource.cpp --- a/clang/lib/Frontend/ChainedIncludesSource.cpp +++ b/clang/lib/Frontend/ChainedIncludesSource.cpp @@ -169,8 +169,8 @@ if (firstInclude) { Preprocessor &PP = Clang->getPreprocessor(); - PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(), - PP.getLangOpts()); + PP.getBuiltinInfo().initializeBuiltins( + PP.getIdentifierTable(), PP.getLangOpts(), PP.getTargetInfo()); } else { assert(!SerialBufs.empty()); SmallVector, 4> Bufs; diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -659,8 +659,8 @@ CI.setSourceManager(&AST->getSourceManager()); CI.setPreprocessor(AST->getPreprocessorPtr()); Preprocessor &PP = CI.getPreprocessor(); - PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(), - PP.getLangOpts()); + PP.getBuiltinInfo().initializeBuiltins( + PP.getIdentifierTable(), PP.getLangOpts(), PP.getTargetInfo()); CI.setASTContext(&AST->getASTContext()); setCurrentInput(Input, std::move(AST)); @@ -900,8 +900,8 @@ if (CI.getLangOpts().Modules || !CI.hasASTContext() || !CI.getASTContext().getExternalSource()) { Preprocessor &PP = CI.getPreprocessor(); - PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(), - PP.getLangOpts()); + PP.getBuiltinInfo().initializeBuiltins( + PP.getIdentifierTable(), PP.getLangOpts(), PP.getTargetInfo()); } else { // FIXME: If this is a problem, recover from it by creating a multiplex // source. diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -1638,6 +1638,12 @@ // usual allocation and deallocation functions. Required by libc++ return 201802; default: + // If we are looking at a long double (or similar) builtin and the + // target doesn't support long double we do not pretend we could use + // the builtin. + if (!getTargetInfo().hasLongDouble() && + getBuiltinInfo().hasLongDouble(II->getBuiltinID())) + return false; return true; } return true; diff --git a/clang/test/Parser/builtin_long_double.c b/clang/test/Parser/builtin_long_double.c new file mode 100644 --- /dev/null +++ b/clang/test/Parser/builtin_long_double.c @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -triple arm-unknown-linux -verify=CPU -fsyntax-only %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux -verify=CPU -fsyntax-only %s +// RUN: %clang_cc1 -triple powerpc64le-unknown-linux -verify=CPU -fsyntax-only %s +// RUN: %clang_cc1 -triple nvptx-unknown-linux -verify=GPU -fsyntax-only %s +// RUN: %clang_cc1 -triple amdgcn-unknown-linux -verify=GPU -fsyntax-only %s +// CPU-no-diagnostics + +double fn(void) { + double d = 0.; + // regular builtin + d += __builtin_canonicalizel(0.0); // GPU-error{{use of unknown builtin}} + // library builtin + d += __builtin_atan2l(0., 0.); // GPU-error{{use of unknown builtin}} + return d; +} diff --git a/clang/test/Preprocessor/has_builtin_long_double.c b/clang/test/Preprocessor/has_builtin_long_double.c new file mode 100644 --- /dev/null +++ b/clang/test/Preprocessor/has_builtin_long_double.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -triple arm-unknown-linux -verify -E %s -o - | FileCheck %s --check-prefix=ARM +// RUN: %clang_cc1 -triple x86_64-unknown-linux -verify -E %s -o - | FileCheck %s --check-prefix=X86 +// RUN: %clang_cc1 -triple powerpc64le-unknown-linux -verify -E %s -o - | FileCheck %s --check-prefix=PPC +// RUN: %clang_cc1 -triple nvptx-unknown-linux -verify -E %s -o - | FileCheck %s --check-prefix=GPU +// RUN: %clang_cc1 -triple amdgcn-unknown-linux -verify -E %s -o - | FileCheck %s --check-prefix=GPU +// expected-no-diagnostics + +// ARM: has_fabs +// X86: has_fabs +// PPC: has_fabs +// PTX: has_fabs +#if __has_builtin(fabs) + void has_fabs(void); +#endif + +// ARM: has_fabsl +// X86: has_fabsl +// PPC: has_fabsl +// GPU-NOT: has_fabsl +#if __has_builtin(fabsl) + void has_fabsl(void); +#endif