diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Basic')
89 files changed, 26692 insertions, 0 deletions
diff --git a/contrib/llvm-project/clang/lib/Basic/Attributes.cpp b/contrib/llvm-project/clang/lib/Basic/Attributes.cpp new file mode 100644 index 000000000000..62eea9c59082 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Attributes.cpp @@ -0,0 +1,127 @@ +#include "clang/Basic/Attributes.h" +#include "clang/Basic/AttrSubjectMatchRules.h" +#include "clang/Basic/AttributeCommonInfo.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/StringSwitch.h" +using namespace clang; + +int clang::hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope, + const IdentifierInfo *Attr, const TargetInfo &Target, + const LangOptions &LangOpts) { + StringRef Name = Attr->getName(); + // Normalize the attribute name, __foo__ becomes foo. + if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__")) + Name = Name.substr(2, Name.size() - 4); + + // Normalize the scope name, but only for gnu and clang attributes. + StringRef ScopeName = Scope ? Scope->getName() : ""; + if (ScopeName == "__gnu__") + ScopeName = "gnu"; + else if (ScopeName == "_Clang") + ScopeName = "clang"; + + // As a special case, look for the omp::sequence and omp::directive + // attributes. We support those, but not through the typical attribute + // machinery that goes through TableGen. We support this in all OpenMP modes + // so long as double square brackets are enabled. + if (LangOpts.OpenMP && LangOpts.DoubleSquareBracketAttributes && + ScopeName == "omp") + return (Name == "directive" || Name == "sequence") ? 1 : 0; + +#include "clang/Basic/AttrHasAttributeImpl.inc" + + return 0; +} + +const char *attr::getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule) { + switch (Rule) { +#define ATTR_MATCH_RULE(NAME, SPELLING, IsAbstract) \ + case attr::NAME: \ + return SPELLING; +#include "clang/Basic/AttrSubMatchRulesList.inc" + } + llvm_unreachable("Invalid subject match rule"); +} + +static StringRef +normalizeAttrScopeName(const IdentifierInfo *Scope, + AttributeCommonInfo::Syntax SyntaxUsed) { + if (!Scope) + return ""; + + // Normalize the "__gnu__" scope name to be "gnu" and the "_Clang" scope name + // to be "clang". + StringRef ScopeName = Scope->getName(); + if (SyntaxUsed == AttributeCommonInfo::AS_CXX11 || + SyntaxUsed == AttributeCommonInfo::AS_C2x) { + if (ScopeName == "__gnu__") + ScopeName = "gnu"; + else if (ScopeName == "_Clang") + ScopeName = "clang"; + } + return ScopeName; +} + +static StringRef normalizeAttrName(const IdentifierInfo *Name, + StringRef NormalizedScopeName, + AttributeCommonInfo::Syntax SyntaxUsed) { + // Normalize the attribute name, __foo__ becomes foo. This is only allowable + // for GNU attributes, and attributes using the double square bracket syntax. + bool ShouldNormalize = + SyntaxUsed == AttributeCommonInfo::AS_GNU || + ((SyntaxUsed == AttributeCommonInfo::AS_CXX11 || + SyntaxUsed == AttributeCommonInfo::AS_C2x) && + (NormalizedScopeName.empty() || NormalizedScopeName == "gnu" || + NormalizedScopeName == "clang")); + StringRef AttrName = Name->getName(); + if (ShouldNormalize && AttrName.size() >= 4 && AttrName.startswith("__") && + AttrName.endswith("__")) + AttrName = AttrName.slice(2, AttrName.size() - 2); + + return AttrName; +} + +bool AttributeCommonInfo::isGNUScope() const { + return ScopeName && (ScopeName->isStr("gnu") || ScopeName->isStr("__gnu__")); +} + +#include "clang/Sema/AttrParsedAttrKinds.inc" + +static SmallString<64> normalizeName(const IdentifierInfo *Name, + const IdentifierInfo *Scope, + AttributeCommonInfo::Syntax SyntaxUsed) { + StringRef ScopeName = normalizeAttrScopeName(Scope, SyntaxUsed); + StringRef AttrName = normalizeAttrName(Name, ScopeName, SyntaxUsed); + + SmallString<64> FullName = ScopeName; + if (!ScopeName.empty()) { + assert(SyntaxUsed == AttributeCommonInfo::AS_CXX11 || + SyntaxUsed == AttributeCommonInfo::AS_C2x); + FullName += "::"; + } + FullName += AttrName; + + return FullName; +} + +AttributeCommonInfo::Kind +AttributeCommonInfo::getParsedKind(const IdentifierInfo *Name, + const IdentifierInfo *ScopeName, + Syntax SyntaxUsed) { + return ::getAttrKind(normalizeName(Name, ScopeName, SyntaxUsed), SyntaxUsed); +} + +std::string AttributeCommonInfo::getNormalizedFullName() const { + return static_cast<std::string>( + normalizeName(getAttrName(), getScopeName(), getSyntax())); +} + +unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const { + // Both variables will be used in tablegen generated + // attribute spell list index matching code. + auto Syntax = static_cast<AttributeCommonInfo::Syntax>(getSyntax()); + StringRef Scope = normalizeAttrScopeName(getScopeName(), Syntax); + StringRef Name = normalizeAttrName(getAttrName(), Scope, Syntax); + +#include "clang/Sema/AttrSpellingListIndex.inc" +} diff --git a/contrib/llvm-project/clang/lib/Basic/Builtins.cpp b/contrib/llvm-project/clang/lib/Basic/Builtins.cpp new file mode 100644 index 000000000000..6d278e9c4a22 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Builtins.cpp @@ -0,0 +1,197 @@ +//===--- Builtins.cpp - Builtin function implementation -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements various things for builtin functions. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Builtins.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/StringRef.h" +using namespace clang; + +static const Builtin::Info BuiltinInfo[] = { + { "not a builtin function", nullptr, nullptr, nullptr, ALL_LANGUAGES,nullptr}, +#define BUILTIN(ID, TYPE, ATTRS) \ + { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, +#define LANGBUILTIN(ID, TYPE, ATTRS, LANGS) \ + { #ID, TYPE, ATTRS, nullptr, LANGS, nullptr }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, LANGS) \ + { #ID, TYPE, ATTRS, HEADER, LANGS, nullptr }, +#include "clang/Basic/Builtins.def" +}; + +const Builtin::Info &Builtin::Context::getRecord(unsigned ID) const { + if (ID < Builtin::FirstTSBuiltin) + return BuiltinInfo[ID]; + assert(((ID - Builtin::FirstTSBuiltin) < + (TSRecords.size() + AuxTSRecords.size())) && + "Invalid builtin ID!"); + if (isAuxBuiltinID(ID)) + return AuxTSRecords[getAuxBuiltinID(ID) - Builtin::FirstTSBuiltin]; + return TSRecords[ID - Builtin::FirstTSBuiltin]; +} + +void Builtin::Context::InitializeTarget(const TargetInfo &Target, + const TargetInfo *AuxTarget) { + assert(TSRecords.empty() && "Already initialized target?"); + TSRecords = Target.getTargetBuiltins(); + if (AuxTarget) + AuxTSRecords = AuxTarget->getTargetBuiltins(); +} + +bool Builtin::Context::isBuiltinFunc(llvm::StringRef FuncName) { + for (unsigned i = Builtin::NotBuiltin + 1; i != Builtin::FirstTSBuiltin; ++i) + if (FuncName.equals(BuiltinInfo[i].Name)) + return strchr(BuiltinInfo[i].Attributes, 'f') != nullptr; + + return false; +} + +bool Builtin::Context::builtinIsSupported(const Builtin::Info &BuiltinInfo, + const LangOptions &LangOpts) { + bool BuiltinsUnsupported = + (LangOpts.NoBuiltin || LangOpts.isNoBuiltinFunc(BuiltinInfo.Name)) && + strchr(BuiltinInfo.Attributes, 'f'); + bool CorBuiltinsUnsupported = + !LangOpts.Coroutines && (BuiltinInfo.Langs & COR_LANG); + bool MathBuiltinsUnsupported = + LangOpts.NoMathBuiltin && BuiltinInfo.HeaderName && + llvm::StringRef(BuiltinInfo.HeaderName).equals("math.h"); + bool GnuModeUnsupported = !LangOpts.GNUMode && (BuiltinInfo.Langs & GNU_LANG); + bool MSModeUnsupported = + !LangOpts.MicrosoftExt && (BuiltinInfo.Langs & MS_LANG); + bool ObjCUnsupported = !LangOpts.ObjC && BuiltinInfo.Langs == OBJC_LANG; + bool OclCUnsupported = + !LangOpts.OpenCL && (BuiltinInfo.Langs & ALL_OCL_LANGUAGES); + bool OclGASUnsupported = + !LangOpts.OpenCLGenericAddressSpace && (BuiltinInfo.Langs & OCL_GAS); + bool OclPipeUnsupported = + !LangOpts.OpenCLPipes && (BuiltinInfo.Langs & OCL_PIPE); + // Device side enqueue is not supported until OpenCL 2.0. In 2.0 and higher + // support is indicated with language option for blocks. + bool OclDSEUnsupported = + (LangOpts.getOpenCLCompatibleVersion() < 200 || !LangOpts.Blocks) && + (BuiltinInfo.Langs & OCL_DSE); + bool OpenMPUnsupported = !LangOpts.OpenMP && BuiltinInfo.Langs == OMP_LANG; + bool CUDAUnsupported = !LangOpts.CUDA && BuiltinInfo.Langs == CUDA_LANG; + bool CPlusPlusUnsupported = + !LangOpts.CPlusPlus && BuiltinInfo.Langs == CXX_LANG; + return !BuiltinsUnsupported && !CorBuiltinsUnsupported && + !MathBuiltinsUnsupported && !OclCUnsupported && !OclGASUnsupported && + !OclPipeUnsupported && !OclDSEUnsupported && !OpenMPUnsupported && + !GnuModeUnsupported && !MSModeUnsupported && !ObjCUnsupported && + !CPlusPlusUnsupported && !CUDAUnsupported; +} + +/// 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) { + // 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)) { + 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)) + Table.get(TSRecords[i].Name).setBuiltinID(i + Builtin::FirstTSBuiltin); + + // Step #3: Register target-specific builtins for AuxTarget. + for (unsigned i = 0, e = AuxTSRecords.size(); i != e; ++i) + Table.get(AuxTSRecords[i].Name) + .setBuiltinID(i + Builtin::FirstTSBuiltin + TSRecords.size()); +} + +unsigned Builtin::Context::getRequiredVectorWidth(unsigned ID) const { + const char *WidthPos = ::strchr(getRecord(ID).Attributes, 'V'); + if (!WidthPos) + return 0; + + ++WidthPos; + assert(*WidthPos == ':' && + "Vector width specifier must be followed by a ':'"); + ++WidthPos; + + char *EndPos; + unsigned Width = ::strtol(WidthPos, &EndPos, 10); + assert(*EndPos == ':' && "Vector width specific must end with a ':'"); + return Width; +} + +bool Builtin::Context::isLike(unsigned ID, unsigned &FormatIdx, + bool &HasVAListArg, const char *Fmt) const { + assert(Fmt && "Not passed a format string"); + assert(::strlen(Fmt) == 2 && + "Format string needs to be two characters long"); + assert(::toupper(Fmt[0]) == Fmt[1] && + "Format string is not in the form \"xX\""); + + const char *Like = ::strpbrk(getRecord(ID).Attributes, Fmt); + if (!Like) + return false; + + HasVAListArg = (*Like == Fmt[1]); + + ++Like; + assert(*Like == ':' && "Format specifier must be followed by a ':'"); + ++Like; + + assert(::strchr(Like, ':') && "Format specifier must end with a ':'"); + FormatIdx = ::strtol(Like, nullptr, 10); + return true; +} + +bool Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx, + bool &HasVAListArg) { + return isLike(ID, FormatIdx, HasVAListArg, "pP"); +} + +bool Builtin::Context::isScanfLike(unsigned ID, unsigned &FormatIdx, + bool &HasVAListArg) { + return isLike(ID, FormatIdx, HasVAListArg, "sS"); +} + +bool Builtin::Context::performsCallback(unsigned ID, + SmallVectorImpl<int> &Encoding) const { + const char *CalleePos = ::strchr(getRecord(ID).Attributes, 'C'); + if (!CalleePos) + return false; + + ++CalleePos; + assert(*CalleePos == '<' && + "Callback callee specifier must be followed by a '<'"); + ++CalleePos; + + char *EndPos; + int CalleeIdx = ::strtol(CalleePos, &EndPos, 10); + assert(CalleeIdx >= 0 && "Callee index is supposed to be positive!"); + Encoding.push_back(CalleeIdx); + + while (*EndPos == ',') { + const char *PayloadPos = EndPos + 1; + + int PayloadIdx = ::strtol(PayloadPos, &EndPos, 10); + Encoding.push_back(PayloadIdx); + } + + assert(*EndPos == '>' && "Callback callee specifier must end with a '>'"); + return true; +} + +bool Builtin::Context::canBeRedeclared(unsigned ID) const { + return ID == Builtin::NotBuiltin || + ID == Builtin::BI__va_start || + (!hasReferenceArgsOrResult(ID) && + !hasCustomTypechecking(ID)); +} diff --git a/contrib/llvm-project/clang/lib/Basic/CLWarnings.cpp b/contrib/llvm-project/clang/lib/Basic/CLWarnings.cpp new file mode 100644 index 000000000000..0cf367d9f7f6 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/CLWarnings.cpp @@ -0,0 +1,28 @@ +//===--- CLWarnings.h - Maps some cl.exe warning ids -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the Diagnostic-related interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/CLWarnings.h" +#include "clang/Basic/DiagnosticCategories.h" + +using namespace clang; + +llvm::Optional<diag::Group> +clang::diagGroupFromCLWarningID(unsigned CLWarningID) { + switch (CLWarningID) { + case 4005: return diag::Group::MacroRedefined; + case 4018: return diag::Group::SignCompare; + case 4100: return diag::Group::UnusedParameter; + case 4910: return diag::Group::DllexportExplicitInstantiationDecl; + case 4996: return diag::Group::DeprecatedDeclarations; + } + return {}; +} diff --git a/contrib/llvm-project/clang/lib/Basic/CharInfo.cpp b/contrib/llvm-project/clang/lib/Basic/CharInfo.cpp new file mode 100644 index 000000000000..d02054c9718f --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/CharInfo.cpp @@ -0,0 +1,80 @@ +//===--- CharInfo.cpp - Static Data for Classifying ASCII Characters ------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/CharInfo.h" + +using namespace clang::charinfo; + +// Statically initialize CharInfo table based on ASCII character set +// Reference: FreeBSD 7.2 /usr/share/misc/ascii +const uint16_t clang::charinfo::InfoTable[256] = { + // 0 NUL 1 SOH 2 STX 3 ETX + // 4 EOT 5 ENQ 6 ACK 7 BEL + 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , + // 8 BS 9 HT 10 NL 11 VT + //12 NP 13 CR 14 SO 15 SI + 0 , CHAR_HORZ_WS, CHAR_VERT_WS, CHAR_HORZ_WS, + CHAR_HORZ_WS, CHAR_VERT_WS, 0 , 0 , + //16 DLE 17 DC1 18 DC2 19 DC3 + //20 DC4 21 NAK 22 SYN 23 ETB + 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , + //24 CAN 25 EM 26 SUB 27 ESC + //28 FS 29 GS 30 RS 31 US + 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , + //32 SP 33 ! 34 " 35 # + //36 $ 37 % 38 & 39 ' + CHAR_SPACE , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , + CHAR_PUNCT , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , + //40 ( 41 ) 42 * 43 + + //44 , 45 - 46 . 47 / + CHAR_PUNCT , CHAR_PUNCT , CHAR_RAWDEL , CHAR_RAWDEL , + CHAR_RAWDEL , CHAR_RAWDEL , CHAR_PERIOD , CHAR_RAWDEL , + //48 0 49 1 50 2 51 3 + //52 4 53 5 54 6 55 7 + CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT , + CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT , + //56 8 57 9 58 : 59 ; + //60 < 61 = 62 > 63 ? + CHAR_DIGIT , CHAR_DIGIT , CHAR_RAWDEL , CHAR_RAWDEL , + CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , + //64 @ 65 A 66 B 67 C + //68 D 69 E 70 F 71 G + CHAR_PUNCT , CHAR_XUPPER , CHAR_XUPPER , CHAR_XUPPER , + CHAR_XUPPER , CHAR_XUPPER , CHAR_XUPPER , CHAR_UPPER , + //72 H 73 I 74 J 75 K + //76 L 77 M 78 N 79 O + CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , + CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , + //80 P 81 Q 82 R 83 S + //84 T 85 U 86 V 87 W + CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , + CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , + //88 X 89 Y 90 Z 91 [ + //92 \ 93 ] 94 ^ 95 _ + CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , CHAR_RAWDEL , + CHAR_PUNCT , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_UNDER , + //96 ` 97 a 98 b 99 c + //100 d 101 e 102 f 103 g + CHAR_PUNCT , CHAR_XLOWER , CHAR_XLOWER , CHAR_XLOWER , + CHAR_XLOWER , CHAR_XLOWER , CHAR_XLOWER , CHAR_LOWER , + //104 h 105 i 106 j 107 k + //108 l 109 m 110 n 111 o + CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , + CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , + //112 p 113 q 114 r 115 s + //116 t 117 u 118 v 119 w + CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , + CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , + //120 x 121 y 122 z 123 { + //124 | 125 } 126 ~ 127 DEL + CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , CHAR_RAWDEL , + CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , 0 +}; diff --git a/contrib/llvm-project/clang/lib/Basic/CodeGenOptions.cpp b/contrib/llvm-project/clang/lib/Basic/CodeGenOptions.cpp new file mode 100644 index 000000000000..0c609cfa61de --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/CodeGenOptions.cpp @@ -0,0 +1,23 @@ +//===--- CodeGenOptions.cpp -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/CodeGenOptions.h" +#include <string.h> + +namespace clang { + +CodeGenOptions::CodeGenOptions() { +#define CODEGENOPT(Name, Bits, Default) Name = Default; +#define ENUM_CODEGENOPT(Name, Type, Bits, Default) set##Name(Default); +#include "clang/Basic/CodeGenOptions.def" + + RelocationModel = llvm::Reloc::PIC_; + memcpy(CoverageVersion, "408*", 4); +} + +} // end namespace clang diff --git a/contrib/llvm-project/clang/lib/Basic/Cuda.cpp b/contrib/llvm-project/clang/lib/Basic/Cuda.cpp new file mode 100644 index 000000000000..2d75578b3de0 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Cuda.cpp @@ -0,0 +1,268 @@ +#include "clang/Basic/Cuda.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/VersionTuple.h" + +namespace clang { + +const char *CudaVersionToString(CudaVersion V) { + switch (V) { + case CudaVersion::UNKNOWN: + return "unknown"; + case CudaVersion::CUDA_70: + return "7.0"; + case CudaVersion::CUDA_75: + return "7.5"; + case CudaVersion::CUDA_80: + return "8.0"; + case CudaVersion::CUDA_90: + return "9.0"; + case CudaVersion::CUDA_91: + return "9.1"; + case CudaVersion::CUDA_92: + return "9.2"; + case CudaVersion::CUDA_100: + return "10.0"; + case CudaVersion::CUDA_101: + return "10.1"; + case CudaVersion::CUDA_102: + return "10.2"; + case CudaVersion::CUDA_110: + return "11.0"; + case CudaVersion::CUDA_111: + return "11.1"; + case CudaVersion::CUDA_112: + return "11.2"; + case CudaVersion::CUDA_113: + return "11.3"; + case CudaVersion::CUDA_114: + return "11.4"; + case CudaVersion::CUDA_115: + return "11.5"; + case CudaVersion::NEW: + return ""; + } + llvm_unreachable("invalid enum"); +} + +CudaVersion CudaStringToVersion(const llvm::Twine &S) { + return llvm::StringSwitch<CudaVersion>(S.str()) + .Case("7.0", CudaVersion::CUDA_70) + .Case("7.5", CudaVersion::CUDA_75) + .Case("8.0", CudaVersion::CUDA_80) + .Case("9.0", CudaVersion::CUDA_90) + .Case("9.1", CudaVersion::CUDA_91) + .Case("9.2", CudaVersion::CUDA_92) + .Case("10.0", CudaVersion::CUDA_100) + .Case("10.1", CudaVersion::CUDA_101) + .Case("10.2", CudaVersion::CUDA_102) + .Case("11.0", CudaVersion::CUDA_110) + .Case("11.1", CudaVersion::CUDA_111) + .Case("11.2", CudaVersion::CUDA_112) + .Case("11.3", CudaVersion::CUDA_113) + .Case("11.4", CudaVersion::CUDA_114) + .Case("11.5", CudaVersion::CUDA_115) + .Default(CudaVersion::UNKNOWN); +} + +namespace { +struct CudaArchToStringMap { + CudaArch arch; + const char *arch_name; + const char *virtual_arch_name; +}; +} // namespace + +#define SM2(sm, ca) \ + { CudaArch::SM_##sm, "sm_" #sm, ca } +#define SM(sm) SM2(sm, "compute_" #sm) +#define GFX(gpu) \ + { CudaArch::GFX##gpu, "gfx" #gpu, "compute_amdgcn" } +static const CudaArchToStringMap arch_names[] = { + // clang-format off + {CudaArch::UNUSED, "", ""}, + SM2(20, "compute_20"), SM2(21, "compute_20"), // Fermi + SM(30), SM(32), SM(35), SM(37), // Kepler + SM(50), SM(52), SM(53), // Maxwell + SM(60), SM(61), SM(62), // Pascal + SM(70), SM(72), // Volta + SM(75), // Turing + SM(80), SM(86), // Ampere + GFX(600), // gfx600 + GFX(601), // gfx601 + GFX(602), // gfx602 + GFX(700), // gfx700 + GFX(701), // gfx701 + GFX(702), // gfx702 + GFX(703), // gfx703 + GFX(704), // gfx704 + GFX(705), // gfx705 + GFX(801), // gfx801 + GFX(802), // gfx802 + GFX(803), // gfx803 + GFX(805), // gfx805 + GFX(810), // gfx810 + GFX(900), // gfx900 + GFX(902), // gfx902 + GFX(904), // gfx903 + GFX(906), // gfx906 + GFX(908), // gfx908 + GFX(909), // gfx909 + GFX(90a), // gfx90a + GFX(90c), // gfx90c + GFX(1010), // gfx1010 + GFX(1011), // gfx1011 + GFX(1012), // gfx1012 + GFX(1013), // gfx1013 + GFX(1030), // gfx1030 + GFX(1031), // gfx1031 + GFX(1032), // gfx1032 + GFX(1033), // gfx1033 + GFX(1034), // gfx1034 + GFX(1035), // gfx1035 + {CudaArch::Generic, "generic", ""}, + // clang-format on +}; +#undef SM +#undef SM2 +#undef GFX + +const char *CudaArchToString(CudaArch A) { + auto result = std::find_if( + std::begin(arch_names), std::end(arch_names), + [A](const CudaArchToStringMap &map) { return A == map.arch; }); + if (result == std::end(arch_names)) + return "unknown"; + return result->arch_name; +} + +const char *CudaArchToVirtualArchString(CudaArch A) { + auto result = std::find_if( + std::begin(arch_names), std::end(arch_names), + [A](const CudaArchToStringMap &map) { return A == map.arch; }); + if (result == std::end(arch_names)) + return "unknown"; + return result->virtual_arch_name; +} + +CudaArch StringToCudaArch(llvm::StringRef S) { + auto result = std::find_if( + std::begin(arch_names), std::end(arch_names), + [S](const CudaArchToStringMap &map) { return S == map.arch_name; }); + if (result == std::end(arch_names)) + return CudaArch::UNKNOWN; + return result->arch; +} + +CudaVersion MinVersionForCudaArch(CudaArch A) { + if (A == CudaArch::UNKNOWN) + return CudaVersion::UNKNOWN; + + // AMD GPUs do not depend on CUDA versions. + if (IsAMDGpuArch(A)) + return CudaVersion::CUDA_70; + + switch (A) { + case CudaArch::SM_20: + case CudaArch::SM_21: + case CudaArch::SM_30: + case CudaArch::SM_32: + case CudaArch::SM_35: + case CudaArch::SM_37: + case CudaArch::SM_50: + case CudaArch::SM_52: + case CudaArch::SM_53: + return CudaVersion::CUDA_70; + case CudaArch::SM_60: + case CudaArch::SM_61: + case CudaArch::SM_62: + return CudaVersion::CUDA_80; + case CudaArch::SM_70: + return CudaVersion::CUDA_90; + case CudaArch::SM_72: + return CudaVersion::CUDA_91; + case CudaArch::SM_75: + return CudaVersion::CUDA_100; + case CudaArch::SM_80: + return CudaVersion::CUDA_110; + case CudaArch::SM_86: + return CudaVersion::CUDA_111; + default: + llvm_unreachable("invalid enum"); + } +} + +CudaVersion MaxVersionForCudaArch(CudaArch A) { + // AMD GPUs do not depend on CUDA versions. + if (IsAMDGpuArch(A)) + return CudaVersion::NEW; + + switch (A) { + case CudaArch::UNKNOWN: + return CudaVersion::UNKNOWN; + case CudaArch::SM_20: + case CudaArch::SM_21: + return CudaVersion::CUDA_80; + case CudaArch::SM_30: + return CudaVersion::CUDA_110; + default: + return CudaVersion::NEW; + } +} + +CudaVersion ToCudaVersion(llvm::VersionTuple Version) { + int IVer = + Version.getMajor() * 10 + Version.getMinor().getValueOr(0); + switch(IVer) { + case 70: + return CudaVersion::CUDA_70; + case 75: + return CudaVersion::CUDA_75; + case 80: + return CudaVersion::CUDA_80; + case 90: + return CudaVersion::CUDA_90; + case 91: + return CudaVersion::CUDA_91; + case 92: + return CudaVersion::CUDA_92; + case 100: + return CudaVersion::CUDA_100; + case 101: + return CudaVersion::CUDA_101; + case 102: + return CudaVersion::CUDA_102; + case 110: + return CudaVersion::CUDA_110; + case 111: + return CudaVersion::CUDA_111; + case 112: + return CudaVersion::CUDA_112; + case 113: + return CudaVersion::CUDA_113; + case 114: + return CudaVersion::CUDA_114; + case 115: + return CudaVersion::CUDA_115; + default: + return CudaVersion::UNKNOWN; + } +} + +bool CudaFeatureEnabled(llvm::VersionTuple Version, CudaFeature Feature) { + return CudaFeatureEnabled(ToCudaVersion(Version), Feature); +} + +bool CudaFeatureEnabled(CudaVersion Version, CudaFeature Feature) { + switch (Feature) { + case CudaFeature::CUDA_USES_NEW_LAUNCH: + return Version >= CudaVersion::CUDA_92; + case CudaFeature::CUDA_USES_FATBIN_REGISTER_END: + return Version >= CudaVersion::CUDA_101; + } + llvm_unreachable("Unknown CUDA feature."); +} +} // namespace clang diff --git a/contrib/llvm-project/clang/lib/Basic/DarwinSDKInfo.cpp b/contrib/llvm-project/clang/lib/Basic/DarwinSDKInfo.cpp new file mode 100644 index 000000000000..64bcb45a4cd8 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/DarwinSDKInfo.cpp @@ -0,0 +1,150 @@ +//===--- DarwinSDKInfo.cpp - SDK Information parser for darwin - ----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/DarwinSDKInfo.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/JSON.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" + +using namespace clang; + +Optional<VersionTuple> DarwinSDKInfo::RelatedTargetVersionMapping::map( + const VersionTuple &Key, const VersionTuple &MinimumValue, + Optional<VersionTuple> MaximumValue) const { + if (Key < MinimumKeyVersion) + return MinimumValue; + if (Key > MaximumKeyVersion) + return MaximumValue; + auto KV = Mapping.find(Key.normalize()); + if (KV != Mapping.end()) + return KV->getSecond(); + // If no exact entry found, try just the major key version. Only do so when + // a minor version number is present, to avoid recursing indefinitely into + // the major-only check. + if (Key.getMinor()) + return map(VersionTuple(Key.getMajor()), MinimumValue, MaximumValue); + // If this a major only key, return None for a missing entry. + return None; +} + +Optional<DarwinSDKInfo::RelatedTargetVersionMapping> +DarwinSDKInfo::RelatedTargetVersionMapping::parseJSON( + const llvm::json::Object &Obj, VersionTuple MaximumDeploymentTarget) { + VersionTuple Min = VersionTuple(std::numeric_limits<unsigned>::max()); + VersionTuple Max = VersionTuple(0); + VersionTuple MinValue = Min; + llvm::DenseMap<VersionTuple, VersionTuple> Mapping; + for (const auto &KV : Obj) { + if (auto Val = KV.getSecond().getAsString()) { + llvm::VersionTuple KeyVersion; + llvm::VersionTuple ValueVersion; + if (KeyVersion.tryParse(KV.getFirst()) || ValueVersion.tryParse(*Val)) + return None; + Mapping[KeyVersion.normalize()] = ValueVersion; + if (KeyVersion < Min) + Min = KeyVersion; + if (KeyVersion > Max) + Max = KeyVersion; + if (ValueVersion < MinValue) + MinValue = ValueVersion; + } + } + if (Mapping.empty()) + return None; + return RelatedTargetVersionMapping( + Min, Max, MinValue, MaximumDeploymentTarget, std::move(Mapping)); +} + +static Optional<VersionTuple> getVersionKey(const llvm::json::Object &Obj, + StringRef Key) { + auto Value = Obj.getString(Key); + if (!Value) + return None; + VersionTuple Version; + if (Version.tryParse(*Value)) + return None; + return Version; +} + +Optional<DarwinSDKInfo> +DarwinSDKInfo::parseDarwinSDKSettingsJSON(const llvm::json::Object *Obj) { + auto Version = getVersionKey(*Obj, "Version"); + if (!Version) + return None; + auto MaximumDeploymentVersion = + getVersionKey(*Obj, "MaximumDeploymentTarget"); + if (!MaximumDeploymentVersion) + return None; + llvm::DenseMap<OSEnvPair::StorageType, Optional<RelatedTargetVersionMapping>> + VersionMappings; + if (const auto *VM = Obj->getObject("VersionMap")) { + // FIXME: Generalize this out beyond iOS-deriving targets. + // Look for ios_<targetos> version mapping for targets that derive from ios. + for (const auto &KV : *VM) { + auto Pair = StringRef(KV.getFirst()).split("_"); + if (Pair.first.compare_insensitive("ios") == 0) { + llvm::Triple TT(llvm::Twine("--") + Pair.second.lower()); + if (TT.getOS() != llvm::Triple::UnknownOS) { + auto Mapping = RelatedTargetVersionMapping::parseJSON( + *KV.getSecond().getAsObject(), *MaximumDeploymentVersion); + if (Mapping) + VersionMappings[OSEnvPair(llvm::Triple::IOS, + llvm::Triple::UnknownEnvironment, + TT.getOS(), + llvm::Triple::UnknownEnvironment) + .Value] = std::move(Mapping); + } + } + } + + if (const auto *Mapping = VM->getObject("macOS_iOSMac")) { + auto VersionMap = RelatedTargetVersionMapping::parseJSON( + *Mapping, *MaximumDeploymentVersion); + if (!VersionMap) + return None; + VersionMappings[OSEnvPair::macOStoMacCatalystPair().Value] = + std::move(VersionMap); + } + if (const auto *Mapping = VM->getObject("iOSMac_macOS")) { + auto VersionMap = RelatedTargetVersionMapping::parseJSON( + *Mapping, *MaximumDeploymentVersion); + if (!VersionMap) + return None; + VersionMappings[OSEnvPair::macCatalystToMacOSPair().Value] = + std::move(VersionMap); + } + } + + return DarwinSDKInfo(std::move(*Version), + std::move(*MaximumDeploymentVersion), + std::move(VersionMappings)); +} + +Expected<Optional<DarwinSDKInfo>> +clang::parseDarwinSDKInfo(llvm::vfs::FileSystem &VFS, StringRef SDKRootPath) { + llvm::SmallString<256> Filepath = SDKRootPath; + llvm::sys::path::append(Filepath, "SDKSettings.json"); + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File = + VFS.getBufferForFile(Filepath); + if (!File) { + // If the file couldn't be read, assume it just doesn't exist. + return None; + } + Expected<llvm::json::Value> Result = + llvm::json::parse(File.get()->getBuffer()); + if (!Result) + return Result.takeError(); + + if (const auto *Obj = Result->getAsObject()) { + if (auto SDKInfo = DarwinSDKInfo::parseDarwinSDKSettingsJSON(Obj)) + return std::move(SDKInfo); + } + return llvm::make_error<llvm::StringError>("invalid SDKSettings.json", + llvm::inconvertibleErrorCode()); +} diff --git a/contrib/llvm-project/clang/lib/Basic/Diagnostic.cpp b/contrib/llvm-project/clang/lib/Basic/Diagnostic.cpp new file mode 100644 index 000000000000..ac4b9d2cd5a2 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Diagnostic.cpp @@ -0,0 +1,1180 @@ +//===- Diagnostic.cpp - C Language Family Diagnostic Handling -------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the Diagnostic-related interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/DiagnosticError.h" +#include "clang/Basic/DiagnosticIDs.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Basic/TokenKinds.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/CrashRecoveryContext.h" +#include "llvm/Support/Locale.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <cstring> +#include <limits> +#include <string> +#include <utility> +#include <vector> + +using namespace clang; + +const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB, + DiagNullabilityKind nullability) { + StringRef string; + switch (nullability.first) { + case NullabilityKind::NonNull: + string = nullability.second ? "'nonnull'" : "'_Nonnull'"; + break; + + case NullabilityKind::Nullable: + string = nullability.second ? "'nullable'" : "'_Nullable'"; + break; + + case NullabilityKind::Unspecified: + string = nullability.second ? "'null_unspecified'" : "'_Null_unspecified'"; + break; + + case NullabilityKind::NullableResult: + assert(!nullability.second && + "_Nullable_result isn't supported as context-sensitive keyword"); + string = "_Nullable_result"; + break; + } + + DB.AddString(string); + return DB; +} + +const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB, + llvm::Error &&E) { + DB.AddString(toString(std::move(E))); + return DB; +} + +static void DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK, intptr_t QT, + StringRef Modifier, StringRef Argument, + ArrayRef<DiagnosticsEngine::ArgumentValue> PrevArgs, + SmallVectorImpl<char> &Output, + void *Cookie, + ArrayRef<intptr_t> QualTypeVals) { + StringRef Str = "<can't format argument>"; + Output.append(Str.begin(), Str.end()); +} + +DiagnosticsEngine::DiagnosticsEngine( + IntrusiveRefCntPtr<DiagnosticIDs> diags, + IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, DiagnosticConsumer *client, + bool ShouldOwnClient) + : Diags(std::move(diags)), DiagOpts(std::move(DiagOpts)) { + setClient(client, ShouldOwnClient); + ArgToStringFn = DummyArgToStringFn; + + Reset(); +} + +DiagnosticsEngine::~DiagnosticsEngine() { + // If we own the diagnostic client, destroy it first so that it can access the + // engine from its destructor. + setClient(nullptr); +} + +void DiagnosticsEngine::dump() const { + DiagStatesByLoc.dump(*SourceMgr); +} + +void DiagnosticsEngine::dump(StringRef DiagName) const { + DiagStatesByLoc.dump(*SourceMgr, DiagName); +} + +void DiagnosticsEngine::setClient(DiagnosticConsumer *client, + bool ShouldOwnClient) { + Owner.reset(ShouldOwnClient ? client : nullptr); + Client = client; +} + +void DiagnosticsEngine::pushMappings(SourceLocation Loc) { + DiagStateOnPushStack.push_back(GetCurDiagState()); +} + +bool DiagnosticsEngine::popMappings(SourceLocation Loc) { + if (DiagStateOnPushStack.empty()) + return false; + + if (DiagStateOnPushStack.back() != GetCurDiagState()) { + // State changed at some point between push/pop. + PushDiagStatePoint(DiagStateOnPushStack.back(), Loc); + } + DiagStateOnPushStack.pop_back(); + return true; +} + +void DiagnosticsEngine::Reset() { + ErrorOccurred = false; + UncompilableErrorOccurred = false; + FatalErrorOccurred = false; + UnrecoverableErrorOccurred = false; + + NumWarnings = 0; + NumErrors = 0; + TrapNumErrorsOccurred = 0; + TrapNumUnrecoverableErrorsOccurred = 0; + + CurDiagID = std::numeric_limits<unsigned>::max(); + LastDiagLevel = DiagnosticIDs::Ignored; + DelayedDiagID = 0; + + // Clear state related to #pragma diagnostic. + DiagStates.clear(); + DiagStatesByLoc.clear(); + DiagStateOnPushStack.clear(); + + // Create a DiagState and DiagStatePoint representing diagnostic changes + // through command-line. + DiagStates.emplace_back(); + DiagStatesByLoc.appendFirst(&DiagStates.back()); +} + +void DiagnosticsEngine::SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1, + StringRef Arg2, StringRef Arg3) { + if (DelayedDiagID) + return; + + DelayedDiagID = DiagID; + DelayedDiagArg1 = Arg1.str(); + DelayedDiagArg2 = Arg2.str(); + DelayedDiagArg3 = Arg3.str(); +} + +void DiagnosticsEngine::ReportDelayed() { + unsigned ID = DelayedDiagID; + DelayedDiagID = 0; + Report(ID) << DelayedDiagArg1 << DelayedDiagArg2 << DelayedDiagArg3; +} + +void DiagnosticsEngine::DiagStateMap::appendFirst(DiagState *State) { + assert(Files.empty() && "not first"); + FirstDiagState = CurDiagState = State; + CurDiagStateLoc = SourceLocation(); +} + +void DiagnosticsEngine::DiagStateMap::append(SourceManager &SrcMgr, + SourceLocation Loc, + DiagState *State) { + CurDiagState = State; + CurDiagStateLoc = Loc; + + std::pair<FileID, unsigned> Decomp = SrcMgr.getDecomposedLoc(Loc); + unsigned Offset = Decomp.second; + for (File *F = getFile(SrcMgr, Decomp.first); F; + Offset = F->ParentOffset, F = F->Parent) { + F->HasLocalTransitions = true; + auto &Last = F->StateTransitions.back(); + assert(Last.Offset <= Offset && "state transitions added out of order"); + + if (Last.Offset == Offset) { + if (Last.State == State) + break; + Last.State = State; + continue; + } + + F->StateTransitions.push_back({State, Offset}); + } +} + +DiagnosticsEngine::DiagState * +DiagnosticsEngine::DiagStateMap::lookup(SourceManager &SrcMgr, + SourceLocation Loc) const { + // Common case: we have not seen any diagnostic pragmas. + if (Files.empty()) + return FirstDiagState; + + std::pair<FileID, unsigned> Decomp = SrcMgr.getDecomposedLoc(Loc); + const File *F = getFile(SrcMgr, Decomp.first); + return F->lookup(Decomp.second); +} + +DiagnosticsEngine::DiagState * +DiagnosticsEngine::DiagStateMap::File::lookup(unsigned Offset) const { + auto OnePastIt = + llvm::partition_point(StateTransitions, [=](const DiagStatePoint &P) { + return P.Offset <= Offset; + }); + assert(OnePastIt != StateTransitions.begin() && "missing initial state"); + return OnePastIt[-1].State; +} + +DiagnosticsEngine::DiagStateMap::File * +DiagnosticsEngine::DiagStateMap::getFile(SourceManager &SrcMgr, + FileID ID) const { + // Get or insert the File for this ID. + auto Range = Files.equal_range(ID); + if (Range.first != Range.second) + return &Range.first->second; + auto &F = Files.insert(Range.first, std::make_pair(ID, File()))->second; + + // We created a new File; look up the diagnostic state at the start of it and + // initialize it. + if (ID.isValid()) { + std::pair<FileID, unsigned> Decomp = SrcMgr.getDecomposedIncludedLoc(ID); + F.Parent = getFile(SrcMgr, Decomp.first); + F.ParentOffset = Decomp.second; + F.StateTransitions.push_back({F.Parent->lookup(Decomp.second), 0}); + } else { + // This is the (imaginary) root file into which we pretend all top-level + // files are included; it descends from the initial state. + // + // FIXME: This doesn't guarantee that we use the same ordering as + // isBeforeInTranslationUnit in the cases where someone invented another + // top-level file and added diagnostic pragmas to it. See the code at the + // end of isBeforeInTranslationUnit for the quirks it deals with. + F.StateTransitions.push_back({FirstDiagState, 0}); + } + return &F; +} + +void DiagnosticsEngine::DiagStateMap::dump(SourceManager &SrcMgr, + StringRef DiagName) const { + llvm::errs() << "diagnostic state at "; + CurDiagStateLoc.print(llvm::errs(), SrcMgr); + llvm::errs() << ": " << CurDiagState << "\n"; + + for (auto &F : Files) { + FileID ID = F.first; + File &File = F.second; + + bool PrintedOuterHeading = false; + auto PrintOuterHeading = [&] { + if (PrintedOuterHeading) return; + PrintedOuterHeading = true; + + llvm::errs() << "File " << &File << " <FileID " << ID.getHashValue() + << ">: " << SrcMgr.getBufferOrFake(ID).getBufferIdentifier(); + + if (F.second.Parent) { + std::pair<FileID, unsigned> Decomp = + SrcMgr.getDecomposedIncludedLoc(ID); + assert(File.ParentOffset == Decomp.second); + llvm::errs() << " parent " << File.Parent << " <FileID " + << Decomp.first.getHashValue() << "> "; + SrcMgr.getLocForStartOfFile(Decomp.first) + .getLocWithOffset(Decomp.second) + .print(llvm::errs(), SrcMgr); + } + if (File.HasLocalTransitions) + llvm::errs() << " has_local_transitions"; + llvm::errs() << "\n"; + }; + + if (DiagName.empty()) + PrintOuterHeading(); + + for (DiagStatePoint &Transition : File.StateTransitions) { + bool PrintedInnerHeading = false; + auto PrintInnerHeading = [&] { + if (PrintedInnerHeading) return; + PrintedInnerHeading = true; + + PrintOuterHeading(); + llvm::errs() << " "; + SrcMgr.getLocForStartOfFile(ID) + .getLocWithOffset(Transition.Offset) + .print(llvm::errs(), SrcMgr); + llvm::errs() << ": state " << Transition.State << ":\n"; + }; + + if (DiagName.empty()) + PrintInnerHeading(); + + for (auto &Mapping : *Transition.State) { + StringRef Option = + DiagnosticIDs::getWarningOptionForDiag(Mapping.first); + if (!DiagName.empty() && DiagName != Option) + continue; + + PrintInnerHeading(); + llvm::errs() << " "; + if (Option.empty()) + llvm::errs() << "<unknown " << Mapping.first << ">"; + else + llvm::errs() << Option; + llvm::errs() << ": "; + + switch (Mapping.second.getSeverity()) { + case diag::Severity::Ignored: llvm::errs() << "ignored"; break; + case diag::Severity::Remark: llvm::errs() << "remark"; break; + case diag::Severity::Warning: llvm::errs() << "warning"; break; + case diag::Severity::Error: llvm::errs() << "error"; break; + case diag::Severity::Fatal: llvm::errs() << "fatal"; break; + } + + if (!Mapping.second.isUser()) + llvm::errs() << " default"; + if (Mapping.second.isPragma()) + llvm::errs() << " pragma"; + if (Mapping.second.hasNoWarningAsError()) + llvm::errs() << " no-error"; + if (Mapping.second.hasNoErrorAsFatal()) + llvm::errs() << " no-fatal"; + if (Mapping.second.wasUpgradedFromWarning()) + llvm::errs() << " overruled"; + llvm::errs() << "\n"; + } + } + } +} + +void DiagnosticsEngine::PushDiagStatePoint(DiagState *State, + SourceLocation Loc) { + assert(Loc.isValid() && "Adding invalid loc point"); + DiagStatesByLoc.append(*SourceMgr, Loc, State); +} + +void DiagnosticsEngine::setSeverity(diag::kind Diag, diag::Severity Map, + SourceLocation L) { + assert(Diag < diag::DIAG_UPPER_LIMIT && + "Can only map builtin diagnostics"); + assert((Diags->isBuiltinWarningOrExtension(Diag) || + (Map == diag::Severity::Fatal || Map == diag::Severity::Error)) && + "Cannot map errors into warnings!"); + assert((L.isInvalid() || SourceMgr) && "No SourceMgr for valid location"); + + // Don't allow a mapping to a warning override an error/fatal mapping. + bool WasUpgradedFromWarning = false; + if (Map == diag::Severity::Warning) { + DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag); + if (Info.getSeverity() == diag::Severity::Error || + Info.getSeverity() == diag::Severity::Fatal) { + Map = Info.getSeverity(); + WasUpgradedFromWarning = true; + } + } + DiagnosticMapping Mapping = makeUserMapping(Map, L); + Mapping.setUpgradedFromWarning(WasUpgradedFromWarning); + + // Make sure we propagate the NoWarningAsError flag from an existing + // mapping (which may be the default mapping). + DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag); + Mapping.setNoWarningAsError(Info.hasNoWarningAsError() || + Mapping.hasNoWarningAsError()); + + // Common case; setting all the diagnostics of a group in one place. + if ((L.isInvalid() || L == DiagStatesByLoc.getCurDiagStateLoc()) && + DiagStatesByLoc.getCurDiagState()) { + // FIXME: This is theoretically wrong: if the current state is shared with + // some other location (via push/pop) we will change the state for that + // other location as well. This cannot currently happen, as we can't update + // the diagnostic state at the same location at which we pop. + DiagStatesByLoc.getCurDiagState()->setMapping(Diag, Mapping); + return; + } + + // A diagnostic pragma occurred, create a new DiagState initialized with + // the current one and a new DiagStatePoint to record at which location + // the new state became active. + DiagStates.push_back(*GetCurDiagState()); + DiagStates.back().setMapping(Diag, Mapping); + PushDiagStatePoint(&DiagStates.back(), L); +} + +bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor, + StringRef Group, diag::Severity Map, + SourceLocation Loc) { + // Get the diagnostics in this group. + SmallVector<diag::kind, 256> GroupDiags; + if (Diags->getDiagnosticsInGroup(Flavor, Group, GroupDiags)) + return true; + + // Set the mapping. + for (diag::kind Diag : GroupDiags) + setSeverity(Diag, Map, Loc); + + return false; +} + +bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor, + diag::Group Group, + diag::Severity Map, + SourceLocation Loc) { + return setSeverityForGroup(Flavor, Diags->getWarningOptionForGroup(Group), + Map, Loc); +} + +bool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group, + bool Enabled) { + // If we are enabling this feature, just set the diagnostic mappings to map to + // errors. + if (Enabled) + return setSeverityForGroup(diag::Flavor::WarningOrError, Group, + diag::Severity::Error); + + // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and + // potentially downgrade anything already mapped to be a warning. + + // Get the diagnostics in this group. + SmallVector<diag::kind, 8> GroupDiags; + if (Diags->getDiagnosticsInGroup(diag::Flavor::WarningOrError, Group, + GroupDiags)) + return true; + + // Perform the mapping change. + for (diag::kind Diag : GroupDiags) { + DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag); + + if (Info.getSeverity() == diag::Severity::Error || + Info.getSeverity() == diag::Severity::Fatal) + Info.setSeverity(diag::Severity::Warning); + + Info.setNoWarningAsError(true); + } + + return false; +} + +bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group, + bool Enabled) { + // If we are enabling this feature, just set the diagnostic mappings to map to + // fatal errors. + if (Enabled) + return setSeverityForGroup(diag::Flavor::WarningOrError, Group, + diag::Severity::Fatal); + + // Otherwise, we want to set the diagnostic mapping's "no Wfatal-errors" bit, + // and potentially downgrade anything already mapped to be a fatal error. + + // Get the diagnostics in this group. + SmallVector<diag::kind, 8> GroupDiags; + if (Diags->getDiagnosticsInGroup(diag::Flavor::WarningOrError, Group, + GroupDiags)) + return true; + + // Perform the mapping change. + for (diag::kind Diag : GroupDiags) { + DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag); + + if (Info.getSeverity() == diag::Severity::Fatal) + Info.setSeverity(diag::Severity::Error); + + Info.setNoErrorAsFatal(true); + } + + return false; +} + +void DiagnosticsEngine::setSeverityForAll(diag::Flavor Flavor, + diag::Severity Map, + SourceLocation Loc) { + // Get all the diagnostics. + std::vector<diag::kind> AllDiags; + DiagnosticIDs::getAllDiagnostics(Flavor, AllDiags); + + // Set the mapping. + for (diag::kind Diag : AllDiags) + if (Diags->isBuiltinWarningOrExtension(Diag)) + setSeverity(Diag, Map, Loc); +} + +void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) { + assert(CurDiagID == std::numeric_limits<unsigned>::max() && + "Multiple diagnostics in flight at once!"); + + CurDiagLoc = storedDiag.getLocation(); + CurDiagID = storedDiag.getID(); + DiagStorage.NumDiagArgs = 0; + + DiagStorage.DiagRanges.clear(); + DiagStorage.DiagRanges.append(storedDiag.range_begin(), + storedDiag.range_end()); + + DiagStorage.FixItHints.clear(); + DiagStorage.FixItHints.append(storedDiag.fixit_begin(), + storedDiag.fixit_end()); + + assert(Client && "DiagnosticConsumer not set!"); + Level DiagLevel = storedDiag.getLevel(); + Diagnostic Info(this, storedDiag.getMessage()); + Client->HandleDiagnostic(DiagLevel, Info); + if (Client->IncludeInDiagnosticCounts()) { + if (DiagLevel == DiagnosticsEngine::Warning) + ++NumWarnings; + } + + CurDiagID = std::numeric_limits<unsigned>::max(); +} + +bool DiagnosticsEngine::EmitCurrentDiagnostic(bool Force) { + assert(getClient() && "DiagnosticClient not set!"); + + bool Emitted; + if (Force) { + Diagnostic Info(this); + + // Figure out the diagnostic level of this message. + DiagnosticIDs::Level DiagLevel + = Diags->getDiagnosticLevel(Info.getID(), Info.getLocation(), *this); + + Emitted = (DiagLevel != DiagnosticIDs::Ignored); + if (Emitted) { + // Emit the diagnostic regardless of suppression level. + Diags->EmitDiag(*this, DiagLevel); + } + } else { + // Process the diagnostic, sending the accumulated information to the + // DiagnosticConsumer. + Emitted = ProcessDiag(); + } + + // Clear out the current diagnostic object. + Clear(); + + // If there was a delayed diagnostic, emit it now. + if (!Force && DelayedDiagID) + ReportDelayed(); + + return Emitted; +} + +DiagnosticConsumer::~DiagnosticConsumer() = default; + +void DiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) { + if (!IncludeInDiagnosticCounts()) + return; + + if (DiagLevel == DiagnosticsEngine::Warning) + ++NumWarnings; + else if (DiagLevel >= DiagnosticsEngine::Error) + ++NumErrors; +} + +/// ModifierIs - Return true if the specified modifier matches specified string. +template <std::size_t StrLen> +static bool ModifierIs(const char *Modifier, unsigned ModifierLen, + const char (&Str)[StrLen]) { + return StrLen-1 == ModifierLen && memcmp(Modifier, Str, StrLen-1) == 0; +} + +/// ScanForward - Scans forward, looking for the given character, skipping +/// nested clauses and escaped characters. +static const char *ScanFormat(const char *I, const char *E, char Target) { + unsigned Depth = 0; + + for ( ; I != E; ++I) { + if (Depth == 0 && *I == Target) return I; + if (Depth != 0 && *I == '}') Depth--; + + if (*I == '%') { + I++; + if (I == E) break; + + // Escaped characters get implicitly skipped here. + + // Format specifier. + if (!isDigit(*I) && !isPunctuation(*I)) { + for (I++; I != E && !isDigit(*I) && *I != '{'; I++) ; + if (I == E) break; + if (*I == '{') + Depth++; + } + } + } + return E; +} + +/// HandleSelectModifier - Handle the integer 'select' modifier. This is used +/// like this: %select{foo|bar|baz}2. This means that the integer argument +/// "%2" has a value from 0-2. If the value is 0, the diagnostic prints 'foo'. +/// If the value is 1, it prints 'bar'. If it has the value 2, it prints 'baz'. +/// This is very useful for certain classes of variant diagnostics. +static void HandleSelectModifier(const Diagnostic &DInfo, unsigned ValNo, + const char *Argument, unsigned ArgumentLen, + SmallVectorImpl<char> &OutStr) { + const char *ArgumentEnd = Argument+ArgumentLen; + + // Skip over 'ValNo' |'s. + while (ValNo) { + const char *NextVal = ScanFormat(Argument, ArgumentEnd, '|'); + assert(NextVal != ArgumentEnd && "Value for integer select modifier was" + " larger than the number of options in the diagnostic string!"); + Argument = NextVal+1; // Skip this string. + --ValNo; + } + + // Get the end of the value. This is either the } or the |. + const char *EndPtr = ScanFormat(Argument, ArgumentEnd, '|'); + + // Recursively format the result of the select clause into the output string. + DInfo.FormatDiagnostic(Argument, EndPtr, OutStr); +} + +/// HandleIntegerSModifier - Handle the integer 's' modifier. This adds the +/// letter 's' to the string if the value is not 1. This is used in cases like +/// this: "you idiot, you have %4 parameter%s4!". +static void HandleIntegerSModifier(unsigned ValNo, + SmallVectorImpl<char> &OutStr) { + if (ValNo != 1) + OutStr.push_back('s'); +} + +/// HandleOrdinalModifier - Handle the integer 'ord' modifier. This +/// prints the ordinal form of the given integer, with 1 corresponding +/// to the first ordinal. Currently this is hard-coded to use the +/// English form. +static void HandleOrdinalModifier(unsigned ValNo, + SmallVectorImpl<char> &OutStr) { + assert(ValNo != 0 && "ValNo must be strictly positive!"); + + llvm::raw_svector_ostream Out(OutStr); + + // We could use text forms for the first N ordinals, but the numeric + // forms are actually nicer in diagnostics because they stand out. + Out << ValNo << llvm::getOrdinalSuffix(ValNo); +} + +/// PluralNumber - Parse an unsigned integer and advance Start. +static unsigned PluralNumber(const char *&Start, const char *End) { + // Programming 101: Parse a decimal number :-) + unsigned Val = 0; + while (Start != End && *Start >= '0' && *Start <= '9') { + Val *= 10; + Val += *Start - '0'; + ++Start; + } + return Val; +} + +/// TestPluralRange - Test if Val is in the parsed range. Modifies Start. +static bool TestPluralRange(unsigned Val, const char *&Start, const char *End) { + if (*Start != '[') { + unsigned Ref = PluralNumber(Start, End); + return Ref == Val; + } + + ++Start; + unsigned Low = PluralNumber(Start, End); + assert(*Start == ',' && "Bad plural expression syntax: expected ,"); + ++Start; + unsigned High = PluralNumber(Start, End); + assert(*Start == ']' && "Bad plural expression syntax: expected )"); + ++Start; + return Low <= Val && Val <= High; +} + +/// EvalPluralExpr - Actual expression evaluator for HandlePluralModifier. +static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End) { + // Empty condition? + if (*Start == ':') + return true; + + while (true) { + char C = *Start; + if (C == '%') { + // Modulo expression + ++Start; + unsigned Arg = PluralNumber(Start, End); + assert(*Start == '=' && "Bad plural expression syntax: expected ="); + ++Start; + unsigned ValMod = ValNo % Arg; + if (TestPluralRange(ValMod, Start, End)) + return true; + } else { + assert((C == '[' || (C >= '0' && C <= '9')) && + "Bad plural expression syntax: unexpected character"); + // Range expression + if (TestPluralRange(ValNo, Start, End)) + return true; + } + + // Scan for next or-expr part. + Start = std::find(Start, End, ','); + if (Start == End) + break; + ++Start; + } + return false; +} + +/// HandlePluralModifier - Handle the integer 'plural' modifier. This is used +/// for complex plural forms, or in languages where all plurals are complex. +/// The syntax is: %plural{cond1:form1|cond2:form2|:form3}, where condn are +/// conditions that are tested in order, the form corresponding to the first +/// that applies being emitted. The empty condition is always true, making the +/// last form a default case. +/// Conditions are simple boolean expressions, where n is the number argument. +/// Here are the rules. +/// condition := expression | empty +/// empty := -> always true +/// expression := numeric [',' expression] -> logical or +/// numeric := range -> true if n in range +/// | '%' number '=' range -> true if n % number in range +/// range := number +/// | '[' number ',' number ']' -> ranges are inclusive both ends +/// +/// Here are some examples from the GNU gettext manual written in this form: +/// English: +/// {1:form0|:form1} +/// Latvian: +/// {0:form2|%100=11,%10=0,%10=[2,9]:form1|:form0} +/// Gaeilge: +/// {1:form0|2:form1|:form2} +/// Romanian: +/// {1:form0|0,%100=[1,19]:form1|:form2} +/// Lithuanian: +/// {%10=0,%100=[10,19]:form2|%10=1:form0|:form1} +/// Russian (requires repeated form): +/// {%100=[11,14]:form2|%10=1:form0|%10=[2,4]:form1|:form2} +/// Slovak +/// {1:form0|[2,4]:form1|:form2} +/// Polish (requires repeated form): +/// {1:form0|%100=[10,20]:form2|%10=[2,4]:form1|:form2} +static void HandlePluralModifier(const Diagnostic &DInfo, unsigned ValNo, + const char *Argument, unsigned ArgumentLen, + SmallVectorImpl<char> &OutStr) { + const char *ArgumentEnd = Argument + ArgumentLen; + while (true) { + assert(Argument < ArgumentEnd && "Plural expression didn't match."); + const char *ExprEnd = Argument; + while (*ExprEnd != ':') { + assert(ExprEnd != ArgumentEnd && "Plural missing expression end"); + ++ExprEnd; + } + if (EvalPluralExpr(ValNo, Argument, ExprEnd)) { + Argument = ExprEnd + 1; + ExprEnd = ScanFormat(Argument, ArgumentEnd, '|'); + + // Recursively format the result of the plural clause into the + // output string. + DInfo.FormatDiagnostic(Argument, ExprEnd, OutStr); + return; + } + Argument = ScanFormat(Argument, ArgumentEnd - 1, '|') + 1; + } +} + +/// Returns the friendly description for a token kind that will appear +/// without quotes in diagnostic messages. These strings may be translatable in +/// future. +static const char *getTokenDescForDiagnostic(tok::TokenKind Kind) { + switch (Kind) { + case tok::identifier: + return "identifier"; + default: + return nullptr; + } +} + +/// FormatDiagnostic - Format this diagnostic into a string, substituting the +/// formal arguments into the %0 slots. The result is appended onto the Str +/// array. +void Diagnostic:: +FormatDiagnostic(SmallVectorImpl<char> &OutStr) const { + if (!StoredDiagMessage.empty()) { + OutStr.append(StoredDiagMessage.begin(), StoredDiagMessage.end()); + return; + } + + StringRef Diag = + getDiags()->getDiagnosticIDs()->getDescription(getID()); + + FormatDiagnostic(Diag.begin(), Diag.end(), OutStr); +} + +void Diagnostic:: +FormatDiagnostic(const char *DiagStr, const char *DiagEnd, + SmallVectorImpl<char> &OutStr) const { + // When the diagnostic string is only "%0", the entire string is being given + // by an outside source. Remove unprintable characters from this string + // and skip all the other string processing. + if (DiagEnd - DiagStr == 2 && + StringRef(DiagStr, DiagEnd - DiagStr).equals("%0") && + getArgKind(0) == DiagnosticsEngine::ak_std_string) { + const std::string &S = getArgStdStr(0); + for (char c : S) { + if (llvm::sys::locale::isPrint(c) || c == '\t') { + OutStr.push_back(c); + } + } + return; + } + + /// FormattedArgs - Keep track of all of the arguments formatted by + /// ConvertArgToString and pass them into subsequent calls to + /// ConvertArgToString, allowing the implementation to avoid redundancies in + /// obvious cases. + SmallVector<DiagnosticsEngine::ArgumentValue, 8> FormattedArgs; + + /// QualTypeVals - Pass a vector of arrays so that QualType names can be + /// compared to see if more information is needed to be printed. + SmallVector<intptr_t, 2> QualTypeVals; + SmallString<64> Tree; + + for (unsigned i = 0, e = getNumArgs(); i < e; ++i) + if (getArgKind(i) == DiagnosticsEngine::ak_qualtype) + QualTypeVals.push_back(getRawArg(i)); + + while (DiagStr != DiagEnd) { + if (DiagStr[0] != '%') { + // Append non-%0 substrings to Str if we have one. + const char *StrEnd = std::find(DiagStr, DiagEnd, '%'); + OutStr.append(DiagStr, StrEnd); + DiagStr = StrEnd; + continue; + } else if (isPunctuation(DiagStr[1])) { + OutStr.push_back(DiagStr[1]); // %% -> %. + DiagStr += 2; + continue; + } + + // Skip the %. + ++DiagStr; + + // This must be a placeholder for a diagnostic argument. The format for a + // placeholder is one of "%0", "%modifier0", or "%modifier{arguments}0". + // The digit is a number from 0-9 indicating which argument this comes from. + // The modifier is a string of digits from the set [-a-z]+, arguments is a + // brace enclosed string. + const char *Modifier = nullptr, *Argument = nullptr; + unsigned ModifierLen = 0, ArgumentLen = 0; + + // Check to see if we have a modifier. If so eat it. + if (!isDigit(DiagStr[0])) { + Modifier = DiagStr; + while (DiagStr[0] == '-' || + (DiagStr[0] >= 'a' && DiagStr[0] <= 'z')) + ++DiagStr; + ModifierLen = DiagStr-Modifier; + + // If we have an argument, get it next. + if (DiagStr[0] == '{') { + ++DiagStr; // Skip {. + Argument = DiagStr; + + DiagStr = ScanFormat(DiagStr, DiagEnd, '}'); + assert(DiagStr != DiagEnd && "Mismatched {}'s in diagnostic string!"); + ArgumentLen = DiagStr-Argument; + ++DiagStr; // Skip }. + } + } + + assert(isDigit(*DiagStr) && "Invalid format for argument in diagnostic"); + unsigned ArgNo = *DiagStr++ - '0'; + + // Only used for type diffing. + unsigned ArgNo2 = ArgNo; + + DiagnosticsEngine::ArgumentKind Kind = getArgKind(ArgNo); + if (ModifierIs(Modifier, ModifierLen, "diff")) { + assert(*DiagStr == ',' && isDigit(*(DiagStr + 1)) && + "Invalid format for diff modifier"); + ++DiagStr; // Comma. + ArgNo2 = *DiagStr++ - '0'; + DiagnosticsEngine::ArgumentKind Kind2 = getArgKind(ArgNo2); + if (Kind == DiagnosticsEngine::ak_qualtype && + Kind2 == DiagnosticsEngine::ak_qualtype) + Kind = DiagnosticsEngine::ak_qualtype_pair; + else { + // %diff only supports QualTypes. For other kinds of arguments, + // use the default printing. For example, if the modifier is: + // "%diff{compare $ to $|other text}1,2" + // treat it as: + // "compare %1 to %2" + const char *ArgumentEnd = Argument + ArgumentLen; + const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|'); + assert(ScanFormat(Pipe + 1, ArgumentEnd, '|') == ArgumentEnd && + "Found too many '|'s in a %diff modifier!"); + const char *FirstDollar = ScanFormat(Argument, Pipe, '$'); + const char *SecondDollar = ScanFormat(FirstDollar + 1, Pipe, '$'); + const char ArgStr1[] = { '%', static_cast<char>('0' + ArgNo) }; + const char ArgStr2[] = { '%', static_cast<char>('0' + ArgNo2) }; + FormatDiagnostic(Argument, FirstDollar, OutStr); + FormatDiagnostic(ArgStr1, ArgStr1 + 2, OutStr); + FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr); + FormatDiagnostic(ArgStr2, ArgStr2 + 2, OutStr); + FormatDiagnostic(SecondDollar + 1, Pipe, OutStr); + continue; + } + } + + switch (Kind) { + // ---- STRINGS ---- + case DiagnosticsEngine::ak_std_string: { + const std::string &S = getArgStdStr(ArgNo); + assert(ModifierLen == 0 && "No modifiers for strings yet"); + OutStr.append(S.begin(), S.end()); + break; + } + case DiagnosticsEngine::ak_c_string: { + const char *S = getArgCStr(ArgNo); + assert(ModifierLen == 0 && "No modifiers for strings yet"); + + // Don't crash if get passed a null pointer by accident. + if (!S) + S = "(null)"; + + OutStr.append(S, S + strlen(S)); + break; + } + // ---- INTEGERS ---- + case DiagnosticsEngine::ak_sint: { + int64_t Val = getArgSInt(ArgNo); + + if (ModifierIs(Modifier, ModifierLen, "select")) { + HandleSelectModifier(*this, (unsigned)Val, Argument, ArgumentLen, + OutStr); + } else if (ModifierIs(Modifier, ModifierLen, "s")) { + HandleIntegerSModifier(Val, OutStr); + } else if (ModifierIs(Modifier, ModifierLen, "plural")) { + HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen, + OutStr); + } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) { + HandleOrdinalModifier((unsigned)Val, OutStr); + } else { + assert(ModifierLen == 0 && "Unknown integer modifier"); + llvm::raw_svector_ostream(OutStr) << Val; + } + break; + } + case DiagnosticsEngine::ak_uint: { + uint64_t Val = getArgUInt(ArgNo); + + if (ModifierIs(Modifier, ModifierLen, "select")) { + HandleSelectModifier(*this, Val, Argument, ArgumentLen, OutStr); + } else if (ModifierIs(Modifier, ModifierLen, "s")) { + HandleIntegerSModifier(Val, OutStr); + } else if (ModifierIs(Modifier, ModifierLen, "plural")) { + HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen, + OutStr); + } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) { + HandleOrdinalModifier(Val, OutStr); + } else { + assert(ModifierLen == 0 && "Unknown integer modifier"); + llvm::raw_svector_ostream(OutStr) << Val; + } + break; + } + // ---- TOKEN SPELLINGS ---- + case DiagnosticsEngine::ak_tokenkind: { + tok::TokenKind Kind = static_cast<tok::TokenKind>(getRawArg(ArgNo)); + assert(ModifierLen == 0 && "No modifiers for token kinds yet"); + + llvm::raw_svector_ostream Out(OutStr); + if (const char *S = tok::getPunctuatorSpelling(Kind)) + // Quoted token spelling for punctuators. + Out << '\'' << S << '\''; + else if (const char *S = tok::getKeywordSpelling(Kind)) + // Unquoted token spelling for keywords. + Out << S; + else if (const char *S = getTokenDescForDiagnostic(Kind)) + // Unquoted translatable token name. + Out << S; + else if (const char *S = tok::getTokenName(Kind)) + // Debug name, shouldn't appear in user-facing diagnostics. + Out << '<' << S << '>'; + else + Out << "(null)"; + break; + } + // ---- NAMES and TYPES ---- + case DiagnosticsEngine::ak_identifierinfo: { + const IdentifierInfo *II = getArgIdentifier(ArgNo); + assert(ModifierLen == 0 && "No modifiers for strings yet"); + + // Don't crash if get passed a null pointer by accident. + if (!II) { + const char *S = "(null)"; + OutStr.append(S, S + strlen(S)); + continue; + } + + llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\''; + break; + } + case DiagnosticsEngine::ak_addrspace: + case DiagnosticsEngine::ak_qual: + case DiagnosticsEngine::ak_qualtype: + case DiagnosticsEngine::ak_declarationname: + case DiagnosticsEngine::ak_nameddecl: + case DiagnosticsEngine::ak_nestednamespec: + case DiagnosticsEngine::ak_declcontext: + case DiagnosticsEngine::ak_attr: + getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo), + StringRef(Modifier, ModifierLen), + StringRef(Argument, ArgumentLen), + FormattedArgs, + OutStr, QualTypeVals); + break; + case DiagnosticsEngine::ak_qualtype_pair: { + // Create a struct with all the info needed for printing. + TemplateDiffTypes TDT; + TDT.FromType = getRawArg(ArgNo); + TDT.ToType = getRawArg(ArgNo2); + TDT.ElideType = getDiags()->ElideType; + TDT.ShowColors = getDiags()->ShowColors; + TDT.TemplateDiffUsed = false; + intptr_t val = reinterpret_cast<intptr_t>(&TDT); + + const char *ArgumentEnd = Argument + ArgumentLen; + const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|'); + + // Print the tree. If this diagnostic already has a tree, skip the + // second tree. + if (getDiags()->PrintTemplateTree && Tree.empty()) { + TDT.PrintFromType = true; + TDT.PrintTree = true; + getDiags()->ConvertArgToString(Kind, val, + StringRef(Modifier, ModifierLen), + StringRef(Argument, ArgumentLen), + FormattedArgs, + Tree, QualTypeVals); + // If there is no tree information, fall back to regular printing. + if (!Tree.empty()) { + FormatDiagnostic(Pipe + 1, ArgumentEnd, OutStr); + break; + } + } + + // Non-tree printing, also the fall-back when tree printing fails. + // The fall-back is triggered when the types compared are not templates. + const char *FirstDollar = ScanFormat(Argument, ArgumentEnd, '$'); + const char *SecondDollar = ScanFormat(FirstDollar + 1, ArgumentEnd, '$'); + + // Append before text + FormatDiagnostic(Argument, FirstDollar, OutStr); + + // Append first type + TDT.PrintTree = false; + TDT.PrintFromType = true; + getDiags()->ConvertArgToString(Kind, val, + StringRef(Modifier, ModifierLen), + StringRef(Argument, ArgumentLen), + FormattedArgs, + OutStr, QualTypeVals); + if (!TDT.TemplateDiffUsed) + FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype, + TDT.FromType)); + + // Append middle text + FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr); + + // Append second type + TDT.PrintFromType = false; + getDiags()->ConvertArgToString(Kind, val, + StringRef(Modifier, ModifierLen), + StringRef(Argument, ArgumentLen), + FormattedArgs, + OutStr, QualTypeVals); + if (!TDT.TemplateDiffUsed) + FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype, + TDT.ToType)); + + // Append end text + FormatDiagnostic(SecondDollar + 1, Pipe, OutStr); + break; + } + } + + // Remember this argument info for subsequent formatting operations. Turn + // std::strings into a null terminated string to make it be the same case as + // all the other ones. + if (Kind == DiagnosticsEngine::ak_qualtype_pair) + continue; + else if (Kind != DiagnosticsEngine::ak_std_string) + FormattedArgs.push_back(std::make_pair(Kind, getRawArg(ArgNo))); + else + FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_c_string, + (intptr_t)getArgStdStr(ArgNo).c_str())); + } + + // Append the type tree to the end of the diagnostics. + OutStr.append(Tree.begin(), Tree.end()); +} + +StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, + StringRef Message) + : ID(ID), Level(Level), Message(Message) {} + +StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, + const Diagnostic &Info) + : ID(Info.getID()), Level(Level) { + assert((Info.getLocation().isInvalid() || Info.hasSourceManager()) && + "Valid source location without setting a source manager for diagnostic"); + if (Info.getLocation().isValid()) + Loc = FullSourceLoc(Info.getLocation(), Info.getSourceManager()); + SmallString<64> Message; + Info.FormatDiagnostic(Message); + this->Message.assign(Message.begin(), Message.end()); + this->Ranges.assign(Info.getRanges().begin(), Info.getRanges().end()); + this->FixIts.assign(Info.getFixItHints().begin(), Info.getFixItHints().end()); +} + +StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, + StringRef Message, FullSourceLoc Loc, + ArrayRef<CharSourceRange> Ranges, + ArrayRef<FixItHint> FixIts) + : ID(ID), Level(Level), Loc(Loc), Message(Message), + Ranges(Ranges.begin(), Ranges.end()), FixIts(FixIts.begin(), FixIts.end()) +{ +} + +/// IncludeInDiagnosticCounts - This method (whose default implementation +/// returns true) indicates whether the diagnostics handled by this +/// DiagnosticConsumer should be included in the number of diagnostics +/// reported by DiagnosticsEngine. +bool DiagnosticConsumer::IncludeInDiagnosticCounts() const { return true; } + +void IgnoringDiagConsumer::anchor() {} + +ForwardingDiagnosticConsumer::~ForwardingDiagnosticConsumer() = default; + +void ForwardingDiagnosticConsumer::HandleDiagnostic( + DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) { + Target.HandleDiagnostic(DiagLevel, Info); +} + +void ForwardingDiagnosticConsumer::clear() { + DiagnosticConsumer::clear(); + Target.clear(); +} + +bool ForwardingDiagnosticConsumer::IncludeInDiagnosticCounts() const { + return Target.IncludeInDiagnosticCounts(); +} + +PartialDiagnostic::DiagStorageAllocator::DiagStorageAllocator() { + for (unsigned I = 0; I != NumCached; ++I) + FreeList[I] = Cached + I; + NumFreeListEntries = NumCached; +} + +PartialDiagnostic::DiagStorageAllocator::~DiagStorageAllocator() { + // Don't assert if we are in a CrashRecovery context, as this invariant may + // be invalidated during a crash. + assert((NumFreeListEntries == NumCached || + llvm::CrashRecoveryContext::isRecoveringFromCrash()) && + "A partial is on the lam"); +} + +char DiagnosticError::ID; diff --git a/contrib/llvm-project/clang/lib/Basic/DiagnosticIDs.cpp b/contrib/llvm-project/clang/lib/Basic/DiagnosticIDs.cpp new file mode 100644 index 000000000000..87db131992e4 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/DiagnosticIDs.cpp @@ -0,0 +1,853 @@ +//===--- DiagnosticIDs.cpp - Diagnostic IDs Handling ----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the Diagnostic IDs-related interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/DiagnosticIDs.h" +#include "clang/Basic/AllDiagnostics.h" +#include "clang/Basic/DiagnosticCategories.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/ErrorHandling.h" +#include <map> +using namespace clang; + +//===----------------------------------------------------------------------===// +// Builtin Diagnostic information +//===----------------------------------------------------------------------===// + +namespace { + +struct StaticDiagInfoRec; + +// Store the descriptions in a separate table to avoid pointers that need to +// be relocated, and also decrease the amount of data needed on 64-bit +// platforms. See "How To Write Shared Libraries" by Ulrich Drepper. +struct StaticDiagInfoDescriptionStringTable { +#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + char ENUM##_desc[sizeof(DESC)]; + // clang-format off +#include "clang/Basic/DiagnosticCommonKinds.inc" +#include "clang/Basic/DiagnosticDriverKinds.inc" +#include "clang/Basic/DiagnosticFrontendKinds.inc" +#include "clang/Basic/DiagnosticSerializationKinds.inc" +#include "clang/Basic/DiagnosticLexKinds.inc" +#include "clang/Basic/DiagnosticParseKinds.inc" +#include "clang/Basic/DiagnosticASTKinds.inc" +#include "clang/Basic/DiagnosticCommentKinds.inc" +#include "clang/Basic/DiagnosticCrossTUKinds.inc" +#include "clang/Basic/DiagnosticSemaKinds.inc" +#include "clang/Basic/DiagnosticAnalysisKinds.inc" +#include "clang/Basic/DiagnosticRefactoringKinds.inc" + // clang-format on +#undef DIAG +}; + +const StaticDiagInfoDescriptionStringTable StaticDiagInfoDescriptions = { +#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + DESC, +// clang-format off +#include "clang/Basic/DiagnosticCommonKinds.inc" +#include "clang/Basic/DiagnosticDriverKinds.inc" +#include "clang/Basic/DiagnosticFrontendKinds.inc" +#include "clang/Basic/DiagnosticSerializationKinds.inc" +#include "clang/Basic/DiagnosticLexKinds.inc" +#include "clang/Basic/DiagnosticParseKinds.inc" +#include "clang/Basic/DiagnosticASTKinds.inc" +#include "clang/Basic/DiagnosticCommentKinds.inc" +#include "clang/Basic/DiagnosticCrossTUKinds.inc" +#include "clang/Basic/DiagnosticSemaKinds.inc" +#include "clang/Basic/DiagnosticAnalysisKinds.inc" +#include "clang/Basic/DiagnosticRefactoringKinds.inc" + // clang-format on +#undef DIAG +}; + +extern const StaticDiagInfoRec StaticDiagInfo[]; + +// Stored separately from StaticDiagInfoRec to pack better. Otherwise, +// StaticDiagInfoRec would have extra padding on 64-bit platforms. +const uint32_t StaticDiagInfoDescriptionOffsets[] = { +#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + offsetof(StaticDiagInfoDescriptionStringTable, ENUM##_desc), +// clang-format off +#include "clang/Basic/DiagnosticCommonKinds.inc" +#include "clang/Basic/DiagnosticDriverKinds.inc" +#include "clang/Basic/DiagnosticFrontendKinds.inc" +#include "clang/Basic/DiagnosticSerializationKinds.inc" +#include "clang/Basic/DiagnosticLexKinds.inc" +#include "clang/Basic/DiagnosticParseKinds.inc" +#include "clang/Basic/DiagnosticASTKinds.inc" +#include "clang/Basic/DiagnosticCommentKinds.inc" +#include "clang/Basic/DiagnosticCrossTUKinds.inc" +#include "clang/Basic/DiagnosticSemaKinds.inc" +#include "clang/Basic/DiagnosticAnalysisKinds.inc" +#include "clang/Basic/DiagnosticRefactoringKinds.inc" + // clang-format on +#undef DIAG +}; + +// Diagnostic classes. +enum { + CLASS_NOTE = 0x01, + CLASS_REMARK = 0x02, + CLASS_WARNING = 0x03, + CLASS_EXTENSION = 0x04, + CLASS_ERROR = 0x05 +}; + +struct StaticDiagInfoRec { + uint16_t DiagID; + uint8_t DefaultSeverity : 3; + uint8_t Class : 3; + uint8_t SFINAE : 2; + uint8_t Category : 6; + uint8_t WarnNoWerror : 1; + uint8_t WarnShowInSystemHeader : 1; + uint8_t WarnShowInSystemMacro : 1; + + uint16_t OptionGroupIndex : 15; + uint16_t Deferrable : 1; + + uint16_t DescriptionLen; + + unsigned getOptionGroupIndex() const { + return OptionGroupIndex; + } + + StringRef getDescription() const { + size_t MyIndex = this - &StaticDiagInfo[0]; + uint32_t StringOffset = StaticDiagInfoDescriptionOffsets[MyIndex]; + const char* Table = reinterpret_cast<const char*>(&StaticDiagInfoDescriptions); + return StringRef(&Table[StringOffset], DescriptionLen); + } + + diag::Flavor getFlavor() const { + return Class == CLASS_REMARK ? diag::Flavor::Remark + : diag::Flavor::WarningOrError; + } + + bool operator<(const StaticDiagInfoRec &RHS) const { + return DiagID < RHS.DiagID; + } +}; + +#define STRINGIFY_NAME(NAME) #NAME +#define VALIDATE_DIAG_SIZE(NAME) \ + static_assert( \ + static_cast<unsigned>(diag::NUM_BUILTIN_##NAME##_DIAGNOSTICS) < \ + static_cast<unsigned>(diag::DIAG_START_##NAME) + \ + static_cast<unsigned>(diag::DIAG_SIZE_##NAME), \ + STRINGIFY_NAME( \ + DIAG_SIZE_##NAME) " is insufficient to contain all " \ + "diagnostics, it may need to be made larger in " \ + "DiagnosticIDs.h."); +VALIDATE_DIAG_SIZE(COMMON) +VALIDATE_DIAG_SIZE(DRIVER) +VALIDATE_DIAG_SIZE(FRONTEND) +VALIDATE_DIAG_SIZE(SERIALIZATION) +VALIDATE_DIAG_SIZE(LEX) +VALIDATE_DIAG_SIZE(PARSE) +VALIDATE_DIAG_SIZE(AST) +VALIDATE_DIAG_SIZE(COMMENT) +VALIDATE_DIAG_SIZE(CROSSTU) +VALIDATE_DIAG_SIZE(SEMA) +VALIDATE_DIAG_SIZE(ANALYSIS) +VALIDATE_DIAG_SIZE(REFACTORING) +#undef VALIDATE_DIAG_SIZE +#undef STRINGIFY_NAME + +const StaticDiagInfoRec StaticDiagInfo[] = { +// clang-format off +#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ + SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \ + { \ + diag::ENUM, \ + DEFAULT_SEVERITY, \ + CLASS, \ + DiagnosticIDs::SFINAE, \ + CATEGORY, \ + NOWERROR, \ + SHOWINSYSHEADER, \ + SHOWINSYSMACRO, \ + GROUP, \ + DEFERRABLE, \ + STR_SIZE(DESC, uint16_t)}, +#include "clang/Basic/DiagnosticCommonKinds.inc" +#include "clang/Basic/DiagnosticDriverKinds.inc" +#include "clang/Basic/DiagnosticFrontendKinds.inc" +#include "clang/Basic/DiagnosticSerializationKinds.inc" +#include "clang/Basic/DiagnosticLexKinds.inc" +#include "clang/Basic/DiagnosticParseKinds.inc" +#include "clang/Basic/DiagnosticASTKinds.inc" +#include "clang/Basic/DiagnosticCommentKinds.inc" +#include "clang/Basic/DiagnosticCrossTUKinds.inc" +#include "clang/Basic/DiagnosticSemaKinds.inc" +#include "clang/Basic/DiagnosticAnalysisKinds.inc" +#include "clang/Basic/DiagnosticRefactoringKinds.inc" +// clang-format on +#undef DIAG +}; + +} // namespace + +static const unsigned StaticDiagInfoSize = llvm::array_lengthof(StaticDiagInfo); + +/// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID, +/// or null if the ID is invalid. +static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) { + // Out of bounds diag. Can't be in the table. + using namespace diag; + if (DiagID >= DIAG_UPPER_LIMIT || DiagID <= DIAG_START_COMMON) + return nullptr; + + // Compute the index of the requested diagnostic in the static table. + // 1. Add the number of diagnostics in each category preceding the + // diagnostic and of the category the diagnostic is in. This gives us + // the offset of the category in the table. + // 2. Subtract the number of IDs in each category from our ID. This gives us + // the offset of the diagnostic in the category. + // This is cheaper than a binary search on the table as it doesn't touch + // memory at all. + unsigned Offset = 0; + unsigned ID = DiagID - DIAG_START_COMMON - 1; +#define CATEGORY(NAME, PREV) \ + if (DiagID > DIAG_START_##NAME) { \ + Offset += NUM_BUILTIN_##PREV##_DIAGNOSTICS - DIAG_START_##PREV - 1; \ + ID -= DIAG_START_##NAME - DIAG_START_##PREV; \ + } +CATEGORY(DRIVER, COMMON) +CATEGORY(FRONTEND, DRIVER) +CATEGORY(SERIALIZATION, FRONTEND) +CATEGORY(LEX, SERIALIZATION) +CATEGORY(PARSE, LEX) +CATEGORY(AST, PARSE) +CATEGORY(COMMENT, AST) +CATEGORY(CROSSTU, COMMENT) +CATEGORY(SEMA, CROSSTU) +CATEGORY(ANALYSIS, SEMA) +CATEGORY(REFACTORING, ANALYSIS) +#undef CATEGORY + + // Avoid out of bounds reads. + if (ID + Offset >= StaticDiagInfoSize) + return nullptr; + + assert(ID < StaticDiagInfoSize && Offset < StaticDiagInfoSize); + + const StaticDiagInfoRec *Found = &StaticDiagInfo[ID + Offset]; + // If the diag id doesn't match we found a different diag, abort. This can + // happen when this function is called with an ID that points into a hole in + // the diagID space. + if (Found->DiagID != DiagID) + return nullptr; + return Found; +} + +static DiagnosticMapping GetDefaultDiagMapping(unsigned DiagID) { + DiagnosticMapping Info = DiagnosticMapping::Make( + diag::Severity::Fatal, /*IsUser=*/false, /*IsPragma=*/false); + + if (const StaticDiagInfoRec *StaticInfo = GetDiagInfo(DiagID)) { + Info.setSeverity((diag::Severity)StaticInfo->DefaultSeverity); + + if (StaticInfo->WarnNoWerror) { + assert(Info.getSeverity() == diag::Severity::Warning && + "Unexpected mapping with no-Werror bit!"); + Info.setNoWarningAsError(true); + } + } + + return Info; +} + +/// getCategoryNumberForDiag - Return the category number that a specified +/// DiagID belongs to, or 0 if no category. +unsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return Info->Category; + return 0; +} + +namespace { + // The diagnostic category names. + struct StaticDiagCategoryRec { + const char *NameStr; + uint8_t NameLen; + + StringRef getName() const { + return StringRef(NameStr, NameLen); + } + }; +} + +// Unfortunately, the split between DiagnosticIDs and Diagnostic is not +// particularly clean, but for now we just implement this method here so we can +// access GetDefaultDiagMapping. +DiagnosticMapping & +DiagnosticsEngine::DiagState::getOrAddMapping(diag::kind Diag) { + std::pair<iterator, bool> Result = + DiagMap.insert(std::make_pair(Diag, DiagnosticMapping())); + + // Initialize the entry if we added it. + if (Result.second) + Result.first->second = GetDefaultDiagMapping(Diag); + + return Result.first->second; +} + +static const StaticDiagCategoryRec CategoryNameTable[] = { +#define GET_CATEGORY_TABLE +#define CATEGORY(X, ENUM) { X, STR_SIZE(X, uint8_t) }, +#include "clang/Basic/DiagnosticGroups.inc" +#undef GET_CATEGORY_TABLE + { nullptr, 0 } +}; + +/// getNumberOfCategories - Return the number of categories +unsigned DiagnosticIDs::getNumberOfCategories() { + return llvm::array_lengthof(CategoryNameTable) - 1; +} + +/// getCategoryNameFromID - Given a category ID, return the name of the +/// category, an empty string if CategoryID is zero, or null if CategoryID is +/// invalid. +StringRef DiagnosticIDs::getCategoryNameFromID(unsigned CategoryID) { + if (CategoryID >= getNumberOfCategories()) + return StringRef(); + return CategoryNameTable[CategoryID].getName(); +} + + + +DiagnosticIDs::SFINAEResponse +DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return static_cast<DiagnosticIDs::SFINAEResponse>(Info->SFINAE); + return SFINAE_Report; +} + +bool DiagnosticIDs::isDeferrable(unsigned DiagID) { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return Info->Deferrable; + return false; +} + +/// getBuiltinDiagClass - Return the class field of the diagnostic. +/// +static unsigned getBuiltinDiagClass(unsigned DiagID) { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return Info->Class; + return ~0U; +} + +//===----------------------------------------------------------------------===// +// Custom Diagnostic information +//===----------------------------------------------------------------------===// + +namespace clang { + namespace diag { + class CustomDiagInfo { + typedef std::pair<DiagnosticIDs::Level, std::string> DiagDesc; + std::vector<DiagDesc> DiagInfo; + std::map<DiagDesc, unsigned> DiagIDs; + public: + + /// getDescription - Return the description of the specified custom + /// diagnostic. + StringRef getDescription(unsigned DiagID) const { + assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() && + "Invalid diagnostic ID"); + return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second; + } + + /// getLevel - Return the level of the specified custom diagnostic. + DiagnosticIDs::Level getLevel(unsigned DiagID) const { + assert(DiagID - DIAG_UPPER_LIMIT < DiagInfo.size() && + "Invalid diagnostic ID"); + return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first; + } + + unsigned getOrCreateDiagID(DiagnosticIDs::Level L, StringRef Message, + DiagnosticIDs &Diags) { + DiagDesc D(L, std::string(Message)); + // Check to see if it already exists. + std::map<DiagDesc, unsigned>::iterator I = DiagIDs.lower_bound(D); + if (I != DiagIDs.end() && I->first == D) + return I->second; + + // If not, assign a new ID. + unsigned ID = DiagInfo.size()+DIAG_UPPER_LIMIT; + DiagIDs.insert(std::make_pair(D, ID)); + DiagInfo.push_back(D); + return ID; + } + }; + + } // end diag namespace +} // end clang namespace + + +//===----------------------------------------------------------------------===// +// Common Diagnostic implementation +//===----------------------------------------------------------------------===// + +DiagnosticIDs::DiagnosticIDs() {} + +DiagnosticIDs::~DiagnosticIDs() {} + +/// getCustomDiagID - Return an ID for a diagnostic with the specified message +/// and level. If this is the first request for this diagnostic, it is +/// registered and created, otherwise the existing ID is returned. +/// +/// \param FormatString A fixed diagnostic format string that will be hashed and +/// mapped to a unique DiagID. +unsigned DiagnosticIDs::getCustomDiagID(Level L, StringRef FormatString) { + if (!CustomDiagInfo) + CustomDiagInfo.reset(new diag::CustomDiagInfo()); + return CustomDiagInfo->getOrCreateDiagID(L, FormatString, *this); +} + + +/// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic +/// level of the specified diagnostic ID is a Warning or Extension. +/// This only works on builtin diagnostics, not custom ones, and is not legal to +/// call on NOTEs. +bool DiagnosticIDs::isBuiltinWarningOrExtension(unsigned DiagID) { + return DiagID < diag::DIAG_UPPER_LIMIT && + getBuiltinDiagClass(DiagID) != CLASS_ERROR; +} + +/// Determine whether the given built-in diagnostic ID is a +/// Note. +bool DiagnosticIDs::isBuiltinNote(unsigned DiagID) { + return DiagID < diag::DIAG_UPPER_LIMIT && + getBuiltinDiagClass(DiagID) == CLASS_NOTE; +} + +/// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic +/// ID is for an extension of some sort. This also returns EnabledByDefault, +/// which is set to indicate whether the diagnostic is ignored by default (in +/// which case -pedantic enables it) or treated as a warning/error by default. +/// +bool DiagnosticIDs::isBuiltinExtensionDiag(unsigned DiagID, + bool &EnabledByDefault) { + if (DiagID >= diag::DIAG_UPPER_LIMIT || + getBuiltinDiagClass(DiagID) != CLASS_EXTENSION) + return false; + + EnabledByDefault = + GetDefaultDiagMapping(DiagID).getSeverity() != diag::Severity::Ignored; + return true; +} + +bool DiagnosticIDs::isDefaultMappingAsError(unsigned DiagID) { + if (DiagID >= diag::DIAG_UPPER_LIMIT) + return false; + + return GetDefaultDiagMapping(DiagID).getSeverity() >= diag::Severity::Error; +} + +/// getDescription - Given a diagnostic ID, return a description of the +/// issue. +StringRef DiagnosticIDs::getDescription(unsigned DiagID) const { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return Info->getDescription(); + assert(CustomDiagInfo && "Invalid CustomDiagInfo"); + return CustomDiagInfo->getDescription(DiagID); +} + +static DiagnosticIDs::Level toLevel(diag::Severity SV) { + switch (SV) { + case diag::Severity::Ignored: + return DiagnosticIDs::Ignored; + case diag::Severity::Remark: + return DiagnosticIDs::Remark; + case diag::Severity::Warning: + return DiagnosticIDs::Warning; + case diag::Severity::Error: + return DiagnosticIDs::Error; + case diag::Severity::Fatal: + return DiagnosticIDs::Fatal; + } + llvm_unreachable("unexpected severity"); +} + +/// getDiagnosticLevel - Based on the way the client configured the +/// DiagnosticsEngine object, classify the specified diagnostic ID into a Level, +/// by consumable the DiagnosticClient. +DiagnosticIDs::Level +DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc, + const DiagnosticsEngine &Diag) const { + // Handle custom diagnostics, which cannot be mapped. + if (DiagID >= diag::DIAG_UPPER_LIMIT) { + assert(CustomDiagInfo && "Invalid CustomDiagInfo"); + return CustomDiagInfo->getLevel(DiagID); + } + + unsigned DiagClass = getBuiltinDiagClass(DiagID); + if (DiagClass == CLASS_NOTE) return DiagnosticIDs::Note; + return toLevel(getDiagnosticSeverity(DiagID, Loc, Diag)); +} + +/// Based on the way the client configured the Diagnostic +/// object, classify the specified diagnostic ID into a Level, consumable by +/// the DiagnosticClient. +/// +/// \param Loc The source location we are interested in finding out the +/// diagnostic state. Can be null in order to query the latest state. +diag::Severity +DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc, + const DiagnosticsEngine &Diag) const { + assert(getBuiltinDiagClass(DiagID) != CLASS_NOTE); + + // Specific non-error diagnostics may be mapped to various levels from ignored + // to error. Errors can only be mapped to fatal. + diag::Severity Result = diag::Severity::Fatal; + + // Get the mapping information, or compute it lazily. + DiagnosticsEngine::DiagState *State = Diag.GetDiagStateForLoc(Loc); + DiagnosticMapping &Mapping = State->getOrAddMapping((diag::kind)DiagID); + + // TODO: Can a null severity really get here? + if (Mapping.getSeverity() != diag::Severity()) + Result = Mapping.getSeverity(); + + // Upgrade ignored diagnostics if -Weverything is enabled. + if (State->EnableAllWarnings && Result == diag::Severity::Ignored && + !Mapping.isUser() && getBuiltinDiagClass(DiagID) != CLASS_REMARK) + Result = diag::Severity::Warning; + + // Ignore -pedantic diagnostics inside __extension__ blocks. + // (The diagnostics controlled by -pedantic are the extension diagnostics + // that are not enabled by default.) + bool EnabledByDefault = false; + bool IsExtensionDiag = isBuiltinExtensionDiag(DiagID, EnabledByDefault); + if (Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault) + return diag::Severity::Ignored; + + // For extension diagnostics that haven't been explicitly mapped, check if we + // should upgrade the diagnostic. + if (IsExtensionDiag && !Mapping.isUser()) + Result = std::max(Result, State->ExtBehavior); + + // At this point, ignored errors can no longer be upgraded. + if (Result == diag::Severity::Ignored) + return Result; + + // Honor -w: this disables all messages which which are not Error/Fatal by + // default (disregarding attempts to upgrade severity from Warning to Error), + // as well as disabling all messages which are currently mapped to Warning + // (whether by default or downgraded from Error via e.g. -Wno-error or #pragma + // diagnostic.) + if (State->IgnoreAllWarnings) { + if (Result == diag::Severity::Warning || + (Result >= diag::Severity::Error && + !isDefaultMappingAsError((diag::kind)DiagID))) + return diag::Severity::Ignored; + } + + // If -Werror is enabled, map warnings to errors unless explicitly disabled. + if (Result == diag::Severity::Warning) { + if (State->WarningsAsErrors && !Mapping.hasNoWarningAsError()) + Result = diag::Severity::Error; + } + + // If -Wfatal-errors is enabled, map errors to fatal unless explicitly + // disabled. + if (Result == diag::Severity::Error) { + if (State->ErrorsAsFatal && !Mapping.hasNoErrorAsFatal()) + Result = diag::Severity::Fatal; + } + + // If explicitly requested, map fatal errors to errors. + if (Result == diag::Severity::Fatal && + Diag.CurDiagID != diag::fatal_too_many_errors && Diag.FatalsAsError) + Result = diag::Severity::Error; + + // Custom diagnostics always are emitted in system headers. + bool ShowInSystemHeader = + !GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemHeader; + + // If we are in a system header, we ignore it. We look at the diagnostic class + // because we also want to ignore extensions and warnings in -Werror and + // -pedantic-errors modes, which *map* warnings/extensions to errors. + if (State->SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() && + Diag.getSourceManager().isInSystemHeader( + Diag.getSourceManager().getExpansionLoc(Loc))) + return diag::Severity::Ignored; + + // We also ignore warnings due to system macros + bool ShowInSystemMacro = + !GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemMacro; + if (State->SuppressSystemWarnings && !ShowInSystemMacro && Loc.isValid() && + Diag.getSourceManager().isInSystemMacro(Loc)) + return diag::Severity::Ignored; + + return Result; +} + +#define GET_DIAG_ARRAYS +#include "clang/Basic/DiagnosticGroups.inc" +#undef GET_DIAG_ARRAYS + +namespace { + struct WarningOption { + uint16_t NameOffset; + uint16_t Members; + uint16_t SubGroups; + + // String is stored with a pascal-style length byte. + StringRef getName() const { + return StringRef(DiagGroupNames + NameOffset + 1, + DiagGroupNames[NameOffset]); + } + }; +} + +// Second the table of options, sorted by name for fast binary lookup. +static const WarningOption OptionTable[] = { +#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups) \ + {FlagNameOffset, Members, SubGroups}, +#include "clang/Basic/DiagnosticGroups.inc" +#undef DIAG_ENTRY +}; + +StringRef DiagnosticIDs::getWarningOptionForGroup(diag::Group Group) { + return OptionTable[static_cast<int>(Group)].getName(); +} + +/// getWarningOptionForDiag - Return the lowest-level warning option that +/// enables the specified diagnostic. If there is no -Wfoo flag that controls +/// the diagnostic, this returns null. +StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return getWarningOptionForGroup( + static_cast<diag::Group>(Info->getOptionGroupIndex())); + return StringRef(); +} + +std::vector<std::string> DiagnosticIDs::getDiagnosticFlags() { + std::vector<std::string> Res; + for (size_t I = 1; DiagGroupNames[I] != '\0';) { + std::string Diag(DiagGroupNames + I + 1, DiagGroupNames[I]); + I += DiagGroupNames[I] + 1; + Res.push_back("-W" + Diag); + Res.push_back("-Wno-" + Diag); + } + + return Res; +} + +/// Return \c true if any diagnostics were found in this group, even if they +/// were filtered out due to having the wrong flavor. +static bool getDiagnosticsInGroup(diag::Flavor Flavor, + const WarningOption *Group, + SmallVectorImpl<diag::kind> &Diags) { + // An empty group is considered to be a warning group: we have empty groups + // for GCC compatibility, and GCC does not have remarks. + if (!Group->Members && !Group->SubGroups) + return Flavor == diag::Flavor::Remark; + + bool NotFound = true; + + // Add the members of the option diagnostic set. + const int16_t *Member = DiagArrays + Group->Members; + for (; *Member != -1; ++Member) { + if (GetDiagInfo(*Member)->getFlavor() == Flavor) { + NotFound = false; + Diags.push_back(*Member); + } + } + + // Add the members of the subgroups. + const int16_t *SubGroups = DiagSubGroups + Group->SubGroups; + for (; *SubGroups != (int16_t)-1; ++SubGroups) + NotFound &= getDiagnosticsInGroup(Flavor, &OptionTable[(short)*SubGroups], + Diags); + + return NotFound; +} + +bool +DiagnosticIDs::getDiagnosticsInGroup(diag::Flavor Flavor, StringRef Group, + SmallVectorImpl<diag::kind> &Diags) const { + auto Found = llvm::partition_point( + OptionTable, [=](const WarningOption &O) { return O.getName() < Group; }); + if (Found == std::end(OptionTable) || Found->getName() != Group) + return true; // Option not found. + + return ::getDiagnosticsInGroup(Flavor, Found, Diags); +} + +void DiagnosticIDs::getAllDiagnostics(diag::Flavor Flavor, + std::vector<diag::kind> &Diags) { + for (unsigned i = 0; i != StaticDiagInfoSize; ++i) + if (StaticDiagInfo[i].getFlavor() == Flavor) + Diags.push_back(StaticDiagInfo[i].DiagID); +} + +StringRef DiagnosticIDs::getNearestOption(diag::Flavor Flavor, + StringRef Group) { + StringRef Best; + unsigned BestDistance = Group.size() + 1; // Maximum threshold. + for (const WarningOption &O : OptionTable) { + // Don't suggest ignored warning flags. + if (!O.Members && !O.SubGroups) + continue; + + unsigned Distance = O.getName().edit_distance(Group, true, BestDistance); + if (Distance > BestDistance) + continue; + + // Don't suggest groups that are not of this kind. + llvm::SmallVector<diag::kind, 8> Diags; + if (::getDiagnosticsInGroup(Flavor, &O, Diags) || Diags.empty()) + continue; + + if (Distance == BestDistance) { + // Two matches with the same distance, don't prefer one over the other. + Best = ""; + } else if (Distance < BestDistance) { + // This is a better match. + Best = O.getName(); + BestDistance = Distance; + } + } + + return Best; +} + +/// ProcessDiag - This is the method used to report a diagnostic that is +/// finally fully formed. +bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const { + Diagnostic Info(&Diag); + + assert(Diag.getClient() && "DiagnosticClient not set!"); + + // Figure out the diagnostic level of this message. + unsigned DiagID = Info.getID(); + DiagnosticIDs::Level DiagLevel + = getDiagnosticLevel(DiagID, Info.getLocation(), Diag); + + // Update counts for DiagnosticErrorTrap even if a fatal error occurred + // or diagnostics are suppressed. + if (DiagLevel >= DiagnosticIDs::Error) { + ++Diag.TrapNumErrorsOccurred; + if (isUnrecoverable(DiagID)) + ++Diag.TrapNumUnrecoverableErrorsOccurred; + } + + if (Diag.SuppressAllDiagnostics) + return false; + + if (DiagLevel != DiagnosticIDs::Note) { + // Record that a fatal error occurred only when we see a second + // non-note diagnostic. This allows notes to be attached to the + // fatal error, but suppresses any diagnostics that follow those + // notes. + if (Diag.LastDiagLevel == DiagnosticIDs::Fatal) + Diag.FatalErrorOccurred = true; + + Diag.LastDiagLevel = DiagLevel; + } + + // If a fatal error has already been emitted, silence all subsequent + // diagnostics. + if (Diag.FatalErrorOccurred) { + if (DiagLevel >= DiagnosticIDs::Error && + Diag.Client->IncludeInDiagnosticCounts()) { + ++Diag.NumErrors; + } + + return false; + } + + // If the client doesn't care about this message, don't issue it. If this is + // a note and the last real diagnostic was ignored, ignore it too. + if (DiagLevel == DiagnosticIDs::Ignored || + (DiagLevel == DiagnosticIDs::Note && + Diag.LastDiagLevel == DiagnosticIDs::Ignored)) + return false; + + if (DiagLevel >= DiagnosticIDs::Error) { + if (isUnrecoverable(DiagID)) + Diag.UnrecoverableErrorOccurred = true; + + // Warnings which have been upgraded to errors do not prevent compilation. + if (isDefaultMappingAsError(DiagID)) + Diag.UncompilableErrorOccurred = true; + + Diag.ErrorOccurred = true; + if (Diag.Client->IncludeInDiagnosticCounts()) { + ++Diag.NumErrors; + } + + // If we've emitted a lot of errors, emit a fatal error instead of it to + // stop a flood of bogus errors. + if (Diag.ErrorLimit && Diag.NumErrors > Diag.ErrorLimit && + DiagLevel == DiagnosticIDs::Error) { + Diag.SetDelayedDiagnostic(diag::fatal_too_many_errors); + return false; + } + } + + // Make sure we set FatalErrorOccurred to ensure that the notes from the + // diagnostic that caused `fatal_too_many_errors` won't be emitted. + if (Diag.CurDiagID == diag::fatal_too_many_errors) + Diag.FatalErrorOccurred = true; + // Finally, report it. + EmitDiag(Diag, DiagLevel); + return true; +} + +void DiagnosticIDs::EmitDiag(DiagnosticsEngine &Diag, Level DiagLevel) const { + Diagnostic Info(&Diag); + assert(DiagLevel != DiagnosticIDs::Ignored && "Cannot emit ignored diagnostics!"); + + Diag.Client->HandleDiagnostic((DiagnosticsEngine::Level)DiagLevel, Info); + if (Diag.Client->IncludeInDiagnosticCounts()) { + if (DiagLevel == DiagnosticIDs::Warning) + ++Diag.NumWarnings; + } + + Diag.CurDiagID = ~0U; +} + +bool DiagnosticIDs::isUnrecoverable(unsigned DiagID) const { + if (DiagID >= diag::DIAG_UPPER_LIMIT) { + assert(CustomDiagInfo && "Invalid CustomDiagInfo"); + // Custom diagnostics. + return CustomDiagInfo->getLevel(DiagID) >= DiagnosticIDs::Error; + } + + // Only errors may be unrecoverable. + if (getBuiltinDiagClass(DiagID) < CLASS_ERROR) + return false; + + if (DiagID == diag::err_unavailable || + DiagID == diag::err_unavailable_message) + return false; + + // Currently we consider all ARC errors as recoverable. + if (isARCDiagnostic(DiagID)) + return false; + + return true; +} + +bool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) { + unsigned cat = getCategoryNumberForDiag(DiagID); + return DiagnosticIDs::getCategoryNameFromID(cat).startswith("ARC "); +} diff --git a/contrib/llvm-project/clang/lib/Basic/DiagnosticOptions.cpp b/contrib/llvm-project/clang/lib/Basic/DiagnosticOptions.cpp new file mode 100644 index 000000000000..68571f2cf94f --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/DiagnosticOptions.cpp @@ -0,0 +1,24 @@ +//===- DiagnosticOptions.cpp - C Language Family Diagnostic Handling ------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the DiagnosticOptions related interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/DiagnosticOptions.h" +#include "llvm/Support/raw_ostream.h" +#include <type_traits> + +namespace clang { + +raw_ostream &operator<<(raw_ostream &Out, DiagnosticLevelMask M) { + using UT = std::underlying_type<DiagnosticLevelMask>::type; + return Out << static_cast<UT>(M); +} + +} // namespace clang diff --git a/contrib/llvm-project/clang/lib/Basic/ExpressionTraits.cpp b/contrib/llvm-project/clang/lib/Basic/ExpressionTraits.cpp new file mode 100644 index 000000000000..5fde1940038f --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/ExpressionTraits.cpp @@ -0,0 +1,36 @@ +//===--- ExpressionTraits.cpp - Expression Traits Support -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the expression traits support functions. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/ExpressionTraits.h" +#include "llvm/Support/ErrorHandling.h" +#include <cassert> +using namespace clang; + +static constexpr const char *ExpressionTraitNames[] = { +#define EXPRESSION_TRAIT(Spelling, Name, Key) #Name, +#include "clang/Basic/TokenKinds.def" +}; + +static constexpr const char *ExpressionTraitSpellings[] = { +#define EXPRESSION_TRAIT(Spelling, Name, Key) #Spelling, +#include "clang/Basic/TokenKinds.def" +}; + +const char *clang::getTraitName(ExpressionTrait T) { + assert(T <= ET_Last && "invalid enum value!"); + return ExpressionTraitNames[T]; +} + +const char *clang::getTraitSpelling(ExpressionTrait T) { + assert(T <= ET_Last && "invalid enum value!"); + return ExpressionTraitSpellings[T]; +} diff --git a/contrib/llvm-project/clang/lib/Basic/FileEntry.cpp b/contrib/llvm-project/clang/lib/Basic/FileEntry.cpp new file mode 100644 index 000000000000..5ee9bef9523e --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/FileEntry.cpp @@ -0,0 +1,24 @@ +//===- FileEntry.cpp - File references --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Defines implementation for clang::FileEntry and clang::FileEntryRef. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/FileEntry.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/VirtualFileSystem.h" + +using namespace clang; + +FileEntry::FileEntry() : UniqueID(0, 0) {} + +FileEntry::~FileEntry() = default; + +void FileEntry::closeFile() const { File.reset(); } diff --git a/contrib/llvm-project/clang/lib/Basic/FileManager.cpp b/contrib/llvm-project/clang/lib/Basic/FileManager.cpp new file mode 100644 index 000000000000..f4cf27848d7d --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/FileManager.cpp @@ -0,0 +1,660 @@ +//===--- FileManager.cpp - File System Probing and Caching ----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the FileManager interface. +// +//===----------------------------------------------------------------------===// +// +// TODO: This should index all interesting directories with dirent calls. +// getdirentries ? +// opendir/readdir_r/closedir ? +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/FileManager.h" +#include "clang/Basic/FileSystemStatCache.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <climits> +#include <cstdint> +#include <cstdlib> +#include <string> +#include <utility> + +using namespace clang; + +#define DEBUG_TYPE "file-search" + +ALWAYS_ENABLED_STATISTIC(NumDirLookups, "Number of directory lookups."); +ALWAYS_ENABLED_STATISTIC(NumFileLookups, "Number of file lookups."); +ALWAYS_ENABLED_STATISTIC(NumDirCacheMisses, + "Number of directory cache misses."); +ALWAYS_ENABLED_STATISTIC(NumFileCacheMisses, "Number of file cache misses."); + +//===----------------------------------------------------------------------===// +// Common logic. +//===----------------------------------------------------------------------===// + +FileManager::FileManager(const FileSystemOptions &FSO, + IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) + : FS(std::move(FS)), FileSystemOpts(FSO), SeenDirEntries(64), + SeenFileEntries(64), NextFileUID(0) { + // If the caller doesn't provide a virtual file system, just grab the real + // file system. + if (!this->FS) + this->FS = llvm::vfs::getRealFileSystem(); +} + +FileManager::~FileManager() = default; + +void FileManager::setStatCache(std::unique_ptr<FileSystemStatCache> statCache) { + assert(statCache && "No stat cache provided?"); + StatCache = std::move(statCache); +} + +void FileManager::clearStatCache() { StatCache.reset(); } + +/// Retrieve the directory that the given file name resides in. +/// Filename can point to either a real file or a virtual file. +static llvm::Expected<DirectoryEntryRef> +getDirectoryFromFile(FileManager &FileMgr, StringRef Filename, + bool CacheFailure) { + if (Filename.empty()) + return llvm::errorCodeToError( + make_error_code(std::errc::no_such_file_or_directory)); + + if (llvm::sys::path::is_separator(Filename[Filename.size() - 1])) + return llvm::errorCodeToError(make_error_code(std::errc::is_a_directory)); + + StringRef DirName = llvm::sys::path::parent_path(Filename); + // Use the current directory if file has no path component. + if (DirName.empty()) + DirName = "."; + + return FileMgr.getDirectoryRef(DirName, CacheFailure); +} + +/// Add all ancestors of the given path (pointing to either a file or +/// a directory) as virtual directories. +void FileManager::addAncestorsAsVirtualDirs(StringRef Path) { + StringRef DirName = llvm::sys::path::parent_path(Path); + if (DirName.empty()) + DirName = "."; + + auto &NamedDirEnt = *SeenDirEntries.insert( + {DirName, std::errc::no_such_file_or_directory}).first; + + // When caching a virtual directory, we always cache its ancestors + // at the same time. Therefore, if DirName is already in the cache, + // we don't need to recurse as its ancestors must also already be in + // the cache (or it's a known non-virtual directory). + if (NamedDirEnt.second) + return; + + // Add the virtual directory to the cache. + auto UDE = std::make_unique<DirectoryEntry>(); + UDE->Name = NamedDirEnt.first(); + NamedDirEnt.second = *UDE.get(); + VirtualDirectoryEntries.push_back(std::move(UDE)); + + // Recursively add the other ancestors. + addAncestorsAsVirtualDirs(DirName); +} + +llvm::Expected<DirectoryEntryRef> +FileManager::getDirectoryRef(StringRef DirName, bool CacheFailure) { + // stat doesn't like trailing separators except for root directory. + // At least, on Win32 MSVCRT, stat() cannot strip trailing '/'. + // (though it can strip '\\') + if (DirName.size() > 1 && + DirName != llvm::sys::path::root_path(DirName) && + llvm::sys::path::is_separator(DirName.back())) + DirName = DirName.substr(0, DirName.size()-1); + Optional<std::string> DirNameStr; + if (is_style_windows(llvm::sys::path::Style::native)) { + // Fixing a problem with "clang C:test.c" on Windows. + // Stat("C:") does not recognize "C:" as a valid directory + if (DirName.size() > 1 && DirName.back() == ':' && + DirName.equals_insensitive(llvm::sys::path::root_name(DirName))) { + DirNameStr = DirName.str() + '.'; + DirName = *DirNameStr; + } + } + + ++NumDirLookups; + + // See if there was already an entry in the map. Note that the map + // contains both virtual and real directories. + auto SeenDirInsertResult = + SeenDirEntries.insert({DirName, std::errc::no_such_file_or_directory}); + if (!SeenDirInsertResult.second) { + if (SeenDirInsertResult.first->second) + return DirectoryEntryRef(*SeenDirInsertResult.first); + return llvm::errorCodeToError(SeenDirInsertResult.first->second.getError()); + } + + // We've not seen this before. Fill it in. + ++NumDirCacheMisses; + auto &NamedDirEnt = *SeenDirInsertResult.first; + assert(!NamedDirEnt.second && "should be newly-created"); + + // Get the null-terminated directory name as stored as the key of the + // SeenDirEntries map. + StringRef InterndDirName = NamedDirEnt.first(); + + // Check to see if the directory exists. + llvm::vfs::Status Status; + auto statError = getStatValue(InterndDirName, Status, false, + nullptr /*directory lookup*/); + if (statError) { + // There's no real directory at the given path. + if (CacheFailure) + NamedDirEnt.second = statError; + else + SeenDirEntries.erase(DirName); + return llvm::errorCodeToError(statError); + } + + // It exists. See if we have already opened a directory with the + // same inode (this occurs on Unix-like systems when one dir is + // symlinked to another, for example) or the same path (on + // Windows). + DirectoryEntry &UDE = UniqueRealDirs[Status.getUniqueID()]; + + NamedDirEnt.second = UDE; + if (UDE.getName().empty()) { + // We don't have this directory yet, add it. We use the string + // key from the SeenDirEntries map as the string. + UDE.Name = InterndDirName; + } + + return DirectoryEntryRef(NamedDirEnt); +} + +llvm::ErrorOr<const DirectoryEntry *> +FileManager::getDirectory(StringRef DirName, bool CacheFailure) { + auto Result = getDirectoryRef(DirName, CacheFailure); + if (Result) + return &Result->getDirEntry(); + return llvm::errorToErrorCode(Result.takeError()); +} + +llvm::ErrorOr<const FileEntry *> +FileManager::getFile(StringRef Filename, bool openFile, bool CacheFailure) { + auto Result = getFileRef(Filename, openFile, CacheFailure); + if (Result) + return &Result->getFileEntry(); + return llvm::errorToErrorCode(Result.takeError()); +} + +llvm::Expected<FileEntryRef> +FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) { + ++NumFileLookups; + + // See if there is already an entry in the map. + auto SeenFileInsertResult = + SeenFileEntries.insert({Filename, std::errc::no_such_file_or_directory}); + if (!SeenFileInsertResult.second) { + if (!SeenFileInsertResult.first->second) + return llvm::errorCodeToError( + SeenFileInsertResult.first->second.getError()); + // Construct and return and FileEntryRef, unless it's a redirect to another + // filename. + FileEntryRef::MapValue Value = *SeenFileInsertResult.first->second; + if (LLVM_LIKELY(Value.V.is<FileEntry *>())) + return FileEntryRef(*SeenFileInsertResult.first); + return FileEntryRef(*reinterpret_cast<const FileEntryRef::MapEntry *>( + Value.V.get<const void *>())); + } + + // We've not seen this before. Fill it in. + ++NumFileCacheMisses; + auto *NamedFileEnt = &*SeenFileInsertResult.first; + assert(!NamedFileEnt->second && "should be newly-created"); + + // Get the null-terminated file name as stored as the key of the + // SeenFileEntries map. + StringRef InterndFileName = NamedFileEnt->first(); + + // Look up the directory for the file. When looking up something like + // sys/foo.h we'll discover all of the search directories that have a 'sys' + // subdirectory. This will let us avoid having to waste time on known-to-fail + // searches when we go to find sys/bar.h, because all the search directories + // without a 'sys' subdir will get a cached failure result. + auto DirInfoOrErr = getDirectoryFromFile(*this, Filename, CacheFailure); + if (!DirInfoOrErr) { // Directory doesn't exist, file can't exist. + std::error_code Err = errorToErrorCode(DirInfoOrErr.takeError()); + if (CacheFailure) + NamedFileEnt->second = Err; + else + SeenFileEntries.erase(Filename); + + return llvm::errorCodeToError(Err); + } + DirectoryEntryRef DirInfo = *DirInfoOrErr; + + // FIXME: Use the directory info to prune this, before doing the stat syscall. + // FIXME: This will reduce the # syscalls. + + // Check to see if the file exists. + std::unique_ptr<llvm::vfs::File> F; + llvm::vfs::Status Status; + auto statError = getStatValue(InterndFileName, Status, true, + openFile ? &F : nullptr); + if (statError) { + // There's no real file at the given path. + if (CacheFailure) + NamedFileEnt->second = statError; + else + SeenFileEntries.erase(Filename); + + return llvm::errorCodeToError(statError); + } + + assert((openFile || !F) && "undesired open file"); + + // It exists. See if we have already opened a file with the same inode. + // This occurs when one dir is symlinked to another, for example. + FileEntry &UFE = UniqueRealFiles[Status.getUniqueID()]; + + if (Status.getName() == Filename) { + // The name matches. Set the FileEntry. + NamedFileEnt->second = FileEntryRef::MapValue(UFE, DirInfo); + } else { + // Name mismatch. We need a redirect. First grab the actual entry we want + // to return. + // + // This redirection logic intentionally leaks the external name of a + // redirected file that uses 'use-external-name' in \a + // vfs::RedirectionFileSystem. This allows clang to report the external + // name to users (in diagnostics) and to tools that don't have access to + // the VFS (in debug info and dependency '.d' files). + // + // FIXME: This is pretty complicated. It's also inconsistent with how + // "real" filesystems behave and confuses parts of clang expect to see the + // name-as-accessed on the \a FileEntryRef. Maybe the returned \a + // FileEntryRef::getName() could return the accessed name unmodified, but + // make the external name available via a separate API. + auto &Redirection = + *SeenFileEntries + .insert({Status.getName(), FileEntryRef::MapValue(UFE, DirInfo)}) + .first; + assert(Redirection.second->V.is<FileEntry *>() && + "filename redirected to a non-canonical filename?"); + assert(Redirection.second->V.get<FileEntry *>() == &UFE && + "filename from getStatValue() refers to wrong file"); + + // Cache the redirection in the previously-inserted entry, still available + // in the tentative return value. + NamedFileEnt->second = FileEntryRef::MapValue(Redirection); + + // Fix the tentative return value. + NamedFileEnt = &Redirection; + } + + FileEntryRef ReturnedRef(*NamedFileEnt); + if (UFE.isValid()) { // Already have an entry with this inode, return it. + + // FIXME: this hack ensures that if we look up a file by a virtual path in + // the VFS that the getDir() will have the virtual path, even if we found + // the file by a 'real' path first. This is required in order to find a + // module's structure when its headers/module map are mapped in the VFS. + // We should remove this as soon as we can properly support a file having + // multiple names. + if (&DirInfo.getDirEntry() != UFE.Dir && Status.IsVFSMapped) + UFE.Dir = &DirInfo.getDirEntry(); + + // Always update LastRef to the last name by which a file was accessed. + // FIXME: Neither this nor always using the first reference is correct; we + // want to switch towards a design where we return a FileName object that + // encapsulates both the name by which the file was accessed and the + // corresponding FileEntry. + // FIXME: LastRef should be removed from FileEntry once all clients adopt + // FileEntryRef. + UFE.LastRef = ReturnedRef; + + return ReturnedRef; + } + + // Otherwise, we don't have this file yet, add it. + UFE.LastRef = ReturnedRef; + UFE.Size = Status.getSize(); + UFE.ModTime = llvm::sys::toTimeT(Status.getLastModificationTime()); + UFE.Dir = &DirInfo.getDirEntry(); + UFE.UID = NextFileUID++; + UFE.UniqueID = Status.getUniqueID(); + UFE.IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file; + UFE.File = std::move(F); + UFE.IsValid = true; + + if (UFE.File) { + if (auto PathName = UFE.File->getName()) + fillRealPathName(&UFE, *PathName); + } else if (!openFile) { + // We should still fill the path even if we aren't opening the file. + fillRealPathName(&UFE, InterndFileName); + } + return ReturnedRef; +} + +llvm::Expected<FileEntryRef> FileManager::getSTDIN() { + // Only read stdin once. + if (STDIN) + return *STDIN; + + std::unique_ptr<llvm::MemoryBuffer> Content; + if (auto ContentOrError = llvm::MemoryBuffer::getSTDIN()) + Content = std::move(*ContentOrError); + else + return llvm::errorCodeToError(ContentOrError.getError()); + + STDIN = getVirtualFileRef(Content->getBufferIdentifier(), + Content->getBufferSize(), 0); + FileEntry &FE = const_cast<FileEntry &>(STDIN->getFileEntry()); + FE.Content = std::move(Content); + FE.IsNamedPipe = true; + return *STDIN; +} + +const FileEntry *FileManager::getVirtualFile(StringRef Filename, off_t Size, + time_t ModificationTime) { + return &getVirtualFileRef(Filename, Size, ModificationTime).getFileEntry(); +} + +FileEntryRef FileManager::getVirtualFileRef(StringRef Filename, off_t Size, + time_t ModificationTime) { + ++NumFileLookups; + + // See if there is already an entry in the map for an existing file. + auto &NamedFileEnt = *SeenFileEntries.insert( + {Filename, std::errc::no_such_file_or_directory}).first; + if (NamedFileEnt.second) { + FileEntryRef::MapValue Value = *NamedFileEnt.second; + if (LLVM_LIKELY(Value.V.is<FileEntry *>())) + return FileEntryRef(NamedFileEnt); + return FileEntryRef(*reinterpret_cast<const FileEntryRef::MapEntry *>( + Value.V.get<const void *>())); + } + + // We've not seen this before, or the file is cached as non-existent. + ++NumFileCacheMisses; + addAncestorsAsVirtualDirs(Filename); + FileEntry *UFE = nullptr; + + // Now that all ancestors of Filename are in the cache, the + // following call is guaranteed to find the DirectoryEntry from the + // cache. A virtual file can also have an empty filename, that could come + // from a source location preprocessor directive with an empty filename as + // an example, so we need to pretend it has a name to ensure a valid directory + // entry can be returned. + auto DirInfo = expectedToOptional(getDirectoryFromFile( + *this, Filename.empty() ? "." : Filename, /*CacheFailure=*/true)); + assert(DirInfo && + "The directory of a virtual file should already be in the cache."); + + // Check to see if the file exists. If so, drop the virtual file + llvm::vfs::Status Status; + const char *InterndFileName = NamedFileEnt.first().data(); + if (!getStatValue(InterndFileName, Status, true, nullptr)) { + UFE = &UniqueRealFiles[Status.getUniqueID()]; + Status = llvm::vfs::Status( + Status.getName(), Status.getUniqueID(), + llvm::sys::toTimePoint(ModificationTime), + Status.getUser(), Status.getGroup(), Size, + Status.getType(), Status.getPermissions()); + + NamedFileEnt.second = FileEntryRef::MapValue(*UFE, *DirInfo); + + // If we had already opened this file, close it now so we don't + // leak the descriptor. We're not going to use the file + // descriptor anyway, since this is a virtual file. + if (UFE->File) + UFE->closeFile(); + + // If we already have an entry with this inode, return it. + // + // FIXME: Surely this should add a reference by the new name, and return + // it instead... + if (UFE->isValid()) + return FileEntryRef(NamedFileEnt); + + UFE->UniqueID = Status.getUniqueID(); + UFE->IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file; + fillRealPathName(UFE, Status.getName()); + } else { + VirtualFileEntries.push_back(std::make_unique<FileEntry>()); + UFE = VirtualFileEntries.back().get(); + NamedFileEnt.second = FileEntryRef::MapValue(*UFE, *DirInfo); + } + + UFE->LastRef = FileEntryRef(NamedFileEnt); + UFE->Size = Size; + UFE->ModTime = ModificationTime; + UFE->Dir = &DirInfo->getDirEntry(); + UFE->UID = NextFileUID++; + UFE->IsValid = true; + UFE->File.reset(); + return FileEntryRef(NamedFileEnt); +} + +llvm::Optional<FileEntryRef> FileManager::getBypassFile(FileEntryRef VF) { + // Stat of the file and return nullptr if it doesn't exist. + llvm::vfs::Status Status; + if (getStatValue(VF.getName(), Status, /*isFile=*/true, /*F=*/nullptr)) + return None; + + if (!SeenBypassFileEntries) + SeenBypassFileEntries = std::make_unique< + llvm::StringMap<llvm::ErrorOr<FileEntryRef::MapValue>>>(); + + // If we've already bypassed just use the existing one. + auto Insertion = SeenBypassFileEntries->insert( + {VF.getName(), std::errc::no_such_file_or_directory}); + if (!Insertion.second) + return FileEntryRef(*Insertion.first); + + // Fill in the new entry from the stat. + BypassFileEntries.push_back(std::make_unique<FileEntry>()); + const FileEntry &VFE = VF.getFileEntry(); + FileEntry &BFE = *BypassFileEntries.back(); + Insertion.first->second = FileEntryRef::MapValue(BFE, VF.getDir()); + BFE.LastRef = FileEntryRef(*Insertion.first); + BFE.Size = Status.getSize(); + BFE.Dir = VFE.Dir; + BFE.ModTime = llvm::sys::toTimeT(Status.getLastModificationTime()); + BFE.UID = NextFileUID++; + BFE.IsValid = true; + + // Save the entry in the bypass table and return. + return FileEntryRef(*Insertion.first); +} + +bool FileManager::FixupRelativePath(SmallVectorImpl<char> &path) const { + StringRef pathRef(path.data(), path.size()); + + if (FileSystemOpts.WorkingDir.empty() + || llvm::sys::path::is_absolute(pathRef)) + return false; + + SmallString<128> NewPath(FileSystemOpts.WorkingDir); + llvm::sys::path::append(NewPath, pathRef); + path = NewPath; + return true; +} + +bool FileManager::makeAbsolutePath(SmallVectorImpl<char> &Path) const { + bool Changed = FixupRelativePath(Path); + + if (!llvm::sys::path::is_absolute(StringRef(Path.data(), Path.size()))) { + FS->makeAbsolute(Path); + Changed = true; + } + + return Changed; +} + +void FileManager::fillRealPathName(FileEntry *UFE, llvm::StringRef FileName) { + llvm::SmallString<128> AbsPath(FileName); + // This is not the same as `VFS::getRealPath()`, which resolves symlinks + // but can be very expensive on real file systems. + // FIXME: the semantic of RealPathName is unclear, and the name might be + // misleading. We need to clean up the interface here. + makeAbsolutePath(AbsPath); + llvm::sys::path::remove_dots(AbsPath, /*remove_dot_dot=*/true); + UFE->RealPathName = std::string(AbsPath.str()); +} + +llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> +FileManager::getBufferForFile(const FileEntry *Entry, bool isVolatile, + bool RequiresNullTerminator) { + // If the content is living on the file entry, return a reference to it. + if (Entry->Content) + return llvm::MemoryBuffer::getMemBuffer(Entry->Content->getMemBufferRef()); + + uint64_t FileSize = Entry->getSize(); + // If there's a high enough chance that the file have changed since we + // got its size, force a stat before opening it. + if (isVolatile || Entry->isNamedPipe()) + FileSize = -1; + + StringRef Filename = Entry->getName(); + // If the file is already open, use the open file descriptor. + if (Entry->File) { + auto Result = Entry->File->getBuffer(Filename, FileSize, + RequiresNullTerminator, isVolatile); + Entry->closeFile(); + return Result; + } + + // Otherwise, open the file. + return getBufferForFileImpl(Filename, FileSize, isVolatile, + RequiresNullTerminator); +} + +llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> +FileManager::getBufferForFileImpl(StringRef Filename, int64_t FileSize, + bool isVolatile, + bool RequiresNullTerminator) { + if (FileSystemOpts.WorkingDir.empty()) + return FS->getBufferForFile(Filename, FileSize, RequiresNullTerminator, + isVolatile); + + SmallString<128> FilePath(Filename); + FixupRelativePath(FilePath); + return FS->getBufferForFile(FilePath, FileSize, RequiresNullTerminator, + isVolatile); +} + +/// getStatValue - Get the 'stat' information for the specified path, +/// using the cache to accelerate it if possible. This returns true +/// if the path points to a virtual file or does not exist, or returns +/// false if it's an existent real file. If FileDescriptor is NULL, +/// do directory look-up instead of file look-up. +std::error_code +FileManager::getStatValue(StringRef Path, llvm::vfs::Status &Status, + bool isFile, std::unique_ptr<llvm::vfs::File> *F) { + // FIXME: FileSystemOpts shouldn't be passed in here, all paths should be + // absolute! + if (FileSystemOpts.WorkingDir.empty()) + return FileSystemStatCache::get(Path, Status, isFile, F, + StatCache.get(), *FS); + + SmallString<128> FilePath(Path); + FixupRelativePath(FilePath); + + return FileSystemStatCache::get(FilePath.c_str(), Status, isFile, F, + StatCache.get(), *FS); +} + +std::error_code +FileManager::getNoncachedStatValue(StringRef Path, + llvm::vfs::Status &Result) { + SmallString<128> FilePath(Path); + FixupRelativePath(FilePath); + + llvm::ErrorOr<llvm::vfs::Status> S = FS->status(FilePath.c_str()); + if (!S) + return S.getError(); + Result = *S; + return std::error_code(); +} + +void FileManager::GetUniqueIDMapping( + SmallVectorImpl<const FileEntry *> &UIDToFiles) const { + UIDToFiles.clear(); + UIDToFiles.resize(NextFileUID); + + // Map file entries + for (llvm::StringMap<llvm::ErrorOr<FileEntryRef::MapValue>, + llvm::BumpPtrAllocator>::const_iterator + FE = SeenFileEntries.begin(), + FEEnd = SeenFileEntries.end(); + FE != FEEnd; ++FE) + if (llvm::ErrorOr<FileEntryRef::MapValue> Entry = FE->getValue()) { + if (const auto *FE = Entry->V.dyn_cast<FileEntry *>()) + UIDToFiles[FE->getUID()] = FE; + } + + // Map virtual file entries + for (const auto &VFE : VirtualFileEntries) + UIDToFiles[VFE->getUID()] = VFE.get(); +} + +StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) { + llvm::DenseMap<const void *, llvm::StringRef>::iterator Known + = CanonicalNames.find(Dir); + if (Known != CanonicalNames.end()) + return Known->second; + + StringRef CanonicalName(Dir->getName()); + + SmallString<4096> CanonicalNameBuf; + if (!FS->getRealPath(Dir->getName(), CanonicalNameBuf)) + CanonicalName = CanonicalNameBuf.str().copy(CanonicalNameStorage); + + CanonicalNames.insert({Dir, CanonicalName}); + return CanonicalName; +} + +StringRef FileManager::getCanonicalName(const FileEntry *File) { + llvm::DenseMap<const void *, llvm::StringRef>::iterator Known + = CanonicalNames.find(File); + if (Known != CanonicalNames.end()) + return Known->second; + + StringRef CanonicalName(File->getName()); + + SmallString<4096> CanonicalNameBuf; + if (!FS->getRealPath(File->getName(), CanonicalNameBuf)) + CanonicalName = CanonicalNameBuf.str().copy(CanonicalNameStorage); + + CanonicalNames.insert({File, CanonicalName}); + return CanonicalName; +} + +void FileManager::PrintStats() const { + llvm::errs() << "\n*** File Manager Stats:\n"; + llvm::errs() << UniqueRealFiles.size() << " real files found, " + << UniqueRealDirs.size() << " real dirs found.\n"; + llvm::errs() << VirtualFileEntries.size() << " virtual files found, " + << VirtualDirectoryEntries.size() << " virtual dirs found.\n"; + llvm::errs() << NumDirLookups << " dir lookups, " + << NumDirCacheMisses << " dir cache misses.\n"; + llvm::errs() << NumFileLookups << " file lookups, " + << NumFileCacheMisses << " file cache misses.\n"; + + //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups; +} diff --git a/contrib/llvm-project/clang/lib/Basic/FileSystemStatCache.cpp b/contrib/llvm-project/clang/lib/Basic/FileSystemStatCache.cpp new file mode 100644 index 000000000000..415a4e2025df --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/FileSystemStatCache.cpp @@ -0,0 +1,120 @@ +//===- FileSystemStatCache.cpp - Caching for 'stat' calls -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the FileSystemStatCache interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/FileSystemStatCache.h" +#include "llvm/Support/Chrono.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/VirtualFileSystem.h" +#include <utility> + +using namespace clang; + +void FileSystemStatCache::anchor() {} + +/// FileSystemStatCache::get - Get the 'stat' information for the specified +/// path, using the cache to accelerate it if possible. This returns true if +/// the path does not exist or false if it exists. +/// +/// If isFile is true, then this lookup should only return success for files +/// (not directories). If it is false this lookup should only return +/// success for directories (not files). On a successful file lookup, the +/// implementation can optionally fill in FileDescriptor with a valid +/// descriptor and the client guarantees that it will close it. +std::error_code +FileSystemStatCache::get(StringRef Path, llvm::vfs::Status &Status, + bool isFile, std::unique_ptr<llvm::vfs::File> *F, + FileSystemStatCache *Cache, + llvm::vfs::FileSystem &FS) { + bool isForDir = !isFile; + std::error_code RetCode; + + // If we have a cache, use it to resolve the stat query. + if (Cache) + RetCode = Cache->getStat(Path, Status, isFile, F, FS); + else if (isForDir || !F) { + // If this is a directory or a file descriptor is not needed and we have + // no cache, just go to the file system. + llvm::ErrorOr<llvm::vfs::Status> StatusOrErr = FS.status(Path); + if (!StatusOrErr) { + RetCode = StatusOrErr.getError(); + } else { + Status = *StatusOrErr; + } + } else { + // Otherwise, we have to go to the filesystem. We can always just use + // 'stat' here, but (for files) the client is asking whether the file exists + // because it wants to turn around and *open* it. It is more efficient to + // do "open+fstat" on success than it is to do "stat+open". + // + // Because of this, check to see if the file exists with 'open'. If the + // open succeeds, use fstat to get the stat info. + auto OwnedFile = FS.openFileForRead(Path); + + if (!OwnedFile) { + // If the open fails, our "stat" fails. + RetCode = OwnedFile.getError(); + } else { + // Otherwise, the open succeeded. Do an fstat to get the information + // about the file. We'll end up returning the open file descriptor to the + // client to do what they please with it. + llvm::ErrorOr<llvm::vfs::Status> StatusOrErr = (*OwnedFile)->status(); + if (StatusOrErr) { + Status = *StatusOrErr; + *F = std::move(*OwnedFile); + } else { + // fstat rarely fails. If it does, claim the initial open didn't + // succeed. + *F = nullptr; + RetCode = StatusOrErr.getError(); + } + } + } + + // If the path doesn't exist, return failure. + if (RetCode) + return RetCode; + + // If the path exists, make sure that its "directoryness" matches the clients + // demands. + if (Status.isDirectory() != isForDir) { + // If not, close the file if opened. + if (F) + *F = nullptr; + return std::make_error_code( + Status.isDirectory() ? + std::errc::is_a_directory : std::errc::not_a_directory); + } + + return std::error_code(); +} + +std::error_code +MemorizeStatCalls::getStat(StringRef Path, llvm::vfs::Status &Status, + bool isFile, + std::unique_ptr<llvm::vfs::File> *F, + llvm::vfs::FileSystem &FS) { + auto err = get(Path, Status, isFile, F, nullptr, FS); + if (err) { + // Do not cache failed stats, it is easy to construct common inconsistent + // situations if we do, and they are not important for PCH performance + // (which currently only needs the stats to construct the initial + // FileManager entries). + return err; + } + + // Cache file 'stat' results and directories with absolutely paths. + if (!Status.isDirectory() || llvm::sys::path::is_absolute(Path)) + StatCalls[Path] = Status; + + return std::error_code(); +} diff --git a/contrib/llvm-project/clang/lib/Basic/IdentifierTable.cpp b/contrib/llvm-project/clang/lib/Basic/IdentifierTable.cpp new file mode 100644 index 000000000000..b86cb7af69bd --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/IdentifierTable.cpp @@ -0,0 +1,775 @@ +//===- IdentifierTable.cpp - Hash table for identifier lookup -------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the IdentifierInfo, IdentifierVisitor, and +// IdentifierTable interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Basic/TargetBuiltins.h" +#include "clang/Basic/TokenKinds.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <cstdio> +#include <cstring> +#include <string> + +using namespace clang; + +// A check to make sure the ObjCOrBuiltinID has sufficient room to store the +// largest possible target/aux-target combination. If we exceed this, we likely +// need to just change the ObjCOrBuiltinIDBits value in IdentifierTable.h. +static_assert(2 * LargestBuiltinID < (2 << (ObjCOrBuiltinIDBits - 1)), + "Insufficient ObjCOrBuiltinID Bits"); + +//===----------------------------------------------------------------------===// +// IdentifierTable Implementation +//===----------------------------------------------------------------------===// + +IdentifierIterator::~IdentifierIterator() = default; + +IdentifierInfoLookup::~IdentifierInfoLookup() = default; + +namespace { + +/// A simple identifier lookup iterator that represents an +/// empty sequence of identifiers. +class EmptyLookupIterator : public IdentifierIterator +{ +public: + StringRef Next() override { return StringRef(); } +}; + +} // namespace + +IdentifierIterator *IdentifierInfoLookup::getIdentifiers() { + return new EmptyLookupIterator(); +} + +IdentifierTable::IdentifierTable(IdentifierInfoLookup *ExternalLookup) + : HashTable(8192), // Start with space for 8K identifiers. + ExternalLookup(ExternalLookup) {} + +IdentifierTable::IdentifierTable(const LangOptions &LangOpts, + IdentifierInfoLookup *ExternalLookup) + : IdentifierTable(ExternalLookup) { + // Populate the identifier table with info about keywords for the current + // language. + AddKeywords(LangOpts); +} + +//===----------------------------------------------------------------------===// +// Language Keyword Implementation +//===----------------------------------------------------------------------===// + +// Constants for TokenKinds.def +namespace { + + enum { + KEYC99 = 0x1, + KEYCXX = 0x2, + KEYCXX11 = 0x4, + KEYGNU = 0x8, + KEYMS = 0x10, + BOOLSUPPORT = 0x20, + KEYALTIVEC = 0x40, + KEYNOCXX = 0x80, + KEYBORLAND = 0x100, + KEYOPENCLC = 0x200, + KEYC11 = 0x400, + KEYNOMS18 = 0x800, + KEYNOOPENCL = 0x1000, + WCHARSUPPORT = 0x2000, + HALFSUPPORT = 0x4000, + CHAR8SUPPORT = 0x8000, + KEYCONCEPTS = 0x10000, + KEYOBJC = 0x20000, + KEYZVECTOR = 0x40000, + KEYCOROUTINES = 0x80000, + KEYMODULES = 0x100000, + KEYCXX20 = 0x200000, + KEYOPENCLCXX = 0x400000, + KEYMSCOMPAT = 0x800000, + KEYSYCL = 0x1000000, + KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX20, + KEYALL = (0x1ffffff & ~KEYNOMS18 & + ~KEYNOOPENCL) // KEYNOMS18 and KEYNOOPENCL are used to exclude. + }; + + /// How a keyword is treated in the selected standard. + enum KeywordStatus { + KS_Disabled, // Disabled + KS_Extension, // Is an extension + KS_Enabled, // Enabled + KS_Future // Is a keyword in future standard + }; + +} // namespace + +/// Translates flags as specified in TokenKinds.def into keyword status +/// in the given language standard. +static KeywordStatus getKeywordStatus(const LangOptions &LangOpts, + unsigned Flags) { + if (Flags == KEYALL) return KS_Enabled; + if (LangOpts.CPlusPlus && (Flags & KEYCXX)) return KS_Enabled; + if (LangOpts.CPlusPlus11 && (Flags & KEYCXX11)) return KS_Enabled; + if (LangOpts.CPlusPlus20 && (Flags & KEYCXX20)) return KS_Enabled; + if (LangOpts.C99 && (Flags & KEYC99)) return KS_Enabled; + if (LangOpts.GNUKeywords && (Flags & KEYGNU)) return KS_Extension; + if (LangOpts.MicrosoftExt && (Flags & KEYMS)) return KS_Extension; + if (LangOpts.MSVCCompat && (Flags & KEYMSCOMPAT)) return KS_Enabled; + if (LangOpts.Borland && (Flags & KEYBORLAND)) return KS_Extension; + if (LangOpts.Bool && (Flags & BOOLSUPPORT)) return KS_Enabled; + if (LangOpts.Half && (Flags & HALFSUPPORT)) return KS_Enabled; + if (LangOpts.WChar && (Flags & WCHARSUPPORT)) return KS_Enabled; + if (LangOpts.Char8 && (Flags & CHAR8SUPPORT)) return KS_Enabled; + if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) return KS_Enabled; + if (LangOpts.ZVector && (Flags & KEYZVECTOR)) return KS_Enabled; + if (LangOpts.OpenCL && !LangOpts.OpenCLCPlusPlus && (Flags & KEYOPENCLC)) + return KS_Enabled; + if (LangOpts.OpenCLCPlusPlus && (Flags & KEYOPENCLCXX)) return KS_Enabled; + if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) return KS_Enabled; + if (LangOpts.C11 && (Flags & KEYC11)) return KS_Enabled; + // We treat bridge casts as objective-C keywords so we can warn on them + // in non-arc mode. + if (LangOpts.ObjC && (Flags & KEYOBJC)) return KS_Enabled; + if (LangOpts.CPlusPlus20 && (Flags & KEYCONCEPTS)) return KS_Enabled; + if (LangOpts.Coroutines && (Flags & KEYCOROUTINES)) return KS_Enabled; + if (LangOpts.ModulesTS && (Flags & KEYMODULES)) return KS_Enabled; + if (LangOpts.CPlusPlus && (Flags & KEYALLCXX)) return KS_Future; + if (LangOpts.CPlusPlus && !LangOpts.CPlusPlus20 && (Flags & CHAR8SUPPORT)) + return KS_Future; + if (LangOpts.isSYCL() && (Flags & KEYSYCL)) + return KS_Enabled; + return KS_Disabled; +} + +/// AddKeyword - This method is used to associate a token ID with specific +/// identifiers because they are language keywords. This causes the lexer to +/// automatically map matching identifiers to specialized token codes. +static void AddKeyword(StringRef Keyword, + tok::TokenKind TokenCode, unsigned Flags, + const LangOptions &LangOpts, IdentifierTable &Table) { + KeywordStatus AddResult = getKeywordStatus(LangOpts, Flags); + + // Don't add this keyword under MSVCCompat. + if (LangOpts.MSVCCompat && (Flags & KEYNOMS18) && + !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2015)) + return; + + // Don't add this keyword under OpenCL. + if (LangOpts.OpenCL && (Flags & KEYNOOPENCL)) + return; + + // Don't add this keyword if disabled in this language. + if (AddResult == KS_Disabled) return; + + IdentifierInfo &Info = + Table.get(Keyword, AddResult == KS_Future ? tok::identifier : TokenCode); + Info.setIsExtensionToken(AddResult == KS_Extension); + Info.setIsFutureCompatKeyword(AddResult == KS_Future); +} + +/// AddCXXOperatorKeyword - Register a C++ operator keyword alternative +/// representations. +static void AddCXXOperatorKeyword(StringRef Keyword, + tok::TokenKind TokenCode, + IdentifierTable &Table) { + IdentifierInfo &Info = Table.get(Keyword, TokenCode); + Info.setIsCPlusPlusOperatorKeyword(); +} + +/// AddObjCKeyword - Register an Objective-C \@keyword like "class" "selector" +/// or "property". +static void AddObjCKeyword(StringRef Name, + tok::ObjCKeywordKind ObjCID, + IdentifierTable &Table) { + Table.get(Name).setObjCKeywordID(ObjCID); +} + +/// AddKeywords - Add all keywords to the symbol table. +/// +void IdentifierTable::AddKeywords(const LangOptions &LangOpts) { + // Add keywords and tokens for the current language. +#define KEYWORD(NAME, FLAGS) \ + AddKeyword(StringRef(#NAME), tok::kw_ ## NAME, \ + FLAGS, LangOpts, *this); +#define ALIAS(NAME, TOK, FLAGS) \ + AddKeyword(StringRef(NAME), tok::kw_ ## TOK, \ + FLAGS, LangOpts, *this); +#define CXX_KEYWORD_OPERATOR(NAME, ALIAS) \ + if (LangOpts.CXXOperatorNames) \ + AddCXXOperatorKeyword(StringRef(#NAME), tok::ALIAS, *this); +#define OBJC_AT_KEYWORD(NAME) \ + if (LangOpts.ObjC) \ + AddObjCKeyword(StringRef(#NAME), tok::objc_##NAME, *this); +#define TESTING_KEYWORD(NAME, FLAGS) +#include "clang/Basic/TokenKinds.def" + + if (LangOpts.ParseUnknownAnytype) + AddKeyword("__unknown_anytype", tok::kw___unknown_anytype, KEYALL, + LangOpts, *this); + + if (LangOpts.DeclSpecKeyword) + AddKeyword("__declspec", tok::kw___declspec, KEYALL, LangOpts, *this); + + if (LangOpts.IEEE128) + AddKeyword("__ieee128", tok::kw___float128, KEYALL, LangOpts, *this); + + // Add the 'import' contextual keyword. + get("import").setModulesImport(true); +} + +/// Checks if the specified token kind represents a keyword in the +/// specified language. +/// \returns Status of the keyword in the language. +static KeywordStatus getTokenKwStatus(const LangOptions &LangOpts, + tok::TokenKind K) { + switch (K) { +#define KEYWORD(NAME, FLAGS) \ + case tok::kw_##NAME: return getKeywordStatus(LangOpts, FLAGS); +#include "clang/Basic/TokenKinds.def" + default: return KS_Disabled; + } +} + +/// Returns true if the identifier represents a keyword in the +/// specified language. +bool IdentifierInfo::isKeyword(const LangOptions &LangOpts) const { + switch (getTokenKwStatus(LangOpts, getTokenID())) { + case KS_Enabled: + case KS_Extension: + return true; + default: + return false; + } +} + +/// Returns true if the identifier represents a C++ keyword in the +/// specified language. +bool IdentifierInfo::isCPlusPlusKeyword(const LangOptions &LangOpts) const { + if (!LangOpts.CPlusPlus || !isKeyword(LangOpts)) + return false; + // This is a C++ keyword if this identifier is not a keyword when checked + // using LangOptions without C++ support. + LangOptions LangOptsNoCPP = LangOpts; + LangOptsNoCPP.CPlusPlus = false; + LangOptsNoCPP.CPlusPlus11 = false; + LangOptsNoCPP.CPlusPlus20 = false; + return !isKeyword(LangOptsNoCPP); +} + +ReservedIdentifierStatus +IdentifierInfo::isReserved(const LangOptions &LangOpts) const { + StringRef Name = getName(); + + // '_' is a reserved identifier, but its use is so common (e.g. to store + // ignored values) that we don't warn on it. + if (Name.size() <= 1) + return ReservedIdentifierStatus::NotReserved; + + // [lex.name] p3 + if (Name[0] == '_') { + + // Each name that begins with an underscore followed by an uppercase letter + // or another underscore is reserved. + if (Name[1] == '_') + return ReservedIdentifierStatus::StartsWithDoubleUnderscore; + + if ('A' <= Name[1] && Name[1] <= 'Z') + return ReservedIdentifierStatus:: + StartsWithUnderscoreFollowedByCapitalLetter; + + // This is a bit misleading: it actually means it's only reserved if we're + // at global scope because it starts with an underscore. + return ReservedIdentifierStatus::StartsWithUnderscoreAtGlobalScope; + } + + // Each name that contains a double underscore (__) is reserved. + if (LangOpts.CPlusPlus && Name.contains("__")) + return ReservedIdentifierStatus::ContainsDoubleUnderscore; + + return ReservedIdentifierStatus::NotReserved; +} + +StringRef IdentifierInfo::deuglifiedName() const { + StringRef Name = getName(); + if (Name.size() >= 2 && Name.front() == '_' && + (Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z'))) + return Name.ltrim('_'); + return Name; +} + +tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const { + // We use a perfect hash function here involving the length of the keyword, + // the first and third character. For preprocessor ID's there are no + // collisions (if there were, the switch below would complain about duplicate + // case values). Note that this depends on 'if' being null terminated. + +#define HASH(LEN, FIRST, THIRD) \ + (LEN << 5) + (((FIRST-'a') + (THIRD-'a')) & 31) +#define CASE(LEN, FIRST, THIRD, NAME) \ + case HASH(LEN, FIRST, THIRD): \ + return memcmp(Name, #NAME, LEN) ? tok::pp_not_keyword : tok::pp_ ## NAME + + unsigned Len = getLength(); + if (Len < 2) return tok::pp_not_keyword; + const char *Name = getNameStart(); + switch (HASH(Len, Name[0], Name[2])) { + default: return tok::pp_not_keyword; + CASE( 2, 'i', '\0', if); + CASE( 4, 'e', 'i', elif); + CASE( 4, 'e', 's', else); + CASE( 4, 'l', 'n', line); + CASE( 4, 's', 'c', sccs); + CASE( 5, 'e', 'd', endif); + CASE( 5, 'e', 'r', error); + CASE( 5, 'i', 'e', ident); + CASE( 5, 'i', 'd', ifdef); + CASE( 5, 'u', 'd', undef); + + CASE( 6, 'a', 's', assert); + CASE( 6, 'd', 'f', define); + CASE( 6, 'i', 'n', ifndef); + CASE( 6, 'i', 'p', import); + CASE( 6, 'p', 'a', pragma); + + CASE( 7, 'd', 'f', defined); + CASE( 7, 'e', 'i', elifdef); + CASE( 7, 'i', 'c', include); + CASE( 7, 'w', 'r', warning); + + CASE( 8, 'e', 'i', elifndef); + CASE( 8, 'u', 'a', unassert); + CASE(12, 'i', 'c', include_next); + + CASE(14, '_', 'p', __public_macro); + + CASE(15, '_', 'p', __private_macro); + + CASE(16, '_', 'i', __include_macros); +#undef CASE +#undef HASH + } +} + +//===----------------------------------------------------------------------===// +// Stats Implementation +//===----------------------------------------------------------------------===// + +/// PrintStats - Print statistics about how well the identifier table is doing +/// at hashing identifiers. +void IdentifierTable::PrintStats() const { + unsigned NumBuckets = HashTable.getNumBuckets(); + unsigned NumIdentifiers = HashTable.getNumItems(); + unsigned NumEmptyBuckets = NumBuckets-NumIdentifiers; + unsigned AverageIdentifierSize = 0; + unsigned MaxIdentifierLength = 0; + + // TODO: Figure out maximum times an identifier had to probe for -stats. + for (llvm::StringMap<IdentifierInfo*, llvm::BumpPtrAllocator>::const_iterator + I = HashTable.begin(), E = HashTable.end(); I != E; ++I) { + unsigned IdLen = I->getKeyLength(); + AverageIdentifierSize += IdLen; + if (MaxIdentifierLength < IdLen) + MaxIdentifierLength = IdLen; + } + + fprintf(stderr, "\n*** Identifier Table Stats:\n"); + fprintf(stderr, "# Identifiers: %d\n", NumIdentifiers); + fprintf(stderr, "# Empty Buckets: %d\n", NumEmptyBuckets); + fprintf(stderr, "Hash density (#identifiers per bucket): %f\n", + NumIdentifiers/(double)NumBuckets); + fprintf(stderr, "Ave identifier length: %f\n", + (AverageIdentifierSize/(double)NumIdentifiers)); + fprintf(stderr, "Max identifier length: %d\n", MaxIdentifierLength); + + // Compute statistics about the memory allocated for identifiers. + HashTable.getAllocator().PrintStats(); +} + +//===----------------------------------------------------------------------===// +// SelectorTable Implementation +//===----------------------------------------------------------------------===// + +unsigned llvm::DenseMapInfo<clang::Selector>::getHashValue(clang::Selector S) { + return DenseMapInfo<void*>::getHashValue(S.getAsOpaquePtr()); +} + +namespace clang { + +/// One of these variable length records is kept for each +/// selector containing more than one keyword. We use a folding set +/// to unique aggregate names (keyword selectors in ObjC parlance). Access to +/// this class is provided strictly through Selector. +class alignas(IdentifierInfoAlignment) MultiKeywordSelector + : public detail::DeclarationNameExtra, + public llvm::FoldingSetNode { + MultiKeywordSelector(unsigned nKeys) : DeclarationNameExtra(nKeys) {} + +public: + // Constructor for keyword selectors. + MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV) + : DeclarationNameExtra(nKeys) { + assert((nKeys > 1) && "not a multi-keyword selector"); + + // Fill in the trailing keyword array. + IdentifierInfo **KeyInfo = reinterpret_cast<IdentifierInfo **>(this + 1); + for (unsigned i = 0; i != nKeys; ++i) + KeyInfo[i] = IIV[i]; + } + + // getName - Derive the full selector name and return it. + std::string getName() const; + + using DeclarationNameExtra::getNumArgs; + + using keyword_iterator = IdentifierInfo *const *; + + keyword_iterator keyword_begin() const { + return reinterpret_cast<keyword_iterator>(this + 1); + } + + keyword_iterator keyword_end() const { + return keyword_begin() + getNumArgs(); + } + + IdentifierInfo *getIdentifierInfoForSlot(unsigned i) const { + assert(i < getNumArgs() && "getIdentifierInfoForSlot(): illegal index"); + return keyword_begin()[i]; + } + + static void Profile(llvm::FoldingSetNodeID &ID, keyword_iterator ArgTys, + unsigned NumArgs) { + ID.AddInteger(NumArgs); + for (unsigned i = 0; i != NumArgs; ++i) + ID.AddPointer(ArgTys[i]); + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, keyword_begin(), getNumArgs()); + } +}; + +} // namespace clang. + +bool Selector::isKeywordSelector(ArrayRef<StringRef> Names) const { + assert(!Names.empty() && "must have >= 1 selector slots"); + if (getNumArgs() != Names.size()) + return false; + for (unsigned I = 0, E = Names.size(); I != E; ++I) { + if (getNameForSlot(I) != Names[I]) + return false; + } + return true; +} + +bool Selector::isUnarySelector(StringRef Name) const { + return isUnarySelector() && getNameForSlot(0) == Name; +} + +unsigned Selector::getNumArgs() const { + unsigned IIF = getIdentifierInfoFlag(); + if (IIF <= ZeroArg) + return 0; + if (IIF == OneArg) + return 1; + // We point to a MultiKeywordSelector. + MultiKeywordSelector *SI = getMultiKeywordSelector(); + return SI->getNumArgs(); +} + +IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const { + if (getIdentifierInfoFlag() < MultiArg) { + assert(argIndex == 0 && "illegal keyword index"); + return getAsIdentifierInfo(); + } + + // We point to a MultiKeywordSelector. + MultiKeywordSelector *SI = getMultiKeywordSelector(); + return SI->getIdentifierInfoForSlot(argIndex); +} + +StringRef Selector::getNameForSlot(unsigned int argIndex) const { + IdentifierInfo *II = getIdentifierInfoForSlot(argIndex); + return II ? II->getName() : StringRef(); +} + +std::string MultiKeywordSelector::getName() const { + SmallString<256> Str; + llvm::raw_svector_ostream OS(Str); + for (keyword_iterator I = keyword_begin(), E = keyword_end(); I != E; ++I) { + if (*I) + OS << (*I)->getName(); + OS << ':'; + } + + return std::string(OS.str()); +} + +std::string Selector::getAsString() const { + if (InfoPtr == 0) + return "<null selector>"; + + if (getIdentifierInfoFlag() < MultiArg) { + IdentifierInfo *II = getAsIdentifierInfo(); + + if (getNumArgs() == 0) { + assert(II && "If the number of arguments is 0 then II is guaranteed to " + "not be null."); + return std::string(II->getName()); + } + + if (!II) + return ":"; + + return II->getName().str() + ":"; + } + + // We have a multiple keyword selector. + return getMultiKeywordSelector()->getName(); +} + +void Selector::print(llvm::raw_ostream &OS) const { + OS << getAsString(); +} + +LLVM_DUMP_METHOD void Selector::dump() const { print(llvm::errs()); } + +/// Interpreting the given string using the normal CamelCase +/// conventions, determine whether the given string starts with the +/// given "word", which is assumed to end in a lowercase letter. +static bool startsWithWord(StringRef name, StringRef word) { + if (name.size() < word.size()) return false; + return ((name.size() == word.size() || !isLowercase(name[word.size()])) && + name.startswith(word)); +} + +ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) { + IdentifierInfo *first = sel.getIdentifierInfoForSlot(0); + if (!first) return OMF_None; + + StringRef name = first->getName(); + if (sel.isUnarySelector()) { + if (name == "autorelease") return OMF_autorelease; + if (name == "dealloc") return OMF_dealloc; + if (name == "finalize") return OMF_finalize; + if (name == "release") return OMF_release; + if (name == "retain") return OMF_retain; + if (name == "retainCount") return OMF_retainCount; + if (name == "self") return OMF_self; + if (name == "initialize") return OMF_initialize; + } + + if (name == "performSelector" || name == "performSelectorInBackground" || + name == "performSelectorOnMainThread") + return OMF_performSelector; + + // The other method families may begin with a prefix of underscores. + while (!name.empty() && name.front() == '_') + name = name.substr(1); + + if (name.empty()) return OMF_None; + switch (name.front()) { + case 'a': + if (startsWithWord(name, "alloc")) return OMF_alloc; + break; + case 'c': + if (startsWithWord(name, "copy")) return OMF_copy; + break; + case 'i': + if (startsWithWord(name, "init")) return OMF_init; + break; + case 'm': + if (startsWithWord(name, "mutableCopy")) return OMF_mutableCopy; + break; + case 'n': + if (startsWithWord(name, "new")) return OMF_new; + break; + default: + break; + } + + return OMF_None; +} + +ObjCInstanceTypeFamily Selector::getInstTypeMethodFamily(Selector sel) { + IdentifierInfo *first = sel.getIdentifierInfoForSlot(0); + if (!first) return OIT_None; + + StringRef name = first->getName(); + + if (name.empty()) return OIT_None; + switch (name.front()) { + case 'a': + if (startsWithWord(name, "array")) return OIT_Array; + break; + case 'd': + if (startsWithWord(name, "default")) return OIT_ReturnsSelf; + if (startsWithWord(name, "dictionary")) return OIT_Dictionary; + break; + case 's': + if (startsWithWord(name, "shared")) return OIT_ReturnsSelf; + if (startsWithWord(name, "standard")) return OIT_Singleton; + break; + case 'i': + if (startsWithWord(name, "init")) return OIT_Init; + break; + default: + break; + } + return OIT_None; +} + +ObjCStringFormatFamily Selector::getStringFormatFamilyImpl(Selector sel) { + IdentifierInfo *first = sel.getIdentifierInfoForSlot(0); + if (!first) return SFF_None; + + StringRef name = first->getName(); + + switch (name.front()) { + case 'a': + if (name == "appendFormat") return SFF_NSString; + break; + + case 'i': + if (name == "initWithFormat") return SFF_NSString; + break; + + case 'l': + if (name == "localizedStringWithFormat") return SFF_NSString; + break; + + case 's': + if (name == "stringByAppendingFormat" || + name == "stringWithFormat") return SFF_NSString; + break; + } + return SFF_None; +} + +namespace { + +struct SelectorTableImpl { + llvm::FoldingSet<MultiKeywordSelector> Table; + llvm::BumpPtrAllocator Allocator; +}; + +} // namespace + +static SelectorTableImpl &getSelectorTableImpl(void *P) { + return *static_cast<SelectorTableImpl*>(P); +} + +SmallString<64> +SelectorTable::constructSetterName(StringRef Name) { + SmallString<64> SetterName("set"); + SetterName += Name; + SetterName[3] = toUppercase(SetterName[3]); + return SetterName; +} + +Selector +SelectorTable::constructSetterSelector(IdentifierTable &Idents, + SelectorTable &SelTable, + const IdentifierInfo *Name) { + IdentifierInfo *SetterName = + &Idents.get(constructSetterName(Name->getName())); + return SelTable.getUnarySelector(SetterName); +} + +std::string SelectorTable::getPropertyNameFromSetterSelector(Selector Sel) { + StringRef Name = Sel.getNameForSlot(0); + assert(Name.startswith("set") && "invalid setter name"); + return (Twine(toLowercase(Name[3])) + Name.drop_front(4)).str(); +} + +size_t SelectorTable::getTotalMemory() const { + SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl); + return SelTabImpl.Allocator.getTotalMemory(); +} + +Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) { + if (nKeys < 2) + return Selector(IIV[0], nKeys); + + SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl); + + // Unique selector, to guarantee there is one per name. + llvm::FoldingSetNodeID ID; + MultiKeywordSelector::Profile(ID, IIV, nKeys); + + void *InsertPos = nullptr; + if (MultiKeywordSelector *SI = + SelTabImpl.Table.FindNodeOrInsertPos(ID, InsertPos)) + return Selector(SI); + + // MultiKeywordSelector objects are not allocated with new because they have a + // variable size array (for parameter types) at the end of them. + unsigned Size = sizeof(MultiKeywordSelector) + nKeys*sizeof(IdentifierInfo *); + MultiKeywordSelector *SI = + (MultiKeywordSelector *)SelTabImpl.Allocator.Allocate( + Size, alignof(MultiKeywordSelector)); + new (SI) MultiKeywordSelector(nKeys, IIV); + SelTabImpl.Table.InsertNode(SI, InsertPos); + return Selector(SI); +} + +SelectorTable::SelectorTable() { + Impl = new SelectorTableImpl(); +} + +SelectorTable::~SelectorTable() { + delete &getSelectorTableImpl(Impl); +} + +const char *clang::getOperatorSpelling(OverloadedOperatorKind Operator) { + switch (Operator) { + case OO_None: + case NUM_OVERLOADED_OPERATORS: + return nullptr; + +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + case OO_##Name: return Spelling; +#include "clang/Basic/OperatorKinds.def" + } + + llvm_unreachable("Invalid OverloadedOperatorKind!"); +} + +StringRef clang::getNullabilitySpelling(NullabilityKind kind, + bool isContextSensitive) { + switch (kind) { + case NullabilityKind::NonNull: + return isContextSensitive ? "nonnull" : "_Nonnull"; + + case NullabilityKind::Nullable: + return isContextSensitive ? "nullable" : "_Nullable"; + + case NullabilityKind::NullableResult: + assert(!isContextSensitive && + "_Nullable_result isn't supported as context-sensitive keyword"); + return "_Nullable_result"; + + case NullabilityKind::Unspecified: + return isContextSensitive ? "null_unspecified" : "_Null_unspecified"; + } + llvm_unreachable("Unknown nullability kind."); +} diff --git a/contrib/llvm-project/clang/lib/Basic/LangOptions.cpp b/contrib/llvm-project/clang/lib/Basic/LangOptions.cpp new file mode 100644 index 000000000000..b6dc73d66304 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/LangOptions.cpp @@ -0,0 +1,99 @@ +//===- LangOptions.cpp - C Language Family Language Options ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the LangOptions class. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/LangOptions.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/Path.h" + +using namespace clang; + +LangOptions::LangOptions() : LangStd(LangStandard::lang_unspecified) { +#define LANGOPT(Name, Bits, Default, Description) Name = Default; +#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) set##Name(Default); +#include "clang/Basic/LangOptions.def" +} + +void LangOptions::resetNonModularOptions() { +#define LANGOPT(Name, Bits, Default, Description) +#define BENIGN_LANGOPT(Name, Bits, Default, Description) Name = Default; +#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + Name = static_cast<unsigned>(Default); +#include "clang/Basic/LangOptions.def" + + // These options do not affect AST generation. + NoSanitizeFiles.clear(); + XRayAlwaysInstrumentFiles.clear(); + XRayNeverInstrumentFiles.clear(); + + CurrentModule.clear(); + IsHeaderFile = false; +} + +bool LangOptions::isNoBuiltinFunc(StringRef FuncName) const { + for (unsigned i = 0, e = NoBuiltinFuncs.size(); i != e; ++i) + if (FuncName.equals(NoBuiltinFuncs[i])) + return true; + return false; +} + +VersionTuple LangOptions::getOpenCLVersionTuple() const { + const int Ver = OpenCLCPlusPlus ? OpenCLCPlusPlusVersion : OpenCLVersion; + if (OpenCLCPlusPlus && Ver != 100) + return VersionTuple(Ver / 100); + return VersionTuple(Ver / 100, (Ver % 100) / 10); +} + +unsigned LangOptions::getOpenCLCompatibleVersion() const { + if (!OpenCLCPlusPlus) + return OpenCLVersion; + if (OpenCLCPlusPlusVersion == 100) + return 200; + if (OpenCLCPlusPlusVersion == 202100) + return 300; + llvm_unreachable("Unknown OpenCL version"); +} + +void LangOptions::remapPathPrefix(SmallString<256> &Path) const { + for (const auto &Entry : MacroPrefixMap) + if (llvm::sys::path::replace_path_prefix(Path, Entry.first, Entry.second)) + break; +} + +std::string LangOptions::getOpenCLVersionString() const { + std::string Result; + { + llvm::raw_string_ostream Out(Result); + Out << (OpenCLCPlusPlus ? "C++ for OpenCL" : "OpenCL C") << " version " + << getOpenCLVersionTuple().getAsString(); + } + return Result; +} + +FPOptions FPOptions::defaultWithoutTrailingStorage(const LangOptions &LO) { + FPOptions result(LO); + return result; +} + +LLVM_DUMP_METHOD void FPOptions::dump() { +#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \ + llvm::errs() << "\n " #NAME " " << get##NAME(); +#include "clang/Basic/FPOptions.def" + llvm::errs() << "\n"; +} + +LLVM_DUMP_METHOD void FPOptionsOverride::dump() { +#define OPTION(NAME, TYPE, WIDTH, PREVIOUS) \ + if (has##NAME##Override()) \ + llvm::errs() << "\n " #NAME " Override is " << get##NAME##Override(); +#include "clang/Basic/FPOptions.def" + llvm::errs() << "\n"; +} diff --git a/contrib/llvm-project/clang/lib/Basic/LangStandards.cpp b/contrib/llvm-project/clang/lib/Basic/LangStandards.cpp new file mode 100644 index 000000000000..ee27bfd12113 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/LangStandards.cpp @@ -0,0 +1,45 @@ +//===--- LangStandards.cpp - Language Standard Definitions ----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/LangStandard.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/ErrorHandling.h" +using namespace clang; + +#define LANGSTANDARD(id, name, lang, desc, features) \ + static const LangStandard Lang_##id = {name, desc, features, Language::lang}; +#include "clang/Basic/LangStandards.def" + +const LangStandard &LangStandard::getLangStandardForKind(Kind K) { + switch (K) { + case lang_unspecified: + llvm::report_fatal_error("getLangStandardForKind() on unspecified kind"); +#define LANGSTANDARD(id, name, lang, desc, features) \ + case lang_##id: return Lang_##id; +#include "clang/Basic/LangStandards.def" + } + llvm_unreachable("Invalid language kind!"); +} + +LangStandard::Kind LangStandard::getLangKind(StringRef Name) { + return llvm::StringSwitch<Kind>(Name) +#define LANGSTANDARD(id, name, lang, desc, features) .Case(name, lang_##id) +#define LANGSTANDARD_ALIAS(id, alias) .Case(alias, lang_##id) +#include "clang/Basic/LangStandards.def" + .Default(lang_unspecified); +} + +const LangStandard *LangStandard::getLangStandardForName(StringRef Name) { + Kind K = getLangKind(Name); + if (K == lang_unspecified) + return nullptr; + + return &getLangStandardForKind(K); +} + + diff --git a/contrib/llvm-project/clang/lib/Basic/Module.cpp b/contrib/llvm-project/clang/lib/Basic/Module.cpp new file mode 100644 index 000000000000..09bd3251fea0 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Module.cpp @@ -0,0 +1,689 @@ +//===- Module.cpp - Describe a module -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the Module class, which describes a module in the source +// code. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Module.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <functional> +#include <string> +#include <utility> +#include <vector> + +using namespace clang; + +Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent, + bool IsFramework, bool IsExplicit, unsigned VisibilityID) + : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent), + VisibilityID(VisibilityID), IsUnimportable(false), + HasIncompatibleModuleFile(false), IsAvailable(true), + IsFromModuleFile(false), IsFramework(IsFramework), IsExplicit(IsExplicit), + IsSystem(false), IsExternC(false), IsInferred(false), + InferSubmodules(false), InferExplicitSubmodules(false), + InferExportWildcard(false), ConfigMacrosExhaustive(false), + NoUndeclaredIncludes(false), ModuleMapIsPrivate(false), + NameVisibility(Hidden) { + if (Parent) { + IsAvailable = Parent->isAvailable(); + IsUnimportable = Parent->isUnimportable(); + IsSystem = Parent->IsSystem; + IsExternC = Parent->IsExternC; + NoUndeclaredIncludes = Parent->NoUndeclaredIncludes; + ModuleMapIsPrivate = Parent->ModuleMapIsPrivate; + + Parent->SubModuleIndex[Name] = Parent->SubModules.size(); + Parent->SubModules.push_back(this); + } +} + +Module::~Module() { + for (submodule_iterator I = submodule_begin(), IEnd = submodule_end(); + I != IEnd; ++I) { + delete *I; + } +} + +static bool isPlatformEnvironment(const TargetInfo &Target, StringRef Feature) { + StringRef Platform = Target.getPlatformName(); + StringRef Env = Target.getTriple().getEnvironmentName(); + + // Attempt to match platform and environment. + if (Platform == Feature || Target.getTriple().getOSName() == Feature || + Env == Feature) + return true; + + auto CmpPlatformEnv = [](StringRef LHS, StringRef RHS) { + auto Pos = LHS.find('-'); + if (Pos == StringRef::npos) + return false; + SmallString<128> NewLHS = LHS.slice(0, Pos); + NewLHS += LHS.slice(Pos+1, LHS.size()); + return NewLHS == RHS; + }; + + SmallString<128> PlatformEnv = Target.getTriple().getOSAndEnvironmentName(); + // Darwin has different but equivalent variants for simulators, example: + // 1. x86_64-apple-ios-simulator + // 2. x86_64-apple-iossimulator + // where both are valid examples of the same platform+environment but in the + // variant (2) the simulator is hardcoded as part of the platform name. Both + // forms above should match for "iossimulator" requirement. + if (Target.getTriple().isOSDarwin() && PlatformEnv.endswith("simulator")) + return PlatformEnv == Feature || CmpPlatformEnv(PlatformEnv, Feature); + + return PlatformEnv == Feature; +} + +/// Determine whether a translation unit built using the current +/// language options has the given feature. +static bool hasFeature(StringRef Feature, const LangOptions &LangOpts, + const TargetInfo &Target) { + bool HasFeature = llvm::StringSwitch<bool>(Feature) + .Case("altivec", LangOpts.AltiVec) + .Case("blocks", LangOpts.Blocks) + .Case("coroutines", LangOpts.Coroutines) + .Case("cplusplus", LangOpts.CPlusPlus) + .Case("cplusplus11", LangOpts.CPlusPlus11) + .Case("cplusplus14", LangOpts.CPlusPlus14) + .Case("cplusplus17", LangOpts.CPlusPlus17) + .Case("c99", LangOpts.C99) + .Case("c11", LangOpts.C11) + .Case("c17", LangOpts.C17) + .Case("freestanding", LangOpts.Freestanding) + .Case("gnuinlineasm", LangOpts.GNUAsm) + .Case("objc", LangOpts.ObjC) + .Case("objc_arc", LangOpts.ObjCAutoRefCount) + .Case("opencl", LangOpts.OpenCL) + .Case("tls", Target.isTLSSupported()) + .Case("zvector", LangOpts.ZVector) + .Default(Target.hasFeature(Feature) || + isPlatformEnvironment(Target, Feature)); + if (!HasFeature) + HasFeature = llvm::is_contained(LangOpts.ModuleFeatures, Feature); + return HasFeature; +} + +bool Module::isUnimportable(const LangOptions &LangOpts, + const TargetInfo &Target, Requirement &Req, + Module *&ShadowingModule) const { + if (!IsUnimportable) + return false; + + for (const Module *Current = this; Current; Current = Current->Parent) { + if (Current->ShadowingModule) { + ShadowingModule = Current->ShadowingModule; + return true; + } + for (unsigned I = 0, N = Current->Requirements.size(); I != N; ++I) { + if (hasFeature(Current->Requirements[I].first, LangOpts, Target) != + Current->Requirements[I].second) { + Req = Current->Requirements[I]; + return true; + } + } + } + + llvm_unreachable("could not find a reason why module is unimportable"); +} + +bool Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target, + Requirement &Req, + UnresolvedHeaderDirective &MissingHeader, + Module *&ShadowingModule) const { + if (IsAvailable) + return true; + + if (isUnimportable(LangOpts, Target, Req, ShadowingModule)) + return false; + + // FIXME: All missing headers are listed on the top-level module. Should we + // just look there? + for (const Module *Current = this; Current; Current = Current->Parent) { + if (!Current->MissingHeaders.empty()) { + MissingHeader = Current->MissingHeaders.front(); + return false; + } + } + + llvm_unreachable("could not find a reason why module is unavailable"); +} + +bool Module::isSubModuleOf(const Module *Other) const { + for (auto *Parent = this; Parent; Parent = Parent->Parent) { + if (Parent == Other) + return true; + } + return false; +} + +const Module *Module::getTopLevelModule() const { + const Module *Result = this; + while (Result->Parent) + Result = Result->Parent; + + return Result; +} + +static StringRef getModuleNameFromComponent( + const std::pair<std::string, SourceLocation> &IdComponent) { + return IdComponent.first; +} + +static StringRef getModuleNameFromComponent(StringRef R) { return R; } + +template<typename InputIter> +static void printModuleId(raw_ostream &OS, InputIter Begin, InputIter End, + bool AllowStringLiterals = true) { + for (InputIter It = Begin; It != End; ++It) { + if (It != Begin) + OS << "."; + + StringRef Name = getModuleNameFromComponent(*It); + if (!AllowStringLiterals || isValidAsciiIdentifier(Name)) + OS << Name; + else { + OS << '"'; + OS.write_escaped(Name); + OS << '"'; + } + } +} + +template<typename Container> +static void printModuleId(raw_ostream &OS, const Container &C) { + return printModuleId(OS, C.begin(), C.end()); +} + +std::string Module::getFullModuleName(bool AllowStringLiterals) const { + SmallVector<StringRef, 2> Names; + + // Build up the set of module names (from innermost to outermost). + for (const Module *M = this; M; M = M->Parent) + Names.push_back(M->Name); + + std::string Result; + + llvm::raw_string_ostream Out(Result); + printModuleId(Out, Names.rbegin(), Names.rend(), AllowStringLiterals); + Out.flush(); + + return Result; +} + +bool Module::fullModuleNameIs(ArrayRef<StringRef> nameParts) const { + for (const Module *M = this; M; M = M->Parent) { + if (nameParts.empty() || M->Name != nameParts.back()) + return false; + nameParts = nameParts.drop_back(); + } + return nameParts.empty(); +} + +Module::DirectoryName Module::getUmbrellaDir() const { + if (Header U = getUmbrellaHeader()) + return {"", "", U.Entry->getDir()}; + + return {UmbrellaAsWritten, UmbrellaRelativeToRootModuleDirectory, + Umbrella.dyn_cast<const DirectoryEntry *>()}; +} + +void Module::addTopHeader(const FileEntry *File) { + assert(File); + TopHeaders.insert(File); +} + +ArrayRef<const FileEntry *> Module::getTopHeaders(FileManager &FileMgr) { + if (!TopHeaderNames.empty()) { + for (std::vector<std::string>::iterator + I = TopHeaderNames.begin(), E = TopHeaderNames.end(); I != E; ++I) { + if (auto FE = FileMgr.getFile(*I)) + TopHeaders.insert(*FE); + } + TopHeaderNames.clear(); + } + + return llvm::makeArrayRef(TopHeaders.begin(), TopHeaders.end()); +} + +bool Module::directlyUses(const Module *Requested) const { + auto *Top = getTopLevelModule(); + + // A top-level module implicitly uses itself. + if (Requested->isSubModuleOf(Top)) + return true; + + for (auto *Use : Top->DirectUses) + if (Requested->isSubModuleOf(Use)) + return true; + + // Anyone is allowed to use our builtin stddef.h and its accompanying module. + if (!Requested->Parent && Requested->Name == "_Builtin_stddef_max_align_t") + return true; + + return false; +} + +void Module::addRequirement(StringRef Feature, bool RequiredState, + const LangOptions &LangOpts, + const TargetInfo &Target) { + Requirements.push_back(Requirement(std::string(Feature), RequiredState)); + + // If this feature is currently available, we're done. + if (hasFeature(Feature, LangOpts, Target) == RequiredState) + return; + + markUnavailable(/*Unimportable*/true); +} + +void Module::markUnavailable(bool Unimportable) { + auto needUpdate = [Unimportable](Module *M) { + return M->IsAvailable || (!M->IsUnimportable && Unimportable); + }; + + if (!needUpdate(this)) + return; + + SmallVector<Module *, 2> Stack; + Stack.push_back(this); + while (!Stack.empty()) { + Module *Current = Stack.back(); + Stack.pop_back(); + + if (!needUpdate(Current)) + continue; + + Current->IsAvailable = false; + Current->IsUnimportable |= Unimportable; + for (submodule_iterator Sub = Current->submodule_begin(), + SubEnd = Current->submodule_end(); + Sub != SubEnd; ++Sub) { + if (needUpdate(*Sub)) + Stack.push_back(*Sub); + } + } +} + +Module *Module::findSubmodule(StringRef Name) const { + llvm::StringMap<unsigned>::const_iterator Pos = SubModuleIndex.find(Name); + if (Pos == SubModuleIndex.end()) + return nullptr; + + return SubModules[Pos->getValue()]; +} + +Module *Module::findOrInferSubmodule(StringRef Name) { + llvm::StringMap<unsigned>::const_iterator Pos = SubModuleIndex.find(Name); + if (Pos != SubModuleIndex.end()) + return SubModules[Pos->getValue()]; + if (!InferSubmodules) + return nullptr; + Module *Result = new Module(Name, SourceLocation(), this, false, InferExplicitSubmodules, 0); + Result->InferExplicitSubmodules = InferExplicitSubmodules; + Result->InferSubmodules = InferSubmodules; + Result->InferExportWildcard = InferExportWildcard; + if (Result->InferExportWildcard) + Result->Exports.push_back(Module::ExportDecl(nullptr, true)); + return Result; +} + +void Module::getExportedModules(SmallVectorImpl<Module *> &Exported) const { + // All non-explicit submodules are exported. + for (std::vector<Module *>::const_iterator I = SubModules.begin(), + E = SubModules.end(); + I != E; ++I) { + Module *Mod = *I; + if (!Mod->IsExplicit) + Exported.push_back(Mod); + } + + // Find re-exported modules by filtering the list of imported modules. + bool AnyWildcard = false; + bool UnrestrictedWildcard = false; + SmallVector<Module *, 4> WildcardRestrictions; + for (unsigned I = 0, N = Exports.size(); I != N; ++I) { + Module *Mod = Exports[I].getPointer(); + if (!Exports[I].getInt()) { + // Export a named module directly; no wildcards involved. + Exported.push_back(Mod); + + continue; + } + + // Wildcard export: export all of the imported modules that match + // the given pattern. + AnyWildcard = true; + if (UnrestrictedWildcard) + continue; + + if (Module *Restriction = Exports[I].getPointer()) + WildcardRestrictions.push_back(Restriction); + else { + WildcardRestrictions.clear(); + UnrestrictedWildcard = true; + } + } + + // If there were any wildcards, push any imported modules that were + // re-exported by the wildcard restriction. + if (!AnyWildcard) + return; + + for (unsigned I = 0, N = Imports.size(); I != N; ++I) { + Module *Mod = Imports[I]; + bool Acceptable = UnrestrictedWildcard; + if (!Acceptable) { + // Check whether this module meets one of the restrictions. + for (unsigned R = 0, NR = WildcardRestrictions.size(); R != NR; ++R) { + Module *Restriction = WildcardRestrictions[R]; + if (Mod == Restriction || Mod->isSubModuleOf(Restriction)) { + Acceptable = true; + break; + } + } + } + + if (!Acceptable) + continue; + + Exported.push_back(Mod); + } +} + +void Module::buildVisibleModulesCache() const { + assert(VisibleModulesCache.empty() && "cache does not need building"); + + // This module is visible to itself. + VisibleModulesCache.insert(this); + + // Every imported module is visible. + SmallVector<Module *, 16> Stack(Imports.begin(), Imports.end()); + while (!Stack.empty()) { + Module *CurrModule = Stack.pop_back_val(); + + // Every module transitively exported by an imported module is visible. + if (VisibleModulesCache.insert(CurrModule).second) + CurrModule->getExportedModules(Stack); + } +} + +void Module::print(raw_ostream &OS, unsigned Indent, bool Dump) const { + OS.indent(Indent); + if (IsFramework) + OS << "framework "; + if (IsExplicit) + OS << "explicit "; + OS << "module "; + printModuleId(OS, &Name, &Name + 1); + + if (IsSystem || IsExternC) { + OS.indent(Indent + 2); + if (IsSystem) + OS << " [system]"; + if (IsExternC) + OS << " [extern_c]"; + } + + OS << " {\n"; + + if (!Requirements.empty()) { + OS.indent(Indent + 2); + OS << "requires "; + for (unsigned I = 0, N = Requirements.size(); I != N; ++I) { + if (I) + OS << ", "; + if (!Requirements[I].second) + OS << "!"; + OS << Requirements[I].first; + } + OS << "\n"; + } + + if (Header H = getUmbrellaHeader()) { + OS.indent(Indent + 2); + OS << "umbrella header \""; + OS.write_escaped(H.NameAsWritten); + OS << "\"\n"; + } else if (DirectoryName D = getUmbrellaDir()) { + OS.indent(Indent + 2); + OS << "umbrella \""; + OS.write_escaped(D.NameAsWritten); + OS << "\"\n"; + } + + if (!ConfigMacros.empty() || ConfigMacrosExhaustive) { + OS.indent(Indent + 2); + OS << "config_macros "; + if (ConfigMacrosExhaustive) + OS << "[exhaustive]"; + for (unsigned I = 0, N = ConfigMacros.size(); I != N; ++I) { + if (I) + OS << ", "; + OS << ConfigMacros[I]; + } + OS << "\n"; + } + + struct { + StringRef Prefix; + HeaderKind Kind; + } Kinds[] = {{"", HK_Normal}, + {"textual ", HK_Textual}, + {"private ", HK_Private}, + {"private textual ", HK_PrivateTextual}, + {"exclude ", HK_Excluded}}; + + for (auto &K : Kinds) { + assert(&K == &Kinds[K.Kind] && "kinds in wrong order"); + for (auto &H : Headers[K.Kind]) { + OS.indent(Indent + 2); + OS << K.Prefix << "header \""; + OS.write_escaped(H.NameAsWritten); + OS << "\" { size " << H.Entry->getSize() + << " mtime " << H.Entry->getModificationTime() << " }\n"; + } + } + for (auto *Unresolved : {&UnresolvedHeaders, &MissingHeaders}) { + for (auto &U : *Unresolved) { + OS.indent(Indent + 2); + OS << Kinds[U.Kind].Prefix << "header \""; + OS.write_escaped(U.FileName); + OS << "\""; + if (U.Size || U.ModTime) { + OS << " {"; + if (U.Size) + OS << " size " << *U.Size; + if (U.ModTime) + OS << " mtime " << *U.ModTime; + OS << " }"; + } + OS << "\n"; + } + } + + if (!ExportAsModule.empty()) { + OS.indent(Indent + 2); + OS << "export_as" << ExportAsModule << "\n"; + } + + for (submodule_const_iterator MI = submodule_begin(), MIEnd = submodule_end(); + MI != MIEnd; ++MI) + // Print inferred subframework modules so that we don't need to re-infer + // them (requires expensive directory iteration + stat calls) when we build + // the module. Regular inferred submodules are OK, as we need to look at all + // those header files anyway. + if (!(*MI)->IsInferred || (*MI)->IsFramework) + (*MI)->print(OS, Indent + 2, Dump); + + for (unsigned I = 0, N = Exports.size(); I != N; ++I) { + OS.indent(Indent + 2); + OS << "export "; + if (Module *Restriction = Exports[I].getPointer()) { + OS << Restriction->getFullModuleName(true); + if (Exports[I].getInt()) + OS << ".*"; + } else { + OS << "*"; + } + OS << "\n"; + } + + for (unsigned I = 0, N = UnresolvedExports.size(); I != N; ++I) { + OS.indent(Indent + 2); + OS << "export "; + printModuleId(OS, UnresolvedExports[I].Id); + if (UnresolvedExports[I].Wildcard) + OS << (UnresolvedExports[I].Id.empty() ? "*" : ".*"); + OS << "\n"; + } + + if (Dump) { + for (Module *M : Imports) { + OS.indent(Indent + 2); + llvm::errs() << "import " << M->getFullModuleName() << "\n"; + } + } + + for (unsigned I = 0, N = DirectUses.size(); I != N; ++I) { + OS.indent(Indent + 2); + OS << "use "; + OS << DirectUses[I]->getFullModuleName(true); + OS << "\n"; + } + + for (unsigned I = 0, N = UnresolvedDirectUses.size(); I != N; ++I) { + OS.indent(Indent + 2); + OS << "use "; + printModuleId(OS, UnresolvedDirectUses[I]); + OS << "\n"; + } + + for (unsigned I = 0, N = LinkLibraries.size(); I != N; ++I) { + OS.indent(Indent + 2); + OS << "link "; + if (LinkLibraries[I].IsFramework) + OS << "framework "; + OS << "\""; + OS.write_escaped(LinkLibraries[I].Library); + OS << "\""; + } + + for (unsigned I = 0, N = UnresolvedConflicts.size(); I != N; ++I) { + OS.indent(Indent + 2); + OS << "conflict "; + printModuleId(OS, UnresolvedConflicts[I].Id); + OS << ", \""; + OS.write_escaped(UnresolvedConflicts[I].Message); + OS << "\"\n"; + } + + for (unsigned I = 0, N = Conflicts.size(); I != N; ++I) { + OS.indent(Indent + 2); + OS << "conflict "; + OS << Conflicts[I].Other->getFullModuleName(true); + OS << ", \""; + OS.write_escaped(Conflicts[I].Message); + OS << "\"\n"; + } + + if (InferSubmodules) { + OS.indent(Indent + 2); + if (InferExplicitSubmodules) + OS << "explicit "; + OS << "module * {\n"; + if (InferExportWildcard) { + OS.indent(Indent + 4); + OS << "export *\n"; + } + OS.indent(Indent + 2); + OS << "}\n"; + } + + OS.indent(Indent); + OS << "}\n"; +} + +LLVM_DUMP_METHOD void Module::dump() const { + print(llvm::errs(), 0, true); +} + +void VisibleModuleSet::setVisible(Module *M, SourceLocation Loc, + VisibleCallback Vis, ConflictCallback Cb) { + assert(Loc.isValid() && "setVisible expects a valid import location"); + if (isVisible(M)) + return; + + ++Generation; + + struct Visiting { + Module *M; + Visiting *ExportedBy; + }; + + std::function<void(Visiting)> VisitModule = [&](Visiting V) { + // Nothing to do for a module that's already visible. + unsigned ID = V.M->getVisibilityID(); + if (ImportLocs.size() <= ID) + ImportLocs.resize(ID + 1); + else if (ImportLocs[ID].isValid()) + return; + + ImportLocs[ID] = Loc; + Vis(M); + + // Make any exported modules visible. + SmallVector<Module *, 16> Exports; + V.M->getExportedModules(Exports); + for (Module *E : Exports) { + // Don't import non-importable modules. + if (!E->isUnimportable()) + VisitModule({E, &V}); + } + + for (auto &C : V.M->Conflicts) { + if (isVisible(C.Other)) { + llvm::SmallVector<Module*, 8> Path; + for (Visiting *I = &V; I; I = I->ExportedBy) + Path.push_back(I->M); + Cb(Path, C.Other, C.Message); + } + } + }; + VisitModule({M, nullptr}); +} + +ASTSourceDescriptor::ASTSourceDescriptor(Module &M) + : Signature(M.Signature), ClangModule(&M) { + if (M.Directory) + Path = M.Directory->getName(); + if (auto File = M.getASTFile()) + ASTFile = File->getName(); +} + +std::string ASTSourceDescriptor::getModuleName() const { + if (ClangModule) + return ClangModule->Name; + else + return std::string(PCHModuleName); +} diff --git a/contrib/llvm-project/clang/lib/Basic/NoSanitizeList.cpp b/contrib/llvm-project/clang/lib/Basic/NoSanitizeList.cpp new file mode 100644 index 000000000000..3efd613b0d33 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/NoSanitizeList.cpp @@ -0,0 +1,54 @@ +//===--- NoSanitizeList.cpp - Ignored list for sanitizers ----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// User-provided ignore-list used to disable/alter instrumentation done in +// sanitizers. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/NoSanitizeList.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SanitizerSpecialCaseList.h" +#include "clang/Basic/Sanitizers.h" +#include "clang/Basic/SourceManager.h" + +using namespace clang; + +NoSanitizeList::NoSanitizeList(const std::vector<std::string> &NoSanitizePaths, + SourceManager &SM) + : SSCL(SanitizerSpecialCaseList::createOrDie( + NoSanitizePaths, SM.getFileManager().getVirtualFileSystem())), + SM(SM) {} + +NoSanitizeList::~NoSanitizeList() = default; + +bool NoSanitizeList::containsGlobal(SanitizerMask Mask, StringRef GlobalName, + StringRef Category) const { + return SSCL->inSection(Mask, "global", GlobalName, Category); +} + +bool NoSanitizeList::containsType(SanitizerMask Mask, StringRef MangledTypeName, + StringRef Category) const { + return SSCL->inSection(Mask, "type", MangledTypeName, Category); +} + +bool NoSanitizeList::containsFunction(SanitizerMask Mask, + StringRef FunctionName) const { + return SSCL->inSection(Mask, "fun", FunctionName); +} + +bool NoSanitizeList::containsFile(SanitizerMask Mask, StringRef FileName, + StringRef Category) const { + return SSCL->inSection(Mask, "src", FileName, Category); +} + +bool NoSanitizeList::containsLocation(SanitizerMask Mask, SourceLocation Loc, + StringRef Category) const { + return Loc.isValid() && + containsFile(Mask, SM.getFilename(SM.getFileLoc(Loc)), Category); +} diff --git a/contrib/llvm-project/clang/lib/Basic/ObjCRuntime.cpp b/contrib/llvm-project/clang/lib/Basic/ObjCRuntime.cpp new file mode 100644 index 000000000000..cfc437409b5d --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/ObjCRuntime.cpp @@ -0,0 +1,97 @@ +//===- ObjCRuntime.cpp - Objective-C Runtime Handling ---------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the ObjCRuntime class, which represents the +// target Objective-C runtime. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/ObjCRuntime.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VersionTuple.h" +#include "llvm/Support/raw_ostream.h" +#include <cstddef> +#include <string> + +using namespace clang; + +std::string ObjCRuntime::getAsString() const { + std::string Result; + { + llvm::raw_string_ostream Out(Result); + Out << *this; + } + return Result; +} + +raw_ostream &clang::operator<<(raw_ostream &out, const ObjCRuntime &value) { + switch (value.getKind()) { + case ObjCRuntime::MacOSX: out << "macosx"; break; + case ObjCRuntime::FragileMacOSX: out << "macosx-fragile"; break; + case ObjCRuntime::iOS: out << "ios"; break; + case ObjCRuntime::WatchOS: out << "watchos"; break; + case ObjCRuntime::GNUstep: out << "gnustep"; break; + case ObjCRuntime::GCC: out << "gcc"; break; + case ObjCRuntime::ObjFW: out << "objfw"; break; + } + if (value.getVersion() > VersionTuple(0)) { + out << '-' << value.getVersion(); + } + return out; +} + +bool ObjCRuntime::tryParse(StringRef input) { + // Look for the last dash. + std::size_t dash = input.rfind('-'); + + // We permit dashes in the runtime name, and we also permit the + // version to be omitted, so if we see a dash not followed by a + // digit then we need to ignore it. + if (dash != StringRef::npos && dash + 1 != input.size() && + (input[dash+1] < '0' || input[dash+1] > '9')) { + dash = StringRef::npos; + } + + // Everything prior to that must be a valid string name. + Kind kind; + StringRef runtimeName = input.substr(0, dash); + Version = VersionTuple(0); + if (runtimeName == "macosx") { + kind = ObjCRuntime::MacOSX; + } else if (runtimeName == "macosx-fragile") { + kind = ObjCRuntime::FragileMacOSX; + } else if (runtimeName == "ios") { + kind = ObjCRuntime::iOS; + } else if (runtimeName == "watchos") { + kind = ObjCRuntime::WatchOS; + } else if (runtimeName == "gnustep") { + // If no version is specified then default to the most recent one that we + // know about. + Version = VersionTuple(1, 6); + kind = ObjCRuntime::GNUstep; + } else if (runtimeName == "gcc") { + kind = ObjCRuntime::GCC; + } else if (runtimeName == "objfw") { + kind = ObjCRuntime::ObjFW; + Version = VersionTuple(0, 8); + } else { + return true; + } + TheKind = kind; + + if (dash != StringRef::npos) { + StringRef verString = input.substr(dash + 1); + if (Version.tryParse(verString)) + return true; + } + + if (kind == ObjCRuntime::ObjFW && Version > VersionTuple(0, 8)) + Version = VersionTuple(0, 8); + + return false; +} diff --git a/contrib/llvm-project/clang/lib/Basic/OpenCLOptions.cpp b/contrib/llvm-project/clang/lib/Basic/OpenCLOptions.cpp new file mode 100644 index 000000000000..7e89b3f1b804 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/OpenCLOptions.cpp @@ -0,0 +1,152 @@ +//===--- OpenCLOptions.cpp---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/OpenCLOptions.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/TargetInfo.h" + +namespace clang { + +const OpenCLOptions::FeatureDepList OpenCLOptions::DependentFeaturesList = { + {"__opencl_c_read_write_images", "__opencl_c_images"}, + {"__opencl_c_3d_image_writes", "__opencl_c_images"}, + {"__opencl_c_pipes", "__opencl_c_generic_address_space"}, + {"__opencl_c_device_enqueue", "__opencl_c_generic_address_space"}, + {"__opencl_c_device_enqueue", "__opencl_c_program_scope_global_variables"}}; + +const llvm::StringMap<llvm::StringRef> OpenCLOptions::FeatureExtensionMap = { + {"cl_khr_fp64", "__opencl_c_fp64"}, + {"cl_khr_3d_image_writes", "__opencl_c_3d_image_writes"}}; + +bool OpenCLOptions::isKnown(llvm::StringRef Ext) const { + return OptMap.find(Ext) != OptMap.end(); +} + +bool OpenCLOptions::isAvailableOption(llvm::StringRef Ext, + const LangOptions &LO) const { + if (!isKnown(Ext)) + return false; + + auto &OptInfo = OptMap.find(Ext)->getValue(); + if (OptInfo.isCoreIn(LO) || OptInfo.isOptionalCoreIn(LO)) + return isSupported(Ext, LO); + + return isEnabled(Ext); +} + +bool OpenCLOptions::isEnabled(llvm::StringRef Ext) const { + auto I = OptMap.find(Ext); + return I != OptMap.end() && I->getValue().Enabled; +} + +bool OpenCLOptions::isWithPragma(llvm::StringRef Ext) const { + auto E = OptMap.find(Ext); + return E != OptMap.end() && E->second.WithPragma; +} + +bool OpenCLOptions::isSupported(llvm::StringRef Ext, + const LangOptions &LO) const { + auto I = OptMap.find(Ext); + return I != OptMap.end() && I->getValue().Supported && + I->getValue().isAvailableIn(LO); +} + +bool OpenCLOptions::isSupportedCore(llvm::StringRef Ext, + const LangOptions &LO) const { + auto I = OptMap.find(Ext); + return I != OptMap.end() && I->getValue().Supported && + I->getValue().isCoreIn(LO); +} + +bool OpenCLOptions::isSupportedOptionalCore(llvm::StringRef Ext, + const LangOptions &LO) const { + auto I = OptMap.find(Ext); + return I != OptMap.end() && I->getValue().Supported && + I->getValue().isOptionalCoreIn(LO); +} + +bool OpenCLOptions::isSupportedCoreOrOptionalCore(llvm::StringRef Ext, + const LangOptions &LO) const { + return isSupportedCore(Ext, LO) || isSupportedOptionalCore(Ext, LO); +} + +bool OpenCLOptions::isSupportedExtension(llvm::StringRef Ext, + const LangOptions &LO) const { + auto I = OptMap.find(Ext); + return I != OptMap.end() && I->getValue().Supported && + I->getValue().isAvailableIn(LO) && + !isSupportedCoreOrOptionalCore(Ext, LO); +} + +void OpenCLOptions::enable(llvm::StringRef Ext, bool V) { + OptMap[Ext].Enabled = V; +} + +void OpenCLOptions::acceptsPragma(llvm::StringRef Ext, bool V) { + OptMap[Ext].WithPragma = V; +} + +void OpenCLOptions::support(llvm::StringRef Ext, bool V) { + assert(!Ext.empty() && "Extension is empty."); + assert(Ext[0] != '+' && Ext[0] != '-'); + OptMap[Ext].Supported = V; +} + +OpenCLOptions::OpenCLOptions() { +#define OPENCL_GENERIC_EXTENSION(Ext, ...) \ + OptMap.insert_or_assign(#Ext, OpenCLOptionInfo{__VA_ARGS__}); +#include "clang/Basic/OpenCLExtensions.def" +} + +void OpenCLOptions::addSupport(const llvm::StringMap<bool> &FeaturesMap, + const LangOptions &Opts) { + for (const auto &F : FeaturesMap) { + const auto &Name = F.getKey(); + if (F.getValue() && isKnown(Name) && OptMap[Name].isAvailableIn(Opts)) + support(Name); + } +} + +void OpenCLOptions::disableAll() { + for (auto &Opt : OptMap) + Opt.getValue().Enabled = false; +} + +bool OpenCLOptions::diagnoseUnsupportedFeatureDependencies( + const TargetInfo &TI, DiagnosticsEngine &Diags) { + auto OpenCLFeaturesMap = TI.getSupportedOpenCLOpts(); + + bool IsValid = true; + for (auto &FeaturePair : DependentFeaturesList) { + auto Feature = FeaturePair.first; + auto Dep = FeaturePair.second; + if (TI.hasFeatureEnabled(OpenCLFeaturesMap, Feature) && + !TI.hasFeatureEnabled(OpenCLFeaturesMap, Dep)) { + IsValid = false; + Diags.Report(diag::err_opencl_feature_requires) << Feature << Dep; + } + } + return IsValid; +} + +bool OpenCLOptions::diagnoseFeatureExtensionDifferences( + const TargetInfo &TI, DiagnosticsEngine &Diags) { + auto OpenCLFeaturesMap = TI.getSupportedOpenCLOpts(); + + bool IsValid = true; + for (auto &ExtAndFeat : FeatureExtensionMap) + if (TI.hasFeatureEnabled(OpenCLFeaturesMap, ExtAndFeat.getKey()) != + TI.hasFeatureEnabled(OpenCLFeaturesMap, ExtAndFeat.getValue())) { + IsValid = false; + Diags.Report(diag::err_opencl_extension_and_feature_differs) + << ExtAndFeat.getKey() << ExtAndFeat.getValue(); + } + return IsValid; +} + +} // end namespace clang diff --git a/contrib/llvm-project/clang/lib/Basic/OpenMPKinds.cpp b/contrib/llvm-project/clang/lib/Basic/OpenMPKinds.cpp new file mode 100644 index 000000000000..1761c6d3d89b --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/OpenMPKinds.cpp @@ -0,0 +1,748 @@ +//===--- OpenMPKinds.cpp - Token Kinds Support ----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file implements the OpenMP enum and support functions. +/// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/OpenMPKinds.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/ErrorHandling.h" +#include <cassert> + +using namespace clang; +using namespace llvm::omp; + +unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, StringRef Str, + const LangOptions &LangOpts) { + switch (Kind) { + case OMPC_default: + return llvm::StringSwitch<unsigned>(Str) +#define OMP_DEFAULT_KIND(Enum, Name) .Case(Name, unsigned(Enum)) +#include "llvm/Frontend/OpenMP/OMPKinds.def" + .Default(unsigned(llvm::omp::OMP_DEFAULT_unknown)); + case OMPC_proc_bind: + return llvm::StringSwitch<unsigned>(Str) +#define OMP_PROC_BIND_KIND(Enum, Name, Value) .Case(Name, Value) +#include "llvm/Frontend/OpenMP/OMPKinds.def" + .Default(unsigned(llvm::omp::OMP_PROC_BIND_unknown)); + case OMPC_schedule: + return llvm::StringSwitch<unsigned>(Str) +#define OPENMP_SCHEDULE_KIND(Name) \ + .Case(#Name, static_cast<unsigned>(OMPC_SCHEDULE_##Name)) +#define OPENMP_SCHEDULE_MODIFIER(Name) \ + .Case(#Name, static_cast<unsigned>(OMPC_SCHEDULE_MODIFIER_##Name)) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_SCHEDULE_unknown); + case OMPC_depend: + return llvm::StringSwitch<OpenMPDependClauseKind>(Str) +#define OPENMP_DEPEND_KIND(Name) .Case(#Name, OMPC_DEPEND_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_DEPEND_unknown); + case OMPC_linear: + return llvm::StringSwitch<OpenMPLinearClauseKind>(Str) +#define OPENMP_LINEAR_KIND(Name) .Case(#Name, OMPC_LINEAR_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_LINEAR_unknown); + case OMPC_map: { + unsigned Type = llvm::StringSwitch<unsigned>(Str) +#define OPENMP_MAP_KIND(Name) \ + .Case(#Name, static_cast<unsigned>(OMPC_MAP_##Name)) +#define OPENMP_MAP_MODIFIER_KIND(Name) \ + .Case(#Name, static_cast<unsigned>(OMPC_MAP_MODIFIER_##Name)) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_MAP_unknown); + if (LangOpts.OpenMP < 51 && Type == OMPC_MAP_MODIFIER_present) + return OMPC_MAP_MODIFIER_unknown; + if (!LangOpts.OpenMPExtensions && Type == OMPC_MAP_MODIFIER_ompx_hold) + return OMPC_MAP_MODIFIER_unknown; + return Type; + } + case OMPC_to: + case OMPC_from: { + unsigned Type = llvm::StringSwitch<unsigned>(Str) +#define OPENMP_MOTION_MODIFIER_KIND(Name) \ + .Case(#Name, static_cast<unsigned>(OMPC_MOTION_MODIFIER_##Name)) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_MOTION_MODIFIER_unknown); + if (LangOpts.OpenMP < 51 && Type == OMPC_MOTION_MODIFIER_present) + return OMPC_MOTION_MODIFIER_unknown; + return Type; + } + case OMPC_dist_schedule: + return llvm::StringSwitch<OpenMPDistScheduleClauseKind>(Str) +#define OPENMP_DIST_SCHEDULE_KIND(Name) .Case(#Name, OMPC_DIST_SCHEDULE_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_DIST_SCHEDULE_unknown); + case OMPC_defaultmap: + return llvm::StringSwitch<unsigned>(Str) +#define OPENMP_DEFAULTMAP_KIND(Name) \ + .Case(#Name, static_cast<unsigned>(OMPC_DEFAULTMAP_##Name)) +#define OPENMP_DEFAULTMAP_MODIFIER(Name) \ + .Case(#Name, static_cast<unsigned>(OMPC_DEFAULTMAP_MODIFIER_##Name)) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_DEFAULTMAP_unknown); + case OMPC_atomic_default_mem_order: + return llvm::StringSwitch<OpenMPAtomicDefaultMemOrderClauseKind>(Str) +#define OPENMP_ATOMIC_DEFAULT_MEM_ORDER_KIND(Name) \ + .Case(#Name, OMPC_ATOMIC_DEFAULT_MEM_ORDER_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_ATOMIC_DEFAULT_MEM_ORDER_unknown); + case OMPC_device_type: + return llvm::StringSwitch<OpenMPDeviceType>(Str) +#define OPENMP_DEVICE_TYPE_KIND(Name) .Case(#Name, OMPC_DEVICE_TYPE_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_DEVICE_TYPE_unknown); + case OMPC_lastprivate: + return llvm::StringSwitch<OpenMPLastprivateModifier>(Str) +#define OPENMP_LASTPRIVATE_KIND(Name) .Case(#Name, OMPC_LASTPRIVATE_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_LASTPRIVATE_unknown); + case OMPC_order: + return llvm::StringSwitch<OpenMPOrderClauseKind>(Str) +#define OPENMP_ORDER_KIND(Name) .Case(#Name, OMPC_ORDER_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_ORDER_unknown); + case OMPC_update: + return llvm::StringSwitch<OpenMPDependClauseKind>(Str) +#define OPENMP_DEPEND_KIND(Name) .Case(#Name, OMPC_DEPEND_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_DEPEND_unknown); + case OMPC_device: + return llvm::StringSwitch<OpenMPDeviceClauseModifier>(Str) +#define OPENMP_DEVICE_MODIFIER(Name) .Case(#Name, OMPC_DEVICE_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_DEVICE_unknown); + case OMPC_reduction: + return llvm::StringSwitch<OpenMPReductionClauseModifier>(Str) +#define OPENMP_REDUCTION_MODIFIER(Name) .Case(#Name, OMPC_REDUCTION_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_REDUCTION_unknown); + case OMPC_adjust_args: + return llvm::StringSwitch<OpenMPAdjustArgsOpKind>(Str) +#define OPENMP_ADJUST_ARGS_KIND(Name) .Case(#Name, OMPC_ADJUST_ARGS_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_ADJUST_ARGS_unknown); + case OMPC_bind: + return llvm::StringSwitch<unsigned>(Str) +#define OPENMP_BIND_KIND(Name) .Case(#Name, OMPC_BIND_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_BIND_unknown); + case OMPC_unknown: + case OMPC_threadprivate: + case OMPC_if: + case OMPC_final: + case OMPC_num_threads: + case OMPC_safelen: + case OMPC_simdlen: + case OMPC_sizes: + case OMPC_allocator: + case OMPC_allocate: + case OMPC_collapse: + case OMPC_private: + case OMPC_firstprivate: + case OMPC_shared: + case OMPC_task_reduction: + case OMPC_in_reduction: + case OMPC_aligned: + case OMPC_copyin: + case OMPC_copyprivate: + case OMPC_ordered: + case OMPC_nowait: + case OMPC_untied: + case OMPC_mergeable: + case OMPC_flush: + case OMPC_depobj: + case OMPC_read: + case OMPC_write: + case OMPC_capture: + case OMPC_compare: + case OMPC_seq_cst: + case OMPC_acq_rel: + case OMPC_acquire: + case OMPC_release: + case OMPC_relaxed: + case OMPC_threads: + case OMPC_simd: + case OMPC_num_teams: + case OMPC_thread_limit: + case OMPC_priority: + case OMPC_grainsize: + case OMPC_nogroup: + case OMPC_num_tasks: + case OMPC_hint: + case OMPC_uniform: + case OMPC_use_device_ptr: + case OMPC_use_device_addr: + case OMPC_is_device_ptr: + case OMPC_unified_address: + case OMPC_unified_shared_memory: + case OMPC_reverse_offload: + case OMPC_dynamic_allocators: + case OMPC_match: + case OMPC_nontemporal: + case OMPC_destroy: + case OMPC_novariants: + case OMPC_nocontext: + case OMPC_detach: + case OMPC_inclusive: + case OMPC_exclusive: + case OMPC_uses_allocators: + case OMPC_affinity: + case OMPC_when: + case OMPC_append_args: + break; + default: + break; + } + llvm_unreachable("Invalid OpenMP simple clause kind"); +} + +const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, + unsigned Type) { + switch (Kind) { + case OMPC_default: + switch (llvm::omp::DefaultKind(Type)) { +#define OMP_DEFAULT_KIND(Enum, Name) \ + case Enum: \ + return Name; +#include "llvm/Frontend/OpenMP/OMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'default' clause type"); + case OMPC_proc_bind: + switch (Type) { +#define OMP_PROC_BIND_KIND(Enum, Name, Value) \ + case Value: \ + return Name; +#include "llvm/Frontend/OpenMP/OMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'proc_bind' clause type"); + case OMPC_schedule: + switch (Type) { + case OMPC_SCHEDULE_unknown: + case OMPC_SCHEDULE_MODIFIER_last: + return "unknown"; +#define OPENMP_SCHEDULE_KIND(Name) \ + case OMPC_SCHEDULE_##Name: \ + return #Name; +#define OPENMP_SCHEDULE_MODIFIER(Name) \ + case OMPC_SCHEDULE_MODIFIER_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'schedule' clause type"); + case OMPC_depend: + switch (Type) { + case OMPC_DEPEND_unknown: + return "unknown"; +#define OPENMP_DEPEND_KIND(Name) \ + case OMPC_DEPEND_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'depend' clause type"); + case OMPC_linear: + switch (Type) { + case OMPC_LINEAR_unknown: + return "unknown"; +#define OPENMP_LINEAR_KIND(Name) \ + case OMPC_LINEAR_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'linear' clause type"); + case OMPC_map: + switch (Type) { + case OMPC_MAP_unknown: + case OMPC_MAP_MODIFIER_last: + return "unknown"; +#define OPENMP_MAP_KIND(Name) \ + case OMPC_MAP_##Name: \ + return #Name; +#define OPENMP_MAP_MODIFIER_KIND(Name) \ + case OMPC_MAP_MODIFIER_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + llvm_unreachable("Invalid OpenMP 'map' clause type"); + case OMPC_to: + case OMPC_from: + switch (Type) { + case OMPC_MOTION_MODIFIER_unknown: + return "unknown"; +#define OPENMP_MOTION_MODIFIER_KIND(Name) \ + case OMPC_MOTION_MODIFIER_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + llvm_unreachable("Invalid OpenMP 'to' or 'from' clause type"); + case OMPC_dist_schedule: + switch (Type) { + case OMPC_DIST_SCHEDULE_unknown: + return "unknown"; +#define OPENMP_DIST_SCHEDULE_KIND(Name) \ + case OMPC_DIST_SCHEDULE_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'dist_schedule' clause type"); + case OMPC_defaultmap: + switch (Type) { + case OMPC_DEFAULTMAP_unknown: + case OMPC_DEFAULTMAP_MODIFIER_last: + return "unknown"; +#define OPENMP_DEFAULTMAP_KIND(Name) \ + case OMPC_DEFAULTMAP_##Name: \ + return #Name; +#define OPENMP_DEFAULTMAP_MODIFIER(Name) \ + case OMPC_DEFAULTMAP_MODIFIER_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'schedule' clause type"); + case OMPC_atomic_default_mem_order: + switch (Type) { + case OMPC_ATOMIC_DEFAULT_MEM_ORDER_unknown: + return "unknown"; +#define OPENMP_ATOMIC_DEFAULT_MEM_ORDER_KIND(Name) \ + case OMPC_ATOMIC_DEFAULT_MEM_ORDER_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" +} + llvm_unreachable("Invalid OpenMP 'atomic_default_mem_order' clause type"); + case OMPC_device_type: + switch (Type) { + case OMPC_DEVICE_TYPE_unknown: + return "unknown"; +#define OPENMP_DEVICE_TYPE_KIND(Name) \ + case OMPC_DEVICE_TYPE_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'device_type' clause type"); + case OMPC_lastprivate: + switch (Type) { + case OMPC_LASTPRIVATE_unknown: + return "unknown"; +#define OPENMP_LASTPRIVATE_KIND(Name) \ + case OMPC_LASTPRIVATE_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'lastprivate' clause type"); + case OMPC_order: + switch (Type) { + case OMPC_ORDER_unknown: + return "unknown"; +#define OPENMP_ORDER_KIND(Name) \ + case OMPC_ORDER_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'order' clause type"); + case OMPC_update: + switch (Type) { + case OMPC_DEPEND_unknown: + return "unknown"; +#define OPENMP_DEPEND_KIND(Name) \ + case OMPC_DEPEND_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'depend' clause type"); + case OMPC_device: + switch (Type) { + case OMPC_DEVICE_unknown: + return "unknown"; +#define OPENMP_DEVICE_MODIFIER(Name) \ + case OMPC_DEVICE_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'device' clause modifier"); + case OMPC_reduction: + switch (Type) { + case OMPC_REDUCTION_unknown: + return "unknown"; +#define OPENMP_REDUCTION_MODIFIER(Name) \ + case OMPC_REDUCTION_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'reduction' clause modifier"); + case OMPC_adjust_args: + switch (Type) { + case OMPC_ADJUST_ARGS_unknown: + return "unknown"; +#define OPENMP_ADJUST_ARGS_KIND(Name) \ + case OMPC_ADJUST_ARGS_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'adjust_args' clause kind"); + case OMPC_bind: + switch (Type) { + case OMPC_BIND_unknown: + return "unknown"; +#define OPENMP_BIND_KIND(Name) \ + case OMPC_BIND_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'bind' clause type"); + case OMPC_unknown: + case OMPC_threadprivate: + case OMPC_if: + case OMPC_final: + case OMPC_num_threads: + case OMPC_safelen: + case OMPC_simdlen: + case OMPC_sizes: + case OMPC_allocator: + case OMPC_allocate: + case OMPC_collapse: + case OMPC_private: + case OMPC_firstprivate: + case OMPC_shared: + case OMPC_task_reduction: + case OMPC_in_reduction: + case OMPC_aligned: + case OMPC_copyin: + case OMPC_copyprivate: + case OMPC_ordered: + case OMPC_nowait: + case OMPC_untied: + case OMPC_mergeable: + case OMPC_flush: + case OMPC_depobj: + case OMPC_read: + case OMPC_write: + case OMPC_capture: + case OMPC_compare: + case OMPC_seq_cst: + case OMPC_acq_rel: + case OMPC_acquire: + case OMPC_release: + case OMPC_relaxed: + case OMPC_threads: + case OMPC_simd: + case OMPC_num_teams: + case OMPC_thread_limit: + case OMPC_priority: + case OMPC_grainsize: + case OMPC_nogroup: + case OMPC_num_tasks: + case OMPC_hint: + case OMPC_uniform: + case OMPC_use_device_ptr: + case OMPC_use_device_addr: + case OMPC_is_device_ptr: + case OMPC_unified_address: + case OMPC_unified_shared_memory: + case OMPC_reverse_offload: + case OMPC_dynamic_allocators: + case OMPC_match: + case OMPC_nontemporal: + case OMPC_destroy: + case OMPC_detach: + case OMPC_novariants: + case OMPC_nocontext: + case OMPC_inclusive: + case OMPC_exclusive: + case OMPC_uses_allocators: + case OMPC_affinity: + case OMPC_when: + case OMPC_append_args: + break; + default: + break; + } + llvm_unreachable("Invalid OpenMP simple clause kind"); +} + +bool clang::isOpenMPLoopDirective(OpenMPDirectiveKind DKind) { + return DKind == OMPD_simd || DKind == OMPD_for || DKind == OMPD_for_simd || + DKind == OMPD_parallel_for || DKind == OMPD_parallel_for_simd || + DKind == OMPD_taskloop || DKind == OMPD_taskloop_simd || + DKind == OMPD_master_taskloop || DKind == OMPD_master_taskloop_simd || + DKind == OMPD_parallel_master_taskloop || + DKind == OMPD_parallel_master_taskloop_simd || + DKind == OMPD_distribute || DKind == OMPD_target_parallel_for || + DKind == OMPD_distribute_parallel_for || + DKind == OMPD_distribute_parallel_for_simd || + DKind == OMPD_distribute_simd || + DKind == OMPD_target_parallel_for_simd || DKind == OMPD_target_simd || + DKind == OMPD_teams_distribute || + DKind == OMPD_teams_distribute_simd || + DKind == OMPD_teams_distribute_parallel_for_simd || + DKind == OMPD_teams_distribute_parallel_for || + DKind == OMPD_target_teams_distribute || + DKind == OMPD_target_teams_distribute_parallel_for || + DKind == OMPD_target_teams_distribute_parallel_for_simd || + DKind == OMPD_target_teams_distribute_simd || DKind == OMPD_tile || + DKind == OMPD_unroll || DKind == OMPD_loop; +} + +bool clang::isOpenMPWorksharingDirective(OpenMPDirectiveKind DKind) { + return DKind == OMPD_for || DKind == OMPD_for_simd || + DKind == OMPD_sections || DKind == OMPD_section || + DKind == OMPD_single || DKind == OMPD_parallel_for || + DKind == OMPD_parallel_for_simd || DKind == OMPD_parallel_sections || + DKind == OMPD_target_parallel_for || + DKind == OMPD_distribute_parallel_for || + DKind == OMPD_distribute_parallel_for_simd || + DKind == OMPD_target_parallel_for_simd || + DKind == OMPD_teams_distribute_parallel_for_simd || + DKind == OMPD_teams_distribute_parallel_for || + DKind == OMPD_target_teams_distribute_parallel_for || + DKind == OMPD_target_teams_distribute_parallel_for_simd; +} + +bool clang::isOpenMPTaskLoopDirective(OpenMPDirectiveKind DKind) { + return DKind == OMPD_taskloop || DKind == OMPD_taskloop_simd || + DKind == OMPD_master_taskloop || DKind == OMPD_master_taskloop_simd || + DKind == OMPD_parallel_master_taskloop || + DKind == OMPD_parallel_master_taskloop_simd; +} + +bool clang::isOpenMPParallelDirective(OpenMPDirectiveKind DKind) { + return DKind == OMPD_parallel || DKind == OMPD_parallel_for || + DKind == OMPD_parallel_for_simd || DKind == OMPD_parallel_sections || + DKind == OMPD_target_parallel || DKind == OMPD_target_parallel_for || + DKind == OMPD_distribute_parallel_for || + DKind == OMPD_distribute_parallel_for_simd || + DKind == OMPD_target_parallel_for_simd || + DKind == OMPD_teams_distribute_parallel_for || + DKind == OMPD_teams_distribute_parallel_for_simd || + DKind == OMPD_target_teams_distribute_parallel_for || + DKind == OMPD_target_teams_distribute_parallel_for_simd || + DKind == OMPD_parallel_master || + DKind == OMPD_parallel_master_taskloop || + DKind == OMPD_parallel_master_taskloop_simd; +} + +bool clang::isOpenMPTargetExecutionDirective(OpenMPDirectiveKind DKind) { + return DKind == OMPD_target || DKind == OMPD_target_parallel || + DKind == OMPD_target_parallel_for || + DKind == OMPD_target_parallel_for_simd || DKind == OMPD_target_simd || + DKind == OMPD_target_teams || DKind == OMPD_target_teams_distribute || + DKind == OMPD_target_teams_distribute_parallel_for || + DKind == OMPD_target_teams_distribute_parallel_for_simd || + DKind == OMPD_target_teams_distribute_simd; +} + +bool clang::isOpenMPTargetDataManagementDirective(OpenMPDirectiveKind DKind) { + return DKind == OMPD_target_data || DKind == OMPD_target_enter_data || + DKind == OMPD_target_exit_data || DKind == OMPD_target_update; +} + +bool clang::isOpenMPNestingTeamsDirective(OpenMPDirectiveKind DKind) { + return DKind == OMPD_teams || DKind == OMPD_teams_distribute || + DKind == OMPD_teams_distribute_simd || + DKind == OMPD_teams_distribute_parallel_for_simd || + DKind == OMPD_teams_distribute_parallel_for; +} + +bool clang::isOpenMPTeamsDirective(OpenMPDirectiveKind DKind) { + return isOpenMPNestingTeamsDirective(DKind) || + DKind == OMPD_target_teams || DKind == OMPD_target_teams_distribute || + DKind == OMPD_target_teams_distribute_parallel_for || + DKind == OMPD_target_teams_distribute_parallel_for_simd || + DKind == OMPD_target_teams_distribute_simd; +} + +bool clang::isOpenMPSimdDirective(OpenMPDirectiveKind DKind) { + return DKind == OMPD_simd || DKind == OMPD_for_simd || + DKind == OMPD_parallel_for_simd || DKind == OMPD_taskloop_simd || + DKind == OMPD_master_taskloop_simd || + DKind == OMPD_parallel_master_taskloop_simd || + DKind == OMPD_distribute_parallel_for_simd || + DKind == OMPD_distribute_simd || DKind == OMPD_target_simd || + DKind == OMPD_teams_distribute_simd || + DKind == OMPD_teams_distribute_parallel_for_simd || + DKind == OMPD_target_teams_distribute_parallel_for_simd || + DKind == OMPD_target_teams_distribute_simd || + DKind == OMPD_target_parallel_for_simd; +} + +bool clang::isOpenMPNestingDistributeDirective(OpenMPDirectiveKind Kind) { + return Kind == OMPD_distribute || Kind == OMPD_distribute_parallel_for || + Kind == OMPD_distribute_parallel_for_simd || + Kind == OMPD_distribute_simd; + // TODO add next directives. +} + +bool clang::isOpenMPDistributeDirective(OpenMPDirectiveKind Kind) { + return isOpenMPNestingDistributeDirective(Kind) || + Kind == OMPD_teams_distribute || Kind == OMPD_teams_distribute_simd || + Kind == OMPD_teams_distribute_parallel_for_simd || + Kind == OMPD_teams_distribute_parallel_for || + Kind == OMPD_target_teams_distribute || + Kind == OMPD_target_teams_distribute_parallel_for || + Kind == OMPD_target_teams_distribute_parallel_for_simd || + Kind == OMPD_target_teams_distribute_simd; +} + +bool clang::isOpenMPGenericLoopDirective(OpenMPDirectiveKind Kind) { + return Kind == OMPD_loop; +} + +bool clang::isOpenMPPrivate(OpenMPClauseKind Kind) { + return Kind == OMPC_private || Kind == OMPC_firstprivate || + Kind == OMPC_lastprivate || Kind == OMPC_linear || + Kind == OMPC_reduction || Kind == OMPC_task_reduction || + Kind == OMPC_in_reduction; // TODO add next clauses like 'reduction'. +} + +bool clang::isOpenMPThreadPrivate(OpenMPClauseKind Kind) { + return Kind == OMPC_threadprivate || Kind == OMPC_copyin; +} + +bool clang::isOpenMPTaskingDirective(OpenMPDirectiveKind Kind) { + return Kind == OMPD_task || isOpenMPTaskLoopDirective(Kind); +} + +bool clang::isOpenMPLoopBoundSharingDirective(OpenMPDirectiveKind Kind) { + return Kind == OMPD_distribute_parallel_for || + Kind == OMPD_distribute_parallel_for_simd || + Kind == OMPD_teams_distribute_parallel_for_simd || + Kind == OMPD_teams_distribute_parallel_for || + Kind == OMPD_target_teams_distribute_parallel_for || + Kind == OMPD_target_teams_distribute_parallel_for_simd; +} + +bool clang::isOpenMPLoopTransformationDirective(OpenMPDirectiveKind DKind) { + return DKind == OMPD_tile || DKind == OMPD_unroll; +} + +void clang::getOpenMPCaptureRegions( + SmallVectorImpl<OpenMPDirectiveKind> &CaptureRegions, + OpenMPDirectiveKind DKind) { + assert(unsigned(DKind) < llvm::omp::Directive_enumSize); + switch (DKind) { + case OMPD_metadirective: + CaptureRegions.push_back(OMPD_metadirective); + break; + case OMPD_parallel: + case OMPD_parallel_for: + case OMPD_parallel_for_simd: + case OMPD_parallel_master: + case OMPD_parallel_sections: + case OMPD_distribute_parallel_for: + case OMPD_distribute_parallel_for_simd: + CaptureRegions.push_back(OMPD_parallel); + break; + case OMPD_target_teams: + case OMPD_target_teams_distribute: + case OMPD_target_teams_distribute_simd: + CaptureRegions.push_back(OMPD_task); + CaptureRegions.push_back(OMPD_target); + CaptureRegions.push_back(OMPD_teams); + break; + case OMPD_teams: + case OMPD_teams_distribute: + case OMPD_teams_distribute_simd: + CaptureRegions.push_back(OMPD_teams); + break; + case OMPD_target: + case OMPD_target_simd: + CaptureRegions.push_back(OMPD_task); + CaptureRegions.push_back(OMPD_target); + break; + case OMPD_teams_distribute_parallel_for: + case OMPD_teams_distribute_parallel_for_simd: + CaptureRegions.push_back(OMPD_teams); + CaptureRegions.push_back(OMPD_parallel); + break; + case OMPD_target_parallel: + case OMPD_target_parallel_for: + case OMPD_target_parallel_for_simd: + CaptureRegions.push_back(OMPD_task); + CaptureRegions.push_back(OMPD_target); + CaptureRegions.push_back(OMPD_parallel); + break; + case OMPD_task: + case OMPD_target_enter_data: + case OMPD_target_exit_data: + case OMPD_target_update: + CaptureRegions.push_back(OMPD_task); + break; + case OMPD_taskloop: + case OMPD_taskloop_simd: + case OMPD_master_taskloop: + case OMPD_master_taskloop_simd: + CaptureRegions.push_back(OMPD_taskloop); + break; + case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: + CaptureRegions.push_back(OMPD_parallel); + CaptureRegions.push_back(OMPD_taskloop); + break; + case OMPD_target_teams_distribute_parallel_for: + case OMPD_target_teams_distribute_parallel_for_simd: + CaptureRegions.push_back(OMPD_task); + CaptureRegions.push_back(OMPD_target); + CaptureRegions.push_back(OMPD_teams); + CaptureRegions.push_back(OMPD_parallel); + break; + case OMPD_loop: + // TODO: 'loop' may require different capture regions depending on the bind + // clause or the parent directive when there is no bind clause. Use + // OMPD_unknown for now. + case OMPD_simd: + case OMPD_for: + case OMPD_for_simd: + case OMPD_sections: + case OMPD_section: + case OMPD_single: + case OMPD_master: + case OMPD_critical: + case OMPD_taskgroup: + case OMPD_distribute: + case OMPD_ordered: + case OMPD_atomic: + case OMPD_target_data: + case OMPD_distribute_simd: + case OMPD_dispatch: + CaptureRegions.push_back(OMPD_unknown); + break; + case OMPD_tile: + case OMPD_unroll: + // loop transformations do not introduce captures. + break; + case OMPD_threadprivate: + case OMPD_allocate: + case OMPD_taskyield: + case OMPD_barrier: + case OMPD_taskwait: + case OMPD_cancellation_point: + case OMPD_cancel: + case OMPD_flush: + case OMPD_depobj: + case OMPD_scan: + case OMPD_declare_reduction: + case OMPD_declare_mapper: + case OMPD_declare_simd: + case OMPD_declare_target: + case OMPD_end_declare_target: + case OMPD_requires: + case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: + llvm_unreachable("OpenMP Directive is not allowed"); + case OMPD_unknown: + default: + llvm_unreachable("Unknown OpenMP directive"); + } +} diff --git a/contrib/llvm-project/clang/lib/Basic/OperatorPrecedence.cpp b/contrib/llvm-project/clang/lib/Basic/OperatorPrecedence.cpp new file mode 100644 index 000000000000..02876f14291d --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/OperatorPrecedence.cpp @@ -0,0 +1,77 @@ +//===--- OperatorPrecedence.cpp ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Defines and computes precedence levels for binary/ternary operators. +/// +//===----------------------------------------------------------------------===// +#include "clang/Basic/OperatorPrecedence.h" + +namespace clang { + +prec::Level getBinOpPrecedence(tok::TokenKind Kind, bool GreaterThanIsOperator, + bool CPlusPlus11) { + switch (Kind) { + case tok::greater: + // C++ [temp.names]p3: + // [...] When parsing a template-argument-list, the first + // non-nested > is taken as the ending delimiter rather than a + // greater-than operator. [...] + if (GreaterThanIsOperator) + return prec::Relational; + return prec::Unknown; + + case tok::greatergreater: + // C++11 [temp.names]p3: + // + // [...] Similarly, the first non-nested >> is treated as two + // consecutive but distinct > tokens, the first of which is + // taken as the end of the template-argument-list and completes + // the template-id. [...] + if (GreaterThanIsOperator || !CPlusPlus11) + return prec::Shift; + return prec::Unknown; + + default: return prec::Unknown; + case tok::comma: return prec::Comma; + case tok::equal: + case tok::starequal: + case tok::slashequal: + case tok::percentequal: + case tok::plusequal: + case tok::minusequal: + case tok::lesslessequal: + case tok::greatergreaterequal: + case tok::ampequal: + case tok::caretequal: + case tok::pipeequal: return prec::Assignment; + case tok::question: return prec::Conditional; + case tok::pipepipe: return prec::LogicalOr; + case tok::caretcaret: + case tok::ampamp: return prec::LogicalAnd; + case tok::pipe: return prec::InclusiveOr; + case tok::caret: return prec::ExclusiveOr; + case tok::amp: return prec::And; + case tok::exclaimequal: + case tok::equalequal: return prec::Equality; + case tok::lessequal: + case tok::less: + case tok::greaterequal: return prec::Relational; + case tok::spaceship: return prec::Spaceship; + case tok::lessless: return prec::Shift; + case tok::plus: + case tok::minus: return prec::Additive; + case tok::percent: + case tok::slash: + case tok::star: return prec::Multiplicative; + case tok::periodstar: + case tok::arrowstar: return prec::PointerToMember; + } +} + +} // namespace clang diff --git a/contrib/llvm-project/clang/lib/Basic/ProfileList.cpp b/contrib/llvm-project/clang/lib/Basic/ProfileList.cpp new file mode 100644 index 000000000000..9c88559d1c33 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/ProfileList.cpp @@ -0,0 +1,114 @@ +//===--- ProfileList.h - ProfileList filter ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// User-provided filters include/exclude profile instrumentation in certain +// functions or files. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/ProfileList.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Support/SpecialCaseList.h" + +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +namespace clang { + +class ProfileSpecialCaseList : public llvm::SpecialCaseList { +public: + static std::unique_ptr<ProfileSpecialCaseList> + create(const std::vector<std::string> &Paths, llvm::vfs::FileSystem &VFS, + std::string &Error); + + static std::unique_ptr<ProfileSpecialCaseList> + createOrDie(const std::vector<std::string> &Paths, + llvm::vfs::FileSystem &VFS); + + bool isEmpty() const { return Sections.empty(); } + + bool hasPrefix(StringRef Prefix) const { + for (auto &SectionIter : Sections) + if (SectionIter.Entries.count(Prefix) > 0) + return true; + return false; + } +}; + +std::unique_ptr<ProfileSpecialCaseList> +ProfileSpecialCaseList::create(const std::vector<std::string> &Paths, + llvm::vfs::FileSystem &VFS, + std::string &Error) { + auto PSCL = std::make_unique<ProfileSpecialCaseList>(); + if (PSCL->createInternal(Paths, VFS, Error)) + return PSCL; + return nullptr; +} + +std::unique_ptr<ProfileSpecialCaseList> +ProfileSpecialCaseList::createOrDie(const std::vector<std::string> &Paths, + llvm::vfs::FileSystem &VFS) { + std::string Error; + if (auto PSCL = create(Paths, VFS, Error)) + return PSCL; + llvm::report_fatal_error(llvm::Twine(Error)); +} + +} + +ProfileList::ProfileList(ArrayRef<std::string> Paths, SourceManager &SM) + : SCL(ProfileSpecialCaseList::createOrDie( + Paths, SM.getFileManager().getVirtualFileSystem())), + Empty(SCL->isEmpty()), + Default(SCL->hasPrefix("fun") || SCL->hasPrefix("src")), SM(SM) {} + +ProfileList::~ProfileList() = default; + +static StringRef getSectionName(CodeGenOptions::ProfileInstrKind Kind) { + switch (Kind) { + case CodeGenOptions::ProfileNone: + return ""; + case CodeGenOptions::ProfileClangInstr: + return "clang"; + case CodeGenOptions::ProfileIRInstr: + return "llvm"; + case CodeGenOptions::ProfileCSIRInstr: + return "csllvm"; + } + llvm_unreachable("Unhandled CodeGenOptions::ProfileInstrKind enum"); +} + +llvm::Optional<bool> +ProfileList::isFunctionExcluded(StringRef FunctionName, + CodeGenOptions::ProfileInstrKind Kind) const { + StringRef Section = getSectionName(Kind); + if (SCL->inSection(Section, "!fun", FunctionName)) + return true; + if (SCL->inSection(Section, "fun", FunctionName)) + return false; + return None; +} + +llvm::Optional<bool> +ProfileList::isLocationExcluded(SourceLocation Loc, + CodeGenOptions::ProfileInstrKind Kind) const { + return isFileExcluded(SM.getFilename(SM.getFileLoc(Loc)), Kind); +} + +llvm::Optional<bool> +ProfileList::isFileExcluded(StringRef FileName, + CodeGenOptions::ProfileInstrKind Kind) const { + StringRef Section = getSectionName(Kind); + if (SCL->inSection(Section, "!src", FileName)) + return true; + if (SCL->inSection(Section, "src", FileName)) + return false; + return None; +} diff --git a/contrib/llvm-project/clang/lib/Basic/SanitizerSpecialCaseList.cpp b/contrib/llvm-project/clang/lib/Basic/SanitizerSpecialCaseList.cpp new file mode 100644 index 000000000000..5bf8d39ffd95 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/SanitizerSpecialCaseList.cpp @@ -0,0 +1,65 @@ +//===--- SanitizerSpecialCaseList.cpp - SCL for sanitizers ----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// An extension of SpecialCaseList to allowing querying sections by +// SanitizerMask. +// +//===----------------------------------------------------------------------===// +#include "clang/Basic/SanitizerSpecialCaseList.h" + +using namespace clang; + +std::unique_ptr<SanitizerSpecialCaseList> +SanitizerSpecialCaseList::create(const std::vector<std::string> &Paths, + llvm::vfs::FileSystem &VFS, + std::string &Error) { + std::unique_ptr<clang::SanitizerSpecialCaseList> SSCL( + new SanitizerSpecialCaseList()); + if (SSCL->createInternal(Paths, VFS, Error)) { + SSCL->createSanitizerSections(); + return SSCL; + } + return nullptr; +} + +std::unique_ptr<SanitizerSpecialCaseList> +SanitizerSpecialCaseList::createOrDie(const std::vector<std::string> &Paths, + llvm::vfs::FileSystem &VFS) { + std::string Error; + if (auto SSCL = create(Paths, VFS, Error)) + return SSCL; + llvm::report_fatal_error(Error); +} + +void SanitizerSpecialCaseList::createSanitizerSections() { + for (auto &S : Sections) { + SanitizerMask Mask; + +#define SANITIZER(NAME, ID) \ + if (S.SectionMatcher->match(NAME)) \ + Mask |= SanitizerKind::ID; +#define SANITIZER_GROUP(NAME, ID, ALIAS) SANITIZER(NAME, ID) + +#include "clang/Basic/Sanitizers.def" +#undef SANITIZER +#undef SANITIZER_GROUP + + SanitizerSections.emplace_back(Mask, S.Entries); + } +} + +bool SanitizerSpecialCaseList::inSection(SanitizerMask Mask, StringRef Prefix, + StringRef Query, + StringRef Category) const { + for (auto &S : SanitizerSections) + if ((S.Mask & Mask) && + SpecialCaseList::inSectionBlame(S.Entries, Prefix, Query, Category)) + return true; + + return false; +} diff --git a/contrib/llvm-project/clang/lib/Basic/Sanitizers.cpp b/contrib/llvm-project/clang/lib/Basic/Sanitizers.cpp new file mode 100644 index 000000000000..7d903c8fdf5e --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Sanitizers.cpp @@ -0,0 +1,115 @@ +//===- Sanitizers.cpp - C Language Family Language Options ----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the classes from Sanitizers.h +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Sanitizers.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/MathExtras.h" + +using namespace clang; + +// Once LLVM switches to C++17, the constexpr variables can be inline and we +// won't need this. +#define SANITIZER(NAME, ID) constexpr SanitizerMask SanitizerKind::ID; +#define SANITIZER_GROUP(NAME, ID, ALIAS) \ + constexpr SanitizerMask SanitizerKind::ID; \ + constexpr SanitizerMask SanitizerKind::ID##Group; +#include "clang/Basic/Sanitizers.def" + +SanitizerMask clang::parseSanitizerValue(StringRef Value, bool AllowGroups) { + SanitizerMask ParsedKind = llvm::StringSwitch<SanitizerMask>(Value) +#define SANITIZER(NAME, ID) .Case(NAME, SanitizerKind::ID) +#define SANITIZER_GROUP(NAME, ID, ALIAS) \ + .Case(NAME, AllowGroups ? SanitizerKind::ID##Group : SanitizerMask()) +#include "clang/Basic/Sanitizers.def" + .Default(SanitizerMask()); + return ParsedKind; +} + +void clang::serializeSanitizerSet(SanitizerSet Set, + SmallVectorImpl<StringRef> &Values) { +#define SANITIZER(NAME, ID) \ + if (Set.has(SanitizerKind::ID)) \ + Values.push_back(NAME); +#include "clang/Basic/Sanitizers.def" +} + +SanitizerMask clang::expandSanitizerGroups(SanitizerMask Kinds) { +#define SANITIZER(NAME, ID) +#define SANITIZER_GROUP(NAME, ID, ALIAS) \ + if (Kinds & SanitizerKind::ID##Group) \ + Kinds |= SanitizerKind::ID; +#include "clang/Basic/Sanitizers.def" + return Kinds; +} + +llvm::hash_code SanitizerMask::hash_value() const { + return llvm::hash_combine_range(&maskLoToHigh[0], &maskLoToHigh[kNumElem]); +} + +namespace clang { +unsigned SanitizerMask::countPopulation() const { + unsigned total = 0; + for (const auto &Val : maskLoToHigh) + total += llvm::countPopulation(Val); + return total; +} + +llvm::hash_code hash_value(const clang::SanitizerMask &Arg) { + return Arg.hash_value(); +} + +StringRef AsanDtorKindToString(llvm::AsanDtorKind kind) { + switch (kind) { + case llvm::AsanDtorKind::None: + return "none"; + case llvm::AsanDtorKind::Global: + return "global"; + case llvm::AsanDtorKind::Invalid: + return "invalid"; + } + return "invalid"; +} + +llvm::AsanDtorKind AsanDtorKindFromString(StringRef kindStr) { + return llvm::StringSwitch<llvm::AsanDtorKind>(kindStr) + .Case("none", llvm::AsanDtorKind::None) + .Case("global", llvm::AsanDtorKind::Global) + .Default(llvm::AsanDtorKind::Invalid); +} + +StringRef AsanDetectStackUseAfterReturnModeToString( + llvm::AsanDetectStackUseAfterReturnMode mode) { + switch (mode) { + case llvm::AsanDetectStackUseAfterReturnMode::Always: + return "always"; + case llvm::AsanDetectStackUseAfterReturnMode::Runtime: + return "runtime"; + case llvm::AsanDetectStackUseAfterReturnMode::Never: + return "never"; + case llvm::AsanDetectStackUseAfterReturnMode::Invalid: + return "invalid"; + } + return "invalid"; +} + +llvm::AsanDetectStackUseAfterReturnMode +AsanDetectStackUseAfterReturnModeFromString(StringRef modeStr) { + return llvm::StringSwitch<llvm::AsanDetectStackUseAfterReturnMode>(modeStr) + .Case("always", llvm::AsanDetectStackUseAfterReturnMode::Always) + .Case("runtime", llvm::AsanDetectStackUseAfterReturnMode::Runtime) + .Case("never", llvm::AsanDetectStackUseAfterReturnMode::Never) + .Default(llvm::AsanDetectStackUseAfterReturnMode::Invalid); +} + +} // namespace clang diff --git a/contrib/llvm-project/clang/lib/Basic/SourceLocation.cpp b/contrib/llvm-project/clang/lib/Basic/SourceLocation.cpp new file mode 100644 index 000000000000..6e5e55fb09ce --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/SourceLocation.cpp @@ -0,0 +1,272 @@ +//===- SourceLocation.cpp - Compact identifier for Source Files -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines accessor methods for the FullSourceLoc class. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/PrettyStackTrace.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <string> +#include <utility> + +using namespace clang; + +//===----------------------------------------------------------------------===// +// PrettyStackTraceLoc +//===----------------------------------------------------------------------===// + +void PrettyStackTraceLoc::print(raw_ostream &OS) const { + if (Loc.isValid()) { + Loc.print(OS, SM); + OS << ": "; + } + OS << Message << '\n'; +} + +//===----------------------------------------------------------------------===// +// SourceLocation +//===----------------------------------------------------------------------===// + +static_assert(std::is_trivially_destructible<SourceLocation>::value, + "SourceLocation must be trivially destructible because it is " + "used in unions"); + +static_assert(std::is_trivially_destructible<SourceRange>::value, + "SourceRange must be trivially destructible because it is " + "used in unions"); + +unsigned SourceLocation::getHashValue() const { + return llvm::DenseMapInfo<UIntTy>::getHashValue(ID); +} + +void llvm::FoldingSetTrait<SourceLocation>::Profile( + const SourceLocation &X, llvm::FoldingSetNodeID &ID) { + ID.AddInteger(X.ID); +} + +void SourceLocation::print(raw_ostream &OS, const SourceManager &SM)const{ + if (!isValid()) { + OS << "<invalid loc>"; + return; + } + + if (isFileID()) { + PresumedLoc PLoc = SM.getPresumedLoc(*this); + + if (PLoc.isInvalid()) { + OS << "<invalid>"; + return; + } + // The macro expansion and spelling pos is identical for file locs. + OS << PLoc.getFilename() << ':' << PLoc.getLine() + << ':' << PLoc.getColumn(); + return; + } + + SM.getExpansionLoc(*this).print(OS, SM); + + OS << " <Spelling="; + SM.getSpellingLoc(*this).print(OS, SM); + OS << '>'; +} + +LLVM_DUMP_METHOD std::string +SourceLocation::printToString(const SourceManager &SM) const { + std::string S; + llvm::raw_string_ostream OS(S); + print(OS, SM); + return S; +} + +LLVM_DUMP_METHOD void SourceLocation::dump(const SourceManager &SM) const { + print(llvm::errs(), SM); + llvm::errs() << '\n'; +} + +LLVM_DUMP_METHOD void SourceRange::dump(const SourceManager &SM) const { + print(llvm::errs(), SM); + llvm::errs() << '\n'; +} + +static PresumedLoc PrintDifference(raw_ostream &OS, const SourceManager &SM, + SourceLocation Loc, PresumedLoc Previous) { + if (Loc.isFileID()) { + + PresumedLoc PLoc = SM.getPresumedLoc(Loc); + + if (PLoc.isInvalid()) { + OS << "<invalid sloc>"; + return Previous; + } + + if (Previous.isInvalid() || + strcmp(PLoc.getFilename(), Previous.getFilename()) != 0) { + OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':' + << PLoc.getColumn(); + } else if (Previous.isInvalid() || PLoc.getLine() != Previous.getLine()) { + OS << "line" << ':' << PLoc.getLine() << ':' << PLoc.getColumn(); + } else { + OS << "col" << ':' << PLoc.getColumn(); + } + return PLoc; + } + auto PrintedLoc = PrintDifference(OS, SM, SM.getExpansionLoc(Loc), Previous); + + OS << " <Spelling="; + PrintedLoc = PrintDifference(OS, SM, SM.getSpellingLoc(Loc), PrintedLoc); + OS << '>'; + return PrintedLoc; +} + +void SourceRange::print(raw_ostream &OS, const SourceManager &SM) const { + + OS << '<'; + auto PrintedLoc = PrintDifference(OS, SM, B, {}); + if (B != E) { + OS << ", "; + PrintDifference(OS, SM, E, PrintedLoc); + } + OS << '>'; +} + +LLVM_DUMP_METHOD std::string +SourceRange::printToString(const SourceManager &SM) const { + std::string S; + llvm::raw_string_ostream OS(S); + print(OS, SM); + return S; +} + +//===----------------------------------------------------------------------===// +// FullSourceLoc +//===----------------------------------------------------------------------===// + +FileID FullSourceLoc::getFileID() const { + assert(isValid()); + return SrcMgr->getFileID(*this); +} + +FullSourceLoc FullSourceLoc::getExpansionLoc() const { + assert(isValid()); + return FullSourceLoc(SrcMgr->getExpansionLoc(*this), *SrcMgr); +} + +FullSourceLoc FullSourceLoc::getSpellingLoc() const { + assert(isValid()); + return FullSourceLoc(SrcMgr->getSpellingLoc(*this), *SrcMgr); +} + +FullSourceLoc FullSourceLoc::getFileLoc() const { + assert(isValid()); + return FullSourceLoc(SrcMgr->getFileLoc(*this), *SrcMgr); +} + +PresumedLoc FullSourceLoc::getPresumedLoc(bool UseLineDirectives) const { + if (!isValid()) + return PresumedLoc(); + + return SrcMgr->getPresumedLoc(*this, UseLineDirectives); +} + +bool FullSourceLoc::isMacroArgExpansion(FullSourceLoc *StartLoc) const { + assert(isValid()); + return SrcMgr->isMacroArgExpansion(*this, StartLoc); +} + +FullSourceLoc FullSourceLoc::getImmediateMacroCallerLoc() const { + assert(isValid()); + return FullSourceLoc(SrcMgr->getImmediateMacroCallerLoc(*this), *SrcMgr); +} + +std::pair<FullSourceLoc, StringRef> FullSourceLoc::getModuleImportLoc() const { + if (!isValid()) + return std::make_pair(FullSourceLoc(), StringRef()); + + std::pair<SourceLocation, StringRef> ImportLoc = + SrcMgr->getModuleImportLoc(*this); + return std::make_pair(FullSourceLoc(ImportLoc.first, *SrcMgr), + ImportLoc.second); +} + +unsigned FullSourceLoc::getFileOffset() const { + assert(isValid()); + return SrcMgr->getFileOffset(*this); +} + +unsigned FullSourceLoc::getLineNumber(bool *Invalid) const { + assert(isValid()); + return SrcMgr->getLineNumber(getFileID(), getFileOffset(), Invalid); +} + +unsigned FullSourceLoc::getColumnNumber(bool *Invalid) const { + assert(isValid()); + return SrcMgr->getColumnNumber(getFileID(), getFileOffset(), Invalid); +} + +const FileEntry *FullSourceLoc::getFileEntry() const { + assert(isValid()); + return SrcMgr->getFileEntryForID(getFileID()); +} + +unsigned FullSourceLoc::getExpansionLineNumber(bool *Invalid) const { + assert(isValid()); + return SrcMgr->getExpansionLineNumber(*this, Invalid); +} + +unsigned FullSourceLoc::getExpansionColumnNumber(bool *Invalid) const { + assert(isValid()); + return SrcMgr->getExpansionColumnNumber(*this, Invalid); +} + +unsigned FullSourceLoc::getSpellingLineNumber(bool *Invalid) const { + assert(isValid()); + return SrcMgr->getSpellingLineNumber(*this, Invalid); +} + +unsigned FullSourceLoc::getSpellingColumnNumber(bool *Invalid) const { + assert(isValid()); + return SrcMgr->getSpellingColumnNumber(*this, Invalid); +} + +bool FullSourceLoc::isInSystemHeader() const { + assert(isValid()); + return SrcMgr->isInSystemHeader(*this); +} + +bool FullSourceLoc::isBeforeInTranslationUnitThan(SourceLocation Loc) const { + assert(isValid()); + return SrcMgr->isBeforeInTranslationUnit(*this, Loc); +} + +LLVM_DUMP_METHOD void FullSourceLoc::dump() const { + SourceLocation::dump(*SrcMgr); +} + +const char *FullSourceLoc::getCharacterData(bool *Invalid) const { + assert(isValid()); + return SrcMgr->getCharacterData(*this, Invalid); +} + +StringRef FullSourceLoc::getBufferData(bool *Invalid) const { + assert(isValid()); + return SrcMgr->getBufferData(SrcMgr->getFileID(*this), Invalid); +} + +std::pair<FileID, unsigned> FullSourceLoc::getDecomposedLoc() const { + return SrcMgr->getDecomposedLoc(*this); +} diff --git a/contrib/llvm-project/clang/lib/Basic/SourceManager.cpp b/contrib/llvm-project/clang/lib/Basic/SourceManager.cpp new file mode 100644 index 000000000000..ec3e35595bb7 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/SourceManager.cpp @@ -0,0 +1,2267 @@ +//===- SourceManager.cpp - Track and cache source files -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the SourceManager interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManagerInternals.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Capacity.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <memory> +#include <tuple> +#include <utility> +#include <vector> + +using namespace clang; +using namespace SrcMgr; +using llvm::MemoryBuffer; + +//===----------------------------------------------------------------------===// +// SourceManager Helper Classes +//===----------------------------------------------------------------------===// + +/// getSizeBytesMapped - Returns the number of bytes actually mapped for this +/// ContentCache. This can be 0 if the MemBuffer was not actually expanded. +unsigned ContentCache::getSizeBytesMapped() const { + return Buffer ? Buffer->getBufferSize() : 0; +} + +/// Returns the kind of memory used to back the memory buffer for +/// this content cache. This is used for performance analysis. +llvm::MemoryBuffer::BufferKind ContentCache::getMemoryBufferKind() const { + if (Buffer == nullptr) { + assert(0 && "Buffer should never be null"); + return llvm::MemoryBuffer::MemoryBuffer_Malloc; + } + return Buffer->getBufferKind(); +} + +/// getSize - Returns the size of the content encapsulated by this ContentCache. +/// This can be the size of the source file or the size of an arbitrary +/// scratch buffer. If the ContentCache encapsulates a source file, that +/// file is not lazily brought in from disk to satisfy this query. +unsigned ContentCache::getSize() const { + return Buffer ? (unsigned)Buffer->getBufferSize() + : (unsigned)ContentsEntry->getSize(); +} + +const char *ContentCache::getInvalidBOM(StringRef BufStr) { + // If the buffer is valid, check to see if it has a UTF Byte Order Mark + // (BOM). We only support UTF-8 with and without a BOM right now. See + // http://en.wikipedia.org/wiki/Byte_order_mark for more information. + const char *InvalidBOM = + llvm::StringSwitch<const char *>(BufStr) + .StartsWith(llvm::StringLiteral::withInnerNUL("\x00\x00\xFE\xFF"), + "UTF-32 (BE)") + .StartsWith(llvm::StringLiteral::withInnerNUL("\xFF\xFE\x00\x00"), + "UTF-32 (LE)") + .StartsWith("\xFE\xFF", "UTF-16 (BE)") + .StartsWith("\xFF\xFE", "UTF-16 (LE)") + .StartsWith("\x2B\x2F\x76", "UTF-7") + .StartsWith("\xF7\x64\x4C", "UTF-1") + .StartsWith("\xDD\x73\x66\x73", "UTF-EBCDIC") + .StartsWith("\x0E\xFE\xFF", "SCSU") + .StartsWith("\xFB\xEE\x28", "BOCU-1") + .StartsWith("\x84\x31\x95\x33", "GB-18030") + .Default(nullptr); + + return InvalidBOM; +} + +llvm::Optional<llvm::MemoryBufferRef> +ContentCache::getBufferOrNone(DiagnosticsEngine &Diag, FileManager &FM, + SourceLocation Loc) const { + // Lazily create the Buffer for ContentCaches that wrap files. If we already + // computed it, just return what we have. + if (IsBufferInvalid) + return None; + if (Buffer) + return Buffer->getMemBufferRef(); + if (!ContentsEntry) + return None; + + // Start with the assumption that the buffer is invalid to simplify early + // return paths. + IsBufferInvalid = true; + + auto BufferOrError = FM.getBufferForFile(ContentsEntry, IsFileVolatile); + + // If we were unable to open the file, then we are in an inconsistent + // situation where the content cache referenced a file which no longer + // exists. Most likely, we were using a stat cache with an invalid entry but + // the file could also have been removed during processing. Since we can't + // really deal with this situation, just create an empty buffer. + if (!BufferOrError) { + if (Diag.isDiagnosticInFlight()) + Diag.SetDelayedDiagnostic(diag::err_cannot_open_file, + ContentsEntry->getName(), + BufferOrError.getError().message()); + else + Diag.Report(Loc, diag::err_cannot_open_file) + << ContentsEntry->getName() << BufferOrError.getError().message(); + + return None; + } + + Buffer = std::move(*BufferOrError); + + // Check that the file's size fits in an 'unsigned' (with room for a + // past-the-end value). This is deeply regrettable, but various parts of + // Clang (including elsewhere in this file!) use 'unsigned' to represent file + // offsets, line numbers, string literal lengths, and so on, and fail + // miserably on large source files. + // + // Note: ContentsEntry could be a named pipe, in which case + // ContentsEntry::getSize() could have the wrong size. Use + // MemoryBuffer::getBufferSize() instead. + if (Buffer->getBufferSize() >= std::numeric_limits<unsigned>::max()) { + if (Diag.isDiagnosticInFlight()) + Diag.SetDelayedDiagnostic(diag::err_file_too_large, + ContentsEntry->getName()); + else + Diag.Report(Loc, diag::err_file_too_large) + << ContentsEntry->getName(); + + return None; + } + + // Unless this is a named pipe (in which case we can handle a mismatch), + // check that the file's size is the same as in the file entry (which may + // have come from a stat cache). + if (!ContentsEntry->isNamedPipe() && + Buffer->getBufferSize() != (size_t)ContentsEntry->getSize()) { + if (Diag.isDiagnosticInFlight()) + Diag.SetDelayedDiagnostic(diag::err_file_modified, + ContentsEntry->getName()); + else + Diag.Report(Loc, diag::err_file_modified) + << ContentsEntry->getName(); + + return None; + } + + // If the buffer is valid, check to see if it has a UTF Byte Order Mark + // (BOM). We only support UTF-8 with and without a BOM right now. See + // http://en.wikipedia.org/wiki/Byte_order_mark for more information. + StringRef BufStr = Buffer->getBuffer(); + const char *InvalidBOM = getInvalidBOM(BufStr); + + if (InvalidBOM) { + Diag.Report(Loc, diag::err_unsupported_bom) + << InvalidBOM << ContentsEntry->getName(); + return None; + } + + // Buffer has been validated. + IsBufferInvalid = false; + return Buffer->getMemBufferRef(); +} + +unsigned LineTableInfo::getLineTableFilenameID(StringRef Name) { + auto IterBool = FilenameIDs.try_emplace(Name, FilenamesByID.size()); + if (IterBool.second) + FilenamesByID.push_back(&*IterBool.first); + return IterBool.first->second; +} + +/// Add a line note to the line table that indicates that there is a \#line or +/// GNU line marker at the specified FID/Offset location which changes the +/// presumed location to LineNo/FilenameID. If EntryExit is 0, then this doesn't +/// change the presumed \#include stack. If it is 1, this is a file entry, if +/// it is 2 then this is a file exit. FileKind specifies whether this is a +/// system header or extern C system header. +void LineTableInfo::AddLineNote(FileID FID, unsigned Offset, unsigned LineNo, + int FilenameID, unsigned EntryExit, + SrcMgr::CharacteristicKind FileKind) { + std::vector<LineEntry> &Entries = LineEntries[FID]; + + assert((Entries.empty() || Entries.back().FileOffset < Offset) && + "Adding line entries out of order!"); + + unsigned IncludeOffset = 0; + if (EntryExit == 1) { + // Push #include + IncludeOffset = Offset-1; + } else { + const auto *PrevEntry = Entries.empty() ? nullptr : &Entries.back(); + if (EntryExit == 2) { + // Pop #include + assert(PrevEntry && PrevEntry->IncludeOffset && + "PPDirectives should have caught case when popping empty include " + "stack"); + PrevEntry = FindNearestLineEntry(FID, PrevEntry->IncludeOffset); + } + if (PrevEntry) { + IncludeOffset = PrevEntry->IncludeOffset; + if (FilenameID == -1) { + // An unspecified FilenameID means use the previous (or containing) + // filename if available, or the main source file otherwise. + FilenameID = PrevEntry->FilenameID; + } + } + } + + Entries.push_back(LineEntry::get(Offset, LineNo, FilenameID, FileKind, + IncludeOffset)); +} + +/// FindNearestLineEntry - Find the line entry nearest to FID that is before +/// it. If there is no line entry before Offset in FID, return null. +const LineEntry *LineTableInfo::FindNearestLineEntry(FileID FID, + unsigned Offset) { + const std::vector<LineEntry> &Entries = LineEntries[FID]; + assert(!Entries.empty() && "No #line entries for this FID after all!"); + + // It is very common for the query to be after the last #line, check this + // first. + if (Entries.back().FileOffset <= Offset) + return &Entries.back(); + + // Do a binary search to find the maximal element that is still before Offset. + std::vector<LineEntry>::const_iterator I = llvm::upper_bound(Entries, Offset); + if (I == Entries.begin()) + return nullptr; + return &*--I; +} + +/// Add a new line entry that has already been encoded into +/// the internal representation of the line table. +void LineTableInfo::AddEntry(FileID FID, + const std::vector<LineEntry> &Entries) { + LineEntries[FID] = Entries; +} + +/// getLineTableFilenameID - Return the uniqued ID for the specified filename. +unsigned SourceManager::getLineTableFilenameID(StringRef Name) { + return getLineTable().getLineTableFilenameID(Name); +} + +/// AddLineNote - Add a line note to the line table for the FileID and offset +/// specified by Loc. If FilenameID is -1, it is considered to be +/// unspecified. +void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo, + int FilenameID, bool IsFileEntry, + bool IsFileExit, + SrcMgr::CharacteristicKind FileKind) { + std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc); + + bool Invalid = false; + const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid); + if (!Entry.isFile() || Invalid) + return; + + const SrcMgr::FileInfo &FileInfo = Entry.getFile(); + + // Remember that this file has #line directives now if it doesn't already. + const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives(); + + (void) getLineTable(); + + unsigned EntryExit = 0; + if (IsFileEntry) + EntryExit = 1; + else if (IsFileExit) + EntryExit = 2; + + LineTable->AddLineNote(LocInfo.first, LocInfo.second, LineNo, FilenameID, + EntryExit, FileKind); +} + +LineTableInfo &SourceManager::getLineTable() { + if (!LineTable) + LineTable.reset(new LineTableInfo()); + return *LineTable; +} + +//===----------------------------------------------------------------------===// +// Private 'Create' methods. +//===----------------------------------------------------------------------===// + +SourceManager::SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr, + bool UserFilesAreVolatile) + : Diag(Diag), FileMgr(FileMgr), UserFilesAreVolatile(UserFilesAreVolatile) { + clearIDTables(); + Diag.setSourceManager(this); +} + +SourceManager::~SourceManager() { + // Delete FileEntry objects corresponding to content caches. Since the actual + // content cache objects are bump pointer allocated, we just have to run the + // dtors, but we call the deallocate method for completeness. + for (unsigned i = 0, e = MemBufferInfos.size(); i != e; ++i) { + if (MemBufferInfos[i]) { + MemBufferInfos[i]->~ContentCache(); + ContentCacheAlloc.Deallocate(MemBufferInfos[i]); + } + } + for (llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*>::iterator + I = FileInfos.begin(), E = FileInfos.end(); I != E; ++I) { + if (I->second) { + I->second->~ContentCache(); + ContentCacheAlloc.Deallocate(I->second); + } + } +} + +void SourceManager::clearIDTables() { + MainFileID = FileID(); + LocalSLocEntryTable.clear(); + LoadedSLocEntryTable.clear(); + SLocEntryLoaded.clear(); + LastLineNoFileIDQuery = FileID(); + LastLineNoContentCache = nullptr; + LastFileIDLookup = FileID(); + + if (LineTable) + LineTable->clear(); + + // Use up FileID #0 as an invalid expansion. + NextLocalOffset = 0; + CurrentLoadedOffset = MaxLoadedOffset; + createExpansionLoc(SourceLocation(), SourceLocation(), SourceLocation(), 1); +} + +bool SourceManager::isMainFile(const FileEntry &SourceFile) { + assert(MainFileID.isValid() && "expected initialized SourceManager"); + if (auto *FE = getFileEntryForID(MainFileID)) + return FE->getUID() == SourceFile.getUID(); + return false; +} + +void SourceManager::initializeForReplay(const SourceManager &Old) { + assert(MainFileID.isInvalid() && "expected uninitialized SourceManager"); + + auto CloneContentCache = [&](const ContentCache *Cache) -> ContentCache * { + auto *Clone = new (ContentCacheAlloc.Allocate<ContentCache>()) ContentCache; + Clone->OrigEntry = Cache->OrigEntry; + Clone->ContentsEntry = Cache->ContentsEntry; + Clone->BufferOverridden = Cache->BufferOverridden; + Clone->IsFileVolatile = Cache->IsFileVolatile; + Clone->IsTransient = Cache->IsTransient; + Clone->setUnownedBuffer(Cache->getBufferIfLoaded()); + return Clone; + }; + + // Ensure all SLocEntries are loaded from the external source. + for (unsigned I = 0, N = Old.LoadedSLocEntryTable.size(); I != N; ++I) + if (!Old.SLocEntryLoaded[I]) + Old.loadSLocEntry(I, nullptr); + + // Inherit any content cache data from the old source manager. + for (auto &FileInfo : Old.FileInfos) { + SrcMgr::ContentCache *&Slot = FileInfos[FileInfo.first]; + if (Slot) + continue; + Slot = CloneContentCache(FileInfo.second); + } +} + +ContentCache &SourceManager::getOrCreateContentCache(FileEntryRef FileEnt, + bool isSystemFile) { + // Do we already have information about this file? + ContentCache *&Entry = FileInfos[FileEnt]; + if (Entry) + return *Entry; + + // Nope, create a new Cache entry. + Entry = ContentCacheAlloc.Allocate<ContentCache>(); + + if (OverriddenFilesInfo) { + // If the file contents are overridden with contents from another file, + // pass that file to ContentCache. + llvm::DenseMap<const FileEntry *, const FileEntry *>::iterator + overI = OverriddenFilesInfo->OverriddenFiles.find(FileEnt); + if (overI == OverriddenFilesInfo->OverriddenFiles.end()) + new (Entry) ContentCache(FileEnt); + else + new (Entry) ContentCache(OverridenFilesKeepOriginalName ? FileEnt + : overI->second, + overI->second); + } else { + new (Entry) ContentCache(FileEnt); + } + + Entry->IsFileVolatile = UserFilesAreVolatile && !isSystemFile; + Entry->IsTransient = FilesAreTransient; + Entry->BufferOverridden |= FileEnt.isNamedPipe(); + + return *Entry; +} + +/// Create a new ContentCache for the specified memory buffer. +/// This does no caching. +ContentCache &SourceManager::createMemBufferContentCache( + std::unique_ptr<llvm::MemoryBuffer> Buffer) { + // Add a new ContentCache to the MemBufferInfos list and return it. + ContentCache *Entry = ContentCacheAlloc.Allocate<ContentCache>(); + new (Entry) ContentCache(); + MemBufferInfos.push_back(Entry); + Entry->setBuffer(std::move(Buffer)); + return *Entry; +} + +const SrcMgr::SLocEntry &SourceManager::loadSLocEntry(unsigned Index, + bool *Invalid) const { + assert(!SLocEntryLoaded[Index]); + if (ExternalSLocEntries->ReadSLocEntry(-(static_cast<int>(Index) + 2))) { + if (Invalid) + *Invalid = true; + // If the file of the SLocEntry changed we could still have loaded it. + if (!SLocEntryLoaded[Index]) { + // Try to recover; create a SLocEntry so the rest of clang can handle it. + if (!FakeSLocEntryForRecovery) + FakeSLocEntryForRecovery = std::make_unique<SLocEntry>(SLocEntry::get( + 0, FileInfo::get(SourceLocation(), getFakeContentCacheForRecovery(), + SrcMgr::C_User, ""))); + return *FakeSLocEntryForRecovery; + } + } + + return LoadedSLocEntryTable[Index]; +} + +std::pair<int, SourceLocation::UIntTy> +SourceManager::AllocateLoadedSLocEntries(unsigned NumSLocEntries, + SourceLocation::UIntTy TotalSize) { + assert(ExternalSLocEntries && "Don't have an external sloc source"); + // Make sure we're not about to run out of source locations. + if (CurrentLoadedOffset - TotalSize < NextLocalOffset) + return std::make_pair(0, 0); + LoadedSLocEntryTable.resize(LoadedSLocEntryTable.size() + NumSLocEntries); + SLocEntryLoaded.resize(LoadedSLocEntryTable.size()); + CurrentLoadedOffset -= TotalSize; + int ID = LoadedSLocEntryTable.size(); + return std::make_pair(-ID - 1, CurrentLoadedOffset); +} + +/// As part of recovering from missing or changed content, produce a +/// fake, non-empty buffer. +llvm::MemoryBufferRef SourceManager::getFakeBufferForRecovery() const { + if (!FakeBufferForRecovery) + FakeBufferForRecovery = + llvm::MemoryBuffer::getMemBuffer("<<<INVALID BUFFER>>"); + + return *FakeBufferForRecovery; +} + +/// As part of recovering from missing or changed content, produce a +/// fake content cache. +SrcMgr::ContentCache &SourceManager::getFakeContentCacheForRecovery() const { + if (!FakeContentCacheForRecovery) { + FakeContentCacheForRecovery = std::make_unique<SrcMgr::ContentCache>(); + FakeContentCacheForRecovery->setUnownedBuffer(getFakeBufferForRecovery()); + } + return *FakeContentCacheForRecovery; +} + +/// Returns the previous in-order FileID or an invalid FileID if there +/// is no previous one. +FileID SourceManager::getPreviousFileID(FileID FID) const { + if (FID.isInvalid()) + return FileID(); + + int ID = FID.ID; + if (ID == -1) + return FileID(); + + if (ID > 0) { + if (ID-1 == 0) + return FileID(); + } else if (unsigned(-(ID-1) - 2) >= LoadedSLocEntryTable.size()) { + return FileID(); + } + + return FileID::get(ID-1); +} + +/// Returns the next in-order FileID or an invalid FileID if there is +/// no next one. +FileID SourceManager::getNextFileID(FileID FID) const { + if (FID.isInvalid()) + return FileID(); + + int ID = FID.ID; + if (ID > 0) { + if (unsigned(ID+1) >= local_sloc_entry_size()) + return FileID(); + } else if (ID+1 >= -1) { + return FileID(); + } + + return FileID::get(ID+1); +} + +//===----------------------------------------------------------------------===// +// Methods to create new FileID's and macro expansions. +//===----------------------------------------------------------------------===// + +/// Create a new FileID that represents the specified file +/// being \#included from the specified IncludePosition. +/// +/// This translates NULL into standard input. +FileID SourceManager::createFileID(const FileEntry *SourceFile, + SourceLocation IncludePos, + SrcMgr::CharacteristicKind FileCharacter, + int LoadedID, + SourceLocation::UIntTy LoadedOffset) { + return createFileID(SourceFile->getLastRef(), IncludePos, FileCharacter, + LoadedID, LoadedOffset); +} + +FileID SourceManager::createFileID(FileEntryRef SourceFile, + SourceLocation IncludePos, + SrcMgr::CharacteristicKind FileCharacter, + int LoadedID, + SourceLocation::UIntTy LoadedOffset) { + SrcMgr::ContentCache &IR = getOrCreateContentCache(SourceFile, + isSystem(FileCharacter)); + + // If this is a named pipe, immediately load the buffer to ensure subsequent + // calls to ContentCache::getSize() are accurate. + if (IR.ContentsEntry->isNamedPipe()) + (void)IR.getBufferOrNone(Diag, getFileManager(), SourceLocation()); + + return createFileIDImpl(IR, SourceFile.getName(), IncludePos, FileCharacter, + LoadedID, LoadedOffset); +} + +/// Create a new FileID that represents the specified memory buffer. +/// +/// This does no caching of the buffer and takes ownership of the +/// MemoryBuffer, so only pass a MemoryBuffer to this once. +FileID SourceManager::createFileID(std::unique_ptr<llvm::MemoryBuffer> Buffer, + SrcMgr::CharacteristicKind FileCharacter, + int LoadedID, + SourceLocation::UIntTy LoadedOffset, + SourceLocation IncludeLoc) { + StringRef Name = Buffer->getBufferIdentifier(); + return createFileIDImpl(createMemBufferContentCache(std::move(Buffer)), Name, + IncludeLoc, FileCharacter, LoadedID, LoadedOffset); +} + +/// Create a new FileID that represents the specified memory buffer. +/// +/// This does not take ownership of the MemoryBuffer. The memory buffer must +/// outlive the SourceManager. +FileID SourceManager::createFileID(const llvm::MemoryBufferRef &Buffer, + SrcMgr::CharacteristicKind FileCharacter, + int LoadedID, + SourceLocation::UIntTy LoadedOffset, + SourceLocation IncludeLoc) { + return createFileID(llvm::MemoryBuffer::getMemBuffer(Buffer), FileCharacter, + LoadedID, LoadedOffset, IncludeLoc); +} + +/// Get the FileID for \p SourceFile if it exists. Otherwise, create a +/// new FileID for the \p SourceFile. +FileID +SourceManager::getOrCreateFileID(const FileEntry *SourceFile, + SrcMgr::CharacteristicKind FileCharacter) { + FileID ID = translateFile(SourceFile); + return ID.isValid() ? ID : createFileID(SourceFile, SourceLocation(), + FileCharacter); +} + +/// createFileID - Create a new FileID for the specified ContentCache and +/// include position. This works regardless of whether the ContentCache +/// corresponds to a file or some other input source. +FileID SourceManager::createFileIDImpl(ContentCache &File, StringRef Filename, + SourceLocation IncludePos, + SrcMgr::CharacteristicKind FileCharacter, + int LoadedID, + SourceLocation::UIntTy LoadedOffset) { + if (LoadedID < 0) { + assert(LoadedID != -1 && "Loading sentinel FileID"); + unsigned Index = unsigned(-LoadedID) - 2; + assert(Index < LoadedSLocEntryTable.size() && "FileID out of range"); + assert(!SLocEntryLoaded[Index] && "FileID already loaded"); + LoadedSLocEntryTable[Index] = SLocEntry::get( + LoadedOffset, FileInfo::get(IncludePos, File, FileCharacter, Filename)); + SLocEntryLoaded[Index] = true; + return FileID::get(LoadedID); + } + unsigned FileSize = File.getSize(); + if (!(NextLocalOffset + FileSize + 1 > NextLocalOffset && + NextLocalOffset + FileSize + 1 <= CurrentLoadedOffset)) { + Diag.Report(IncludePos, diag::err_include_too_large); + return FileID(); + } + LocalSLocEntryTable.push_back( + SLocEntry::get(NextLocalOffset, + FileInfo::get(IncludePos, File, FileCharacter, Filename))); + // We do a +1 here because we want a SourceLocation that means "the end of the + // file", e.g. for the "no newline at the end of the file" diagnostic. + NextLocalOffset += FileSize + 1; + + // Set LastFileIDLookup to the newly created file. The next getFileID call is + // almost guaranteed to be from that file. + FileID FID = FileID::get(LocalSLocEntryTable.size()-1); + return LastFileIDLookup = FID; +} + +SourceLocation +SourceManager::createMacroArgExpansionLoc(SourceLocation SpellingLoc, + SourceLocation ExpansionLoc, + unsigned TokLength) { + ExpansionInfo Info = ExpansionInfo::createForMacroArg(SpellingLoc, + ExpansionLoc); + return createExpansionLocImpl(Info, TokLength); +} + +SourceLocation SourceManager::createExpansionLoc( + SourceLocation SpellingLoc, SourceLocation ExpansionLocStart, + SourceLocation ExpansionLocEnd, unsigned TokLength, + bool ExpansionIsTokenRange, int LoadedID, + SourceLocation::UIntTy LoadedOffset) { + ExpansionInfo Info = ExpansionInfo::create( + SpellingLoc, ExpansionLocStart, ExpansionLocEnd, ExpansionIsTokenRange); + return createExpansionLocImpl(Info, TokLength, LoadedID, LoadedOffset); +} + +SourceLocation SourceManager::createTokenSplitLoc(SourceLocation Spelling, + SourceLocation TokenStart, + SourceLocation TokenEnd) { + assert(getFileID(TokenStart) == getFileID(TokenEnd) && + "token spans multiple files"); + return createExpansionLocImpl( + ExpansionInfo::createForTokenSplit(Spelling, TokenStart, TokenEnd), + TokenEnd.getOffset() - TokenStart.getOffset()); +} + +SourceLocation +SourceManager::createExpansionLocImpl(const ExpansionInfo &Info, + unsigned TokLength, int LoadedID, + SourceLocation::UIntTy LoadedOffset) { + if (LoadedID < 0) { + assert(LoadedID != -1 && "Loading sentinel FileID"); + unsigned Index = unsigned(-LoadedID) - 2; + assert(Index < LoadedSLocEntryTable.size() && "FileID out of range"); + assert(!SLocEntryLoaded[Index] && "FileID already loaded"); + LoadedSLocEntryTable[Index] = SLocEntry::get(LoadedOffset, Info); + SLocEntryLoaded[Index] = true; + return SourceLocation::getMacroLoc(LoadedOffset); + } + LocalSLocEntryTable.push_back(SLocEntry::get(NextLocalOffset, Info)); + assert(NextLocalOffset + TokLength + 1 > NextLocalOffset && + NextLocalOffset + TokLength + 1 <= CurrentLoadedOffset && + "Ran out of source locations!"); + // See createFileID for that +1. + NextLocalOffset += TokLength + 1; + return SourceLocation::getMacroLoc(NextLocalOffset - (TokLength + 1)); +} + +llvm::Optional<llvm::MemoryBufferRef> +SourceManager::getMemoryBufferForFileOrNone(const FileEntry *File) { + SrcMgr::ContentCache &IR = getOrCreateContentCache(File->getLastRef()); + return IR.getBufferOrNone(Diag, getFileManager(), SourceLocation()); +} + +void SourceManager::overrideFileContents( + const FileEntry *SourceFile, std::unique_ptr<llvm::MemoryBuffer> Buffer) { + SrcMgr::ContentCache &IR = getOrCreateContentCache(SourceFile->getLastRef()); + + IR.setBuffer(std::move(Buffer)); + IR.BufferOverridden = true; + + getOverriddenFilesInfo().OverriddenFilesWithBuffer.insert(SourceFile); +} + +void SourceManager::overrideFileContents(const FileEntry *SourceFile, + const FileEntry *NewFile) { + assert(SourceFile->getSize() == NewFile->getSize() && + "Different sizes, use the FileManager to create a virtual file with " + "the correct size"); + assert(FileInfos.count(SourceFile) == 0 && + "This function should be called at the initialization stage, before " + "any parsing occurs."); + getOverriddenFilesInfo().OverriddenFiles[SourceFile] = NewFile; +} + +Optional<FileEntryRef> +SourceManager::bypassFileContentsOverride(FileEntryRef File) { + assert(isFileOverridden(&File.getFileEntry())); + llvm::Optional<FileEntryRef> BypassFile = FileMgr.getBypassFile(File); + + // If the file can't be found in the FS, give up. + if (!BypassFile) + return None; + + (void)getOrCreateContentCache(*BypassFile); + return BypassFile; +} + +void SourceManager::setFileIsTransient(const FileEntry *File) { + getOrCreateContentCache(File->getLastRef()).IsTransient = true; +} + +Optional<StringRef> +SourceManager::getNonBuiltinFilenameForID(FileID FID) const { + if (const SrcMgr::SLocEntry *Entry = getSLocEntryForFile(FID)) + if (Entry->getFile().getContentCache().OrigEntry) + return Entry->getFile().getName(); + return None; +} + +StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const { + auto B = getBufferDataOrNone(FID); + if (Invalid) + *Invalid = !B; + return B ? *B : "<<<<<INVALID SOURCE LOCATION>>>>>"; +} + +llvm::Optional<StringRef> +SourceManager::getBufferDataIfLoaded(FileID FID) const { + if (const SrcMgr::SLocEntry *Entry = getSLocEntryForFile(FID)) + return Entry->getFile().getContentCache().getBufferDataIfLoaded(); + return None; +} + +llvm::Optional<StringRef> SourceManager::getBufferDataOrNone(FileID FID) const { + if (const SrcMgr::SLocEntry *Entry = getSLocEntryForFile(FID)) + if (auto B = Entry->getFile().getContentCache().getBufferOrNone( + Diag, getFileManager(), SourceLocation())) + return B->getBuffer(); + return None; +} + +//===----------------------------------------------------------------------===// +// SourceLocation manipulation methods. +//===----------------------------------------------------------------------===// + +/// Return the FileID for a SourceLocation. +/// +/// This is the cache-miss path of getFileID. Not as hot as that function, but +/// still very important. It is responsible for finding the entry in the +/// SLocEntry tables that contains the specified location. +FileID SourceManager::getFileIDSlow(SourceLocation::UIntTy SLocOffset) const { + if (!SLocOffset) + return FileID::get(0); + + // Now it is time to search for the correct file. See where the SLocOffset + // sits in the global view and consult local or loaded buffers for it. + if (SLocOffset < NextLocalOffset) + return getFileIDLocal(SLocOffset); + return getFileIDLoaded(SLocOffset); +} + +/// Return the FileID for a SourceLocation with a low offset. +/// +/// This function knows that the SourceLocation is in a local buffer, not a +/// loaded one. +FileID SourceManager::getFileIDLocal(SourceLocation::UIntTy SLocOffset) const { + assert(SLocOffset < NextLocalOffset && "Bad function choice"); + + // After the first and second level caches, I see two common sorts of + // behavior: 1) a lot of searched FileID's are "near" the cached file + // location or are "near" the cached expansion location. 2) others are just + // completely random and may be a very long way away. + // + // To handle this, we do a linear search for up to 8 steps to catch #1 quickly + // then we fall back to a less cache efficient, but more scalable, binary + // search to find the location. + + // See if this is near the file point - worst case we start scanning from the + // most newly created FileID. + const SrcMgr::SLocEntry *I; + + if (LastFileIDLookup.ID < 0 || + LocalSLocEntryTable[LastFileIDLookup.ID].getOffset() < SLocOffset) { + // Neither loc prunes our search. + I = LocalSLocEntryTable.end(); + } else { + // Perhaps it is near the file point. + I = LocalSLocEntryTable.begin()+LastFileIDLookup.ID; + } + + // Find the FileID that contains this. "I" is an iterator that points to a + // FileID whose offset is known to be larger than SLocOffset. + unsigned NumProbes = 0; + while (true) { + --I; + if (I->getOffset() <= SLocOffset) { + FileID Res = FileID::get(int(I - LocalSLocEntryTable.begin())); + // Remember it. We have good locality across FileID lookups. + LastFileIDLookup = Res; + NumLinearScans += NumProbes+1; + return Res; + } + if (++NumProbes == 8) + break; + } + + // Convert "I" back into an index. We know that it is an entry whose index is + // larger than the offset we are looking for. + unsigned GreaterIndex = I - LocalSLocEntryTable.begin(); + // LessIndex - This is the lower bound of the range that we're searching. + // We know that the offset corresponding to the FileID is is less than + // SLocOffset. + unsigned LessIndex = 0; + NumProbes = 0; + while (true) { + unsigned MiddleIndex = (GreaterIndex-LessIndex)/2+LessIndex; + SourceLocation::UIntTy MidOffset = + getLocalSLocEntry(MiddleIndex).getOffset(); + + ++NumProbes; + + // If the offset of the midpoint is too large, chop the high side of the + // range to the midpoint. + if (MidOffset > SLocOffset) { + GreaterIndex = MiddleIndex; + continue; + } + + // If the middle index contains the value, succeed and return. + if (MiddleIndex + 1 == LocalSLocEntryTable.size() || + SLocOffset < getLocalSLocEntry(MiddleIndex + 1).getOffset()) { + FileID Res = FileID::get(MiddleIndex); + + // Remember it. We have good locality across FileID lookups. + LastFileIDLookup = Res; + NumBinaryProbes += NumProbes; + return Res; + } + + // Otherwise, move the low-side up to the middle index. + LessIndex = MiddleIndex; + } +} + +/// Return the FileID for a SourceLocation with a high offset. +/// +/// This function knows that the SourceLocation is in a loaded buffer, not a +/// local one. +FileID SourceManager::getFileIDLoaded(SourceLocation::UIntTy SLocOffset) const { + if (SLocOffset < CurrentLoadedOffset) { + assert(0 && "Invalid SLocOffset or bad function choice"); + return FileID(); + } + + // Essentially the same as the local case, but the loaded array is sorted + // in the other direction. + + // First do a linear scan from the last lookup position, if possible. + unsigned I; + int LastID = LastFileIDLookup.ID; + if (LastID >= 0 || getLoadedSLocEntryByID(LastID).getOffset() < SLocOffset) + I = 0; + else + I = (-LastID - 2) + 1; + + unsigned NumProbes; + for (NumProbes = 0; NumProbes < 8; ++NumProbes, ++I) { + // Make sure the entry is loaded! + const SrcMgr::SLocEntry &E = getLoadedSLocEntry(I); + if (E.getOffset() <= SLocOffset) { + FileID Res = FileID::get(-int(I) - 2); + LastFileIDLookup = Res; + NumLinearScans += NumProbes + 1; + return Res; + } + } + + // Linear scan failed. Do the binary search. Note the reverse sorting of the + // table: GreaterIndex is the one where the offset is greater, which is + // actually a lower index! + unsigned GreaterIndex = I; + unsigned LessIndex = LoadedSLocEntryTable.size(); + NumProbes = 0; + while (true) { + ++NumProbes; + unsigned MiddleIndex = (LessIndex - GreaterIndex) / 2 + GreaterIndex; + const SrcMgr::SLocEntry &E = getLoadedSLocEntry(MiddleIndex); + if (E.getOffset() == 0) + return FileID(); // invalid entry. + + ++NumProbes; + + if (E.getOffset() > SLocOffset) { + if (GreaterIndex == MiddleIndex) { + assert(0 && "binary search missed the entry"); + return FileID(); + } + GreaterIndex = MiddleIndex; + continue; + } + + if (isOffsetInFileID(FileID::get(-int(MiddleIndex) - 2), SLocOffset)) { + FileID Res = FileID::get(-int(MiddleIndex) - 2); + LastFileIDLookup = Res; + NumBinaryProbes += NumProbes; + return Res; + } + + if (LessIndex == MiddleIndex) { + assert(0 && "binary search missed the entry"); + return FileID(); + } + LessIndex = MiddleIndex; + } +} + +SourceLocation SourceManager:: +getExpansionLocSlowCase(SourceLocation Loc) const { + do { + // Note: If Loc indicates an offset into a token that came from a macro + // expansion (e.g. the 5th character of the token) we do not want to add + // this offset when going to the expansion location. The expansion + // location is the macro invocation, which the offset has nothing to do + // with. This is unlike when we get the spelling loc, because the offset + // directly correspond to the token whose spelling we're inspecting. + Loc = getSLocEntry(getFileID(Loc)).getExpansion().getExpansionLocStart(); + } while (!Loc.isFileID()); + + return Loc; +} + +SourceLocation SourceManager::getSpellingLocSlowCase(SourceLocation Loc) const { + do { + std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(Loc); + Loc = getSLocEntry(LocInfo.first).getExpansion().getSpellingLoc(); + Loc = Loc.getLocWithOffset(LocInfo.second); + } while (!Loc.isFileID()); + return Loc; +} + +SourceLocation SourceManager::getFileLocSlowCase(SourceLocation Loc) const { + do { + if (isMacroArgExpansion(Loc)) + Loc = getImmediateSpellingLoc(Loc); + else + Loc = getImmediateExpansionRange(Loc).getBegin(); + } while (!Loc.isFileID()); + return Loc; +} + + +std::pair<FileID, unsigned> +SourceManager::getDecomposedExpansionLocSlowCase( + const SrcMgr::SLocEntry *E) const { + // If this is an expansion record, walk through all the expansion points. + FileID FID; + SourceLocation Loc; + unsigned Offset; + do { + Loc = E->getExpansion().getExpansionLocStart(); + + FID = getFileID(Loc); + E = &getSLocEntry(FID); + Offset = Loc.getOffset()-E->getOffset(); + } while (!Loc.isFileID()); + + return std::make_pair(FID, Offset); +} + +std::pair<FileID, unsigned> +SourceManager::getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E, + unsigned Offset) const { + // If this is an expansion record, walk through all the expansion points. + FileID FID; + SourceLocation Loc; + do { + Loc = E->getExpansion().getSpellingLoc(); + Loc = Loc.getLocWithOffset(Offset); + + FID = getFileID(Loc); + E = &getSLocEntry(FID); + Offset = Loc.getOffset()-E->getOffset(); + } while (!Loc.isFileID()); + + return std::make_pair(FID, Offset); +} + +/// getImmediateSpellingLoc - Given a SourceLocation object, return the +/// spelling location referenced by the ID. This is the first level down +/// towards the place where the characters that make up the lexed token can be +/// found. This should not generally be used by clients. +SourceLocation SourceManager::getImmediateSpellingLoc(SourceLocation Loc) const{ + if (Loc.isFileID()) return Loc; + std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(Loc); + Loc = getSLocEntry(LocInfo.first).getExpansion().getSpellingLoc(); + return Loc.getLocWithOffset(LocInfo.second); +} + +/// Return the filename of the file containing a SourceLocation. +StringRef SourceManager::getFilename(SourceLocation SpellingLoc) const { + if (const FileEntry *F = getFileEntryForID(getFileID(SpellingLoc))) + return F->getName(); + return StringRef(); +} + +/// getImmediateExpansionRange - Loc is required to be an expansion location. +/// Return the start/end of the expansion information. +CharSourceRange +SourceManager::getImmediateExpansionRange(SourceLocation Loc) const { + assert(Loc.isMacroID() && "Not a macro expansion loc!"); + const ExpansionInfo &Expansion = getSLocEntry(getFileID(Loc)).getExpansion(); + return Expansion.getExpansionLocRange(); +} + +SourceLocation SourceManager::getTopMacroCallerLoc(SourceLocation Loc) const { + while (isMacroArgExpansion(Loc)) + Loc = getImmediateSpellingLoc(Loc); + return Loc; +} + +/// getExpansionRange - Given a SourceLocation object, return the range of +/// tokens covered by the expansion in the ultimate file. +CharSourceRange SourceManager::getExpansionRange(SourceLocation Loc) const { + if (Loc.isFileID()) + return CharSourceRange(SourceRange(Loc, Loc), true); + + CharSourceRange Res = getImmediateExpansionRange(Loc); + + // Fully resolve the start and end locations to their ultimate expansion + // points. + while (!Res.getBegin().isFileID()) + Res.setBegin(getImmediateExpansionRange(Res.getBegin()).getBegin()); + while (!Res.getEnd().isFileID()) { + CharSourceRange EndRange = getImmediateExpansionRange(Res.getEnd()); + Res.setEnd(EndRange.getEnd()); + Res.setTokenRange(EndRange.isTokenRange()); + } + return Res; +} + +bool SourceManager::isMacroArgExpansion(SourceLocation Loc, + SourceLocation *StartLoc) const { + if (!Loc.isMacroID()) return false; + + FileID FID = getFileID(Loc); + const SrcMgr::ExpansionInfo &Expansion = getSLocEntry(FID).getExpansion(); + if (!Expansion.isMacroArgExpansion()) return false; + + if (StartLoc) + *StartLoc = Expansion.getExpansionLocStart(); + return true; +} + +bool SourceManager::isMacroBodyExpansion(SourceLocation Loc) const { + if (!Loc.isMacroID()) return false; + + FileID FID = getFileID(Loc); + const SrcMgr::ExpansionInfo &Expansion = getSLocEntry(FID).getExpansion(); + return Expansion.isMacroBodyExpansion(); +} + +bool SourceManager::isAtStartOfImmediateMacroExpansion(SourceLocation Loc, + SourceLocation *MacroBegin) const { + assert(Loc.isValid() && Loc.isMacroID() && "Expected a valid macro loc"); + + std::pair<FileID, unsigned> DecompLoc = getDecomposedLoc(Loc); + if (DecompLoc.second > 0) + return false; // Does not point at the start of expansion range. + + bool Invalid = false; + const SrcMgr::ExpansionInfo &ExpInfo = + getSLocEntry(DecompLoc.first, &Invalid).getExpansion(); + if (Invalid) + return false; + SourceLocation ExpLoc = ExpInfo.getExpansionLocStart(); + + if (ExpInfo.isMacroArgExpansion()) { + // For macro argument expansions, check if the previous FileID is part of + // the same argument expansion, in which case this Loc is not at the + // beginning of the expansion. + FileID PrevFID = getPreviousFileID(DecompLoc.first); + if (!PrevFID.isInvalid()) { + const SrcMgr::SLocEntry &PrevEntry = getSLocEntry(PrevFID, &Invalid); + if (Invalid) + return false; + if (PrevEntry.isExpansion() && + PrevEntry.getExpansion().getExpansionLocStart() == ExpLoc) + return false; + } + } + + if (MacroBegin) + *MacroBegin = ExpLoc; + return true; +} + +bool SourceManager::isAtEndOfImmediateMacroExpansion(SourceLocation Loc, + SourceLocation *MacroEnd) const { + assert(Loc.isValid() && Loc.isMacroID() && "Expected a valid macro loc"); + + FileID FID = getFileID(Loc); + SourceLocation NextLoc = Loc.getLocWithOffset(1); + if (isInFileID(NextLoc, FID)) + return false; // Does not point at the end of expansion range. + + bool Invalid = false; + const SrcMgr::ExpansionInfo &ExpInfo = + getSLocEntry(FID, &Invalid).getExpansion(); + if (Invalid) + return false; + + if (ExpInfo.isMacroArgExpansion()) { + // For macro argument expansions, check if the next FileID is part of the + // same argument expansion, in which case this Loc is not at the end of the + // expansion. + FileID NextFID = getNextFileID(FID); + if (!NextFID.isInvalid()) { + const SrcMgr::SLocEntry &NextEntry = getSLocEntry(NextFID, &Invalid); + if (Invalid) + return false; + if (NextEntry.isExpansion() && + NextEntry.getExpansion().getExpansionLocStart() == + ExpInfo.getExpansionLocStart()) + return false; + } + } + + if (MacroEnd) + *MacroEnd = ExpInfo.getExpansionLocEnd(); + return true; +} + +//===----------------------------------------------------------------------===// +// Queries about the code at a SourceLocation. +//===----------------------------------------------------------------------===// + +/// getCharacterData - Return a pointer to the start of the specified location +/// in the appropriate MemoryBuffer. +const char *SourceManager::getCharacterData(SourceLocation SL, + bool *Invalid) const { + // Note that this is a hot function in the getSpelling() path, which is + // heavily used by -E mode. + std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(SL); + + // Note that calling 'getBuffer()' may lazily page in a source file. + bool CharDataInvalid = false; + const SLocEntry &Entry = getSLocEntry(LocInfo.first, &CharDataInvalid); + if (CharDataInvalid || !Entry.isFile()) { + if (Invalid) + *Invalid = true; + + return "<<<<INVALID BUFFER>>>>"; + } + llvm::Optional<llvm::MemoryBufferRef> Buffer = + Entry.getFile().getContentCache().getBufferOrNone(Diag, getFileManager(), + SourceLocation()); + if (Invalid) + *Invalid = !Buffer; + return Buffer ? Buffer->getBufferStart() + LocInfo.second + : "<<<<INVALID BUFFER>>>>"; +} + +/// getColumnNumber - Return the column # for the specified file position. +/// this is significantly cheaper to compute than the line number. +unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos, + bool *Invalid) const { + llvm::Optional<llvm::MemoryBufferRef> MemBuf = getBufferOrNone(FID); + if (Invalid) + *Invalid = !MemBuf; + + if (!MemBuf) + return 1; + + // It is okay to request a position just past the end of the buffer. + if (FilePos > MemBuf->getBufferSize()) { + if (Invalid) + *Invalid = true; + return 1; + } + + const char *Buf = MemBuf->getBufferStart(); + // See if we just calculated the line number for this FilePos and can use + // that to lookup the start of the line instead of searching for it. + if (LastLineNoFileIDQuery == FID && LastLineNoContentCache->SourceLineCache && + LastLineNoResult < LastLineNoContentCache->SourceLineCache.size()) { + const unsigned *SourceLineCache = + LastLineNoContentCache->SourceLineCache.begin(); + unsigned LineStart = SourceLineCache[LastLineNoResult - 1]; + unsigned LineEnd = SourceLineCache[LastLineNoResult]; + if (FilePos >= LineStart && FilePos < LineEnd) { + // LineEnd is the LineStart of the next line. + // A line ends with separator LF or CR+LF on Windows. + // FilePos might point to the last separator, + // but we need a column number at most 1 + the last column. + if (FilePos + 1 == LineEnd && FilePos > LineStart) { + if (Buf[FilePos - 1] == '\r' || Buf[FilePos - 1] == '\n') + --FilePos; + } + return FilePos - LineStart + 1; + } + } + + unsigned LineStart = FilePos; + while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r') + --LineStart; + return FilePos-LineStart+1; +} + +// isInvalid - Return the result of calling loc.isInvalid(), and +// if Invalid is not null, set its value to same. +template<typename LocType> +static bool isInvalid(LocType Loc, bool *Invalid) { + bool MyInvalid = Loc.isInvalid(); + if (Invalid) + *Invalid = MyInvalid; + return MyInvalid; +} + +unsigned SourceManager::getSpellingColumnNumber(SourceLocation Loc, + bool *Invalid) const { + if (isInvalid(Loc, Invalid)) return 0; + std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc); + return getColumnNumber(LocInfo.first, LocInfo.second, Invalid); +} + +unsigned SourceManager::getExpansionColumnNumber(SourceLocation Loc, + bool *Invalid) const { + if (isInvalid(Loc, Invalid)) return 0; + std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc); + return getColumnNumber(LocInfo.first, LocInfo.second, Invalid); +} + +unsigned SourceManager::getPresumedColumnNumber(SourceLocation Loc, + bool *Invalid) const { + PresumedLoc PLoc = getPresumedLoc(Loc); + if (isInvalid(PLoc, Invalid)) return 0; + return PLoc.getColumn(); +} + +// Check if mutli-byte word x has bytes between m and n, included. This may also +// catch bytes equal to n + 1. +// The returned value holds a 0x80 at each byte position that holds a match. +// see http://graphics.stanford.edu/~seander/bithacks.html#HasBetweenInWord +template <class T> +static constexpr inline T likelyhasbetween(T x, unsigned char m, + unsigned char n) { + return ((x - ~static_cast<T>(0) / 255 * (n + 1)) & ~x & + ((x & ~static_cast<T>(0) / 255 * 127) + + (~static_cast<T>(0) / 255 * (127 - (m - 1))))) & + ~static_cast<T>(0) / 255 * 128; +} + +LineOffsetMapping LineOffsetMapping::get(llvm::MemoryBufferRef Buffer, + llvm::BumpPtrAllocator &Alloc) { + + // Find the file offsets of all of the *physical* source lines. This does + // not look at trigraphs, escaped newlines, or anything else tricky. + SmallVector<unsigned, 256> LineOffsets; + + // Line #1 starts at char 0. + LineOffsets.push_back(0); + + const unsigned char *Buf = (const unsigned char *)Buffer.getBufferStart(); + const unsigned char *End = (const unsigned char *)Buffer.getBufferEnd(); + const std::size_t BufLen = End - Buf; + + unsigned I = 0; + uint64_t Word; + + // scan sizeof(Word) bytes at a time for new lines. + // This is much faster than scanning each byte independently. + if (BufLen > sizeof(Word)) { + do { + Word = llvm::support::endian::read64(Buf + I, llvm::support::little); + // no new line => jump over sizeof(Word) bytes. + auto Mask = likelyhasbetween(Word, '\n', '\r'); + if (!Mask) { + I += sizeof(Word); + continue; + } + + // At that point, Mask contains 0x80 set at each byte that holds a value + // in [\n, \r + 1 [ + + // Scan for the next newline - it's very likely there's one. + unsigned N = + llvm::countTrailingZeros(Mask) - 7; // -7 because 0x80 is the marker + Word >>= N; + I += N / 8 + 1; + unsigned char Byte = Word; + if (Byte == '\n') { + LineOffsets.push_back(I); + } else if (Byte == '\r') { + // If this is \r\n, skip both characters. + if (Buf[I] == '\n') + ++I; + LineOffsets.push_back(I); + } + } while (I < BufLen - sizeof(Word) - 1); + } + + // Handle tail using a regular check. + while (I < BufLen) { + if (Buf[I] == '\n') { + LineOffsets.push_back(I + 1); + } else if (Buf[I] == '\r') { + // If this is \r\n, skip both characters. + if (I + 1 < BufLen && Buf[I + 1] == '\n') + ++I; + LineOffsets.push_back(I + 1); + } + ++I; + } + + return LineOffsetMapping(LineOffsets, Alloc); +} + +LineOffsetMapping::LineOffsetMapping(ArrayRef<unsigned> LineOffsets, + llvm::BumpPtrAllocator &Alloc) + : Storage(Alloc.Allocate<unsigned>(LineOffsets.size() + 1)) { + Storage[0] = LineOffsets.size(); + std::copy(LineOffsets.begin(), LineOffsets.end(), Storage + 1); +} + +/// getLineNumber - Given a SourceLocation, return the spelling line number +/// for the position indicated. This requires building and caching a table of +/// line offsets for the MemoryBuffer, so this is not cheap: use only when +/// about to emit a diagnostic. +unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos, + bool *Invalid) const { + if (FID.isInvalid()) { + if (Invalid) + *Invalid = true; + return 1; + } + + const ContentCache *Content; + if (LastLineNoFileIDQuery == FID) + Content = LastLineNoContentCache; + else { + bool MyInvalid = false; + const SLocEntry &Entry = getSLocEntry(FID, &MyInvalid); + if (MyInvalid || !Entry.isFile()) { + if (Invalid) + *Invalid = true; + return 1; + } + + Content = &Entry.getFile().getContentCache(); + } + + // If this is the first use of line information for this buffer, compute the + /// SourceLineCache for it on demand. + if (!Content->SourceLineCache) { + llvm::Optional<llvm::MemoryBufferRef> Buffer = + Content->getBufferOrNone(Diag, getFileManager(), SourceLocation()); + if (Invalid) + *Invalid = !Buffer; + if (!Buffer) + return 1; + + Content->SourceLineCache = + LineOffsetMapping::get(*Buffer, ContentCacheAlloc); + } else if (Invalid) + *Invalid = false; + + // Okay, we know we have a line number table. Do a binary search to find the + // line number that this character position lands on. + const unsigned *SourceLineCache = Content->SourceLineCache.begin(); + const unsigned *SourceLineCacheStart = SourceLineCache; + const unsigned *SourceLineCacheEnd = Content->SourceLineCache.end(); + + unsigned QueriedFilePos = FilePos+1; + + // FIXME: I would like to be convinced that this code is worth being as + // complicated as it is, binary search isn't that slow. + // + // If it is worth being optimized, then in my opinion it could be more + // performant, simpler, and more obviously correct by just "galloping" outward + // from the queried file position. In fact, this could be incorporated into a + // generic algorithm such as lower_bound_with_hint. + // + // If someone gives me a test case where this matters, and I will do it! - DWD + + // If the previous query was to the same file, we know both the file pos from + // that query and the line number returned. This allows us to narrow the + // search space from the entire file to something near the match. + if (LastLineNoFileIDQuery == FID) { + if (QueriedFilePos >= LastLineNoFilePos) { + // FIXME: Potential overflow? + SourceLineCache = SourceLineCache+LastLineNoResult-1; + + // The query is likely to be nearby the previous one. Here we check to + // see if it is within 5, 10 or 20 lines. It can be far away in cases + // where big comment blocks and vertical whitespace eat up lines but + // contribute no tokens. + if (SourceLineCache+5 < SourceLineCacheEnd) { + if (SourceLineCache[5] > QueriedFilePos) + SourceLineCacheEnd = SourceLineCache+5; + else if (SourceLineCache+10 < SourceLineCacheEnd) { + if (SourceLineCache[10] > QueriedFilePos) + SourceLineCacheEnd = SourceLineCache+10; + else if (SourceLineCache+20 < SourceLineCacheEnd) { + if (SourceLineCache[20] > QueriedFilePos) + SourceLineCacheEnd = SourceLineCache+20; + } + } + } + } else { + if (LastLineNoResult < Content->SourceLineCache.size()) + SourceLineCacheEnd = SourceLineCache+LastLineNoResult+1; + } + } + + const unsigned *Pos = + std::lower_bound(SourceLineCache, SourceLineCacheEnd, QueriedFilePos); + unsigned LineNo = Pos-SourceLineCacheStart; + + LastLineNoFileIDQuery = FID; + LastLineNoContentCache = Content; + LastLineNoFilePos = QueriedFilePos; + LastLineNoResult = LineNo; + return LineNo; +} + +unsigned SourceManager::getSpellingLineNumber(SourceLocation Loc, + bool *Invalid) const { + if (isInvalid(Loc, Invalid)) return 0; + std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(Loc); + return getLineNumber(LocInfo.first, LocInfo.second); +} +unsigned SourceManager::getExpansionLineNumber(SourceLocation Loc, + bool *Invalid) const { + if (isInvalid(Loc, Invalid)) return 0; + std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc); + return getLineNumber(LocInfo.first, LocInfo.second); +} +unsigned SourceManager::getPresumedLineNumber(SourceLocation Loc, + bool *Invalid) const { + PresumedLoc PLoc = getPresumedLoc(Loc); + if (isInvalid(PLoc, Invalid)) return 0; + return PLoc.getLine(); +} + +/// getFileCharacteristic - return the file characteristic of the specified +/// source location, indicating whether this is a normal file, a system +/// header, or an "implicit extern C" system header. +/// +/// This state can be modified with flags on GNU linemarker directives like: +/// # 4 "foo.h" 3 +/// which changes all source locations in the current file after that to be +/// considered to be from a system header. +SrcMgr::CharacteristicKind +SourceManager::getFileCharacteristic(SourceLocation Loc) const { + assert(Loc.isValid() && "Can't get file characteristic of invalid loc!"); + std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc); + const SLocEntry *SEntry = getSLocEntryForFile(LocInfo.first); + if (!SEntry) + return C_User; + + const SrcMgr::FileInfo &FI = SEntry->getFile(); + + // If there are no #line directives in this file, just return the whole-file + // state. + if (!FI.hasLineDirectives()) + return FI.getFileCharacteristic(); + + assert(LineTable && "Can't have linetable entries without a LineTable!"); + // See if there is a #line directive before the location. + const LineEntry *Entry = + LineTable->FindNearestLineEntry(LocInfo.first, LocInfo.second); + + // If this is before the first line marker, use the file characteristic. + if (!Entry) + return FI.getFileCharacteristic(); + + return Entry->FileKind; +} + +/// Return the filename or buffer identifier of the buffer the location is in. +/// Note that this name does not respect \#line directives. Use getPresumedLoc +/// for normal clients. +StringRef SourceManager::getBufferName(SourceLocation Loc, + bool *Invalid) const { + if (isInvalid(Loc, Invalid)) return "<invalid loc>"; + + auto B = getBufferOrNone(getFileID(Loc)); + if (Invalid) + *Invalid = !B; + return B ? B->getBufferIdentifier() : "<invalid buffer>"; +} + +/// getPresumedLoc - This method returns the "presumed" location of a +/// SourceLocation specifies. A "presumed location" can be modified by \#line +/// or GNU line marker directives. This provides a view on the data that a +/// user should see in diagnostics, for example. +/// +/// Note that a presumed location is always given as the expansion point of an +/// expansion location, not at the spelling location. +PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc, + bool UseLineDirectives) const { + if (Loc.isInvalid()) return PresumedLoc(); + + // Presumed locations are always for expansion points. + std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc); + + bool Invalid = false; + const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid); + if (Invalid || !Entry.isFile()) + return PresumedLoc(); + + const SrcMgr::FileInfo &FI = Entry.getFile(); + const SrcMgr::ContentCache *C = &FI.getContentCache(); + + // To get the source name, first consult the FileEntry (if one exists) + // before the MemBuffer as this will avoid unnecessarily paging in the + // MemBuffer. + FileID FID = LocInfo.first; + StringRef Filename; + if (C->OrigEntry) + Filename = C->OrigEntry->getName(); + else if (auto Buffer = C->getBufferOrNone(Diag, getFileManager())) + Filename = Buffer->getBufferIdentifier(); + + unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second, &Invalid); + if (Invalid) + return PresumedLoc(); + unsigned ColNo = getColumnNumber(LocInfo.first, LocInfo.second, &Invalid); + if (Invalid) + return PresumedLoc(); + + SourceLocation IncludeLoc = FI.getIncludeLoc(); + + // If we have #line directives in this file, update and overwrite the physical + // location info if appropriate. + if (UseLineDirectives && FI.hasLineDirectives()) { + assert(LineTable && "Can't have linetable entries without a LineTable!"); + // See if there is a #line directive before this. If so, get it. + if (const LineEntry *Entry = + LineTable->FindNearestLineEntry(LocInfo.first, LocInfo.second)) { + // If the LineEntry indicates a filename, use it. + if (Entry->FilenameID != -1) { + Filename = LineTable->getFilename(Entry->FilenameID); + // The contents of files referenced by #line are not in the + // SourceManager + FID = FileID::get(0); + } + + // Use the line number specified by the LineEntry. This line number may + // be multiple lines down from the line entry. Add the difference in + // physical line numbers from the query point and the line marker to the + // total. + unsigned MarkerLineNo = getLineNumber(LocInfo.first, Entry->FileOffset); + LineNo = Entry->LineNo + (LineNo-MarkerLineNo-1); + + // Note that column numbers are not molested by line markers. + + // Handle virtual #include manipulation. + if (Entry->IncludeOffset) { + IncludeLoc = getLocForStartOfFile(LocInfo.first); + IncludeLoc = IncludeLoc.getLocWithOffset(Entry->IncludeOffset); + } + } + } + + return PresumedLoc(Filename.data(), FID, LineNo, ColNo, IncludeLoc); +} + +/// Returns whether the PresumedLoc for a given SourceLocation is +/// in the main file. +/// +/// This computes the "presumed" location for a SourceLocation, then checks +/// whether it came from a file other than the main file. This is different +/// from isWrittenInMainFile() because it takes line marker directives into +/// account. +bool SourceManager::isInMainFile(SourceLocation Loc) const { + if (Loc.isInvalid()) return false; + + // Presumed locations are always for expansion points. + std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc); + + const SLocEntry *Entry = getSLocEntryForFile(LocInfo.first); + if (!Entry) + return false; + + const SrcMgr::FileInfo &FI = Entry->getFile(); + + // Check if there is a line directive for this location. + if (FI.hasLineDirectives()) + if (const LineEntry *Entry = + LineTable->FindNearestLineEntry(LocInfo.first, LocInfo.second)) + if (Entry->IncludeOffset) + return false; + + return FI.getIncludeLoc().isInvalid(); +} + +/// The size of the SLocEntry that \p FID represents. +unsigned SourceManager::getFileIDSize(FileID FID) const { + bool Invalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid); + if (Invalid) + return 0; + + int ID = FID.ID; + SourceLocation::UIntTy NextOffset; + if ((ID > 0 && unsigned(ID+1) == local_sloc_entry_size())) + NextOffset = getNextLocalOffset(); + else if (ID+1 == -1) + NextOffset = MaxLoadedOffset; + else + NextOffset = getSLocEntry(FileID::get(ID+1)).getOffset(); + + return NextOffset - Entry.getOffset() - 1; +} + +//===----------------------------------------------------------------------===// +// Other miscellaneous methods. +//===----------------------------------------------------------------------===// + +/// Get the source location for the given file:line:col triplet. +/// +/// If the source file is included multiple times, the source location will +/// be based upon an arbitrary inclusion. +SourceLocation SourceManager::translateFileLineCol(const FileEntry *SourceFile, + unsigned Line, + unsigned Col) const { + assert(SourceFile && "Null source file!"); + assert(Line && Col && "Line and column should start from 1!"); + + FileID FirstFID = translateFile(SourceFile); + return translateLineCol(FirstFID, Line, Col); +} + +/// Get the FileID for the given file. +/// +/// If the source file is included multiple times, the FileID will be the +/// first inclusion. +FileID SourceManager::translateFile(const FileEntry *SourceFile) const { + assert(SourceFile && "Null source file!"); + + // First, check the main file ID, since it is common to look for a + // location in the main file. + if (MainFileID.isValid()) { + bool Invalid = false; + const SLocEntry &MainSLoc = getSLocEntry(MainFileID, &Invalid); + if (Invalid) + return FileID(); + + if (MainSLoc.isFile()) { + if (MainSLoc.getFile().getContentCache().OrigEntry == SourceFile) + return MainFileID; + } + } + + // The location we're looking for isn't in the main file; look + // through all of the local source locations. + for (unsigned I = 0, N = local_sloc_entry_size(); I != N; ++I) { + const SLocEntry &SLoc = getLocalSLocEntry(I); + if (SLoc.isFile() && + SLoc.getFile().getContentCache().OrigEntry == SourceFile) + return FileID::get(I); + } + + // If that still didn't help, try the modules. + for (unsigned I = 0, N = loaded_sloc_entry_size(); I != N; ++I) { + const SLocEntry &SLoc = getLoadedSLocEntry(I); + if (SLoc.isFile() && + SLoc.getFile().getContentCache().OrigEntry == SourceFile) + return FileID::get(-int(I) - 2); + } + + return FileID(); +} + +/// Get the source location in \arg FID for the given line:col. +/// Returns null location if \arg FID is not a file SLocEntry. +SourceLocation SourceManager::translateLineCol(FileID FID, + unsigned Line, + unsigned Col) const { + // Lines are used as a one-based index into a zero-based array. This assert + // checks for possible buffer underruns. + assert(Line && Col && "Line and column should start from 1!"); + + if (FID.isInvalid()) + return SourceLocation(); + + bool Invalid = false; + const SLocEntry &Entry = getSLocEntry(FID, &Invalid); + if (Invalid) + return SourceLocation(); + + if (!Entry.isFile()) + return SourceLocation(); + + SourceLocation FileLoc = SourceLocation::getFileLoc(Entry.getOffset()); + + if (Line == 1 && Col == 1) + return FileLoc; + + const ContentCache *Content = &Entry.getFile().getContentCache(); + + // If this is the first use of line information for this buffer, compute the + // SourceLineCache for it on demand. + llvm::Optional<llvm::MemoryBufferRef> Buffer = + Content->getBufferOrNone(Diag, getFileManager()); + if (!Buffer) + return SourceLocation(); + if (!Content->SourceLineCache) + Content->SourceLineCache = + LineOffsetMapping::get(*Buffer, ContentCacheAlloc); + + if (Line > Content->SourceLineCache.size()) { + unsigned Size = Buffer->getBufferSize(); + if (Size > 0) + --Size; + return FileLoc.getLocWithOffset(Size); + } + + unsigned FilePos = Content->SourceLineCache[Line - 1]; + const char *Buf = Buffer->getBufferStart() + FilePos; + unsigned BufLength = Buffer->getBufferSize() - FilePos; + if (BufLength == 0) + return FileLoc.getLocWithOffset(FilePos); + + unsigned i = 0; + + // Check that the given column is valid. + while (i < BufLength-1 && i < Col-1 && Buf[i] != '\n' && Buf[i] != '\r') + ++i; + return FileLoc.getLocWithOffset(FilePos + i); +} + +/// Compute a map of macro argument chunks to their expanded source +/// location. Chunks that are not part of a macro argument will map to an +/// invalid source location. e.g. if a file contains one macro argument at +/// offset 100 with length 10, this is how the map will be formed: +/// 0 -> SourceLocation() +/// 100 -> Expanded macro arg location +/// 110 -> SourceLocation() +void SourceManager::computeMacroArgsCache(MacroArgsMap &MacroArgsCache, + FileID FID) const { + assert(FID.isValid()); + + // Initially no macro argument chunk is present. + MacroArgsCache.insert(std::make_pair(0, SourceLocation())); + + int ID = FID.ID; + while (true) { + ++ID; + // Stop if there are no more FileIDs to check. + if (ID > 0) { + if (unsigned(ID) >= local_sloc_entry_size()) + return; + } else if (ID == -1) { + return; + } + + bool Invalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntryByID(ID, &Invalid); + if (Invalid) + return; + if (Entry.isFile()) { + auto& File = Entry.getFile(); + if (File.getFileCharacteristic() == C_User_ModuleMap || + File.getFileCharacteristic() == C_System_ModuleMap) + continue; + + SourceLocation IncludeLoc = File.getIncludeLoc(); + bool IncludedInFID = + (IncludeLoc.isValid() && isInFileID(IncludeLoc, FID)) || + // Predefined header doesn't have a valid include location in main + // file, but any files created by it should still be skipped when + // computing macro args expanded in the main file. + (FID == MainFileID && Entry.getFile().getName() == "<built-in>"); + if (IncludedInFID) { + // Skip the files/macros of the #include'd file, we only care about + // macros that lexed macro arguments from our file. + if (Entry.getFile().NumCreatedFIDs) + ID += Entry.getFile().NumCreatedFIDs - 1 /*because of next ++ID*/; + continue; + } else if (IncludeLoc.isValid()) { + // If file was included but not from FID, there is no more files/macros + // that may be "contained" in this file. + return; + } + continue; + } + + const ExpansionInfo &ExpInfo = Entry.getExpansion(); + + if (ExpInfo.getExpansionLocStart().isFileID()) { + if (!isInFileID(ExpInfo.getExpansionLocStart(), FID)) + return; // No more files/macros that may be "contained" in this file. + } + + if (!ExpInfo.isMacroArgExpansion()) + continue; + + associateFileChunkWithMacroArgExp(MacroArgsCache, FID, + ExpInfo.getSpellingLoc(), + SourceLocation::getMacroLoc(Entry.getOffset()), + getFileIDSize(FileID::get(ID))); + } +} + +void SourceManager::associateFileChunkWithMacroArgExp( + MacroArgsMap &MacroArgsCache, + FileID FID, + SourceLocation SpellLoc, + SourceLocation ExpansionLoc, + unsigned ExpansionLength) const { + if (!SpellLoc.isFileID()) { + SourceLocation::UIntTy SpellBeginOffs = SpellLoc.getOffset(); + SourceLocation::UIntTy SpellEndOffs = SpellBeginOffs + ExpansionLength; + + // The spelling range for this macro argument expansion can span multiple + // consecutive FileID entries. Go through each entry contained in the + // spelling range and if one is itself a macro argument expansion, recurse + // and associate the file chunk that it represents. + + FileID SpellFID; // Current FileID in the spelling range. + unsigned SpellRelativeOffs; + std::tie(SpellFID, SpellRelativeOffs) = getDecomposedLoc(SpellLoc); + while (true) { + const SLocEntry &Entry = getSLocEntry(SpellFID); + SourceLocation::UIntTy SpellFIDBeginOffs = Entry.getOffset(); + unsigned SpellFIDSize = getFileIDSize(SpellFID); + SourceLocation::UIntTy SpellFIDEndOffs = SpellFIDBeginOffs + SpellFIDSize; + const ExpansionInfo &Info = Entry.getExpansion(); + if (Info.isMacroArgExpansion()) { + unsigned CurrSpellLength; + if (SpellFIDEndOffs < SpellEndOffs) + CurrSpellLength = SpellFIDSize - SpellRelativeOffs; + else + CurrSpellLength = ExpansionLength; + associateFileChunkWithMacroArgExp(MacroArgsCache, FID, + Info.getSpellingLoc().getLocWithOffset(SpellRelativeOffs), + ExpansionLoc, CurrSpellLength); + } + + if (SpellFIDEndOffs >= SpellEndOffs) + return; // we covered all FileID entries in the spelling range. + + // Move to the next FileID entry in the spelling range. + unsigned advance = SpellFIDSize - SpellRelativeOffs + 1; + ExpansionLoc = ExpansionLoc.getLocWithOffset(advance); + ExpansionLength -= advance; + ++SpellFID.ID; + SpellRelativeOffs = 0; + } + } + + assert(SpellLoc.isFileID()); + + unsigned BeginOffs; + if (!isInFileID(SpellLoc, FID, &BeginOffs)) + return; + + unsigned EndOffs = BeginOffs + ExpansionLength; + + // Add a new chunk for this macro argument. A previous macro argument chunk + // may have been lexed again, so e.g. if the map is + // 0 -> SourceLocation() + // 100 -> Expanded loc #1 + // 110 -> SourceLocation() + // and we found a new macro FileID that lexed from offset 105 with length 3, + // the new map will be: + // 0 -> SourceLocation() + // 100 -> Expanded loc #1 + // 105 -> Expanded loc #2 + // 108 -> Expanded loc #1 + // 110 -> SourceLocation() + // + // Since re-lexed macro chunks will always be the same size or less of + // previous chunks, we only need to find where the ending of the new macro + // chunk is mapped to and update the map with new begin/end mappings. + + MacroArgsMap::iterator I = MacroArgsCache.upper_bound(EndOffs); + --I; + SourceLocation EndOffsMappedLoc = I->second; + MacroArgsCache[BeginOffs] = ExpansionLoc; + MacroArgsCache[EndOffs] = EndOffsMappedLoc; +} + +/// If \arg Loc points inside a function macro argument, the returned +/// location will be the macro location in which the argument was expanded. +/// If a macro argument is used multiple times, the expanded location will +/// be at the first expansion of the argument. +/// e.g. +/// MY_MACRO(foo); +/// ^ +/// Passing a file location pointing at 'foo', will yield a macro location +/// where 'foo' was expanded into. +SourceLocation +SourceManager::getMacroArgExpandedLocation(SourceLocation Loc) const { + if (Loc.isInvalid() || !Loc.isFileID()) + return Loc; + + FileID FID; + unsigned Offset; + std::tie(FID, Offset) = getDecomposedLoc(Loc); + if (FID.isInvalid()) + return Loc; + + std::unique_ptr<MacroArgsMap> &MacroArgsCache = MacroArgsCacheMap[FID]; + if (!MacroArgsCache) { + MacroArgsCache = std::make_unique<MacroArgsMap>(); + computeMacroArgsCache(*MacroArgsCache, FID); + } + + assert(!MacroArgsCache->empty()); + MacroArgsMap::iterator I = MacroArgsCache->upper_bound(Offset); + // In case every element in MacroArgsCache is greater than Offset we can't + // decrement the iterator. + if (I == MacroArgsCache->begin()) + return Loc; + + --I; + + SourceLocation::UIntTy MacroArgBeginOffs = I->first; + SourceLocation MacroArgExpandedLoc = I->second; + if (MacroArgExpandedLoc.isValid()) + return MacroArgExpandedLoc.getLocWithOffset(Offset - MacroArgBeginOffs); + + return Loc; +} + +std::pair<FileID, unsigned> +SourceManager::getDecomposedIncludedLoc(FileID FID) const { + if (FID.isInvalid()) + return std::make_pair(FileID(), 0); + + // Uses IncludedLocMap to retrieve/cache the decomposed loc. + + using DecompTy = std::pair<FileID, unsigned>; + auto InsertOp = IncludedLocMap.try_emplace(FID); + DecompTy &DecompLoc = InsertOp.first->second; + if (!InsertOp.second) + return DecompLoc; // already in map. + + SourceLocation UpperLoc; + bool Invalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid); + if (!Invalid) { + if (Entry.isExpansion()) + UpperLoc = Entry.getExpansion().getExpansionLocStart(); + else + UpperLoc = Entry.getFile().getIncludeLoc(); + } + + if (UpperLoc.isValid()) + DecompLoc = getDecomposedLoc(UpperLoc); + + return DecompLoc; +} + +/// Given a decomposed source location, move it up the include/expansion stack +/// to the parent source location. If this is possible, return the decomposed +/// version of the parent in Loc and return false. If Loc is the top-level +/// entry, return true and don't modify it. +static bool MoveUpIncludeHierarchy(std::pair<FileID, unsigned> &Loc, + const SourceManager &SM) { + std::pair<FileID, unsigned> UpperLoc = SM.getDecomposedIncludedLoc(Loc.first); + if (UpperLoc.first.isInvalid()) + return true; // We reached the top. + + Loc = UpperLoc; + return false; +} + +/// Return the cache entry for comparing the given file IDs +/// for isBeforeInTranslationUnit. +InBeforeInTUCacheEntry &SourceManager::getInBeforeInTUCache(FileID LFID, + FileID RFID) const { + // This is a magic number for limiting the cache size. It was experimentally + // derived from a small Objective-C project (where the cache filled + // out to ~250 items). We can make it larger if necessary. + enum { MagicCacheSize = 300 }; + IsBeforeInTUCacheKey Key(LFID, RFID); + + // If the cache size isn't too large, do a lookup and if necessary default + // construct an entry. We can then return it to the caller for direct + // use. When they update the value, the cache will get automatically + // updated as well. + if (IBTUCache.size() < MagicCacheSize) + return IBTUCache[Key]; + + // Otherwise, do a lookup that will not construct a new value. + InBeforeInTUCache::iterator I = IBTUCache.find(Key); + if (I != IBTUCache.end()) + return I->second; + + // Fall back to the overflow value. + return IBTUCacheOverflow; +} + +/// Determines the order of 2 source locations in the translation unit. +/// +/// \returns true if LHS source location comes before RHS, false otherwise. +bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, + SourceLocation RHS) const { + assert(LHS.isValid() && RHS.isValid() && "Passed invalid source location!"); + if (LHS == RHS) + return false; + + std::pair<FileID, unsigned> LOffs = getDecomposedLoc(LHS); + std::pair<FileID, unsigned> ROffs = getDecomposedLoc(RHS); + + // getDecomposedLoc may have failed to return a valid FileID because, e.g. it + // is a serialized one referring to a file that was removed after we loaded + // the PCH. + if (LOffs.first.isInvalid() || ROffs.first.isInvalid()) + return LOffs.first.isInvalid() && !ROffs.first.isInvalid(); + + std::pair<bool, bool> InSameTU = isInTheSameTranslationUnit(LOffs, ROffs); + if (InSameTU.first) + return InSameTU.second; + + // If we arrived here, the location is either in a built-ins buffer or + // associated with global inline asm. PR5662 and PR22576 are examples. + + StringRef LB = getBufferOrFake(LOffs.first).getBufferIdentifier(); + StringRef RB = getBufferOrFake(ROffs.first).getBufferIdentifier(); + bool LIsBuiltins = LB == "<built-in>"; + bool RIsBuiltins = RB == "<built-in>"; + // Sort built-in before non-built-in. + if (LIsBuiltins || RIsBuiltins) { + if (LIsBuiltins != RIsBuiltins) + return LIsBuiltins; + // Both are in built-in buffers, but from different files. We just claim that + // lower IDs come first. + return LOffs.first < ROffs.first; + } + bool LIsAsm = LB == "<inline asm>"; + bool RIsAsm = RB == "<inline asm>"; + // Sort assembler after built-ins, but before the rest. + if (LIsAsm || RIsAsm) { + if (LIsAsm != RIsAsm) + return RIsAsm; + assert(LOffs.first == ROffs.first); + return false; + } + bool LIsScratch = LB == "<scratch space>"; + bool RIsScratch = RB == "<scratch space>"; + // Sort scratch after inline asm, but before the rest. + if (LIsScratch || RIsScratch) { + if (LIsScratch != RIsScratch) + return LIsScratch; + return LOffs.second < ROffs.second; + } + llvm_unreachable("Unsortable locations found"); +} + +std::pair<bool, bool> SourceManager::isInTheSameTranslationUnit( + std::pair<FileID, unsigned> &LOffs, + std::pair<FileID, unsigned> &ROffs) const { + // If the source locations are in the same file, just compare offsets. + if (LOffs.first == ROffs.first) + return std::make_pair(true, LOffs.second < ROffs.second); + + // If we are comparing a source location with multiple locations in the same + // file, we get a big win by caching the result. + InBeforeInTUCacheEntry &IsBeforeInTUCache = + getInBeforeInTUCache(LOffs.first, ROffs.first); + + // If we are comparing a source location with multiple locations in the same + // file, we get a big win by caching the result. + if (IsBeforeInTUCache.isCacheValid(LOffs.first, ROffs.first)) + return std::make_pair( + true, IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second)); + + // Okay, we missed in the cache, start updating the cache for this query. + IsBeforeInTUCache.setQueryFIDs(LOffs.first, ROffs.first, + /*isLFIDBeforeRFID=*/LOffs.first.ID < ROffs.first.ID); + + // We need to find the common ancestor. The only way of doing this is to + // build the complete include chain for one and then walking up the chain + // of the other looking for a match. + // We use a map from FileID to Offset to store the chain. Easier than writing + // a custom set hash info that only depends on the first part of a pair. + using LocSet = llvm::SmallDenseMap<FileID, unsigned, 16>; + LocSet LChain; + do { + LChain.insert(LOffs); + // We catch the case where LOffs is in a file included by ROffs and + // quit early. The other way round unfortunately remains suboptimal. + } while (LOffs.first != ROffs.first && !MoveUpIncludeHierarchy(LOffs, *this)); + LocSet::iterator I; + while((I = LChain.find(ROffs.first)) == LChain.end()) { + if (MoveUpIncludeHierarchy(ROffs, *this)) + break; // Met at topmost file. + } + if (I != LChain.end()) + LOffs = *I; + + // If we exited because we found a nearest common ancestor, compare the + // locations within the common file and cache them. + if (LOffs.first == ROffs.first) { + IsBeforeInTUCache.setCommonLoc(LOffs.first, LOffs.second, ROffs.second); + return std::make_pair( + true, IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second)); + } + // Clear the lookup cache, it depends on a common location. + IsBeforeInTUCache.clear(); + return std::make_pair(false, false); +} + +void SourceManager::PrintStats() const { + llvm::errs() << "\n*** Source Manager Stats:\n"; + llvm::errs() << FileInfos.size() << " files mapped, " << MemBufferInfos.size() + << " mem buffers mapped.\n"; + llvm::errs() << LocalSLocEntryTable.size() << " local SLocEntry's allocated (" + << llvm::capacity_in_bytes(LocalSLocEntryTable) + << " bytes of capacity), " + << NextLocalOffset << "B of Sloc address space used.\n"; + llvm::errs() << LoadedSLocEntryTable.size() + << " loaded SLocEntries allocated, " + << MaxLoadedOffset - CurrentLoadedOffset + << "B of Sloc address space used.\n"; + + unsigned NumLineNumsComputed = 0; + unsigned NumFileBytesMapped = 0; + for (fileinfo_iterator I = fileinfo_begin(), E = fileinfo_end(); I != E; ++I){ + NumLineNumsComputed += bool(I->second->SourceLineCache); + NumFileBytesMapped += I->second->getSizeBytesMapped(); + } + unsigned NumMacroArgsComputed = MacroArgsCacheMap.size(); + + llvm::errs() << NumFileBytesMapped << " bytes of files mapped, " + << NumLineNumsComputed << " files with line #'s computed, " + << NumMacroArgsComputed << " files with macro args computed.\n"; + llvm::errs() << "FileID scans: " << NumLinearScans << " linear, " + << NumBinaryProbes << " binary.\n"; +} + +LLVM_DUMP_METHOD void SourceManager::dump() const { + llvm::raw_ostream &out = llvm::errs(); + + auto DumpSLocEntry = [&](int ID, const SrcMgr::SLocEntry &Entry, + llvm::Optional<SourceLocation::UIntTy> NextStart) { + out << "SLocEntry <FileID " << ID << "> " << (Entry.isFile() ? "file" : "expansion") + << " <SourceLocation " << Entry.getOffset() << ":"; + if (NextStart) + out << *NextStart << ">\n"; + else + out << "???\?>\n"; + if (Entry.isFile()) { + auto &FI = Entry.getFile(); + if (FI.NumCreatedFIDs) + out << " covers <FileID " << ID << ":" << int(ID + FI.NumCreatedFIDs) + << ">\n"; + if (FI.getIncludeLoc().isValid()) + out << " included from " << FI.getIncludeLoc().getOffset() << "\n"; + auto &CC = FI.getContentCache(); + out << " for " << (CC.OrigEntry ? CC.OrigEntry->getName() : "<none>") + << "\n"; + if (CC.BufferOverridden) + out << " contents overridden\n"; + if (CC.ContentsEntry != CC.OrigEntry) { + out << " contents from " + << (CC.ContentsEntry ? CC.ContentsEntry->getName() : "<none>") + << "\n"; + } + } else { + auto &EI = Entry.getExpansion(); + out << " spelling from " << EI.getSpellingLoc().getOffset() << "\n"; + out << " macro " << (EI.isMacroArgExpansion() ? "arg" : "body") + << " range <" << EI.getExpansionLocStart().getOffset() << ":" + << EI.getExpansionLocEnd().getOffset() << ">\n"; + } + }; + + // Dump local SLocEntries. + for (unsigned ID = 0, NumIDs = LocalSLocEntryTable.size(); ID != NumIDs; ++ID) { + DumpSLocEntry(ID, LocalSLocEntryTable[ID], + ID == NumIDs - 1 ? NextLocalOffset + : LocalSLocEntryTable[ID + 1].getOffset()); + } + // Dump loaded SLocEntries. + llvm::Optional<SourceLocation::UIntTy> NextStart; + for (unsigned Index = 0; Index != LoadedSLocEntryTable.size(); ++Index) { + int ID = -(int)Index - 2; + if (SLocEntryLoaded[Index]) { + DumpSLocEntry(ID, LoadedSLocEntryTable[Index], NextStart); + NextStart = LoadedSLocEntryTable[Index].getOffset(); + } else { + NextStart = None; + } + } +} + +ExternalSLocEntrySource::~ExternalSLocEntrySource() = default; + +/// Return the amount of memory used by memory buffers, breaking down +/// by heap-backed versus mmap'ed memory. +SourceManager::MemoryBufferSizes SourceManager::getMemoryBufferSizes() const { + size_t malloc_bytes = 0; + size_t mmap_bytes = 0; + + for (unsigned i = 0, e = MemBufferInfos.size(); i != e; ++i) + if (size_t sized_mapped = MemBufferInfos[i]->getSizeBytesMapped()) + switch (MemBufferInfos[i]->getMemoryBufferKind()) { + case llvm::MemoryBuffer::MemoryBuffer_MMap: + mmap_bytes += sized_mapped; + break; + case llvm::MemoryBuffer::MemoryBuffer_Malloc: + malloc_bytes += sized_mapped; + break; + } + + return MemoryBufferSizes(malloc_bytes, mmap_bytes); +} + +size_t SourceManager::getDataStructureSizes() const { + size_t size = llvm::capacity_in_bytes(MemBufferInfos) + + llvm::capacity_in_bytes(LocalSLocEntryTable) + + llvm::capacity_in_bytes(LoadedSLocEntryTable) + + llvm::capacity_in_bytes(SLocEntryLoaded) + + llvm::capacity_in_bytes(FileInfos); + + if (OverriddenFilesInfo) + size += llvm::capacity_in_bytes(OverriddenFilesInfo->OverriddenFiles); + + return size; +} + +SourceManagerForFile::SourceManagerForFile(StringRef FileName, + StringRef Content) { + // This is referenced by `FileMgr` and will be released by `FileMgr` when it + // is deleted. + IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( + new llvm::vfs::InMemoryFileSystem); + InMemoryFileSystem->addFile( + FileName, 0, + llvm::MemoryBuffer::getMemBuffer(Content, FileName, + /*RequiresNullTerminator=*/false)); + // This is passed to `SM` as reference, so the pointer has to be referenced + // in `Environment` so that `FileMgr` can out-live this function scope. + FileMgr = + std::make_unique<FileManager>(FileSystemOptions(), InMemoryFileSystem); + // This is passed to `SM` as reference, so the pointer has to be referenced + // by `Environment` due to the same reason above. + Diagnostics = std::make_unique<DiagnosticsEngine>( + IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), + new DiagnosticOptions); + SourceMgr = std::make_unique<SourceManager>(*Diagnostics, *FileMgr); + FileID ID = SourceMgr->createFileID(*FileMgr->getFile(FileName), + SourceLocation(), clang::SrcMgr::C_User); + assert(ID.isValid()); + SourceMgr->setMainFileID(ID); +} diff --git a/contrib/llvm-project/clang/lib/Basic/Stack.cpp b/contrib/llvm-project/clang/lib/Basic/Stack.cpp new file mode 100644 index 000000000000..5e4750931500 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Stack.cpp @@ -0,0 +1,75 @@ +//===--- Stack.cpp - Utilities for dealing with stack space ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Defines utilities for dealing with stack allocation and stack space. +/// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Stack.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Support/CrashRecoveryContext.h" + +#ifdef _MSC_VER +#include <intrin.h> // for _AddressOfReturnAddress +#endif + +static LLVM_THREAD_LOCAL void *BottomOfStack = nullptr; + +static void *getStackPointer() { +#if __GNUC__ || __has_builtin(__builtin_frame_address) + return __builtin_frame_address(0); +#elif defined(_MSC_VER) + return _AddressOfReturnAddress(); +#else + char CharOnStack = 0; + // The volatile store here is intended to escape the local variable, to + // prevent the compiler from optimizing CharOnStack into anything other + // than a char on the stack. + // + // Tested on: MSVC 2015 - 2019, GCC 4.9 - 9, Clang 3.2 - 9, ICC 13 - 19. + char *volatile Ptr = &CharOnStack; + return Ptr; +#endif +} + +void clang::noteBottomOfStack() { + if (!BottomOfStack) + BottomOfStack = getStackPointer(); +} + +bool clang::isStackNearlyExhausted() { + // We consider 256 KiB to be sufficient for any code that runs between checks + // for stack size. + constexpr size_t SufficientStack = 256 << 10; + + // If we don't know where the bottom of the stack is, hope for the best. + if (!BottomOfStack) + return false; + + intptr_t StackDiff = (intptr_t)getStackPointer() - (intptr_t)BottomOfStack; + size_t StackUsage = (size_t)std::abs(StackDiff); + + // If the stack pointer has a surprising value, we do not understand this + // stack usage scheme. (Perhaps the target allocates new stack regions on + // demand for us.) Don't try to guess what's going on. + if (StackUsage > DesiredStackSize) + return false; + + return StackUsage >= DesiredStackSize - SufficientStack; +} + +void clang::runWithSufficientStackSpaceSlow(llvm::function_ref<void()> Diag, + llvm::function_ref<void()> Fn) { + llvm::CrashRecoveryContext CRC; + CRC.RunSafelyOnThread([&] { + noteBottomOfStack(); + Diag(); + Fn(); + }, DesiredStackSize); +} diff --git a/contrib/llvm-project/clang/lib/Basic/TargetID.cpp b/contrib/llvm-project/clang/lib/Basic/TargetID.cpp new file mode 100644 index 000000000000..3b8f4c13b9bf --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/TargetID.cpp @@ -0,0 +1,169 @@ +//===--- TargetID.cpp - Utilities for parsing target ID -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/TargetID.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/TargetParser.h" +#include "llvm/Support/raw_ostream.h" +#include <map> + +namespace clang { + +static llvm::SmallVector<llvm::StringRef, 4> +getAllPossibleAMDGPUTargetIDFeatures(const llvm::Triple &T, + llvm::StringRef Proc) { + // Entries in returned vector should be in alphabetical order. + llvm::SmallVector<llvm::StringRef, 4> Ret; + auto ProcKind = T.isAMDGCN() ? llvm::AMDGPU::parseArchAMDGCN(Proc) + : llvm::AMDGPU::parseArchR600(Proc); + if (ProcKind == llvm::AMDGPU::GK_NONE) + return Ret; + auto Features = T.isAMDGCN() ? llvm::AMDGPU::getArchAttrAMDGCN(ProcKind) + : llvm::AMDGPU::getArchAttrR600(ProcKind); + if (Features & llvm::AMDGPU::FEATURE_SRAMECC) + Ret.push_back("sramecc"); + if (Features & llvm::AMDGPU::FEATURE_XNACK) + Ret.push_back("xnack"); + return Ret; +} + +llvm::SmallVector<llvm::StringRef, 4> +getAllPossibleTargetIDFeatures(const llvm::Triple &T, + llvm::StringRef Processor) { + llvm::SmallVector<llvm::StringRef, 4> Ret; + if (T.isAMDGPU()) + return getAllPossibleAMDGPUTargetIDFeatures(T, Processor); + return Ret; +} + +/// Returns canonical processor name or empty string if \p Processor is invalid. +static llvm::StringRef getCanonicalProcessorName(const llvm::Triple &T, + llvm::StringRef Processor) { + if (T.isAMDGPU()) + return llvm::AMDGPU::getCanonicalArchName(T, Processor); + return Processor; +} + +llvm::StringRef getProcessorFromTargetID(const llvm::Triple &T, + llvm::StringRef TargetID) { + auto Split = TargetID.split(':'); + return getCanonicalProcessorName(T, Split.first); +} + +// Parse a target ID with format checking only. Do not check whether processor +// name or features are valid for the processor. +// +// A target ID is a processor name followed by a list of target features +// delimited by colon. Each target feature is a string post-fixed by a plus +// or minus sign, e.g. gfx908:sramecc+:xnack-. +static llvm::Optional<llvm::StringRef> +parseTargetIDWithFormatCheckingOnly(llvm::StringRef TargetID, + llvm::StringMap<bool> *FeatureMap) { + llvm::StringRef Processor; + + if (TargetID.empty()) + return llvm::StringRef(); + + auto Split = TargetID.split(':'); + Processor = Split.first; + if (Processor.empty()) + return llvm::None; + + auto Features = Split.second; + if (Features.empty()) + return Processor; + + llvm::StringMap<bool> LocalFeatureMap; + if (!FeatureMap) + FeatureMap = &LocalFeatureMap; + + while (!Features.empty()) { + auto Splits = Features.split(':'); + auto Sign = Splits.first.back(); + auto Feature = Splits.first.drop_back(); + if (Sign != '+' && Sign != '-') + return llvm::None; + bool IsOn = Sign == '+'; + auto Loc = FeatureMap->find(Feature); + // Each feature can only show up at most once in target ID. + if (Loc != FeatureMap->end()) + return llvm::None; + (*FeatureMap)[Feature] = IsOn; + Features = Splits.second; + } + return Processor; +} + +llvm::Optional<llvm::StringRef> +parseTargetID(const llvm::Triple &T, llvm::StringRef TargetID, + llvm::StringMap<bool> *FeatureMap) { + auto OptionalProcessor = + parseTargetIDWithFormatCheckingOnly(TargetID, FeatureMap); + + if (!OptionalProcessor) + return llvm::None; + + llvm::StringRef Processor = + getCanonicalProcessorName(T, OptionalProcessor.getValue()); + if (Processor.empty()) + return llvm::None; + + llvm::SmallSet<llvm::StringRef, 4> AllFeatures; + for (auto &&F : getAllPossibleTargetIDFeatures(T, Processor)) + AllFeatures.insert(F); + + for (auto &&F : *FeatureMap) + if (!AllFeatures.count(F.first())) + return llvm::None; + + return Processor; +} + +// A canonical target ID is a target ID containing a canonical processor name +// and features in alphabetical order. +std::string getCanonicalTargetID(llvm::StringRef Processor, + const llvm::StringMap<bool> &Features) { + std::string TargetID = Processor.str(); + std::map<const llvm::StringRef, bool> OrderedMap; + for (const auto &F : Features) + OrderedMap[F.first()] = F.second; + for (auto F : OrderedMap) + TargetID = TargetID + ':' + F.first.str() + (F.second ? "+" : "-"); + return TargetID; +} + +// For a specific processor, a feature either shows up in all target IDs, or +// does not show up in any target IDs. Otherwise the target ID combination +// is invalid. +llvm::Optional<std::pair<llvm::StringRef, llvm::StringRef>> +getConflictTargetIDCombination(const std::set<llvm::StringRef> &TargetIDs) { + struct Info { + llvm::StringRef TargetID; + llvm::StringMap<bool> Features; + }; + llvm::StringMap<Info> FeatureMap; + for (auto &&ID : TargetIDs) { + llvm::StringMap<bool> Features; + llvm::StringRef Proc = + parseTargetIDWithFormatCheckingOnly(ID, &Features).getValue(); + auto Loc = FeatureMap.find(Proc); + if (Loc == FeatureMap.end()) + FeatureMap[Proc] = Info{ID, Features}; + else { + auto &ExistingFeatures = Loc->second.Features; + if (llvm::any_of(Features, [&](auto &F) { + return ExistingFeatures.count(F.first()) == 0; + })) + return std::make_pair(Loc->second.TargetID, ID); + } + } + return llvm::None; +} + +} // namespace clang diff --git a/contrib/llvm-project/clang/lib/Basic/TargetInfo.cpp b/contrib/llvm-project/clang/lib/Basic/TargetInfo.cpp new file mode 100644 index 000000000000..e3a2f30febe7 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/TargetInfo.cpp @@ -0,0 +1,888 @@ +//===--- TargetInfo.cpp - Information about Target machine ----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the TargetInfo and TargetInfoImpl interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LangOptions.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetParser.h" +#include <cstdlib> +using namespace clang; + +static const LangASMap DefaultAddrSpaceMap = {0}; + +// TargetInfo Constructor. +TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) { + // Set defaults. Defaults are set for a 32-bit RISC platform, like PPC or + // SPARC. These should be overridden by concrete targets as needed. + BigEndian = !T.isLittleEndian(); + TLSSupported = true; + VLASupported = true; + NoAsmVariants = false; + HasLegalHalfType = false; + HasFloat128 = false; + HasIbm128 = false; + HasFloat16 = false; + HasBFloat16 = false; + HasLongDouble = true; + HasFPReturn = true; + HasStrictFP = false; + PointerWidth = PointerAlign = 32; + BoolWidth = BoolAlign = 8; + IntWidth = IntAlign = 32; + LongWidth = LongAlign = 32; + LongLongWidth = LongLongAlign = 64; + + // Fixed point default bit widths + ShortAccumWidth = ShortAccumAlign = 16; + AccumWidth = AccumAlign = 32; + LongAccumWidth = LongAccumAlign = 64; + ShortFractWidth = ShortFractAlign = 8; + FractWidth = FractAlign = 16; + LongFractWidth = LongFractAlign = 32; + + // Fixed point default integral and fractional bit sizes + // We give the _Accum 1 fewer fractional bits than their corresponding _Fract + // types by default to have the same number of fractional bits between _Accum + // and _Fract types. + PaddingOnUnsignedFixedPoint = false; + ShortAccumScale = 7; + AccumScale = 15; + LongAccumScale = 31; + + SuitableAlign = 64; + DefaultAlignForAttributeAligned = 128; + MinGlobalAlign = 0; + // From the glibc documentation, on GNU systems, malloc guarantees 16-byte + // alignment on 64-bit systems and 8-byte alignment on 32-bit systems. See + // https://www.gnu.org/software/libc/manual/html_node/Malloc-Examples.html. + // This alignment guarantee also applies to Windows and Android. On Darwin, + // the alignment is 16 bytes on both 64-bit and 32-bit systems. + if (T.isGNUEnvironment() || T.isWindowsMSVCEnvironment() || T.isAndroid()) + NewAlign = Triple.isArch64Bit() ? 128 : Triple.isArch32Bit() ? 64 : 0; + else if (T.isOSDarwin()) + NewAlign = 128; + else + NewAlign = 0; // Infer from basic type alignment. + HalfWidth = 16; + HalfAlign = 16; + FloatWidth = 32; + FloatAlign = 32; + DoubleWidth = 64; + DoubleAlign = 64; + LongDoubleWidth = 64; + LongDoubleAlign = 64; + Float128Align = 128; + Ibm128Align = 128; + LargeArrayMinWidth = 0; + LargeArrayAlign = 0; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 0; + MaxVectorAlign = 0; + MaxTLSAlign = 0; + SimdDefaultAlign = 0; + SizeType = UnsignedLong; + PtrDiffType = SignedLong; + IntMaxType = SignedLongLong; + IntPtrType = SignedLong; + WCharType = SignedInt; + WIntType = SignedInt; + Char16Type = UnsignedShort; + Char32Type = UnsignedInt; + Int64Type = SignedLongLong; + Int16Type = SignedShort; + SigAtomicType = SignedInt; + ProcessIDType = SignedInt; + UseSignedCharForObjCBool = true; + UseBitFieldTypeAlignment = true; + UseZeroLengthBitfieldAlignment = false; + UseLeadingZeroLengthBitfield = true; + UseExplicitBitFieldAlignment = true; + ZeroLengthBitfieldBoundary = 0; + MaxAlignedAttribute = 0; + HalfFormat = &llvm::APFloat::IEEEhalf(); + FloatFormat = &llvm::APFloat::IEEEsingle(); + DoubleFormat = &llvm::APFloat::IEEEdouble(); + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + Float128Format = &llvm::APFloat::IEEEquad(); + Ibm128Format = &llvm::APFloat::PPCDoubleDouble(); + MCountName = "mcount"; + UserLabelPrefix = "_"; + RegParmMax = 0; + SSERegParmMax = 0; + HasAlignMac68kSupport = false; + HasBuiltinMSVaList = false; + IsRenderScriptTarget = false; + HasAArch64SVETypes = false; + HasRISCVVTypes = false; + AllowAMDGPUUnsafeFPAtomics = false; + ARMCDECoprocMask = 0; + + // Default to no types using fpret. + RealTypeUsesObjCFPRet = 0; + + // Default to not using fp2ret for __Complex long double + ComplexLongDoubleUsesFP2Ret = false; + + // Set the C++ ABI based on the triple. + TheCXXABI.set(Triple.isKnownWindowsMSVCEnvironment() + ? TargetCXXABI::Microsoft + : TargetCXXABI::GenericItanium); + + // Default to an empty address space map. + AddrSpaceMap = &DefaultAddrSpaceMap; + UseAddrSpaceMapMangling = false; + + // Default to an unknown platform name. + PlatformName = "unknown"; + PlatformMinVersion = VersionTuple(); + + MaxOpenCLWorkGroupSize = 1024; + ProgramAddrSpace = 0; +} + +// Out of line virtual dtor for TargetInfo. +TargetInfo::~TargetInfo() {} + +void TargetInfo::resetDataLayout(StringRef DL, const char *ULP) { + DataLayoutString = DL.str(); + UserLabelPrefix = ULP; +} + +bool +TargetInfo::checkCFProtectionBranchSupported(DiagnosticsEngine &Diags) const { + Diags.Report(diag::err_opt_not_valid_on_target) << "cf-protection=branch"; + return false; +} + +bool +TargetInfo::checkCFProtectionReturnSupported(DiagnosticsEngine &Diags) const { + Diags.Report(diag::err_opt_not_valid_on_target) << "cf-protection=return"; + return false; +} + +/// getTypeName - Return the user string for the specified integer type enum. +/// For example, SignedShort -> "short". +const char *TargetInfo::getTypeName(IntType T) { + switch (T) { + default: llvm_unreachable("not an integer!"); + case SignedChar: return "signed char"; + case UnsignedChar: return "unsigned char"; + case SignedShort: return "short"; + case UnsignedShort: return "unsigned short"; + case SignedInt: return "int"; + case UnsignedInt: return "unsigned int"; + case SignedLong: return "long int"; + case UnsignedLong: return "long unsigned int"; + case SignedLongLong: return "long long int"; + case UnsignedLongLong: return "long long unsigned int"; + } +} + +/// getTypeConstantSuffix - Return the constant suffix for the specified +/// integer type enum. For example, SignedLong -> "L". +const char *TargetInfo::getTypeConstantSuffix(IntType T) const { + switch (T) { + default: llvm_unreachable("not an integer!"); + case SignedChar: + case SignedShort: + case SignedInt: return ""; + case SignedLong: return "L"; + case SignedLongLong: return "LL"; + case UnsignedChar: + if (getCharWidth() < getIntWidth()) + return ""; + LLVM_FALLTHROUGH; + case UnsignedShort: + if (getShortWidth() < getIntWidth()) + return ""; + LLVM_FALLTHROUGH; + case UnsignedInt: return "U"; + case UnsignedLong: return "UL"; + case UnsignedLongLong: return "ULL"; + } +} + +/// getTypeFormatModifier - Return the printf format modifier for the +/// specified integer type enum. For example, SignedLong -> "l". + +const char *TargetInfo::getTypeFormatModifier(IntType T) { + switch (T) { + default: llvm_unreachable("not an integer!"); + case SignedChar: + case UnsignedChar: return "hh"; + case SignedShort: + case UnsignedShort: return "h"; + case SignedInt: + case UnsignedInt: return ""; + case SignedLong: + case UnsignedLong: return "l"; + case SignedLongLong: + case UnsignedLongLong: return "ll"; + } +} + +/// getTypeWidth - Return the width (in bits) of the specified integer type +/// enum. For example, SignedInt -> getIntWidth(). +unsigned TargetInfo::getTypeWidth(IntType T) const { + switch (T) { + default: llvm_unreachable("not an integer!"); + case SignedChar: + case UnsignedChar: return getCharWidth(); + case SignedShort: + case UnsignedShort: return getShortWidth(); + case SignedInt: + case UnsignedInt: return getIntWidth(); + case SignedLong: + case UnsignedLong: return getLongWidth(); + case SignedLongLong: + case UnsignedLongLong: return getLongLongWidth(); + }; +} + +TargetInfo::IntType TargetInfo::getIntTypeByWidth( + unsigned BitWidth, bool IsSigned) const { + if (getCharWidth() == BitWidth) + return IsSigned ? SignedChar : UnsignedChar; + if (getShortWidth() == BitWidth) + return IsSigned ? SignedShort : UnsignedShort; + if (getIntWidth() == BitWidth) + return IsSigned ? SignedInt : UnsignedInt; + if (getLongWidth() == BitWidth) + return IsSigned ? SignedLong : UnsignedLong; + if (getLongLongWidth() == BitWidth) + return IsSigned ? SignedLongLong : UnsignedLongLong; + return NoInt; +} + +TargetInfo::IntType TargetInfo::getLeastIntTypeByWidth(unsigned BitWidth, + bool IsSigned) const { + if (getCharWidth() >= BitWidth) + return IsSigned ? SignedChar : UnsignedChar; + if (getShortWidth() >= BitWidth) + return IsSigned ? SignedShort : UnsignedShort; + if (getIntWidth() >= BitWidth) + return IsSigned ? SignedInt : UnsignedInt; + if (getLongWidth() >= BitWidth) + return IsSigned ? SignedLong : UnsignedLong; + if (getLongLongWidth() >= BitWidth) + return IsSigned ? SignedLongLong : UnsignedLongLong; + return NoInt; +} + +FloatModeKind TargetInfo::getRealTypeByWidth(unsigned BitWidth, + FloatModeKind ExplicitType) const { + if (getFloatWidth() == BitWidth) + return FloatModeKind::Float; + if (getDoubleWidth() == BitWidth) + return FloatModeKind::Double; + + switch (BitWidth) { + case 96: + if (&getLongDoubleFormat() == &llvm::APFloat::x87DoubleExtended()) + return FloatModeKind::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 (ExplicitType == FloatModeKind::Float128) + return hasFloat128Type() ? FloatModeKind::Float128 + : FloatModeKind::NoFloat; + if (ExplicitType == FloatModeKind::Ibm128) + return hasIbm128Type() ? FloatModeKind::Ibm128 + : FloatModeKind::NoFloat; + if (&getLongDoubleFormat() == &llvm::APFloat::PPCDoubleDouble() || + &getLongDoubleFormat() == &llvm::APFloat::IEEEquad()) + return FloatModeKind::LongDouble; + if (hasFloat128Type()) + return FloatModeKind::Float128; + break; + } + + return FloatModeKind::NoFloat; +} + +/// getTypeAlign - Return the alignment (in bits) of the specified integer type +/// enum. For example, SignedInt -> getIntAlign(). +unsigned TargetInfo::getTypeAlign(IntType T) const { + switch (T) { + default: llvm_unreachable("not an integer!"); + case SignedChar: + case UnsignedChar: return getCharAlign(); + case SignedShort: + case UnsignedShort: return getShortAlign(); + case SignedInt: + case UnsignedInt: return getIntAlign(); + case SignedLong: + case UnsignedLong: return getLongAlign(); + case SignedLongLong: + case UnsignedLongLong: return getLongLongAlign(); + }; +} + +/// isTypeSigned - Return whether an integer types is signed. Returns true if +/// the type is signed; false otherwise. +bool TargetInfo::isTypeSigned(IntType T) { + switch (T) { + default: llvm_unreachable("not an integer!"); + case SignedChar: + case SignedShort: + case SignedInt: + case SignedLong: + case SignedLongLong: + return true; + case UnsignedChar: + case UnsignedShort: + case UnsignedInt: + case UnsignedLong: + case UnsignedLongLong: + return false; + }; +} + +/// adjust - Set forced language options. +/// Apply changes to the target information with respect to certain +/// language options which change the target configuration and adjust +/// the language based on the target options where applicable. +void TargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) { + if (Opts.NoBitFieldTypeAlign) + UseBitFieldTypeAlignment = false; + + switch (Opts.WCharSize) { + default: llvm_unreachable("invalid wchar_t width"); + case 0: break; + case 1: WCharType = Opts.WCharIsSigned ? SignedChar : UnsignedChar; break; + case 2: WCharType = Opts.WCharIsSigned ? SignedShort : UnsignedShort; break; + case 4: WCharType = Opts.WCharIsSigned ? SignedInt : UnsignedInt; break; + } + + if (Opts.AlignDouble) { + DoubleAlign = LongLongAlign = 64; + LongDoubleAlign = 64; + } + + if (Opts.OpenCL) { + // OpenCL C requires specific widths for types, irrespective of + // what these normally are for the target. + // We also define long long and long double here, although the + // OpenCL standard only mentions these as "reserved". + IntWidth = IntAlign = 32; + LongWidth = LongAlign = 64; + LongLongWidth = LongLongAlign = 128; + HalfWidth = HalfAlign = 16; + FloatWidth = FloatAlign = 32; + + // Embedded 32-bit targets (OpenCL EP) might have double C type + // defined as float. Let's not override this as it might lead + // to generating illegal code that uses 64bit doubles. + if (DoubleWidth != FloatWidth) { + DoubleWidth = DoubleAlign = 64; + DoubleFormat = &llvm::APFloat::IEEEdouble(); + } + LongDoubleWidth = LongDoubleAlign = 128; + + unsigned MaxPointerWidth = getMaxPointerWidth(); + assert(MaxPointerWidth == 32 || MaxPointerWidth == 64); + bool Is32BitArch = MaxPointerWidth == 32; + SizeType = Is32BitArch ? UnsignedInt : UnsignedLong; + PtrDiffType = Is32BitArch ? SignedInt : SignedLong; + IntPtrType = Is32BitArch ? SignedInt : SignedLong; + + IntMaxType = SignedLongLong; + Int64Type = SignedLong; + + HalfFormat = &llvm::APFloat::IEEEhalf(); + FloatFormat = &llvm::APFloat::IEEEsingle(); + LongDoubleFormat = &llvm::APFloat::IEEEquad(); + + // OpenCL C v3.0 s6.7.5 - The generic address space requires support for + // OpenCL C 2.0 or OpenCL C 3.0 with the __opencl_c_generic_address_space + // feature + // OpenCL C v3.0 s6.2.1 - OpenCL pipes require support of OpenCL C 2.0 + // or later and __opencl_c_pipes feature + // FIXME: These language options are also defined in setLangDefaults() + // for OpenCL C 2.0 but with no access to target capabilities. Target + // should be immutable once created and thus these language options need + // to be defined only once. + if (Opts.getOpenCLCompatibleVersion() == 300) { + const auto &OpenCLFeaturesMap = getSupportedOpenCLOpts(); + Opts.OpenCLGenericAddressSpace = hasFeatureEnabled( + OpenCLFeaturesMap, "__opencl_c_generic_address_space"); + Opts.OpenCLPipes = + hasFeatureEnabled(OpenCLFeaturesMap, "__opencl_c_pipes"); + Opts.Blocks = + hasFeatureEnabled(OpenCLFeaturesMap, "__opencl_c_device_enqueue"); + } + } + + if (Opts.DoubleSize) { + if (Opts.DoubleSize == 32) { + DoubleWidth = 32; + LongDoubleWidth = 32; + DoubleFormat = &llvm::APFloat::IEEEsingle(); + LongDoubleFormat = &llvm::APFloat::IEEEsingle(); + } else if (Opts.DoubleSize == 64) { + DoubleWidth = 64; + LongDoubleWidth = 64; + DoubleFormat = &llvm::APFloat::IEEEdouble(); + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + } + } + + if (Opts.LongDoubleSize) { + if (Opts.LongDoubleSize == DoubleWidth) { + LongDoubleWidth = DoubleWidth; + LongDoubleAlign = DoubleAlign; + LongDoubleFormat = DoubleFormat; + } else if (Opts.LongDoubleSize == 128) { + LongDoubleWidth = LongDoubleAlign = 128; + LongDoubleFormat = &llvm::APFloat::IEEEquad(); + } + } + + if (Opts.NewAlignOverride) + NewAlign = Opts.NewAlignOverride * getCharWidth(); + + // Each unsigned fixed point type has the same number of fractional bits as + // its corresponding signed type. + PaddingOnUnsignedFixedPoint |= Opts.PaddingOnUnsignedFixedPoint; + CheckFixedPointBits(); + + if (Opts.ProtectParens && !checkArithmeticFenceSupported()) { + Diags.Report(diag::err_opt_not_valid_on_target) << "-fprotect-parens"; + Opts.ProtectParens = false; + } +} + +bool TargetInfo::initFeatureMap( + llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, + const std::vector<std::string> &FeatureVec) const { + for (const auto &F : FeatureVec) { + StringRef Name = F; + // Apply the feature via the target. + bool Enabled = Name[0] == '+'; + setFeatureEnabled(Features, Name.substr(1), Enabled); + } + return true; +} + +TargetInfo::CallingConvKind +TargetInfo::getCallingConvKind(bool ClangABICompat4) const { + if (getCXXABI() != TargetCXXABI::Microsoft && + (ClangABICompat4 || getTriple().getOS() == llvm::Triple::PS4)) + return CCK_ClangABI4OrPS4; + return CCK_Default; +} + +LangAS TargetInfo::getOpenCLTypeAddrSpace(OpenCLTypeKind TK) const { + switch (TK) { + case OCLTK_Image: + case OCLTK_Pipe: + return LangAS::opencl_global; + + case OCLTK_Sampler: + return LangAS::opencl_constant; + + default: + return LangAS::Default; + } +} + +//===----------------------------------------------------------------------===// + + +static StringRef removeGCCRegisterPrefix(StringRef Name) { + if (Name[0] == '%' || Name[0] == '#') + Name = Name.substr(1); + + return Name; +} + +/// isValidClobber - Returns whether the passed in string is +/// a valid clobber in an inline asm statement. This is used by +/// Sema. +bool TargetInfo::isValidClobber(StringRef Name) const { + return (isValidGCCRegisterName(Name) || Name == "memory" || Name == "cc" || + Name == "unwind"); +} + +/// isValidGCCRegisterName - Returns whether the passed in string +/// is a valid register name according to GCC. This is used by Sema for +/// inline asm statements. +bool TargetInfo::isValidGCCRegisterName(StringRef Name) const { + if (Name.empty()) + return false; + + // Get rid of any register prefix. + Name = removeGCCRegisterPrefix(Name); + if (Name.empty()) + return false; + + ArrayRef<const char *> Names = getGCCRegNames(); + + // If we have a number it maps to an entry in the register name array. + if (isDigit(Name[0])) { + unsigned n; + if (!Name.getAsInteger(0, n)) + return n < Names.size(); + } + + // Check register names. + if (llvm::is_contained(Names, Name)) + return true; + + // Check any additional names that we have. + for (const AddlRegName &ARN : getGCCAddlRegNames()) + for (const char *AN : ARN.Names) { + if (!AN) + break; + // Make sure the register that the additional name is for is within + // the bounds of the register names from above. + if (AN == Name && ARN.RegNum < Names.size()) + return true; + } + + // Now check aliases. + for (const GCCRegAlias &GRA : getGCCRegAliases()) + for (const char *A : GRA.Aliases) { + if (!A) + break; + if (A == Name) + return true; + } + + return false; +} + +StringRef TargetInfo::getNormalizedGCCRegisterName(StringRef Name, + bool ReturnCanonical) const { + assert(isValidGCCRegisterName(Name) && "Invalid register passed in"); + + // Get rid of any register prefix. + Name = removeGCCRegisterPrefix(Name); + + ArrayRef<const char *> Names = getGCCRegNames(); + + // First, check if we have a number. + if (isDigit(Name[0])) { + unsigned n; + if (!Name.getAsInteger(0, n)) { + assert(n < Names.size() && "Out of bounds register number!"); + return Names[n]; + } + } + + // Check any additional names that we have. + for (const AddlRegName &ARN : getGCCAddlRegNames()) + for (const char *AN : ARN.Names) { + if (!AN) + break; + // Make sure the register that the additional name is for is within + // the bounds of the register names from above. + if (AN == Name && ARN.RegNum < Names.size()) + return ReturnCanonical ? Names[ARN.RegNum] : Name; + } + + // Now check aliases. + for (const GCCRegAlias &RA : getGCCRegAliases()) + for (const char *A : RA.Aliases) { + if (!A) + break; + if (A == Name) + return RA.Register; + } + + return Name; +} + +bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const { + const char *Name = Info.getConstraintStr().c_str(); + // An output constraint must start with '=' or '+' + if (*Name != '=' && *Name != '+') + return false; + + if (*Name == '+') + Info.setIsReadWrite(); + + Name++; + while (*Name) { + switch (*Name) { + default: + if (!validateAsmConstraint(Name, Info)) { + // FIXME: We temporarily return false + // so we can add more constraints as we hit it. + // Eventually, an unknown constraint should just be treated as 'g'. + return false; + } + break; + case '&': // early clobber. + Info.setEarlyClobber(); + break; + case '%': // commutative. + // FIXME: Check that there is a another register after this one. + break; + case 'r': // general register. + Info.setAllowsRegister(); + break; + case 'm': // memory operand. + case 'o': // offsetable memory operand. + case 'V': // non-offsetable memory operand. + case '<': // autodecrement memory operand. + case '>': // autoincrement memory operand. + Info.setAllowsMemory(); + break; + case 'g': // general register, memory operand or immediate integer. + case 'X': // any operand. + Info.setAllowsRegister(); + Info.setAllowsMemory(); + break; + case ',': // multiple alternative constraint. Pass it. + // Handle additional optional '=' or '+' modifiers. + if (Name[1] == '=' || Name[1] == '+') + Name++; + break; + case '#': // Ignore as constraint. + while (Name[1] && Name[1] != ',') + Name++; + break; + case '?': // Disparage slightly code. + case '!': // Disparage severely. + case '*': // Ignore for choosing register preferences. + case 'i': // Ignore i,n,E,F as output constraints (match from the other + // chars) + case 'n': + case 'E': + case 'F': + break; // Pass them. + } + + Name++; + } + + // Early clobber with a read-write constraint which doesn't permit registers + // is invalid. + if (Info.earlyClobber() && Info.isReadWrite() && !Info.allowsRegister()) + return false; + + // If a constraint allows neither memory nor register operands it contains + // only modifiers. Reject it. + return Info.allowsMemory() || Info.allowsRegister(); +} + +bool TargetInfo::resolveSymbolicName(const char *&Name, + ArrayRef<ConstraintInfo> OutputConstraints, + unsigned &Index) const { + assert(*Name == '[' && "Symbolic name did not start with '['"); + Name++; + const char *Start = Name; + while (*Name && *Name != ']') + Name++; + + if (!*Name) { + // Missing ']' + return false; + } + + std::string SymbolicName(Start, Name - Start); + + for (Index = 0; Index != OutputConstraints.size(); ++Index) + if (SymbolicName == OutputConstraints[Index].getName()) + return true; + + return false; +} + +bool TargetInfo::validateInputConstraint( + MutableArrayRef<ConstraintInfo> OutputConstraints, + ConstraintInfo &Info) const { + const char *Name = Info.ConstraintStr.c_str(); + + if (!*Name) + return false; + + while (*Name) { + switch (*Name) { + default: + // Check if we have a matching constraint + if (*Name >= '0' && *Name <= '9') { + const char *DigitStart = Name; + while (Name[1] >= '0' && Name[1] <= '9') + Name++; + const char *DigitEnd = Name; + unsigned i; + if (StringRef(DigitStart, DigitEnd - DigitStart + 1) + .getAsInteger(10, i)) + return false; + + // Check if matching constraint is out of bounds. + if (i >= OutputConstraints.size()) return false; + + // A number must refer to an output only operand. + if (OutputConstraints[i].isReadWrite()) + return false; + + // If the constraint is already tied, it must be tied to the + // same operand referenced to by the number. + if (Info.hasTiedOperand() && Info.getTiedOperand() != i) + return false; + + // The constraint should have the same info as the respective + // output constraint. + Info.setTiedOperand(i, OutputConstraints[i]); + } else if (!validateAsmConstraint(Name, Info)) { + // FIXME: This error return is in place temporarily so we can + // add more constraints as we hit it. Eventually, an unknown + // constraint should just be treated as 'g'. + return false; + } + break; + case '[': { + unsigned Index = 0; + if (!resolveSymbolicName(Name, OutputConstraints, Index)) + return false; + + // If the constraint is already tied, it must be tied to the + // same operand referenced to by the number. + if (Info.hasTiedOperand() && Info.getTiedOperand() != Index) + return false; + + // A number must refer to an output only operand. + if (OutputConstraints[Index].isReadWrite()) + return false; + + Info.setTiedOperand(Index, OutputConstraints[Index]); + break; + } + case '%': // commutative + // FIXME: Fail if % is used with the last operand. + break; + case 'i': // immediate integer. + break; + case 'n': // immediate integer with a known value. + Info.setRequiresImmediate(); + break; + case 'I': // Various constant constraints with target-specific meanings. + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + if (!validateAsmConstraint(Name, Info)) + return false; + break; + case 'r': // general register. + Info.setAllowsRegister(); + break; + case 'm': // memory operand. + case 'o': // offsettable memory operand. + case 'V': // non-offsettable memory operand. + case '<': // autodecrement memory operand. + case '>': // autoincrement memory operand. + Info.setAllowsMemory(); + break; + case 'g': // general register, memory operand or immediate integer. + case 'X': // any operand. + Info.setAllowsRegister(); + Info.setAllowsMemory(); + break; + case 'E': // immediate floating point. + case 'F': // immediate floating point. + case 'p': // address operand. + break; + case ',': // multiple alternative constraint. Ignore comma. + break; + case '#': // Ignore as constraint. + while (Name[1] && Name[1] != ',') + Name++; + break; + case '?': // Disparage slightly code. + case '!': // Disparage severely. + case '*': // Ignore for choosing register preferences. + break; // Pass them. + } + + Name++; + } + + return true; +} + +void TargetInfo::CheckFixedPointBits() const { + // Check that the number of fractional and integral bits (and maybe sign) can + // fit into the bits given for a fixed point type. + assert(ShortAccumScale + getShortAccumIBits() + 1 <= ShortAccumWidth); + assert(AccumScale + getAccumIBits() + 1 <= AccumWidth); + assert(LongAccumScale + getLongAccumIBits() + 1 <= LongAccumWidth); + assert(getUnsignedShortAccumScale() + getUnsignedShortAccumIBits() <= + ShortAccumWidth); + assert(getUnsignedAccumScale() + getUnsignedAccumIBits() <= AccumWidth); + assert(getUnsignedLongAccumScale() + getUnsignedLongAccumIBits() <= + LongAccumWidth); + + assert(getShortFractScale() + 1 <= ShortFractWidth); + assert(getFractScale() + 1 <= FractWidth); + assert(getLongFractScale() + 1 <= LongFractWidth); + assert(getUnsignedShortFractScale() <= ShortFractWidth); + assert(getUnsignedFractScale() <= FractWidth); + assert(getUnsignedLongFractScale() <= LongFractWidth); + + // Each unsigned fract type has either the same number of fractional bits + // as, or one more fractional bit than, its corresponding signed fract type. + assert(getShortFractScale() == getUnsignedShortFractScale() || + getShortFractScale() == getUnsignedShortFractScale() - 1); + assert(getFractScale() == getUnsignedFractScale() || + getFractScale() == getUnsignedFractScale() - 1); + assert(getLongFractScale() == getUnsignedLongFractScale() || + getLongFractScale() == getUnsignedLongFractScale() - 1); + + // When arranged in order of increasing rank (see 6.3.1.3a), the number of + // fractional bits is nondecreasing for each of the following sets of + // fixed-point types: + // - signed fract types + // - unsigned fract types + // - signed accum types + // - unsigned accum types. + assert(getLongFractScale() >= getFractScale() && + getFractScale() >= getShortFractScale()); + assert(getUnsignedLongFractScale() >= getUnsignedFractScale() && + getUnsignedFractScale() >= getUnsignedShortFractScale()); + assert(LongAccumScale >= AccumScale && AccumScale >= ShortAccumScale); + assert(getUnsignedLongAccumScale() >= getUnsignedAccumScale() && + getUnsignedAccumScale() >= getUnsignedShortAccumScale()); + + // When arranged in order of increasing rank (see 6.3.1.3a), the number of + // integral bits is nondecreasing for each of the following sets of + // fixed-point types: + // - signed accum types + // - unsigned accum types + assert(getLongAccumIBits() >= getAccumIBits() && + getAccumIBits() >= getShortAccumIBits()); + assert(getUnsignedLongAccumIBits() >= getUnsignedAccumIBits() && + getUnsignedAccumIBits() >= getUnsignedShortAccumIBits()); + + // Each signed accum type has at least as many integral bits as its + // corresponding unsigned accum type. + assert(getShortAccumIBits() >= getUnsignedShortAccumIBits()); + assert(getAccumIBits() >= getUnsignedAccumIBits()); + assert(getLongAccumIBits() >= getUnsignedLongAccumIBits()); +} + +void TargetInfo::copyAuxTarget(const TargetInfo *Aux) { + auto *Target = static_cast<TransferrableTargetInfo*>(this); + auto *Src = static_cast<const TransferrableTargetInfo*>(Aux); + *Target = *Src; +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets.cpp b/contrib/llvm-project/clang/lib/Basic/Targets.cpp new file mode 100644 index 000000000000..994a491cddf2 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets.cpp @@ -0,0 +1,765 @@ +//===--- Targets.cpp - Implement target feature support -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements construction of a TargetInfo object from a +// target triple. +// +//===----------------------------------------------------------------------===// + +#include "Targets.h" + +#include "Targets/AArch64.h" +#include "Targets/AMDGPU.h" +#include "Targets/ARC.h" +#include "Targets/ARM.h" +#include "Targets/AVR.h" +#include "Targets/BPF.h" +#include "Targets/Hexagon.h" +#include "Targets/Lanai.h" +#include "Targets/Le64.h" +#include "Targets/M68k.h" +#include "Targets/MSP430.h" +#include "Targets/Mips.h" +#include "Targets/NVPTX.h" +#include "Targets/OSTargets.h" +#include "Targets/PNaCl.h" +#include "Targets/PPC.h" +#include "Targets/RISCV.h" +#include "Targets/SPIR.h" +#include "Targets/Sparc.h" +#include "Targets/SystemZ.h" +#include "Targets/TCE.h" +#include "Targets/VE.h" +#include "Targets/WebAssembly.h" +#include "Targets/X86.h" +#include "Targets/XCore.h" +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Triple.h" + +using namespace clang; + +namespace clang { +namespace targets { +//===----------------------------------------------------------------------===// +// Common code shared among targets. +//===----------------------------------------------------------------------===// + +/// DefineStd - Define a macro name and standard variants. For example if +/// MacroName is "unix", then this will define "__unix", "__unix__", and "unix" +/// when in GNU mode. +void DefineStd(MacroBuilder &Builder, StringRef MacroName, + const LangOptions &Opts) { + assert(MacroName[0] != '_' && "Identifier should be in the user's namespace"); + + // If in GNU mode (e.g. -std=gnu99 but not -std=c99) define the raw identifier + // in the user's namespace. + if (Opts.GNUMode) + Builder.defineMacro(MacroName); + + // Define __unix. + Builder.defineMacro("__" + MacroName); + + // Define __unix__. + Builder.defineMacro("__" + MacroName + "__"); +} + +void defineCPUMacros(MacroBuilder &Builder, StringRef CPUName, bool Tuning) { + Builder.defineMacro("__" + CPUName); + Builder.defineMacro("__" + CPUName + "__"); + if (Tuning) + Builder.defineMacro("__tune_" + CPUName + "__"); +} + +void addCygMingDefines(const LangOptions &Opts, MacroBuilder &Builder) { + // Mingw and cygwin define __declspec(a) to __attribute__((a)). Clang + // supports __declspec natively under -fms-extensions, but we define a no-op + // __declspec macro anyway for pre-processor compatibility. + if (Opts.MicrosoftExt) + Builder.defineMacro("__declspec", "__declspec"); + else + Builder.defineMacro("__declspec(a)", "__attribute__((a))"); + + if (!Opts.MicrosoftExt) { + // Provide macros for all the calling convention keywords. Provide both + // single and double underscore prefixed variants. These are available on + // x64 as well as x86, even though they have no effect. + const char *CCs[] = {"cdecl", "stdcall", "fastcall", "thiscall", "pascal"}; + for (const char *CC : CCs) { + std::string GCCSpelling = "__attribute__((__"; + GCCSpelling += CC; + GCCSpelling += "__))"; + Builder.defineMacro(Twine("_") + CC, GCCSpelling); + Builder.defineMacro(Twine("__") + CC, GCCSpelling); + } + } +} + +//===----------------------------------------------------------------------===// +// Driver code +//===----------------------------------------------------------------------===// + +TargetInfo *AllocateTarget(const llvm::Triple &Triple, + const TargetOptions &Opts) { + llvm::Triple::OSType os = Triple.getOS(); + + switch (Triple.getArch()) { + default: + return nullptr; + + case llvm::Triple::arc: + return new ARCTargetInfo(Triple, Opts); + + case llvm::Triple::xcore: + return new XCoreTargetInfo(Triple, Opts); + + case llvm::Triple::hexagon: + if (os == llvm::Triple::Linux && + Triple.getEnvironment() == llvm::Triple::Musl) + return new LinuxTargetInfo<HexagonTargetInfo>(Triple, Opts); + return new HexagonTargetInfo(Triple, Opts); + + case llvm::Triple::lanai: + return new LanaiTargetInfo(Triple, Opts); + + case llvm::Triple::aarch64_32: + if (Triple.isOSDarwin()) + return new DarwinAArch64TargetInfo(Triple, Opts); + + return nullptr; + case llvm::Triple::aarch64: + if (Triple.isOSDarwin()) + return new DarwinAArch64TargetInfo(Triple, Opts); + + switch (os) { + case llvm::Triple::CloudABI: + return new CloudABITargetInfo<AArch64leTargetInfo>(Triple, Opts); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<AArch64leTargetInfo>(Triple, Opts); + case llvm::Triple::Fuchsia: + return new FuchsiaTargetInfo<AArch64leTargetInfo>(Triple, Opts); + case llvm::Triple::Linux: + return new LinuxTargetInfo<AArch64leTargetInfo>(Triple, Opts); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<AArch64leTargetInfo>(Triple, Opts); + case llvm::Triple::OpenBSD: + return new OpenBSDTargetInfo<AArch64leTargetInfo>(Triple, Opts); + case llvm::Triple::Win32: + switch (Triple.getEnvironment()) { + case llvm::Triple::GNU: + return new MinGWARM64TargetInfo(Triple, Opts); + case llvm::Triple::MSVC: + default: // Assume MSVC for unknown environments + return new MicrosoftARM64TargetInfo(Triple, Opts); + } + default: + return new AArch64leTargetInfo(Triple, Opts); + } + + case llvm::Triple::aarch64_be: + switch (os) { + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<AArch64beTargetInfo>(Triple, Opts); + case llvm::Triple::Fuchsia: + return new FuchsiaTargetInfo<AArch64beTargetInfo>(Triple, Opts); + case llvm::Triple::Linux: + return new LinuxTargetInfo<AArch64beTargetInfo>(Triple, Opts); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<AArch64beTargetInfo>(Triple, Opts); + default: + return new AArch64beTargetInfo(Triple, Opts); + } + + case llvm::Triple::arm: + case llvm::Triple::thumb: + if (Triple.isOSBinFormatMachO()) + return new DarwinARMTargetInfo(Triple, Opts); + + switch (os) { + case llvm::Triple::CloudABI: + return new CloudABITargetInfo<ARMleTargetInfo>(Triple, Opts); + case llvm::Triple::Linux: + return new LinuxTargetInfo<ARMleTargetInfo>(Triple, Opts); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<ARMleTargetInfo>(Triple, Opts); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<ARMleTargetInfo>(Triple, Opts); + case llvm::Triple::OpenBSD: + return new OpenBSDTargetInfo<ARMleTargetInfo>(Triple, Opts); + case llvm::Triple::RTEMS: + return new RTEMSTargetInfo<ARMleTargetInfo>(Triple, Opts); + case llvm::Triple::NaCl: + return new NaClTargetInfo<ARMleTargetInfo>(Triple, Opts); + case llvm::Triple::Win32: + switch (Triple.getEnvironment()) { + case llvm::Triple::Cygnus: + return new CygwinARMTargetInfo(Triple, Opts); + case llvm::Triple::GNU: + return new MinGWARMTargetInfo(Triple, Opts); + case llvm::Triple::Itanium: + return new ItaniumWindowsARMleTargetInfo(Triple, Opts); + case llvm::Triple::MSVC: + default: // Assume MSVC for unknown environments + return new MicrosoftARMleTargetInfo(Triple, Opts); + } + default: + return new ARMleTargetInfo(Triple, Opts); + } + + case llvm::Triple::armeb: + case llvm::Triple::thumbeb: + if (Triple.isOSDarwin()) + return new DarwinARMTargetInfo(Triple, Opts); + + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<ARMbeTargetInfo>(Triple, Opts); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<ARMbeTargetInfo>(Triple, Opts); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<ARMbeTargetInfo>(Triple, Opts); + case llvm::Triple::OpenBSD: + return new OpenBSDTargetInfo<ARMbeTargetInfo>(Triple, Opts); + case llvm::Triple::RTEMS: + return new RTEMSTargetInfo<ARMbeTargetInfo>(Triple, Opts); + case llvm::Triple::NaCl: + return new NaClTargetInfo<ARMbeTargetInfo>(Triple, Opts); + default: + return new ARMbeTargetInfo(Triple, Opts); + } + + case llvm::Triple::avr: + return new AVRTargetInfo(Triple, Opts); + case llvm::Triple::bpfeb: + case llvm::Triple::bpfel: + return new BPFTargetInfo(Triple, Opts); + + case llvm::Triple::msp430: + return new MSP430TargetInfo(Triple, Opts); + + case llvm::Triple::mips: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<MipsTargetInfo>(Triple, Opts); + case llvm::Triple::RTEMS: + return new RTEMSTargetInfo<MipsTargetInfo>(Triple, Opts); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<MipsTargetInfo>(Triple, Opts); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<MipsTargetInfo>(Triple, Opts); + default: + return new MipsTargetInfo(Triple, Opts); + } + + case llvm::Triple::mipsel: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<MipsTargetInfo>(Triple, Opts); + case llvm::Triple::RTEMS: + return new RTEMSTargetInfo<MipsTargetInfo>(Triple, Opts); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<MipsTargetInfo>(Triple, Opts); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<MipsTargetInfo>(Triple, Opts); + case llvm::Triple::NaCl: + return new NaClTargetInfo<NaClMips32TargetInfo>(Triple, Opts); + default: + return new MipsTargetInfo(Triple, Opts); + } + + case llvm::Triple::mips64: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<MipsTargetInfo>(Triple, Opts); + case llvm::Triple::RTEMS: + return new RTEMSTargetInfo<MipsTargetInfo>(Triple, Opts); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<MipsTargetInfo>(Triple, Opts); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<MipsTargetInfo>(Triple, Opts); + case llvm::Triple::OpenBSD: + return new OpenBSDTargetInfo<MipsTargetInfo>(Triple, Opts); + default: + return new MipsTargetInfo(Triple, Opts); + } + + case llvm::Triple::mips64el: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<MipsTargetInfo>(Triple, Opts); + case llvm::Triple::RTEMS: + return new RTEMSTargetInfo<MipsTargetInfo>(Triple, Opts); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<MipsTargetInfo>(Triple, Opts); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<MipsTargetInfo>(Triple, Opts); + case llvm::Triple::OpenBSD: + return new OpenBSDTargetInfo<MipsTargetInfo>(Triple, Opts); + default: + return new MipsTargetInfo(Triple, Opts); + } + + case llvm::Triple::m68k: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<M68kTargetInfo>(Triple, Opts); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<M68kTargetInfo>(Triple, Opts); + default: + return new M68kTargetInfo(Triple, Opts); + } + + case llvm::Triple::le32: + switch (os) { + case llvm::Triple::NaCl: + return new NaClTargetInfo<PNaClTargetInfo>(Triple, Opts); + default: + return nullptr; + } + + case llvm::Triple::le64: + return new Le64TargetInfo(Triple, Opts); + + case llvm::Triple::ppc: + if (Triple.isOSDarwin()) + return new DarwinPPC32TargetInfo(Triple, Opts); + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<PPC32TargetInfo>(Triple, Opts); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<PPC32TargetInfo>(Triple, Opts); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<PPC32TargetInfo>(Triple, Opts); + case llvm::Triple::OpenBSD: + return new OpenBSDTargetInfo<PPC32TargetInfo>(Triple, Opts); + case llvm::Triple::RTEMS: + return new RTEMSTargetInfo<PPC32TargetInfo>(Triple, Opts); + case llvm::Triple::AIX: + return new AIXPPC32TargetInfo(Triple, Opts); + default: + return new PPC32TargetInfo(Triple, Opts); + } + + case llvm::Triple::ppcle: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<PPC32TargetInfo>(Triple, Opts); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<PPC32TargetInfo>(Triple, Opts); + default: + return new PPC32TargetInfo(Triple, Opts); + } + + case llvm::Triple::ppc64: + if (Triple.isOSDarwin()) + return new DarwinPPC64TargetInfo(Triple, Opts); + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<PPC64TargetInfo>(Triple, Opts); + case llvm::Triple::Lv2: + return new PS3PPUTargetInfo<PPC64TargetInfo>(Triple, Opts); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<PPC64TargetInfo>(Triple, Opts); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<PPC64TargetInfo>(Triple, Opts); + case llvm::Triple::OpenBSD: + return new OpenBSDTargetInfo<PPC64TargetInfo>(Triple, Opts); + case llvm::Triple::AIX: + return new AIXPPC64TargetInfo(Triple, Opts); + default: + return new PPC64TargetInfo(Triple, Opts); + } + + case llvm::Triple::ppc64le: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<PPC64TargetInfo>(Triple, Opts); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<PPC64TargetInfo>(Triple, Opts); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<PPC64TargetInfo>(Triple, Opts); + case llvm::Triple::OpenBSD: + return new OpenBSDTargetInfo<PPC64TargetInfo>(Triple, Opts); + default: + return new PPC64TargetInfo(Triple, Opts); + } + + case llvm::Triple::nvptx: + return new NVPTXTargetInfo(Triple, Opts, /*TargetPointerWidth=*/32); + case llvm::Triple::nvptx64: + return new NVPTXTargetInfo(Triple, Opts, /*TargetPointerWidth=*/64); + + case llvm::Triple::amdgcn: + case llvm::Triple::r600: + return new AMDGPUTargetInfo(Triple, Opts); + + case llvm::Triple::riscv32: + // TODO: add cases for NetBSD, RTEMS once tested. + switch (os) { + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<RISCV32TargetInfo>(Triple, Opts); + case llvm::Triple::Linux: + return new LinuxTargetInfo<RISCV32TargetInfo>(Triple, Opts); + default: + return new RISCV32TargetInfo(Triple, Opts); + } + + case llvm::Triple::riscv64: + // TODO: add cases for NetBSD, RTEMS once tested. + switch (os) { + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<RISCV64TargetInfo>(Triple, Opts); + case llvm::Triple::OpenBSD: + return new OpenBSDTargetInfo<RISCV64TargetInfo>(Triple, Opts); + case llvm::Triple::Fuchsia: + return new FuchsiaTargetInfo<RISCV64TargetInfo>(Triple, Opts); + case llvm::Triple::Linux: + return new LinuxTargetInfo<RISCV64TargetInfo>(Triple, Opts); + default: + return new RISCV64TargetInfo(Triple, Opts); + } + + case llvm::Triple::sparc: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<SparcV8TargetInfo>(Triple, Opts); + case llvm::Triple::Solaris: + return new SolarisTargetInfo<SparcV8TargetInfo>(Triple, Opts); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<SparcV8TargetInfo>(Triple, Opts); + case llvm::Triple::RTEMS: + return new RTEMSTargetInfo<SparcV8TargetInfo>(Triple, Opts); + default: + return new SparcV8TargetInfo(Triple, Opts); + } + + // The 'sparcel' architecture copies all the above cases except for Solaris. + case llvm::Triple::sparcel: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<SparcV8elTargetInfo>(Triple, Opts); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<SparcV8elTargetInfo>(Triple, Opts); + case llvm::Triple::RTEMS: + return new RTEMSTargetInfo<SparcV8elTargetInfo>(Triple, Opts); + default: + return new SparcV8elTargetInfo(Triple, Opts); + } + + case llvm::Triple::sparcv9: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<SparcV9TargetInfo>(Triple, Opts); + case llvm::Triple::Solaris: + return new SolarisTargetInfo<SparcV9TargetInfo>(Triple, Opts); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<SparcV9TargetInfo>(Triple, Opts); + case llvm::Triple::OpenBSD: + return new OpenBSDTargetInfo<SparcV9TargetInfo>(Triple, Opts); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<SparcV9TargetInfo>(Triple, Opts); + default: + return new SparcV9TargetInfo(Triple, Opts); + } + + case llvm::Triple::systemz: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<SystemZTargetInfo>(Triple, Opts); + case llvm::Triple::ZOS: + return new ZOSTargetInfo<SystemZTargetInfo>(Triple, Opts); + default: + return new SystemZTargetInfo(Triple, Opts); + } + + case llvm::Triple::tce: + return new TCETargetInfo(Triple, Opts); + + case llvm::Triple::tcele: + return new TCELETargetInfo(Triple, Opts); + + case llvm::Triple::x86: + if (Triple.isOSDarwin()) + return new DarwinI386TargetInfo(Triple, Opts); + + switch (os) { + case llvm::Triple::Ananas: + return new AnanasTargetInfo<X86_32TargetInfo>(Triple, Opts); + case llvm::Triple::CloudABI: + return new CloudABITargetInfo<X86_32TargetInfo>(Triple, Opts); + case llvm::Triple::Linux: { + switch (Triple.getEnvironment()) { + default: + return new LinuxTargetInfo<X86_32TargetInfo>(Triple, Opts); + case llvm::Triple::Android: + return new AndroidX86_32TargetInfo(Triple, Opts); + } + } + case llvm::Triple::DragonFly: + return new DragonFlyBSDTargetInfo<X86_32TargetInfo>(Triple, Opts); + case llvm::Triple::NetBSD: + return new NetBSDI386TargetInfo(Triple, Opts); + case llvm::Triple::OpenBSD: + return new OpenBSDI386TargetInfo(Triple, Opts); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<X86_32TargetInfo>(Triple, Opts); + case llvm::Triple::Fuchsia: + return new FuchsiaTargetInfo<X86_32TargetInfo>(Triple, Opts); + case llvm::Triple::KFreeBSD: + return new KFreeBSDTargetInfo<X86_32TargetInfo>(Triple, Opts); + case llvm::Triple::Minix: + return new MinixTargetInfo<X86_32TargetInfo>(Triple, Opts); + case llvm::Triple::Solaris: + return new SolarisTargetInfo<X86_32TargetInfo>(Triple, Opts); + case llvm::Triple::Win32: { + switch (Triple.getEnvironment()) { + case llvm::Triple::Cygnus: + return new CygwinX86_32TargetInfo(Triple, Opts); + case llvm::Triple::GNU: + return new MinGWX86_32TargetInfo(Triple, Opts); + case llvm::Triple::Itanium: + case llvm::Triple::MSVC: + default: // Assume MSVC for unknown environments + return new MicrosoftX86_32TargetInfo(Triple, Opts); + } + } + case llvm::Triple::Haiku: + return new HaikuX86_32TargetInfo(Triple, Opts); + case llvm::Triple::RTEMS: + return new RTEMSX86_32TargetInfo(Triple, Opts); + case llvm::Triple::NaCl: + return new NaClTargetInfo<X86_32TargetInfo>(Triple, Opts); + case llvm::Triple::ELFIAMCU: + return new MCUX86_32TargetInfo(Triple, Opts); + case llvm::Triple::Hurd: + return new HurdTargetInfo<X86_32TargetInfo>(Triple, Opts); + default: + return new X86_32TargetInfo(Triple, Opts); + } + + case llvm::Triple::x86_64: + if (Triple.isOSDarwin() || Triple.isOSBinFormatMachO()) + return new DarwinX86_64TargetInfo(Triple, Opts); + + switch (os) { + case llvm::Triple::Ananas: + return new AnanasTargetInfo<X86_64TargetInfo>(Triple, Opts); + case llvm::Triple::CloudABI: + return new CloudABITargetInfo<X86_64TargetInfo>(Triple, Opts); + case llvm::Triple::Linux: { + switch (Triple.getEnvironment()) { + default: + return new LinuxTargetInfo<X86_64TargetInfo>(Triple, Opts); + case llvm::Triple::Android: + return new AndroidX86_64TargetInfo(Triple, Opts); + } + } + case llvm::Triple::DragonFly: + return new DragonFlyBSDTargetInfo<X86_64TargetInfo>(Triple, Opts); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<X86_64TargetInfo>(Triple, Opts); + case llvm::Triple::OpenBSD: + return new OpenBSDX86_64TargetInfo(Triple, Opts); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<X86_64TargetInfo>(Triple, Opts); + case llvm::Triple::Fuchsia: + return new FuchsiaTargetInfo<X86_64TargetInfo>(Triple, Opts); + case llvm::Triple::KFreeBSD: + return new KFreeBSDTargetInfo<X86_64TargetInfo>(Triple, Opts); + case llvm::Triple::Solaris: + return new SolarisTargetInfo<X86_64TargetInfo>(Triple, Opts); + case llvm::Triple::Win32: { + switch (Triple.getEnvironment()) { + case llvm::Triple::Cygnus: + return new CygwinX86_64TargetInfo(Triple, Opts); + case llvm::Triple::GNU: + return new MinGWX86_64TargetInfo(Triple, Opts); + case llvm::Triple::MSVC: + default: // Assume MSVC for unknown environments + return new MicrosoftX86_64TargetInfo(Triple, Opts); + } + } + case llvm::Triple::Haiku: + return new HaikuTargetInfo<X86_64TargetInfo>(Triple, Opts); + case llvm::Triple::NaCl: + return new NaClTargetInfo<X86_64TargetInfo>(Triple, Opts); + case llvm::Triple::PS4: + return new PS4OSTargetInfo<X86_64TargetInfo>(Triple, Opts); + default: + return new X86_64TargetInfo(Triple, Opts); + } + + case llvm::Triple::spir: { + if (os != llvm::Triple::UnknownOS || + Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) + return nullptr; + return new SPIR32TargetInfo(Triple, Opts); + } + case llvm::Triple::spir64: { + if (os != llvm::Triple::UnknownOS || + Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) + return nullptr; + return new SPIR64TargetInfo(Triple, Opts); + } + case llvm::Triple::spirv32: { + if (os != llvm::Triple::UnknownOS || + Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) + return nullptr; + return new SPIRV32TargetInfo(Triple, Opts); + } + case llvm::Triple::spirv64: { + if (os != llvm::Triple::UnknownOS || + Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) + return nullptr; + return new SPIRV64TargetInfo(Triple, Opts); + } + case llvm::Triple::wasm32: + if (Triple.getSubArch() != llvm::Triple::NoSubArch || + Triple.getVendor() != llvm::Triple::UnknownVendor || + !Triple.isOSBinFormatWasm()) + return nullptr; + switch (os) { + case llvm::Triple::WASI: + return new WASITargetInfo<WebAssembly32TargetInfo>(Triple, Opts); + case llvm::Triple::Emscripten: + return new EmscriptenTargetInfo<WebAssembly32TargetInfo>(Triple, Opts); + case llvm::Triple::UnknownOS: + return new WebAssemblyOSTargetInfo<WebAssembly32TargetInfo>(Triple, Opts); + default: + return nullptr; + } + case llvm::Triple::wasm64: + if (Triple.getSubArch() != llvm::Triple::NoSubArch || + Triple.getVendor() != llvm::Triple::UnknownVendor || + !Triple.isOSBinFormatWasm()) + return nullptr; + switch (os) { + case llvm::Triple::WASI: + return new WASITargetInfo<WebAssembly64TargetInfo>(Triple, Opts); + case llvm::Triple::Emscripten: + return new EmscriptenTargetInfo<WebAssembly64TargetInfo>(Triple, Opts); + case llvm::Triple::UnknownOS: + return new WebAssemblyOSTargetInfo<WebAssembly64TargetInfo>(Triple, Opts); + default: + return nullptr; + } + + case llvm::Triple::renderscript32: + return new LinuxTargetInfo<RenderScript32TargetInfo>(Triple, Opts); + case llvm::Triple::renderscript64: + return new LinuxTargetInfo<RenderScript64TargetInfo>(Triple, Opts); + + case llvm::Triple::ve: + return new LinuxTargetInfo<VETargetInfo>(Triple, Opts); + } +} +} // namespace targets +} // namespace clang + +using namespace clang::targets; +/// CreateTargetInfo - Return the target info object for the specified target +/// options. +TargetInfo * +TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, + const std::shared_ptr<TargetOptions> &Opts) { + llvm::Triple Triple(Opts->Triple); + + // Construct the target + std::unique_ptr<TargetInfo> Target(AllocateTarget(Triple, *Opts)); + if (!Target) { + Diags.Report(diag::err_target_unknown_triple) << Triple.str(); + return nullptr; + } + Target->TargetOpts = Opts; + + // Set the target CPU if specified. + if (!Opts->CPU.empty() && !Target->setCPU(Opts->CPU)) { + Diags.Report(diag::err_target_unknown_cpu) << Opts->CPU; + SmallVector<StringRef, 32> ValidList; + Target->fillValidCPUList(ValidList); + if (!ValidList.empty()) + Diags.Report(diag::note_valid_options) << llvm::join(ValidList, ", "); + return nullptr; + } + + // Check the TuneCPU name if specified. + if (!Opts->TuneCPU.empty() && + !Target->isValidTuneCPUName(Opts->TuneCPU)) { + Diags.Report(diag::err_target_unknown_cpu) << Opts->TuneCPU; + SmallVector<StringRef, 32> ValidList; + Target->fillValidTuneCPUList(ValidList); + if (!ValidList.empty()) + Diags.Report(diag::note_valid_options) << llvm::join(ValidList, ", "); + return nullptr; + } + + // Set the target ABI if specified. + if (!Opts->ABI.empty() && !Target->setABI(Opts->ABI)) { + Diags.Report(diag::err_target_unknown_abi) << Opts->ABI; + return nullptr; + } + + // Set the fp math unit. + if (!Opts->FPMath.empty() && !Target->setFPMath(Opts->FPMath)) { + Diags.Report(diag::err_target_unknown_fpmath) << Opts->FPMath; + return nullptr; + } + + // Compute the default target features, we need the target to handle this + // because features may have dependencies on one another. + if (!Target->initFeatureMap(Opts->FeatureMap, Diags, Opts->CPU, + Opts->FeaturesAsWritten)) + return nullptr; + + // Add the features to the compile options. + Opts->Features.clear(); + for (const auto &F : Opts->FeatureMap) + Opts->Features.push_back((F.getValue() ? "+" : "-") + F.getKey().str()); + // Sort here, so we handle the features in a predictable order. (This matters + // when we're dealing with features that overlap.) + llvm::sort(Opts->Features); + + if (!Target->handleTargetFeatures(Opts->Features, Diags)) + return nullptr; + + Target->setSupportedOpenCLOpts(); + Target->setCommandLineOpenCLOpts(); + Target->setMaxAtomicWidth(); + + if (!Target->validateTarget(Diags)) + return nullptr; + + Target->CheckFixedPointBits(); + + return Target.release(); +} +/// validateOpenCLTarget - Check that OpenCL target has valid +/// options setting based on OpenCL version. +bool TargetInfo::validateOpenCLTarget(const LangOptions &Opts, + DiagnosticsEngine &Diags) const { + const llvm::StringMap<bool> &OpenCLFeaturesMap = getSupportedOpenCLOpts(); + + auto diagnoseNotSupportedCore = [&](llvm::StringRef Name, auto... OptArgs) { + if (OpenCLOptions::isOpenCLOptionCoreIn(Opts, OptArgs...) && + !hasFeatureEnabled(OpenCLFeaturesMap, Name)) + Diags.Report(diag::warn_opencl_unsupported_core_feature) + << Name << Opts.OpenCLCPlusPlus + << Opts.getOpenCLVersionTuple().getAsString(); + }; +#define OPENCL_GENERIC_EXTENSION(Ext, ...) \ + diagnoseNotSupportedCore(#Ext, __VA_ARGS__); +#include "clang/Basic/OpenCLExtensions.def" + + // Validate that feature macros are set properly for OpenCL C 3.0. + // In other cases assume that target is always valid. + if (Opts.getOpenCLCompatibleVersion() < 300) + return true; + + return OpenCLOptions::diagnoseUnsupportedFeatureDependencies(*this, Diags) && + OpenCLOptions::diagnoseFeatureExtensionDifferences(*this, Diags); +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets.h b/contrib/llvm-project/clang/lib/Basic/Targets.h new file mode 100644 index 000000000000..a063204e69e6 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets.h @@ -0,0 +1,46 @@ +//===------- Targets.h - Declare target feature support ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares things required for construction of a TargetInfo object +// from a target triple. Typically individual targets will need to include from +// here in order to get these functions if required. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_H + +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +namespace targets { + +LLVM_LIBRARY_VISIBILITY +clang::TargetInfo *AllocateTarget(const llvm::Triple &Triple, + const clang::TargetOptions &Opts); + +/// DefineStd - Define a macro name and standard variants. For example if +/// MacroName is "unix", then this will define "__unix", "__unix__", and "unix" +/// when in GNU mode. +LLVM_LIBRARY_VISIBILITY +void DefineStd(clang::MacroBuilder &Builder, llvm::StringRef MacroName, + const clang::LangOptions &Opts); + +LLVM_LIBRARY_VISIBILITY +void defineCPUMacros(clang::MacroBuilder &Builder, llvm::StringRef CPUName, + bool Tuning = true); + +LLVM_LIBRARY_VISIBILITY +void addCygMingDefines(const clang::LangOptions &Opts, + clang::MacroBuilder &Builder); +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/AArch64.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/AArch64.cpp new file mode 100644 index 000000000000..34bdb58dffc1 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/AArch64.cpp @@ -0,0 +1,1066 @@ +//===--- AArch64.cpp - Implement AArch64 target feature support -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements AArch64 TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "AArch64.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/TargetBuiltins.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/AArch64TargetParser.h" + +using namespace clang; +using namespace clang::targets; + +const Builtin::Info AArch64TargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsNEON.def" + +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsSVE.def" + +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define LANGBUILTIN(ID, TYPE, ATTRS, LANG) \ + {#ID, TYPE, ATTRS, nullptr, LANG, nullptr}, +#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \ + {#ID, TYPE, ATTRS, HEADER, LANGS, FEATURE}, +#include "clang/Basic/BuiltinsAArch64.def" +}; + +static StringRef getArchVersionString(llvm::AArch64::ArchKind Kind) { + switch (Kind) { + case llvm::AArch64::ArchKind::ARMV9A: + case llvm::AArch64::ArchKind::ARMV9_1A: + case llvm::AArch64::ArchKind::ARMV9_2A: + case llvm::AArch64::ArchKind::ARMV9_3A: + return "9"; + default: + return "8"; + } +} + +StringRef AArch64TargetInfo::getArchProfile() const { + switch (ArchKind) { + case llvm::AArch64::ArchKind::ARMV8R: + return "R"; + default: + return "A"; + } +} + +AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : TargetInfo(Triple), ABI("aapcs") { + if (getTriple().isOSOpenBSD()) { + Int64Type = SignedLongLong; + IntMaxType = SignedLongLong; + } else { + if (!getTriple().isOSDarwin() && !getTriple().isOSNetBSD()) + WCharType = UnsignedInt; + + Int64Type = SignedLong; + IntMaxType = SignedLong; + } + + // All AArch64 implementations support ARMv8 FP, which makes half a legal type. + HasLegalHalfType = true; + HasFloat16 = true; + + if (Triple.isArch64Bit()) + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + else + LongWidth = LongAlign = PointerWidth = PointerAlign = 32; + + MaxVectorAlign = 128; + MaxAtomicInlineWidth = 128; + MaxAtomicPromoteWidth = 128; + + LongDoubleWidth = LongDoubleAlign = SuitableAlign = 128; + LongDoubleFormat = &llvm::APFloat::IEEEquad(); + + BFloat16Width = BFloat16Align = 16; + BFloat16Format = &llvm::APFloat::BFloat(); + + // Make __builtin_ms_va_list available. + HasBuiltinMSVaList = true; + + // Make the SVE types available. Note that this deliberately doesn't + // depend on SveMode, since in principle it should be possible to turn + // SVE on and off within a translation unit. It should also be possible + // to compile the global declaration: + // + // __SVInt8_t *ptr; + // + // even without SVE. + HasAArch64SVETypes = true; + + // {} in inline assembly are neon specifiers, not assembly variant + // specifiers. + NoAsmVariants = true; + + // AAPCS gives rules for bitfields. 7.1.7 says: "The container type + // contributes to the alignment of the containing aggregate in the same way + // a plain (non bit-field) member of that type would, without exception for + // zero-sized or anonymous bit-fields." + assert(UseBitFieldTypeAlignment && "bitfields affect type alignment"); + UseZeroLengthBitfieldAlignment = true; + + // AArch64 targets default to using the ARM C++ ABI. + TheCXXABI.set(TargetCXXABI::GenericAArch64); + + if (Triple.getOS() == llvm::Triple::Linux) + this->MCountName = "\01_mcount"; + else if (Triple.getOS() == llvm::Triple::UnknownOS) + this->MCountName = + Opts.EABIVersion == llvm::EABI::GNU ? "\01_mcount" : "mcount"; +} + +StringRef AArch64TargetInfo::getABI() const { return ABI; } + +bool AArch64TargetInfo::setABI(const std::string &Name) { + if (Name != "aapcs" && Name != "darwinpcs") + return false; + + ABI = Name; + return true; +} + +bool AArch64TargetInfo::validateBranchProtection(StringRef Spec, StringRef, + BranchProtectionInfo &BPI, + StringRef &Err) const { + llvm::ARM::ParsedBranchProtection PBP; + if (!llvm::ARM::parseBranchProtection(Spec, PBP, Err)) + return false; + + BPI.SignReturnAddr = + llvm::StringSwitch<LangOptions::SignReturnAddressScopeKind>(PBP.Scope) + .Case("non-leaf", LangOptions::SignReturnAddressScopeKind::NonLeaf) + .Case("all", LangOptions::SignReturnAddressScopeKind::All) + .Default(LangOptions::SignReturnAddressScopeKind::None); + + if (PBP.Key == "a_key") + BPI.SignKey = LangOptions::SignReturnAddressKeyKind::AKey; + else + BPI.SignKey = LangOptions::SignReturnAddressKeyKind::BKey; + + BPI.BranchTargetEnforcement = PBP.BranchTargetEnforcement; + return true; +} + +bool AArch64TargetInfo::isValidCPUName(StringRef Name) const { + return Name == "generic" || + llvm::AArch64::parseCPUArch(Name) != llvm::AArch64::ArchKind::INVALID; +} + +bool AArch64TargetInfo::setCPU(const std::string &Name) { + return isValidCPUName(Name); +} + +void AArch64TargetInfo::fillValidCPUList( + SmallVectorImpl<StringRef> &Values) const { + llvm::AArch64::fillValidCPUArchList(Values); +} + +void AArch64TargetInfo::getTargetDefinesARMV81A(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__ARM_FEATURE_QRDMX", "1"); + Builder.defineMacro("__ARM_FEATURE_ATOMICS", "1"); + Builder.defineMacro("__ARM_FEATURE_CRC32", "1"); +} + +void AArch64TargetInfo::getTargetDefinesARMV82A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Also include the ARMv8.1 defines + getTargetDefinesARMV81A(Opts, Builder); +} + +void AArch64TargetInfo::getTargetDefinesARMV83A(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__ARM_FEATURE_COMPLEX", "1"); + Builder.defineMacro("__ARM_FEATURE_JCVT", "1"); + // Also include the Armv8.2 defines + getTargetDefinesARMV82A(Opts, Builder); +} + +void AArch64TargetInfo::getTargetDefinesARMV84A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Also include the Armv8.3 defines + getTargetDefinesARMV83A(Opts, Builder); +} + +void AArch64TargetInfo::getTargetDefinesARMV85A(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__ARM_FEATURE_FRINT", "1"); + // Also include the Armv8.4 defines + getTargetDefinesARMV84A(Opts, Builder); +} + +void AArch64TargetInfo::getTargetDefinesARMV86A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Also include the Armv8.5 defines + // FIXME: Armv8.6 makes the following extensions mandatory: + // - __ARM_FEATURE_BF16 + // - __ARM_FEATURE_MATMUL_INT8 + // Handle them here. + getTargetDefinesARMV85A(Opts, Builder); +} + +void AArch64TargetInfo::getTargetDefinesARMV87A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Also include the Armv8.6 defines + getTargetDefinesARMV86A(Opts, Builder); +} + +void AArch64TargetInfo::getTargetDefinesARMV88A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Also include the Armv8.7 defines + getTargetDefinesARMV87A(Opts, Builder); +} + +void AArch64TargetInfo::getTargetDefinesARMV9A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Armv9-A maps to Armv8.5-A + getTargetDefinesARMV85A(Opts, Builder); +} + +void AArch64TargetInfo::getTargetDefinesARMV91A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Armv9.1-A maps to Armv8.6-A + getTargetDefinesARMV86A(Opts, Builder); +} + +void AArch64TargetInfo::getTargetDefinesARMV92A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Armv9.2-A maps to Armv8.7-A + getTargetDefinesARMV87A(Opts, Builder); +} + +void AArch64TargetInfo::getTargetDefinesARMV93A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Armv9.3-A maps to Armv8.8-A + getTargetDefinesARMV88A(Opts, Builder); +} + +void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Target identification. + Builder.defineMacro("__aarch64__"); + // For bare-metal. + if (getTriple().getOS() == llvm::Triple::UnknownOS && + getTriple().isOSBinFormatELF()) + Builder.defineMacro("__ELF__"); + + // Target properties. + if (!getTriple().isOSWindows() && getTriple().isArch64Bit()) { + Builder.defineMacro("_LP64"); + Builder.defineMacro("__LP64__"); + } + + std::string CodeModel = getTargetOpts().CodeModel; + if (CodeModel == "default") + CodeModel = "small"; + for (char &c : CodeModel) + c = toupper(c); + Builder.defineMacro("__AARCH64_CMODEL_" + CodeModel + "__"); + + // ACLE predefines. Many can only have one possible value on v8 AArch64. + Builder.defineMacro("__ARM_ACLE", "200"); + Builder.defineMacro("__ARM_ARCH", getArchVersionString(ArchKind)); + Builder.defineMacro("__ARM_ARCH_PROFILE", "'" + getArchProfile() + "'"); + + Builder.defineMacro("__ARM_64BIT_STATE", "1"); + Builder.defineMacro("__ARM_PCS_AAPCS64", "1"); + Builder.defineMacro("__ARM_ARCH_ISA_A64", "1"); + + Builder.defineMacro("__ARM_FEATURE_CLZ", "1"); + Builder.defineMacro("__ARM_FEATURE_FMA", "1"); + Builder.defineMacro("__ARM_FEATURE_LDREX", "0xF"); + Builder.defineMacro("__ARM_FEATURE_IDIV", "1"); // As specified in ACLE + Builder.defineMacro("__ARM_FEATURE_DIV"); // For backwards compatibility + Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN", "1"); + Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING", "1"); + + Builder.defineMacro("__ARM_ALIGN_MAX_STACK_PWR", "4"); + + // 0xe implies support for half, single and double precision operations. + Builder.defineMacro("__ARM_FP", "0xE"); + + // PCS specifies this for SysV variants, which is all we support. Other ABIs + // may choose __ARM_FP16_FORMAT_ALTERNATIVE. + Builder.defineMacro("__ARM_FP16_FORMAT_IEEE", "1"); + Builder.defineMacro("__ARM_FP16_ARGS", "1"); + + if (Opts.UnsafeFPMath) + Builder.defineMacro("__ARM_FP_FAST", "1"); + + Builder.defineMacro("__ARM_SIZEOF_WCHAR_T", + Twine(Opts.WCharSize ? Opts.WCharSize : 4)); + + Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM", Opts.ShortEnums ? "1" : "4"); + + if (FPU & NeonMode) { + Builder.defineMacro("__ARM_NEON", "1"); + // 64-bit NEON supports half, single and double precision operations. + Builder.defineMacro("__ARM_NEON_FP", "0xE"); + } + + if (FPU & SveMode) + Builder.defineMacro("__ARM_FEATURE_SVE", "1"); + + if ((FPU & NeonMode) && (FPU & SveMode)) + Builder.defineMacro("__ARM_NEON_SVE_BRIDGE", "1"); + + if (HasSVE2) + Builder.defineMacro("__ARM_FEATURE_SVE2", "1"); + + if (HasSVE2 && HasSVE2AES) + Builder.defineMacro("__ARM_FEATURE_SVE2_AES", "1"); + + if (HasSVE2 && HasSVE2BitPerm) + Builder.defineMacro("__ARM_FEATURE_SVE2_BITPERM", "1"); + + if (HasSVE2 && HasSVE2SHA3) + Builder.defineMacro("__ARM_FEATURE_SVE2_SHA3", "1"); + + if (HasSVE2 && HasSVE2SM4) + Builder.defineMacro("__ARM_FEATURE_SVE2_SM4", "1"); + + if (HasCRC) + Builder.defineMacro("__ARM_FEATURE_CRC32", "1"); + + // The __ARM_FEATURE_CRYPTO is deprecated in favor of finer grained feature + // macros for AES, SHA2, SHA3 and SM4 + if (HasAES && HasSHA2) + Builder.defineMacro("__ARM_FEATURE_CRYPTO", "1"); + + if (HasAES) + Builder.defineMacro("__ARM_FEATURE_AES", "1"); + + if (HasSHA2) + Builder.defineMacro("__ARM_FEATURE_SHA2", "1"); + + if (HasSHA3) { + Builder.defineMacro("__ARM_FEATURE_SHA3", "1"); + Builder.defineMacro("__ARM_FEATURE_SHA512", "1"); + } + + if (HasSM4) { + Builder.defineMacro("__ARM_FEATURE_SM3", "1"); + Builder.defineMacro("__ARM_FEATURE_SM4", "1"); + } + + if (HasUnaligned) + Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1"); + + if ((FPU & NeonMode) && HasFullFP16) + Builder.defineMacro("__ARM_FEATURE_FP16_VECTOR_ARITHMETIC", "1"); + if (HasFullFP16) + Builder.defineMacro("__ARM_FEATURE_FP16_SCALAR_ARITHMETIC", "1"); + + if (HasDotProd) + Builder.defineMacro("__ARM_FEATURE_DOTPROD", "1"); + + if (HasMTE) + Builder.defineMacro("__ARM_FEATURE_MEMORY_TAGGING", "1"); + + if (HasTME) + Builder.defineMacro("__ARM_FEATURE_TME", "1"); + + if (HasMatMul) + Builder.defineMacro("__ARM_FEATURE_MATMUL_INT8", "1"); + + if (HasLSE) + Builder.defineMacro("__ARM_FEATURE_ATOMICS", "1"); + + if (HasBFloat16) { + Builder.defineMacro("__ARM_FEATURE_BF16", "1"); + Builder.defineMacro("__ARM_FEATURE_BF16_VECTOR_ARITHMETIC", "1"); + Builder.defineMacro("__ARM_BF16_FORMAT_ALTERNATIVE", "1"); + Builder.defineMacro("__ARM_FEATURE_BF16_SCALAR_ARITHMETIC", "1"); + } + + if ((FPU & SveMode) && HasBFloat16) { + Builder.defineMacro("__ARM_FEATURE_SVE_BF16", "1"); + } + + if ((FPU & SveMode) && HasMatmulFP64) + Builder.defineMacro("__ARM_FEATURE_SVE_MATMUL_FP64", "1"); + + if ((FPU & SveMode) && HasMatmulFP32) + Builder.defineMacro("__ARM_FEATURE_SVE_MATMUL_FP32", "1"); + + if ((FPU & SveMode) && HasMatMul) + Builder.defineMacro("__ARM_FEATURE_SVE_MATMUL_INT8", "1"); + + if ((FPU & NeonMode) && HasFP16FML) + Builder.defineMacro("__ARM_FEATURE_FP16_FML", "1"); + + if (Opts.hasSignReturnAddress()) { + // Bitmask: + // 0: Protection using the A key + // 1: Protection using the B key + // 2: Protection including leaf functions + unsigned Value = 0; + + if (Opts.isSignReturnAddressWithAKey()) + Value |= (1 << 0); + else + Value |= (1 << 1); + + if (Opts.isSignReturnAddressScopeAll()) + Value |= (1 << 2); + + Builder.defineMacro("__ARM_FEATURE_PAC_DEFAULT", std::to_string(Value)); + } + + if (Opts.BranchTargetEnforcement) + Builder.defineMacro("__ARM_FEATURE_BTI_DEFAULT", "1"); + + if (HasLS64) + Builder.defineMacro("__ARM_FEATURE_LS64", "1"); + + if (HasRandGen) + Builder.defineMacro("__ARM_FEATURE_RNG", "1"); + + switch (ArchKind) { + default: + break; + case llvm::AArch64::ArchKind::ARMV8_1A: + getTargetDefinesARMV81A(Opts, Builder); + break; + case llvm::AArch64::ArchKind::ARMV8_2A: + getTargetDefinesARMV82A(Opts, Builder); + break; + case llvm::AArch64::ArchKind::ARMV8_3A: + getTargetDefinesARMV83A(Opts, Builder); + break; + case llvm::AArch64::ArchKind::ARMV8_4A: + getTargetDefinesARMV84A(Opts, Builder); + break; + case llvm::AArch64::ArchKind::ARMV8_5A: + getTargetDefinesARMV85A(Opts, Builder); + break; + case llvm::AArch64::ArchKind::ARMV8_6A: + getTargetDefinesARMV86A(Opts, Builder); + break; + case llvm::AArch64::ArchKind::ARMV8_7A: + getTargetDefinesARMV87A(Opts, Builder); + break; + case llvm::AArch64::ArchKind::ARMV8_8A: + getTargetDefinesARMV88A(Opts, Builder); + break; + case llvm::AArch64::ArchKind::ARMV9A: + getTargetDefinesARMV9A(Opts, Builder); + break; + case llvm::AArch64::ArchKind::ARMV9_1A: + getTargetDefinesARMV91A(Opts, Builder); + break; + case llvm::AArch64::ArchKind::ARMV9_2A: + getTargetDefinesARMV92A(Opts, Builder); + break; + case llvm::AArch64::ArchKind::ARMV9_3A: + getTargetDefinesARMV93A(Opts, Builder); + break; + } + + // All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work. + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); + + if (Opts.VScaleMin && Opts.VScaleMin == Opts.VScaleMax) { + Builder.defineMacro("__ARM_FEATURE_SVE_BITS", Twine(Opts.VScaleMin * 128)); + Builder.defineMacro("__ARM_FEATURE_SVE_VECTOR_OPERATORS"); + } +} + +ArrayRef<Builtin::Info> AArch64TargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::AArch64::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} + +Optional<std::pair<unsigned, unsigned>> +AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts) const { + if (LangOpts.VScaleMin || LangOpts.VScaleMax) + return std::pair<unsigned, unsigned>( + LangOpts.VScaleMin ? LangOpts.VScaleMin : 1, LangOpts.VScaleMax); + + if (hasFeature("sve")) + return std::pair<unsigned, unsigned>(1, 16); + + return None; +} + +bool AArch64TargetInfo::hasFeature(StringRef Feature) const { + return Feature == "aarch64" || Feature == "arm64" || Feature == "arm" || + (Feature == "neon" && (FPU & NeonMode)) || + ((Feature == "sve" || Feature == "sve2" || Feature == "sve2-bitperm" || + Feature == "sve2-aes" || Feature == "sve2-sha3" || + Feature == "sve2-sm4" || Feature == "f64mm" || Feature == "f32mm" || + Feature == "i8mm" || Feature == "bf16") && + (FPU & SveMode)) || + (Feature == "ls64" && HasLS64); +} + +bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) { + FPU = FPUMode; + HasCRC = false; + HasCrypto = false; + HasAES = false; + HasSHA2 = false; + HasSHA3 = false; + HasSM4 = false; + HasUnaligned = true; + HasFullFP16 = false; + HasDotProd = false; + HasFP16FML = false; + HasMTE = false; + HasTME = false; + HasLS64 = false; + HasRandGen = false; + HasMatMul = false; + HasBFloat16 = false; + HasSVE2 = false; + HasSVE2AES = false; + HasSVE2SHA3 = false; + HasSVE2SM4 = false; + HasSVE2BitPerm = false; + HasMatmulFP64 = false; + HasMatmulFP32 = false; + HasLSE = false; + HasHBC = false; + HasMOPS = false; + + ArchKind = llvm::AArch64::ArchKind::INVALID; + + for (const auto &Feature : Features) { + if (Feature == "+neon") + FPU |= NeonMode; + if (Feature == "+sve") { + FPU |= SveMode; + HasFullFP16 = true; + } + if (Feature == "+sve2") { + FPU |= SveMode; + HasFullFP16 = true; + HasSVE2 = true; + } + if (Feature == "+sve2-aes") { + FPU |= SveMode; + HasFullFP16 = true; + HasSVE2 = true; + HasSVE2AES = true; + } + if (Feature == "+sve2-sha3") { + FPU |= SveMode; + HasFullFP16 = true; + HasSVE2 = true; + HasSVE2SHA3 = true; + } + if (Feature == "+sve2-sm4") { + FPU |= SveMode; + HasFullFP16 = true; + HasSVE2 = true; + HasSVE2SM4 = true; + } + if (Feature == "+sve2-bitperm") { + FPU |= SveMode; + HasFullFP16 = true; + HasSVE2 = true; + HasSVE2BitPerm = true; + } + if (Feature == "+f32mm") { + FPU |= SveMode; + HasMatmulFP32 = true; + } + if (Feature == "+f64mm") { + FPU |= SveMode; + HasMatmulFP64 = true; + } + if (Feature == "+crc") + HasCRC = true; + if (Feature == "+crypto") + HasCrypto = true; + if (Feature == "+aes") + HasAES = true; + if (Feature == "+sha2") + HasSHA2 = true; + if (Feature == "+sha3") { + HasSHA2 = true; + HasSHA3 = true; + } + if (Feature == "+sm4") + HasSM4 = true; + if (Feature == "+strict-align") + HasUnaligned = false; + if (Feature == "+v8a") + ArchKind = llvm::AArch64::ArchKind::ARMV8A; + if (Feature == "+v8.1a") + ArchKind = llvm::AArch64::ArchKind::ARMV8_1A; + if (Feature == "+v8.2a") + ArchKind = llvm::AArch64::ArchKind::ARMV8_2A; + if (Feature == "+v8.3a") + ArchKind = llvm::AArch64::ArchKind::ARMV8_3A; + if (Feature == "+v8.4a") + ArchKind = llvm::AArch64::ArchKind::ARMV8_4A; + if (Feature == "+v8.5a") + ArchKind = llvm::AArch64::ArchKind::ARMV8_5A; + if (Feature == "+v8.6a") + ArchKind = llvm::AArch64::ArchKind::ARMV8_6A; + if (Feature == "+v8.7a") + ArchKind = llvm::AArch64::ArchKind::ARMV8_7A; + if (Feature == "+v8.8a") + ArchKind = llvm::AArch64::ArchKind::ARMV8_8A; + if (Feature == "+v9a") + ArchKind = llvm::AArch64::ArchKind::ARMV9A; + if (Feature == "+v9.1a") + ArchKind = llvm::AArch64::ArchKind::ARMV9_1A; + if (Feature == "+v9.2a") + ArchKind = llvm::AArch64::ArchKind::ARMV9_2A; + if (Feature == "+v9.3a") + ArchKind = llvm::AArch64::ArchKind::ARMV9_3A; + if (Feature == "+v8r") + ArchKind = llvm::AArch64::ArchKind::ARMV8R; + if (Feature == "+fullfp16") + HasFullFP16 = true; + if (Feature == "+dotprod") + HasDotProd = true; + if (Feature == "+fp16fml") + HasFP16FML = true; + if (Feature == "+mte") + HasMTE = true; + if (Feature == "+tme") + HasTME = true; + if (Feature == "+pauth") + HasPAuth = true; + if (Feature == "+i8mm") + HasMatMul = true; + if (Feature == "+bf16") + HasBFloat16 = true; + if (Feature == "+lse") + HasLSE = true; + if (Feature == "+ls64") + HasLS64 = true; + if (Feature == "+rand") + HasRandGen = true; + if (Feature == "+flagm") + HasFlagM = true; + if (Feature == "+hbc") + HasHBC = true; + } + + setDataLayout(); + + return true; +} + +TargetInfo::CallingConvCheckResult +AArch64TargetInfo::checkCallingConvention(CallingConv CC) const { + switch (CC) { + case CC_C: + case CC_Swift: + case CC_SwiftAsync: + case CC_PreserveMost: + case CC_PreserveAll: + case CC_OpenCLKernel: + case CC_AArch64VectorCall: + case CC_Win64: + return CCCR_OK; + default: + return CCCR_Warning; + } +} + +bool AArch64TargetInfo::isCLZForZeroUndef() const { return false; } + +TargetInfo::BuiltinVaListKind AArch64TargetInfo::getBuiltinVaListKind() const { + return TargetInfo::AArch64ABIBuiltinVaList; +} + +const char *const AArch64TargetInfo::GCCRegNames[] = { + // 32-bit Integer registers + "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9", "w10", "w11", + "w12", "w13", "w14", "w15", "w16", "w17", "w18", "w19", "w20", "w21", "w22", + "w23", "w24", "w25", "w26", "w27", "w28", "w29", "w30", "wsp", + + // 64-bit Integer registers + "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", + "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", + "x23", "x24", "x25", "x26", "x27", "x28", "fp", "lr", "sp", + + // 32-bit floating point regsisters + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", + "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22", + "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", + + // 64-bit floating point regsisters + "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", + "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21", "d22", + "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", + + // Neon vector registers + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", + "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", + "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", + + // SVE vector registers + "z0", "z1", "z2", "z3", "z4", "z5", "z6", "z7", "z8", "z9", "z10", + "z11", "z12", "z13", "z14", "z15", "z16", "z17", "z18", "z19", "z20", "z21", + "z22", "z23", "z24", "z25", "z26", "z27", "z28", "z29", "z30", "z31", + + // SVE predicate registers + "p0", "p1", "p2", "p3", "p4", "p5", "p6", "p7", "p8", "p9", "p10", + "p11", "p12", "p13", "p14", "p15" +}; + +ArrayRef<const char *> AArch64TargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +const TargetInfo::GCCRegAlias AArch64TargetInfo::GCCRegAliases[] = { + {{"w31"}, "wsp"}, + {{"x31"}, "sp"}, + // GCC rN registers are aliases of xN registers. + {{"r0"}, "x0"}, + {{"r1"}, "x1"}, + {{"r2"}, "x2"}, + {{"r3"}, "x3"}, + {{"r4"}, "x4"}, + {{"r5"}, "x5"}, + {{"r6"}, "x6"}, + {{"r7"}, "x7"}, + {{"r8"}, "x8"}, + {{"r9"}, "x9"}, + {{"r10"}, "x10"}, + {{"r11"}, "x11"}, + {{"r12"}, "x12"}, + {{"r13"}, "x13"}, + {{"r14"}, "x14"}, + {{"r15"}, "x15"}, + {{"r16"}, "x16"}, + {{"r17"}, "x17"}, + {{"r18"}, "x18"}, + {{"r19"}, "x19"}, + {{"r20"}, "x20"}, + {{"r21"}, "x21"}, + {{"r22"}, "x22"}, + {{"r23"}, "x23"}, + {{"r24"}, "x24"}, + {{"r25"}, "x25"}, + {{"r26"}, "x26"}, + {{"r27"}, "x27"}, + {{"r28"}, "x28"}, + {{"r29", "x29"}, "fp"}, + {{"r30", "x30"}, "lr"}, + // The S/D/Q and W/X registers overlap, but aren't really aliases; we + // don't want to substitute one of these for a different-sized one. +}; + +ArrayRef<TargetInfo::GCCRegAlias> AArch64TargetInfo::getGCCRegAliases() const { + return llvm::makeArrayRef(GCCRegAliases); +} + +bool AArch64TargetInfo::validateAsmConstraint( + const char *&Name, TargetInfo::ConstraintInfo &Info) const { + switch (*Name) { + default: + return false; + case 'w': // Floating point and SIMD registers (V0-V31) + Info.setAllowsRegister(); + return true; + case 'I': // Constant that can be used with an ADD instruction + case 'J': // Constant that can be used with a SUB instruction + case 'K': // Constant that can be used with a 32-bit logical instruction + case 'L': // Constant that can be used with a 64-bit logical instruction + case 'M': // Constant that can be used as a 32-bit MOV immediate + case 'N': // Constant that can be used as a 64-bit MOV immediate + case 'Y': // Floating point constant zero + case 'Z': // Integer constant zero + return true; + case 'Q': // A memory reference with base register and no offset + Info.setAllowsMemory(); + return true; + case 'S': // A symbolic address + Info.setAllowsRegister(); + return true; + case 'U': + if (Name[1] == 'p' && (Name[2] == 'l' || Name[2] == 'a')) { + // SVE predicate registers ("Upa"=P0-15, "Upl"=P0-P7) + Info.setAllowsRegister(); + Name += 2; + return true; + } + // Ump: A memory address suitable for ldp/stp in SI, DI, SF and DF modes. + // Utf: A memory address suitable for ldp/stp in TF mode. + // Usa: An absolute symbolic address. + // Ush: The high part (bits 32:12) of a pc-relative symbolic address. + + // Better to return an error saying that it's an unrecognised constraint + // even if this is a valid constraint in gcc. + return false; + case 'z': // Zero register, wzr or xzr + Info.setAllowsRegister(); + return true; + case 'x': // Floating point and SIMD registers (V0-V15) + Info.setAllowsRegister(); + return true; + case 'y': // SVE registers (V0-V7) + Info.setAllowsRegister(); + return true; + } + return false; +} + +bool AArch64TargetInfo::validateConstraintModifier( + StringRef Constraint, char Modifier, unsigned Size, + std::string &SuggestedModifier) const { + // Strip off constraint modifiers. + while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&') + Constraint = Constraint.substr(1); + + switch (Constraint[0]) { + default: + return true; + case 'z': + case 'r': { + switch (Modifier) { + case 'x': + case 'w': + // For now assume that the person knows what they're + // doing with the modifier. + return true; + default: + // By default an 'r' constraint will be in the 'x' + // registers. + if (Size == 64) + return true; + + if (Size == 512) + return HasLS64; + + SuggestedModifier = "w"; + return false; + } + } + } +} + +const char *AArch64TargetInfo::getClobbers() const { return ""; } + +int AArch64TargetInfo::getEHDataRegisterNumber(unsigned RegNo) const { + if (RegNo == 0) + return 0; + if (RegNo == 1) + return 1; + return -1; +} + +bool AArch64TargetInfo::hasInt128Type() const { return true; } + +AArch64leTargetInfo::AArch64leTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : AArch64TargetInfo(Triple, Opts) {} + +void AArch64leTargetInfo::setDataLayout() { + if (getTriple().isOSBinFormatMachO()) { + if(getTriple().isArch32Bit()) + resetDataLayout("e-m:o-p:32:32-i64:64-i128:128-n32:64-S128", "_"); + else + resetDataLayout("e-m:o-i64:64-i128:128-n32:64-S128", "_"); + } else + resetDataLayout("e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"); +} + +void AArch64leTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__AARCH64EL__"); + AArch64TargetInfo::getTargetDefines(Opts, Builder); +} + +AArch64beTargetInfo::AArch64beTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : AArch64TargetInfo(Triple, Opts) {} + +void AArch64beTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__AARCH64EB__"); + Builder.defineMacro("__AARCH_BIG_ENDIAN"); + Builder.defineMacro("__ARM_BIG_ENDIAN"); + AArch64TargetInfo::getTargetDefines(Opts, Builder); +} + +void AArch64beTargetInfo::setDataLayout() { + assert(!getTriple().isOSBinFormatMachO()); + resetDataLayout("E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"); +} + +WindowsARM64TargetInfo::WindowsARM64TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : WindowsTargetInfo<AArch64leTargetInfo>(Triple, Opts), Triple(Triple) { + + // This is an LLP64 platform. + // int:4, long:4, long long:8, long double:8. + IntWidth = IntAlign = 32; + LongWidth = LongAlign = 32; + DoubleAlign = LongLongAlign = 64; + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + IntMaxType = SignedLongLong; + Int64Type = SignedLongLong; + SizeType = UnsignedLongLong; + PtrDiffType = SignedLongLong; + IntPtrType = SignedLongLong; +} + +void WindowsARM64TargetInfo::setDataLayout() { + resetDataLayout(Triple.isOSBinFormatMachO() + ? "e-m:o-i64:64-i128:128-n32:64-S128" + : "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128", + Triple.isOSBinFormatMachO() ? "_" : ""); +} + +TargetInfo::BuiltinVaListKind +WindowsARM64TargetInfo::getBuiltinVaListKind() const { + return TargetInfo::CharPtrBuiltinVaList; +} + +TargetInfo::CallingConvCheckResult +WindowsARM64TargetInfo::checkCallingConvention(CallingConv CC) const { + switch (CC) { + case CC_X86StdCall: + case CC_X86ThisCall: + case CC_X86FastCall: + case CC_X86VectorCall: + return CCCR_Ignore; + case CC_C: + case CC_OpenCLKernel: + case CC_PreserveMost: + case CC_PreserveAll: + case CC_Swift: + case CC_SwiftAsync: + case CC_Win64: + return CCCR_OK; + default: + return CCCR_Warning; + } +} + +MicrosoftARM64TargetInfo::MicrosoftARM64TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : WindowsARM64TargetInfo(Triple, Opts) { + TheCXXABI.set(TargetCXXABI::Microsoft); +} + +void MicrosoftARM64TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + WindowsARM64TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("_M_ARM64", "1"); +} + +TargetInfo::CallingConvKind +MicrosoftARM64TargetInfo::getCallingConvKind(bool ClangABICompat4) const { + return CCK_MicrosoftWin64; +} + +unsigned MicrosoftARM64TargetInfo::getMinGlobalAlign(uint64_t TypeSize) const { + unsigned Align = WindowsARM64TargetInfo::getMinGlobalAlign(TypeSize); + + // MSVC does size based alignment for arm64 based on alignment section in + // below document, replicate that to keep alignment consistent with object + // files compiled by MSVC. + // https://docs.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions + if (TypeSize >= 512) { // TypeSize >= 64 bytes + Align = std::max(Align, 128u); // align type at least 16 bytes + } else if (TypeSize >= 64) { // TypeSize >= 8 bytes + Align = std::max(Align, 64u); // align type at least 8 butes + } else if (TypeSize >= 16) { // TypeSize >= 2 bytes + Align = std::max(Align, 32u); // align type at least 4 bytes + } + return Align; +} + +MinGWARM64TargetInfo::MinGWARM64TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : WindowsARM64TargetInfo(Triple, Opts) { + TheCXXABI.set(TargetCXXABI::GenericAArch64); +} + +DarwinAArch64TargetInfo::DarwinAArch64TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : DarwinTargetInfo<AArch64leTargetInfo>(Triple, Opts) { + Int64Type = SignedLongLong; + if (getTriple().isArch32Bit()) + IntMaxType = SignedLongLong; + + WCharType = SignedInt; + UseSignedCharForObjCBool = false; + + LongDoubleWidth = LongDoubleAlign = SuitableAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + + UseZeroLengthBitfieldAlignment = false; + + if (getTriple().isArch32Bit()) { + UseBitFieldTypeAlignment = false; + ZeroLengthBitfieldBoundary = 32; + UseZeroLengthBitfieldAlignment = true; + TheCXXABI.set(TargetCXXABI::WatchOS); + } else + TheCXXABI.set(TargetCXXABI::AppleARM64); +} + +void DarwinAArch64TargetInfo::getOSDefines(const LangOptions &Opts, + const llvm::Triple &Triple, + MacroBuilder &Builder) const { + Builder.defineMacro("__AARCH64_SIMD__"); + if (Triple.isArch32Bit()) + Builder.defineMacro("__ARM64_ARCH_8_32__"); + else + Builder.defineMacro("__ARM64_ARCH_8__"); + Builder.defineMacro("__ARM_NEON__"); + Builder.defineMacro("__LITTLE_ENDIAN__"); + Builder.defineMacro("__REGISTER_PREFIX__", ""); + Builder.defineMacro("__arm64", "1"); + Builder.defineMacro("__arm64__", "1"); + + if (Triple.isArm64e()) + Builder.defineMacro("__arm64e__", "1"); + + getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion); +} + +TargetInfo::BuiltinVaListKind +DarwinAArch64TargetInfo::getBuiltinVaListKind() const { + return TargetInfo::CharPtrBuiltinVaList; +} + +// 64-bit RenderScript is aarch64 +RenderScript64TargetInfo::RenderScript64TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : AArch64leTargetInfo(llvm::Triple("aarch64", Triple.getVendorName(), + Triple.getOSName(), + Triple.getEnvironmentName()), + Opts) { + IsRenderScriptTarget = true; +} + +void RenderScript64TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__RENDERSCRIPT__"); + AArch64leTargetInfo::getTargetDefines(Opts, Builder); +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/AArch64.h b/contrib/llvm-project/clang/lib/Basic/Targets/AArch64.h new file mode 100644 index 000000000000..9e22aeaff251 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/AArch64.h @@ -0,0 +1,247 @@ +//===--- AArch64.h - Declare AArch64 target feature support -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares AArch64 TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_AARCH64_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_AARCH64_H + +#include "OSTargets.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/Support/AArch64TargetParser.h" +#include "llvm/Support/TargetParser.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo { + virtual void setDataLayout() = 0; + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + static const char *const GCCRegNames[]; + + enum FPUModeEnum { FPUMode, NeonMode = (1 << 0), SveMode = (1 << 1) }; + + unsigned FPU; + bool HasCRC; + bool HasCrypto; + bool HasAES; + bool HasSHA2; + bool HasSHA3; + bool HasSM4; + bool HasUnaligned; + bool HasFullFP16; + bool HasDotProd; + bool HasFP16FML; + bool HasMTE; + bool HasTME; + bool HasPAuth; + bool HasLS64; + bool HasRandGen; + bool HasMatMul; + bool HasSVE2; + bool HasSVE2AES; + bool HasSVE2SHA3; + bool HasSVE2SM4; + bool HasSVE2BitPerm; + bool HasMatmulFP64; + bool HasMatmulFP32; + bool HasLSE; + bool HasFlagM; + bool HasHBC; + bool HasMOPS; + + llvm::AArch64::ArchKind ArchKind; + + static const Builtin::Info BuiltinInfo[]; + + std::string ABI; + StringRef getArchProfile() const; + +public: + AArch64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + + StringRef getABI() const override; + bool setABI(const std::string &Name) override; + + bool validateBranchProtection(StringRef Spec, StringRef Arch, + BranchProtectionInfo &BPI, + StringRef &Err) const override; + + bool isValidCPUName(StringRef Name) const override; + void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; + bool setCPU(const std::string &Name) override; + + bool useFP16ConversionIntrinsics() const override { + return false; + } + + void getTargetDefinesARMV81A(const LangOptions &Opts, + MacroBuilder &Builder) const; + void getTargetDefinesARMV82A(const LangOptions &Opts, + MacroBuilder &Builder) const; + void getTargetDefinesARMV83A(const LangOptions &Opts, + MacroBuilder &Builder) const; + void getTargetDefinesARMV84A(const LangOptions &Opts, + MacroBuilder &Builder) const; + void getTargetDefinesARMV85A(const LangOptions &Opts, + MacroBuilder &Builder) const; + void getTargetDefinesARMV86A(const LangOptions &Opts, + MacroBuilder &Builder) const; + void getTargetDefinesARMV87A(const LangOptions &Opts, + MacroBuilder &Builder) const; + void getTargetDefinesARMV88A(const LangOptions &Opts, + MacroBuilder &Builder) const; + void getTargetDefinesARMV9A(const LangOptions &Opts, + MacroBuilder &Builder) const; + void getTargetDefinesARMV91A(const LangOptions &Opts, + MacroBuilder &Builder) const; + void getTargetDefinesARMV92A(const LangOptions &Opts, + MacroBuilder &Builder) const; + void getTargetDefinesARMV93A(const LangOptions &Opts, + MacroBuilder &Builder) const; + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + Optional<std::pair<unsigned, unsigned>> + getVScaleRange(const LangOptions &LangOpts) const override; + + bool hasFeature(StringRef Feature) const override; + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override; + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override; + + bool isCLZForZeroUndef() const override; + + BuiltinVaListKind getBuiltinVaListKind() const override; + + ArrayRef<const char *> getGCCRegNames() const override; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; + + std::string convertConstraint(const char *&Constraint) const override { + std::string R; + switch (*Constraint) { + case 'U': // Three-character constraint; add "@3" hint for later parsing. + R = std::string("@3") + std::string(Constraint, 3); + Constraint += 2; + break; + default: + R = TargetInfo::convertConstraint(Constraint); + break; + } + return R; + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override; + bool + validateConstraintModifier(StringRef Constraint, char Modifier, unsigned Size, + std::string &SuggestedModifier) const override; + const char *getClobbers() const override; + + StringRef getConstraintRegister(StringRef Constraint, + StringRef Expression) const override { + return Expression; + } + + int getEHDataRegisterNumber(unsigned RegNo) const override; + + const char *getBFloat16Mangling() const override { return "u6__bf16"; }; + bool hasInt128Type() const override; + + bool hasBitIntType() const override { return true; } +}; + +class LLVM_LIBRARY_VISIBILITY AArch64leTargetInfo : public AArch64TargetInfo { +public: + AArch64leTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +private: + void setDataLayout() override; +}; + +class LLVM_LIBRARY_VISIBILITY WindowsARM64TargetInfo + : public WindowsTargetInfo<AArch64leTargetInfo> { + const llvm::Triple Triple; + +public: + WindowsARM64TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts); + + void setDataLayout() override; + + BuiltinVaListKind getBuiltinVaListKind() const override; + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override; +}; + +// Windows ARM, MS (C++) ABI +class LLVM_LIBRARY_VISIBILITY MicrosoftARM64TargetInfo + : public WindowsARM64TargetInfo { +public: + MicrosoftARM64TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts); + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + TargetInfo::CallingConvKind + getCallingConvKind(bool ClangABICompat4) const override; + + unsigned getMinGlobalAlign(uint64_t TypeSize) const override; +}; + +// ARM64 MinGW target +class LLVM_LIBRARY_VISIBILITY MinGWARM64TargetInfo + : public WindowsARM64TargetInfo { +public: + MinGWARM64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); +}; + +class LLVM_LIBRARY_VISIBILITY AArch64beTargetInfo : public AArch64TargetInfo { +public: + AArch64beTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + +private: + void setDataLayout() override; +}; + +class LLVM_LIBRARY_VISIBILITY DarwinAArch64TargetInfo + : public DarwinTargetInfo<AArch64leTargetInfo> { +public: + DarwinAArch64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + + BuiltinVaListKind getBuiltinVaListKind() const override; + + protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override; +}; + +// 64-bit RenderScript is aarch64 +class LLVM_LIBRARY_VISIBILITY RenderScript64TargetInfo + : public AArch64leTargetInfo { +public: + RenderScript64TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts); + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +} // namespace targets +} // namespace clang + +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_AARCH64_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/AMDGPU.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/AMDGPU.cpp new file mode 100644 index 000000000000..ba7ffa34c73e --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/AMDGPU.cpp @@ -0,0 +1,448 @@ +//===--- AMDGPU.cpp - Implement AMDGPU target feature support -------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements AMDGPU TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "AMDGPU.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/CodeGenOptions.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +namespace clang { +namespace targets { + +// If you edit the description strings, make sure you update +// getPointerWidthV(). + +static const char *const DataLayoutStringR600 = + "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128" + "-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1"; + +static const char *const DataLayoutStringAMDGCN = + "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32" + "-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128" + "-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1" + "-ni:7"; + +const LangASMap AMDGPUTargetInfo::AMDGPUDefIsGenMap = { + Generic, // Default + Global, // opencl_global + Local, // opencl_local + Constant, // opencl_constant + Private, // opencl_private + Generic, // opencl_generic + Global, // opencl_global_device + Global, // opencl_global_host + Global, // cuda_device + Constant, // cuda_constant + Local, // cuda_shared + Global, // sycl_global + Global, // sycl_global_device + Global, // sycl_global_host + Local, // sycl_local + Private, // sycl_private + Generic, // ptr32_sptr + Generic, // ptr32_uptr + Generic // ptr64 +}; + +const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = { + Private, // Default + Global, // opencl_global + Local, // opencl_local + Constant, // opencl_constant + Private, // opencl_private + Generic, // opencl_generic + Global, // opencl_global_device + Global, // opencl_global_host + Global, // cuda_device + Constant, // cuda_constant + Local, // cuda_shared + // SYCL address space values for this map are dummy + Generic, // sycl_global + Generic, // sycl_global_device + Generic, // sycl_global_host + Generic, // sycl_local + Generic, // sycl_private + Generic, // ptr32_sptr + Generic, // ptr32_uptr + Generic // ptr64 + +}; +} // namespace targets +} // namespace clang + +const Builtin::Info AMDGPUTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, +#include "clang/Basic/BuiltinsAMDGPU.def" +}; + +const char *const AMDGPUTargetInfo::GCCRegNames[] = { + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", + "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", + "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", + "v27", "v28", "v29", "v30", "v31", "v32", "v33", "v34", "v35", + "v36", "v37", "v38", "v39", "v40", "v41", "v42", "v43", "v44", + "v45", "v46", "v47", "v48", "v49", "v50", "v51", "v52", "v53", + "v54", "v55", "v56", "v57", "v58", "v59", "v60", "v61", "v62", + "v63", "v64", "v65", "v66", "v67", "v68", "v69", "v70", "v71", + "v72", "v73", "v74", "v75", "v76", "v77", "v78", "v79", "v80", + "v81", "v82", "v83", "v84", "v85", "v86", "v87", "v88", "v89", + "v90", "v91", "v92", "v93", "v94", "v95", "v96", "v97", "v98", + "v99", "v100", "v101", "v102", "v103", "v104", "v105", "v106", "v107", + "v108", "v109", "v110", "v111", "v112", "v113", "v114", "v115", "v116", + "v117", "v118", "v119", "v120", "v121", "v122", "v123", "v124", "v125", + "v126", "v127", "v128", "v129", "v130", "v131", "v132", "v133", "v134", + "v135", "v136", "v137", "v138", "v139", "v140", "v141", "v142", "v143", + "v144", "v145", "v146", "v147", "v148", "v149", "v150", "v151", "v152", + "v153", "v154", "v155", "v156", "v157", "v158", "v159", "v160", "v161", + "v162", "v163", "v164", "v165", "v166", "v167", "v168", "v169", "v170", + "v171", "v172", "v173", "v174", "v175", "v176", "v177", "v178", "v179", + "v180", "v181", "v182", "v183", "v184", "v185", "v186", "v187", "v188", + "v189", "v190", "v191", "v192", "v193", "v194", "v195", "v196", "v197", + "v198", "v199", "v200", "v201", "v202", "v203", "v204", "v205", "v206", + "v207", "v208", "v209", "v210", "v211", "v212", "v213", "v214", "v215", + "v216", "v217", "v218", "v219", "v220", "v221", "v222", "v223", "v224", + "v225", "v226", "v227", "v228", "v229", "v230", "v231", "v232", "v233", + "v234", "v235", "v236", "v237", "v238", "v239", "v240", "v241", "v242", + "v243", "v244", "v245", "v246", "v247", "v248", "v249", "v250", "v251", + "v252", "v253", "v254", "v255", "s0", "s1", "s2", "s3", "s4", + "s5", "s6", "s7", "s8", "s9", "s10", "s11", "s12", "s13", + "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22", + "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", + "s32", "s33", "s34", "s35", "s36", "s37", "s38", "s39", "s40", + "s41", "s42", "s43", "s44", "s45", "s46", "s47", "s48", "s49", + "s50", "s51", "s52", "s53", "s54", "s55", "s56", "s57", "s58", + "s59", "s60", "s61", "s62", "s63", "s64", "s65", "s66", "s67", + "s68", "s69", "s70", "s71", "s72", "s73", "s74", "s75", "s76", + "s77", "s78", "s79", "s80", "s81", "s82", "s83", "s84", "s85", + "s86", "s87", "s88", "s89", "s90", "s91", "s92", "s93", "s94", + "s95", "s96", "s97", "s98", "s99", "s100", "s101", "s102", "s103", + "s104", "s105", "s106", "s107", "s108", "s109", "s110", "s111", "s112", + "s113", "s114", "s115", "s116", "s117", "s118", "s119", "s120", "s121", + "s122", "s123", "s124", "s125", "s126", "s127", "exec", "vcc", "scc", + "m0", "flat_scratch", "exec_lo", "exec_hi", "vcc_lo", "vcc_hi", + "flat_scratch_lo", "flat_scratch_hi", + "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", + "a9", "a10", "a11", "a12", "a13", "a14", "a15", "a16", "a17", + "a18", "a19", "a20", "a21", "a22", "a23", "a24", "a25", "a26", + "a27", "a28", "a29", "a30", "a31", "a32", "a33", "a34", "a35", + "a36", "a37", "a38", "a39", "a40", "a41", "a42", "a43", "a44", + "a45", "a46", "a47", "a48", "a49", "a50", "a51", "a52", "a53", + "a54", "a55", "a56", "a57", "a58", "a59", "a60", "a61", "a62", + "a63", "a64", "a65", "a66", "a67", "a68", "a69", "a70", "a71", + "a72", "a73", "a74", "a75", "a76", "a77", "a78", "a79", "a80", + "a81", "a82", "a83", "a84", "a85", "a86", "a87", "a88", "a89", + "a90", "a91", "a92", "a93", "a94", "a95", "a96", "a97", "a98", + "a99", "a100", "a101", "a102", "a103", "a104", "a105", "a106", "a107", + "a108", "a109", "a110", "a111", "a112", "a113", "a114", "a115", "a116", + "a117", "a118", "a119", "a120", "a121", "a122", "a123", "a124", "a125", + "a126", "a127", "a128", "a129", "a130", "a131", "a132", "a133", "a134", + "a135", "a136", "a137", "a138", "a139", "a140", "a141", "a142", "a143", + "a144", "a145", "a146", "a147", "a148", "a149", "a150", "a151", "a152", + "a153", "a154", "a155", "a156", "a157", "a158", "a159", "a160", "a161", + "a162", "a163", "a164", "a165", "a166", "a167", "a168", "a169", "a170", + "a171", "a172", "a173", "a174", "a175", "a176", "a177", "a178", "a179", + "a180", "a181", "a182", "a183", "a184", "a185", "a186", "a187", "a188", + "a189", "a190", "a191", "a192", "a193", "a194", "a195", "a196", "a197", + "a198", "a199", "a200", "a201", "a202", "a203", "a204", "a205", "a206", + "a207", "a208", "a209", "a210", "a211", "a212", "a213", "a214", "a215", + "a216", "a217", "a218", "a219", "a220", "a221", "a222", "a223", "a224", + "a225", "a226", "a227", "a228", "a229", "a230", "a231", "a232", "a233", + "a234", "a235", "a236", "a237", "a238", "a239", "a240", "a241", "a242", + "a243", "a244", "a245", "a246", "a247", "a248", "a249", "a250", "a251", + "a252", "a253", "a254", "a255" +}; + +ArrayRef<const char *> AMDGPUTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +bool AMDGPUTargetInfo::initFeatureMap( + llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, + const std::vector<std::string> &FeatureVec) const { + + using namespace llvm::AMDGPU; + + // XXX - What does the member GPU mean if device name string passed here? + if (isAMDGCN(getTriple())) { + switch (llvm::AMDGPU::parseArchAMDGCN(CPU)) { + case GK_GFX1035: + case GK_GFX1034: + case GK_GFX1033: + case GK_GFX1032: + case GK_GFX1031: + case GK_GFX1030: + Features["ci-insts"] = true; + Features["dot1-insts"] = true; + Features["dot2-insts"] = true; + Features["dot5-insts"] = true; + Features["dot6-insts"] = true; + Features["dot7-insts"] = true; + Features["dl-insts"] = true; + Features["flat-address-space"] = true; + Features["16-bit-insts"] = true; + Features["dpp"] = true; + Features["gfx8-insts"] = true; + Features["gfx9-insts"] = true; + Features["gfx10-insts"] = true; + Features["gfx10-3-insts"] = true; + Features["s-memrealtime"] = true; + Features["s-memtime-inst"] = true; + break; + case GK_GFX1012: + case GK_GFX1011: + Features["dot1-insts"] = true; + Features["dot2-insts"] = true; + Features["dot5-insts"] = true; + Features["dot6-insts"] = true; + Features["dot7-insts"] = true; + LLVM_FALLTHROUGH; + case GK_GFX1013: + case GK_GFX1010: + Features["dl-insts"] = true; + Features["ci-insts"] = true; + Features["flat-address-space"] = true; + Features["16-bit-insts"] = true; + Features["dpp"] = true; + Features["gfx8-insts"] = true; + Features["gfx9-insts"] = true; + Features["gfx10-insts"] = true; + Features["s-memrealtime"] = true; + Features["s-memtime-inst"] = true; + break; + case GK_GFX90A: + Features["gfx90a-insts"] = true; + LLVM_FALLTHROUGH; + case GK_GFX908: + Features["dot3-insts"] = true; + Features["dot4-insts"] = true; + Features["dot5-insts"] = true; + Features["dot6-insts"] = true; + Features["mai-insts"] = true; + LLVM_FALLTHROUGH; + case GK_GFX906: + Features["dl-insts"] = true; + Features["dot1-insts"] = true; + Features["dot2-insts"] = true; + Features["dot7-insts"] = true; + LLVM_FALLTHROUGH; + case GK_GFX90C: + case GK_GFX909: + case GK_GFX904: + case GK_GFX902: + case GK_GFX900: + Features["gfx9-insts"] = true; + LLVM_FALLTHROUGH; + case GK_GFX810: + case GK_GFX805: + case GK_GFX803: + case GK_GFX802: + case GK_GFX801: + Features["gfx8-insts"] = true; + Features["16-bit-insts"] = true; + Features["dpp"] = true; + Features["s-memrealtime"] = true; + LLVM_FALLTHROUGH; + case GK_GFX705: + case GK_GFX704: + case GK_GFX703: + case GK_GFX702: + case GK_GFX701: + case GK_GFX700: + Features["ci-insts"] = true; + Features["flat-address-space"] = true; + LLVM_FALLTHROUGH; + case GK_GFX602: + case GK_GFX601: + case GK_GFX600: + Features["s-memtime-inst"] = true; + break; + case GK_NONE: + break; + default: + llvm_unreachable("Unhandled GPU!"); + } + } else { + if (CPU.empty()) + CPU = "r600"; + + switch (llvm::AMDGPU::parseArchR600(CPU)) { + case GK_CAYMAN: + case GK_CYPRESS: + case GK_RV770: + case GK_RV670: + // TODO: Add fp64 when implemented. + break; + case GK_TURKS: + case GK_CAICOS: + case GK_BARTS: + case GK_SUMO: + case GK_REDWOOD: + case GK_JUNIPER: + case GK_CEDAR: + case GK_RV730: + case GK_RV710: + case GK_RS880: + case GK_R630: + case GK_R600: + break; + default: + llvm_unreachable("Unhandled GPU!"); + } + } + + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec); +} + +void AMDGPUTargetInfo::fillValidCPUList( + SmallVectorImpl<StringRef> &Values) const { + if (isAMDGCN(getTriple())) + llvm::AMDGPU::fillValidArchListAMDGCN(Values); + else + llvm::AMDGPU::fillValidArchListR600(Values); +} + +void AMDGPUTargetInfo::setAddressSpaceMap(bool DefaultIsPrivate) { + AddrSpaceMap = DefaultIsPrivate ? &AMDGPUDefIsPrivMap : &AMDGPUDefIsGenMap; +} + +AMDGPUTargetInfo::AMDGPUTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : TargetInfo(Triple), + GPUKind(isAMDGCN(Triple) ? + llvm::AMDGPU::parseArchAMDGCN(Opts.CPU) : + llvm::AMDGPU::parseArchR600(Opts.CPU)), + GPUFeatures(isAMDGCN(Triple) ? + llvm::AMDGPU::getArchAttrAMDGCN(GPUKind) : + llvm::AMDGPU::getArchAttrR600(GPUKind)) { + resetDataLayout(isAMDGCN(getTriple()) ? DataLayoutStringAMDGCN + : DataLayoutStringR600); + + setAddressSpaceMap(Triple.getOS() == llvm::Triple::Mesa3D || + !isAMDGCN(Triple)); + UseAddrSpaceMapMangling = true; + + HasLegalHalfType = true; + HasFloat16 = true; + WavefrontSize = GPUFeatures & llvm::AMDGPU::FEATURE_WAVE32 ? 32 : 64; + AllowAMDGPUUnsafeFPAtomics = Opts.AllowAMDGPUUnsafeFPAtomics; + + // Set pointer width and alignment for target address space 0. + PointerWidth = PointerAlign = getPointerWidthV(Generic); + if (getMaxPointerWidth() == 64) { + LongWidth = LongAlign = 64; + SizeType = UnsignedLong; + PtrDiffType = SignedLong; + IntPtrType = SignedLong; + } + + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; +} + +void AMDGPUTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) { + TargetInfo::adjust(Diags, Opts); + // ToDo: There are still a few places using default address space as private + // address space in OpenCL, which needs to be cleaned up, then Opts.OpenCL + // can be removed from the following line. + setAddressSpaceMap(/*DefaultIsPrivate=*/Opts.OpenCL || + !isAMDGCN(getTriple())); +} + +ArrayRef<Builtin::Info> AMDGPUTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::AMDGPU::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} + +void AMDGPUTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__AMD__"); + Builder.defineMacro("__AMDGPU__"); + + if (isAMDGCN(getTriple())) + Builder.defineMacro("__AMDGCN__"); + else + Builder.defineMacro("__R600__"); + + if (GPUKind != llvm::AMDGPU::GK_NONE) { + StringRef CanonName = isAMDGCN(getTriple()) ? + getArchNameAMDGCN(GPUKind) : getArchNameR600(GPUKind); + Builder.defineMacro(Twine("__") + Twine(CanonName) + Twine("__")); + if (isAMDGCN(getTriple())) { + Builder.defineMacro("__amdgcn_processor__", + Twine("\"") + Twine(CanonName) + Twine("\"")); + Builder.defineMacro("__amdgcn_target_id__", + Twine("\"") + Twine(getTargetID().getValue()) + + Twine("\"")); + for (auto F : getAllPossibleTargetIDFeatures(getTriple(), CanonName)) { + auto Loc = OffloadArchFeatures.find(F); + if (Loc != OffloadArchFeatures.end()) { + std::string NewF = F.str(); + std::replace(NewF.begin(), NewF.end(), '-', '_'); + Builder.defineMacro(Twine("__amdgcn_feature_") + Twine(NewF) + + Twine("__"), + Loc->second ? "1" : "0"); + } + } + } + } + + // TODO: __HAS_FMAF__, __HAS_LDEXPF__, __HAS_FP64__ are deprecated and will be + // removed in the near future. + if (hasFMAF()) + Builder.defineMacro("__HAS_FMAF__"); + if (hasFastFMAF()) + Builder.defineMacro("FP_FAST_FMAF"); + if (hasLDEXPF()) + Builder.defineMacro("__HAS_LDEXPF__"); + if (hasFP64()) + Builder.defineMacro("__HAS_FP64__"); + if (hasFastFMA()) + Builder.defineMacro("FP_FAST_FMA"); + + Builder.defineMacro("__AMDGCN_WAVEFRONT_SIZE", Twine(WavefrontSize)); +} + +void AMDGPUTargetInfo::setAuxTarget(const TargetInfo *Aux) { + assert(HalfFormat == Aux->HalfFormat); + assert(FloatFormat == Aux->FloatFormat); + assert(DoubleFormat == Aux->DoubleFormat); + + // On x86_64 long double is 80-bit extended precision format, which is + // not supported by AMDGPU. 128-bit floating point format is also not + // supported by AMDGPU. Therefore keep its own format for these two types. + auto SaveLongDoubleFormat = LongDoubleFormat; + auto SaveFloat128Format = Float128Format; + copyAuxTarget(Aux); + LongDoubleFormat = SaveLongDoubleFormat; + Float128Format = SaveFloat128Format; + // For certain builtin types support on the host target, claim they are + // support to pass the compilation of the host code during the device-side + // compilation. + // FIXME: As the side effect, we also accept `__float128` uses in the device + // code. To rejct these builtin types supported in the host target but not in + // the device target, one approach would support `device_builtin` attribute + // so that we could tell the device builtin types from the host ones. The + // also solves the different representations of the same builtin type, such + // as `size_t` in the MSVC environment. + if (Aux->hasFloat128Type()) { + HasFloat128 = true; + Float128Format = DoubleFormat; + } +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/AMDGPU.h b/contrib/llvm-project/clang/lib/Basic/Targets/AMDGPU.h new file mode 100644 index 000000000000..974922191488 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/AMDGPU.h @@ -0,0 +1,466 @@ +//===--- AMDGPU.h - Declare AMDGPU target feature support -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares AMDGPU TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_AMDGPU_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_AMDGPU_H + +#include "clang/Basic/TargetID.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/TargetParser.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo { + + static const Builtin::Info BuiltinInfo[]; + static const char *const GCCRegNames[]; + + enum AddrSpace { + Generic = 0, + Global = 1, + Local = 3, + Constant = 4, + Private = 5 + }; + static const LangASMap AMDGPUDefIsGenMap; + static const LangASMap AMDGPUDefIsPrivMap; + + llvm::AMDGPU::GPUKind GPUKind; + unsigned GPUFeatures; + unsigned WavefrontSize; + + /// Target ID is device name followed by optional feature name postfixed + /// by plus or minus sign delimitted by colon, e.g. gfx908:xnack+:sramecc-. + /// If the target ID contains feature+, map it to true. + /// If the target ID contains feature-, map it to false. + /// If the target ID does not contain a feature (default), do not map it. + llvm::StringMap<bool> OffloadArchFeatures; + std::string TargetID; + + bool hasFP64() const { + return getTriple().getArch() == llvm::Triple::amdgcn || + !!(GPUFeatures & llvm::AMDGPU::FEATURE_FP64); + } + + /// Has fast fma f32 + bool hasFastFMAF() const { + return !!(GPUFeatures & llvm::AMDGPU::FEATURE_FAST_FMA_F32); + } + + /// Has fast fma f64 + bool hasFastFMA() const { + return getTriple().getArch() == llvm::Triple::amdgcn; + } + + bool hasFMAF() const { + return getTriple().getArch() == llvm::Triple::amdgcn || + !!(GPUFeatures & llvm::AMDGPU::FEATURE_FMA); + } + + bool hasFullRateDenormalsF32() const { + return !!(GPUFeatures & llvm::AMDGPU::FEATURE_FAST_DENORMAL_F32); + } + + bool hasLDEXPF() const { + return getTriple().getArch() == llvm::Triple::amdgcn || + !!(GPUFeatures & llvm::AMDGPU::FEATURE_LDEXP); + } + + static bool isAMDGCN(const llvm::Triple &TT) { + return TT.getArch() == llvm::Triple::amdgcn; + } + + static bool isR600(const llvm::Triple &TT) { + return TT.getArch() == llvm::Triple::r600; + } + +public: + AMDGPUTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + + void setAddressSpaceMap(bool DefaultIsPrivate); + + void adjust(DiagnosticsEngine &Diags, LangOptions &Opts) override; + + uint64_t getPointerWidthV(unsigned AddrSpace) const override { + if (isR600(getTriple())) + return 32; + + if (AddrSpace == Private || AddrSpace == Local) + return 32; + + return 64; + } + + uint64_t getPointerAlignV(unsigned AddrSpace) const override { + return getPointerWidthV(AddrSpace); + } + + uint64_t getMaxPointerWidth() const override { + return getTriple().getArch() == llvm::Triple::amdgcn ? 64 : 32; + } + + const char *getClobbers() const override { return ""; } + + ArrayRef<const char *> getGCCRegNames() const override; + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; + } + + /// Accepted register names: (n, m is unsigned integer, n < m) + /// v + /// s + /// a + /// {vn}, {v[n]} + /// {sn}, {s[n]} + /// {an}, {a[n]} + /// {S} , where S is a special register name + ////{v[n:m]} + /// {s[n:m]} + /// {a[n:m]} + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + static const ::llvm::StringSet<> SpecialRegs({ + "exec", "vcc", "flat_scratch", "m0", "scc", "tba", "tma", + "flat_scratch_lo", "flat_scratch_hi", "vcc_lo", "vcc_hi", "exec_lo", + "exec_hi", "tma_lo", "tma_hi", "tba_lo", "tba_hi", + }); + + switch (*Name) { + case 'I': + Info.setRequiresImmediate(-16, 64); + return true; + case 'J': + Info.setRequiresImmediate(-32768, 32767); + return true; + case 'A': + case 'B': + case 'C': + Info.setRequiresImmediate(); + return true; + default: + break; + } + + StringRef S(Name); + + if (S == "DA" || S == "DB") { + Name++; + Info.setRequiresImmediate(); + return true; + } + + bool HasLeftParen = false; + if (S.front() == '{') { + HasLeftParen = true; + S = S.drop_front(); + } + if (S.empty()) + return false; + if (S.front() != 'v' && S.front() != 's' && S.front() != 'a') { + if (!HasLeftParen) + return false; + auto E = S.find('}'); + if (!SpecialRegs.count(S.substr(0, E))) + return false; + S = S.drop_front(E + 1); + if (!S.empty()) + return false; + // Found {S} where S is a special register. + Info.setAllowsRegister(); + Name = S.data() - 1; + return true; + } + S = S.drop_front(); + if (!HasLeftParen) { + if (!S.empty()) + return false; + // Found s, v or a. + Info.setAllowsRegister(); + Name = S.data() - 1; + return true; + } + bool HasLeftBracket = false; + if (!S.empty() && S.front() == '[') { + HasLeftBracket = true; + S = S.drop_front(); + } + unsigned long long N; + if (S.empty() || consumeUnsignedInteger(S, 10, N)) + return false; + if (!S.empty() && S.front() == ':') { + if (!HasLeftBracket) + return false; + S = S.drop_front(); + unsigned long long M; + if (consumeUnsignedInteger(S, 10, M) || N >= M) + return false; + } + if (HasLeftBracket) { + if (S.empty() || S.front() != ']') + return false; + S = S.drop_front(); + } + if (S.empty() || S.front() != '}') + return false; + S = S.drop_front(); + if (!S.empty()) + return false; + // Found {vn}, {sn}, {an}, {v[n]}, {s[n]}, {a[n]}, {v[n:m]}, {s[n:m]} + // or {a[n:m]}. + Info.setAllowsRegister(); + Name = S.data() - 1; + return true; + } + + // \p Constraint will be left pointing at the last character of + // the constraint. In practice, it won't be changed unless the + // constraint is longer than one character. + std::string convertConstraint(const char *&Constraint) const override { + + StringRef S(Constraint); + if (S == "DA" || S == "DB") { + return std::string("^") + std::string(Constraint++, 2); + } + + const char *Begin = Constraint; + TargetInfo::ConstraintInfo Info("", ""); + if (validateAsmConstraint(Constraint, Info)) + return std::string(Begin).substr(0, Constraint - Begin + 1); + + Constraint = Begin; + return std::string(1, *Constraint); + } + + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeatureVec) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + bool useFP16ConversionIntrinsics() const override { return false; } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::CharPtrBuiltinVaList; + } + + bool isValidCPUName(StringRef Name) const override { + if (getTriple().getArch() == llvm::Triple::amdgcn) + return llvm::AMDGPU::parseArchAMDGCN(Name) != llvm::AMDGPU::GK_NONE; + return llvm::AMDGPU::parseArchR600(Name) != llvm::AMDGPU::GK_NONE; + } + + void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; + + bool setCPU(const std::string &Name) override { + if (getTriple().getArch() == llvm::Triple::amdgcn) { + GPUKind = llvm::AMDGPU::parseArchAMDGCN(Name); + GPUFeatures = llvm::AMDGPU::getArchAttrAMDGCN(GPUKind); + } else { + GPUKind = llvm::AMDGPU::parseArchR600(Name); + GPUFeatures = llvm::AMDGPU::getArchAttrR600(GPUKind); + } + + return GPUKind != llvm::AMDGPU::GK_NONE; + } + + void setSupportedOpenCLOpts() override { + auto &Opts = getSupportedOpenCLOpts(); + Opts["cl_clang_storage_class_specifiers"] = true; + Opts["__cl_clang_variadic_functions"] = true; + Opts["__cl_clang_function_pointers"] = true; + Opts["__cl_clang_non_portable_kernel_param_types"] = true; + Opts["__cl_clang_bitfields"] = true; + + bool IsAMDGCN = isAMDGCN(getTriple()); + + Opts["cl_khr_fp64"] = hasFP64(); + Opts["__opencl_c_fp64"] = hasFP64(); + + if (IsAMDGCN || GPUKind >= llvm::AMDGPU::GK_CEDAR) { + Opts["cl_khr_byte_addressable_store"] = true; + Opts["cl_khr_global_int32_base_atomics"] = true; + Opts["cl_khr_global_int32_extended_atomics"] = true; + Opts["cl_khr_local_int32_base_atomics"] = true; + Opts["cl_khr_local_int32_extended_atomics"] = true; + } + + if (IsAMDGCN) { + Opts["cl_khr_fp16"] = true; + Opts["cl_khr_int64_base_atomics"] = true; + Opts["cl_khr_int64_extended_atomics"] = true; + Opts["cl_khr_mipmap_image"] = true; + Opts["cl_khr_mipmap_image_writes"] = true; + Opts["cl_khr_subgroups"] = true; + Opts["cl_amd_media_ops"] = true; + Opts["cl_amd_media_ops2"] = true; + + Opts["__opencl_c_images"] = true; + Opts["__opencl_c_3d_image_writes"] = true; + Opts["cl_khr_3d_image_writes"] = true; + } + } + + LangAS getOpenCLTypeAddrSpace(OpenCLTypeKind TK) const override { + switch (TK) { + case OCLTK_Image: + return LangAS::opencl_constant; + + case OCLTK_ClkEvent: + case OCLTK_Queue: + case OCLTK_ReserveID: + return LangAS::opencl_global; + + default: + return TargetInfo::getOpenCLTypeAddrSpace(TK); + } + } + + LangAS getOpenCLBuiltinAddressSpace(unsigned AS) const override { + switch (AS) { + case 0: + return LangAS::opencl_generic; + case 1: + return LangAS::opencl_global; + case 3: + return LangAS::opencl_local; + case 4: + return LangAS::opencl_constant; + case 5: + return LangAS::opencl_private; + default: + return getLangASFromTargetAS(AS); + } + } + + LangAS getCUDABuiltinAddressSpace(unsigned AS) const override { + switch (AS) { + case 0: + return LangAS::Default; + case 1: + return LangAS::cuda_device; + case 3: + return LangAS::cuda_shared; + case 4: + return LangAS::cuda_constant; + default: + return getLangASFromTargetAS(AS); + } + } + + llvm::Optional<LangAS> getConstantAddressSpace() const override { + return getLangASFromTargetAS(Constant); + } + + const llvm::omp::GV &getGridValue() const override { + switch (WavefrontSize) { + case 32: + return llvm::omp::getAMDGPUGridValues<32>(); + case 64: + return llvm::omp::getAMDGPUGridValues<64>(); + default: + llvm_unreachable("getGridValue not implemented for this wavesize"); + } + } + + /// \returns Target specific vtbl ptr address space. + unsigned getVtblPtrAddressSpace() const override { + return static_cast<unsigned>(Constant); + } + + /// \returns If a target requires an address within a target specific address + /// space \p AddressSpace to be converted in order to be used, then return the + /// corresponding target specific DWARF address space. + /// + /// \returns Otherwise return None and no conversion will be emitted in the + /// DWARF. + Optional<unsigned> + getDWARFAddressSpace(unsigned AddressSpace) const override { + const unsigned DWARF_Private = 1; + const unsigned DWARF_Local = 2; + if (AddressSpace == Private) { + return DWARF_Private; + } else if (AddressSpace == Local) { + return DWARF_Local; + } else { + return None; + } + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + switch (CC) { + default: + return CCCR_Warning; + case CC_C: + case CC_OpenCLKernel: + return CCCR_OK; + } + } + + // In amdgcn target the null pointer in global, constant, and generic + // address space has value 0 but in private and local address space has + // value ~0. + uint64_t getNullPointerValue(LangAS AS) const override { + // FIXME: Also should handle region. + return (AS == LangAS::opencl_local || AS == LangAS::opencl_private) + ? ~0 : 0; + } + + void setAuxTarget(const TargetInfo *Aux) override; + + bool hasBitIntType() const override { return true; } + + // Record offload arch features since they are needed for defining the + // pre-defined macros. + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override { + auto TargetIDFeatures = + getAllPossibleTargetIDFeatures(getTriple(), getArchNameAMDGCN(GPUKind)); + llvm::for_each(Features, [&](const auto &F) { + assert(F.front() == '+' || F.front() == '-'); + if (F == "+wavefrontsize64") + WavefrontSize = 64; + bool IsOn = F.front() == '+'; + StringRef Name = StringRef(F).drop_front(); + if (!llvm::is_contained(TargetIDFeatures, Name)) + return; + assert(OffloadArchFeatures.find(Name) == OffloadArchFeatures.end()); + OffloadArchFeatures[Name] = IsOn; + }); + return true; + } + + Optional<std::string> getTargetID() const override { + if (!isAMDGCN(getTriple())) + return llvm::None; + // When -target-cpu is not set, we assume generic code that it is valid + // for all GPU and use an empty string as target ID to represent that. + if (GPUKind == llvm::AMDGPU::GK_NONE) + return std::string(""); + return getCanonicalTargetID(getArchNameAMDGCN(GPUKind), + OffloadArchFeatures); + } +}; + +} // namespace targets +} // namespace clang + +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_AMDGPU_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/ARC.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/ARC.cpp new file mode 100644 index 000000000000..5cc13e2cf728 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/ARC.cpp @@ -0,0 +1,24 @@ +//===--- ARC.cpp - Implement ARC target feature support -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements ARC TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "ARC.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" + +using namespace clang; +using namespace clang::targets; + +void ARCTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__arc__"); +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/ARC.h b/contrib/llvm-project/clang/lib/Basic/Targets/ARC.h new file mode 100644 index 000000000000..5411cd2cd869 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/ARC.h @@ -0,0 +1,77 @@ +//===--- ARC.h - Declare ARC target feature support -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares ARC TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_ARC_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_ARC_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY ARCTargetInfo : public TargetInfo { +public: + ARCTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + NoAsmVariants = true; + LongLongAlign = 32; + SuitableAlign = 32; + DoubleAlign = LongDoubleAlign = 32; + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + UseZeroLengthBitfieldAlignment = true; + resetDataLayout("e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-" + "i32:32:32-f32:32:32-i64:32-f64:32-a:0:32-n32"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + const char *getClobbers() const override { return ""; } + + ArrayRef<const char *> getGCCRegNames() const override { + static const char *const GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "gp", "sp", "fp", "ilink1", "r30", "blink"}; + return llvm::makeArrayRef(GCCRegNames); + } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + return false; + } + + bool hasBitIntType() const override { return true; } + + bool isCLZForZeroUndef() const override { return false; } +}; + +} // namespace targets +} // namespace clang + +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_ARC_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/ARM.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/ARM.cpp new file mode 100644 index 000000000000..9c9d198e8f32 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/ARM.cpp @@ -0,0 +1,1412 @@ +//===--- ARM.cpp - Implement ARM target feature support -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements ARM TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "ARM.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +void ARMTargetInfo::setABIAAPCS() { + IsAAPCS = true; + + DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64; + BFloat16Width = BFloat16Align = 16; + BFloat16Format = &llvm::APFloat::BFloat(); + + const llvm::Triple &T = getTriple(); + + bool IsNetBSD = T.isOSNetBSD(); + bool IsOpenBSD = T.isOSOpenBSD(); + if (!T.isOSWindows() && !IsNetBSD && !IsOpenBSD) + WCharType = UnsignedInt; + + UseBitFieldTypeAlignment = true; + + ZeroLengthBitfieldBoundary = 0; + + // Thumb1 add sp, #imm requires the immediate value be multiple of 4, + // so set preferred for small types to 32. + if (T.isOSBinFormatMachO()) { + resetDataLayout(BigEndian + ? "E-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" + : "e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64", + "_"); + } else if (T.isOSWindows()) { + assert(!BigEndian && "Windows on ARM does not support big endian"); + resetDataLayout("e" + "-m:w" + "-p:32:32" + "-Fi8" + "-i64:64" + "-v128:64:128" + "-a:0:32" + "-n32" + "-S64"); + } else if (T.isOSNaCl()) { + assert(!BigEndian && "NaCl on ARM does not support big endian"); + resetDataLayout("e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S128"); + } else { + resetDataLayout(BigEndian + ? "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" + : "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"); + } + + // FIXME: Enumerated types are variable width in straight AAPCS. +} + +void ARMTargetInfo::setABIAPCS(bool IsAAPCS16) { + const llvm::Triple &T = getTriple(); + + IsAAPCS = false; + + if (IsAAPCS16) + DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64; + else + DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 32; + BFloat16Width = BFloat16Align = 16; + BFloat16Format = &llvm::APFloat::BFloat(); + + WCharType = SignedInt; + + // Do not respect the alignment of bit-field types when laying out + // structures. This corresponds to PCC_BITFIELD_TYPE_MATTERS in gcc. + UseBitFieldTypeAlignment = false; + + /// gcc forces the alignment to 4 bytes, regardless of the type of the + /// zero length bitfield. This corresponds to EMPTY_FIELD_BOUNDARY in + /// gcc. + ZeroLengthBitfieldBoundary = 32; + + if (T.isOSBinFormatMachO() && IsAAPCS16) { + assert(!BigEndian && "AAPCS16 does not support big-endian"); + resetDataLayout("e-m:o-p:32:32-Fi8-i64:64-a:0:32-n32-S128", "_"); + } else if (T.isOSBinFormatMachO()) + resetDataLayout( + BigEndian + ? "E-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" + : "e-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32", + "_"); + else + resetDataLayout( + BigEndian + ? "E-m:e-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" + : "e-m:e-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"); + + // FIXME: Override "preferred align" for double and long long. +} + +void ARMTargetInfo::setArchInfo() { + StringRef ArchName = getTriple().getArchName(); + + ArchISA = llvm::ARM::parseArchISA(ArchName); + CPU = std::string(llvm::ARM::getDefaultCPU(ArchName)); + llvm::ARM::ArchKind AK = llvm::ARM::parseArch(ArchName); + if (AK != llvm::ARM::ArchKind::INVALID) + ArchKind = AK; + setArchInfo(ArchKind); +} + +void ARMTargetInfo::setArchInfo(llvm::ARM::ArchKind Kind) { + StringRef SubArch; + + // cache TargetParser info + ArchKind = Kind; + SubArch = llvm::ARM::getSubArch(ArchKind); + ArchProfile = llvm::ARM::parseArchProfile(SubArch); + ArchVersion = llvm::ARM::parseArchVersion(SubArch); + + // cache CPU related strings + CPUAttr = getCPUAttr(); + CPUProfile = getCPUProfile(); +} + +void ARMTargetInfo::setAtomic() { + // when triple does not specify a sub arch, + // then we are not using inline atomics + bool ShouldUseInlineAtomic = + (ArchISA == llvm::ARM::ISAKind::ARM && ArchVersion >= 6) || + (ArchISA == llvm::ARM::ISAKind::THUMB && ArchVersion >= 7); + // Cortex M does not support 8 byte atomics, while general Thumb2 does. + if (ArchProfile == llvm::ARM::ProfileKind::M) { + MaxAtomicPromoteWidth = 32; + if (ShouldUseInlineAtomic) + MaxAtomicInlineWidth = 32; + } else { + MaxAtomicPromoteWidth = 64; + if (ShouldUseInlineAtomic) + MaxAtomicInlineWidth = 64; + } +} + +bool ARMTargetInfo::hasMVE() const { + return ArchKind == llvm::ARM::ArchKind::ARMV8_1MMainline && MVE != 0; +} + +bool ARMTargetInfo::hasMVEFloat() const { + return hasMVE() && (MVE & MVE_FP); +} + +bool ARMTargetInfo::hasCDE() const { return getARMCDECoprocMask() != 0; } + +bool ARMTargetInfo::isThumb() const { + return ArchISA == llvm::ARM::ISAKind::THUMB; +} + +bool ARMTargetInfo::supportsThumb() const { + return CPUAttr.count('T') || ArchVersion >= 6; +} + +bool ARMTargetInfo::supportsThumb2() const { + return CPUAttr.equals("6T2") || + (ArchVersion >= 7 && !CPUAttr.equals("8M_BASE")); +} + +StringRef ARMTargetInfo::getCPUAttr() const { + // For most sub-arches, the build attribute CPU name is enough. + // For Cortex variants, it's slightly different. + switch (ArchKind) { + default: + return llvm::ARM::getCPUAttr(ArchKind); + case llvm::ARM::ArchKind::ARMV6M: + return "6M"; + case llvm::ARM::ArchKind::ARMV7S: + return "7S"; + case llvm::ARM::ArchKind::ARMV7A: + return "7A"; + case llvm::ARM::ArchKind::ARMV7R: + return "7R"; + case llvm::ARM::ArchKind::ARMV7M: + return "7M"; + case llvm::ARM::ArchKind::ARMV7EM: + return "7EM"; + case llvm::ARM::ArchKind::ARMV7VE: + return "7VE"; + case llvm::ARM::ArchKind::ARMV8A: + return "8A"; + case llvm::ARM::ArchKind::ARMV8_1A: + return "8_1A"; + case llvm::ARM::ArchKind::ARMV8_2A: + return "8_2A"; + case llvm::ARM::ArchKind::ARMV8_3A: + return "8_3A"; + case llvm::ARM::ArchKind::ARMV8_4A: + return "8_4A"; + case llvm::ARM::ArchKind::ARMV8_5A: + return "8_5A"; + case llvm::ARM::ArchKind::ARMV8_6A: + return "8_6A"; + case llvm::ARM::ArchKind::ARMV8_7A: + return "8_7A"; + case llvm::ARM::ArchKind::ARMV8_8A: + return "8_8A"; + case llvm::ARM::ArchKind::ARMV9A: + return "9A"; + case llvm::ARM::ArchKind::ARMV9_1A: + return "9_1A"; + case llvm::ARM::ArchKind::ARMV9_2A: + return "9_2A"; + case llvm::ARM::ArchKind::ARMV9_3A: + return "9_3A"; + case llvm::ARM::ArchKind::ARMV8MBaseline: + return "8M_BASE"; + case llvm::ARM::ArchKind::ARMV8MMainline: + return "8M_MAIN"; + case llvm::ARM::ArchKind::ARMV8R: + return "8R"; + case llvm::ARM::ArchKind::ARMV8_1MMainline: + return "8_1M_MAIN"; + } +} + +StringRef ARMTargetInfo::getCPUProfile() const { + switch (ArchProfile) { + case llvm::ARM::ProfileKind::A: + return "A"; + case llvm::ARM::ProfileKind::R: + return "R"; + case llvm::ARM::ProfileKind::M: + return "M"; + default: + return ""; + } +} + +ARMTargetInfo::ARMTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : TargetInfo(Triple), FPMath(FP_Default), IsAAPCS(true), LDREX(0), + HW_FP(0) { + bool IsOpenBSD = Triple.isOSOpenBSD(); + bool IsNetBSD = Triple.isOSNetBSD(); + + // FIXME: the isOSBinFormatMachO is a workaround for identifying a Darwin-like + // environment where size_t is `unsigned long` rather than `unsigned int` + + PtrDiffType = IntPtrType = + (Triple.isOSDarwin() || Triple.isOSBinFormatMachO() || IsOpenBSD || + IsNetBSD) + ? SignedLong + : SignedInt; + + SizeType = (Triple.isOSDarwin() || Triple.isOSBinFormatMachO() || IsOpenBSD || + IsNetBSD) + ? UnsignedLong + : UnsignedInt; + + // ptrdiff_t is inconsistent on Darwin + if ((Triple.isOSDarwin() || Triple.isOSBinFormatMachO()) && + !Triple.isWatchABI()) + PtrDiffType = SignedInt; + + // Cache arch related info. + setArchInfo(); + + // {} in inline assembly are neon specifiers, not assembly variant + // specifiers. + NoAsmVariants = true; + + // FIXME: This duplicates code from the driver that sets the -target-abi + // option - this code is used if -target-abi isn't passed and should + // be unified in some way. + if (Triple.isOSBinFormatMachO()) { + // The backend is hardwired to assume AAPCS for M-class processors, ensure + // the frontend matches that. + if (Triple.getEnvironment() == llvm::Triple::EABI || + Triple.getOS() == llvm::Triple::UnknownOS || + ArchProfile == llvm::ARM::ProfileKind::M) { + setABI("aapcs"); + } else if (Triple.isWatchABI()) { + setABI("aapcs16"); + } else { + setABI("apcs-gnu"); + } + } else if (Triple.isOSWindows()) { + // FIXME: this is invalid for WindowsCE + setABI("aapcs"); + } else { + // Select the default based on the platform. + switch (Triple.getEnvironment()) { + case llvm::Triple::Android: + case llvm::Triple::GNUEABI: + case llvm::Triple::GNUEABIHF: + case llvm::Triple::MuslEABI: + case llvm::Triple::MuslEABIHF: + setABI("aapcs-linux"); + break; + case llvm::Triple::EABIHF: + case llvm::Triple::EABI: + setABI("aapcs"); + break; + case llvm::Triple::GNU: + setABI("apcs-gnu"); + break; + default: + if (IsNetBSD) + setABI("apcs-gnu"); + else if (IsOpenBSD) + setABI("aapcs-linux"); + else + setABI("aapcs"); + break; + } + } + + // ARM targets default to using the ARM C++ ABI. + TheCXXABI.set(TargetCXXABI::GenericARM); + + // ARM has atomics up to 8 bytes + setAtomic(); + + // Maximum alignment for ARM NEON data types should be 64-bits (AAPCS) + // as well the default alignment + if (IsAAPCS && !Triple.isAndroid()) + DefaultAlignForAttributeAligned = MaxVectorAlign = 64; + + // Do force alignment of members that follow zero length bitfields. If + // the alignment of the zero-length bitfield is greater than the member + // that follows it, `bar', `bar' will be aligned as the type of the + // zero length bitfield. + UseZeroLengthBitfieldAlignment = true; + + if (Triple.getOS() == llvm::Triple::Linux || + Triple.getOS() == llvm::Triple::UnknownOS) + this->MCountName = Opts.EABIVersion == llvm::EABI::GNU + ? "llvm.arm.gnu.eabi.mcount" + : "\01mcount"; + + SoftFloatABI = llvm::is_contained(Opts.FeaturesAsWritten, "+soft-float-abi"); +} + +StringRef ARMTargetInfo::getABI() const { return ABI; } + +bool ARMTargetInfo::setABI(const std::string &Name) { + ABI = Name; + + // The defaults (above) are for AAPCS, check if we need to change them. + // + // FIXME: We need support for -meabi... we could just mangle it into the + // name. + if (Name == "apcs-gnu" || Name == "aapcs16") { + setABIAPCS(Name == "aapcs16"); + return true; + } + if (Name == "aapcs" || Name == "aapcs-vfp" || Name == "aapcs-linux") { + setABIAAPCS(); + return true; + } + return false; +} + +bool ARMTargetInfo::isBranchProtectionSupportedArch(StringRef Arch) const { + llvm::ARM::ArchKind CPUArch = llvm::ARM::parseCPUArch(Arch); + if (CPUArch == llvm::ARM::ArchKind::INVALID) + CPUArch = llvm::ARM::parseArch(getTriple().getArchName()); + + if (CPUArch == llvm::ARM::ArchKind::INVALID) + return false; + + StringRef ArchFeature = llvm::ARM::getArchName(CPUArch); + auto a = + llvm::Triple(ArchFeature, getTriple().getVendorName(), + getTriple().getOSName(), getTriple().getEnvironmentName()); + + StringRef SubArch = llvm::ARM::getSubArch(CPUArch); + llvm::ARM::ProfileKind Profile = llvm::ARM::parseArchProfile(SubArch); + return a.isArmT32() && (Profile == llvm::ARM::ProfileKind::M); +} + +bool ARMTargetInfo::validateBranchProtection(StringRef Spec, StringRef Arch, + BranchProtectionInfo &BPI, + StringRef &Err) const { + llvm::ARM::ParsedBranchProtection PBP; + if (!llvm::ARM::parseBranchProtection(Spec, PBP, Err)) + return false; + + if (!isBranchProtectionSupportedArch(Arch)) + return false; + + BPI.SignReturnAddr = + llvm::StringSwitch<LangOptions::SignReturnAddressScopeKind>(PBP.Scope) + .Case("non-leaf", LangOptions::SignReturnAddressScopeKind::NonLeaf) + .Case("all", LangOptions::SignReturnAddressScopeKind::All) + .Default(LangOptions::SignReturnAddressScopeKind::None); + + // Don't care for the sign key, beyond issuing a warning. + if (PBP.Key == "b_key") + Err = "b-key"; + BPI.SignKey = LangOptions::SignReturnAddressKeyKind::AKey; + + BPI.BranchTargetEnforcement = PBP.BranchTargetEnforcement; + return true; +} + +// FIXME: This should be based on Arch attributes, not CPU names. +bool ARMTargetInfo::initFeatureMap( + llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, + const std::vector<std::string> &FeaturesVec) const { + + std::string ArchFeature; + std::vector<StringRef> TargetFeatures; + llvm::ARM::ArchKind Arch = llvm::ARM::parseArch(getTriple().getArchName()); + + // Map the base architecture to an appropriate target feature, so we don't + // rely on the target triple. + llvm::ARM::ArchKind CPUArch = llvm::ARM::parseCPUArch(CPU); + if (CPUArch == llvm::ARM::ArchKind::INVALID) + CPUArch = Arch; + if (CPUArch != llvm::ARM::ArchKind::INVALID) { + ArchFeature = ("+" + llvm::ARM::getArchName(CPUArch)).str(); + TargetFeatures.push_back(ArchFeature); + } + + // get default FPU features + unsigned FPUKind = llvm::ARM::getDefaultFPU(CPU, Arch); + llvm::ARM::getFPUFeatures(FPUKind, TargetFeatures); + + // get default Extension features + uint64_t Extensions = llvm::ARM::getDefaultExtensions(CPU, Arch); + llvm::ARM::getExtensionFeatures(Extensions, TargetFeatures); + + for (auto Feature : TargetFeatures) + if (Feature[0] == '+') + Features[Feature.drop_front(1)] = true; + + // Enable or disable thumb-mode explicitly per function to enable mixed + // ARM and Thumb code generation. + if (isThumb()) + Features["thumb-mode"] = true; + else + Features["thumb-mode"] = false; + + // Convert user-provided arm and thumb GNU target attributes to + // [-|+]thumb-mode target features respectively. + std::vector<std::string> UpdatedFeaturesVec; + for (const auto &Feature : FeaturesVec) { + // Skip soft-float-abi; it's something we only use to initialize a bit of + // class state, and is otherwise unrecognized. + if (Feature == "+soft-float-abi") + continue; + + StringRef FixedFeature; + if (Feature == "+arm") + FixedFeature = "-thumb-mode"; + else if (Feature == "+thumb") + FixedFeature = "+thumb-mode"; + else + FixedFeature = Feature; + UpdatedFeaturesVec.push_back(FixedFeature.str()); + } + + return TargetInfo::initFeatureMap(Features, Diags, CPU, UpdatedFeaturesVec); +} + + +bool ARMTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) { + FPU = 0; + MVE = 0; + CRC = 0; + Crypto = 0; + SHA2 = 0; + AES = 0; + DSP = 0; + Unaligned = 1; + SoftFloat = false; + // Note that SoftFloatABI is initialized in our constructor. + HWDiv = 0; + DotProd = 0; + HasMatMul = 0; + HasPAC = 0; + HasBTI = 0; + HasFloat16 = true; + ARMCDECoprocMask = 0; + HasBFloat16 = false; + FPRegsDisabled = false; + + // This does not diagnose illegal cases like having both + // "+vfpv2" and "+vfpv3" or having "+neon" and "-fp64". + for (const auto &Feature : Features) { + if (Feature == "+soft-float") { + SoftFloat = true; + } else if (Feature == "+vfp2sp" || Feature == "+vfp2") { + FPU |= VFP2FPU; + HW_FP |= HW_FP_SP; + if (Feature == "+vfp2") + HW_FP |= HW_FP_DP; + } else if (Feature == "+vfp3sp" || Feature == "+vfp3d16sp" || + Feature == "+vfp3" || Feature == "+vfp3d16") { + FPU |= VFP3FPU; + HW_FP |= HW_FP_SP; + if (Feature == "+vfp3" || Feature == "+vfp3d16") + HW_FP |= HW_FP_DP; + } else if (Feature == "+vfp4sp" || Feature == "+vfp4d16sp" || + Feature == "+vfp4" || Feature == "+vfp4d16") { + FPU |= VFP4FPU; + HW_FP |= HW_FP_SP | HW_FP_HP; + if (Feature == "+vfp4" || Feature == "+vfp4d16") + HW_FP |= HW_FP_DP; + } else if (Feature == "+fp-armv8sp" || Feature == "+fp-armv8d16sp" || + Feature == "+fp-armv8" || Feature == "+fp-armv8d16") { + FPU |= FPARMV8; + HW_FP |= HW_FP_SP | HW_FP_HP; + if (Feature == "+fp-armv8" || Feature == "+fp-armv8d16") + HW_FP |= HW_FP_DP; + } else if (Feature == "+neon") { + FPU |= NeonFPU; + HW_FP |= HW_FP_SP; + } else if (Feature == "+hwdiv") { + HWDiv |= HWDivThumb; + } else if (Feature == "+hwdiv-arm") { + HWDiv |= HWDivARM; + } else if (Feature == "+crc") { + CRC = 1; + } else if (Feature == "+crypto") { + Crypto = 1; + } else if (Feature == "+sha2") { + SHA2 = 1; + } else if (Feature == "+aes") { + AES = 1; + } else if (Feature == "+dsp") { + DSP = 1; + } else if (Feature == "+fp64") { + HW_FP |= HW_FP_DP; + } else if (Feature == "+8msecext") { + if (CPUProfile != "M" || ArchVersion != 8) { + Diags.Report(diag::err_target_unsupported_mcmse) << CPU; + return false; + } + } else if (Feature == "+strict-align") { + Unaligned = 0; + } else if (Feature == "+fp16") { + HW_FP |= HW_FP_HP; + } else if (Feature == "+fullfp16") { + HasLegalHalfType = true; + } else if (Feature == "+dotprod") { + DotProd = true; + } else if (Feature == "+mve") { + MVE |= MVE_INT; + } else if (Feature == "+mve.fp") { + HasLegalHalfType = true; + FPU |= FPARMV8; + MVE |= MVE_INT | MVE_FP; + HW_FP |= HW_FP_SP | HW_FP_HP; + } else if (Feature == "+i8mm") { + HasMatMul = 1; + } else if (Feature.size() == strlen("+cdecp0") && Feature >= "+cdecp0" && + Feature <= "+cdecp7") { + unsigned Coproc = Feature.back() - '0'; + ARMCDECoprocMask |= (1U << Coproc); + } else if (Feature == "+bf16") { + HasBFloat16 = true; + } else if (Feature == "-fpregs") { + FPRegsDisabled = true; + } else if (Feature == "+pacbti") { + HasPAC = 1; + HasBTI = 1; + } + } + + switch (ArchVersion) { + case 6: + if (ArchProfile == llvm::ARM::ProfileKind::M) + LDREX = 0; + else if (ArchKind == llvm::ARM::ArchKind::ARMV6K) + LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B; + else + LDREX = LDREX_W; + break; + case 7: + if (ArchProfile == llvm::ARM::ProfileKind::M) + LDREX = LDREX_W | LDREX_H | LDREX_B; + else + LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B; + break; + case 8: + case 9: + LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B; + } + + if (!(FPU & NeonFPU) && FPMath == FP_Neon) { + Diags.Report(diag::err_target_unsupported_fpmath) << "neon"; + return false; + } + + if (FPMath == FP_Neon) + Features.push_back("+neonfp"); + else if (FPMath == FP_VFP) + Features.push_back("-neonfp"); + + return true; +} + +bool ARMTargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature) + .Case("arm", true) + .Case("aarch32", true) + .Case("softfloat", SoftFloat) + .Case("thumb", isThumb()) + .Case("neon", (FPU & NeonFPU) && !SoftFloat) + .Case("vfp", FPU && !SoftFloat) + .Case("hwdiv", HWDiv & HWDivThumb) + .Case("hwdiv-arm", HWDiv & HWDivARM) + .Case("mve", hasMVE()) + .Default(false); +} + +bool ARMTargetInfo::hasBFloat16Type() const { + return HasBFloat16 && !SoftFloat; +} + +bool ARMTargetInfo::isValidCPUName(StringRef Name) const { + return Name == "generic" || + llvm::ARM::parseCPUArch(Name) != llvm::ARM::ArchKind::INVALID; +} + +void ARMTargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const { + llvm::ARM::fillValidCPUArchList(Values); +} + +bool ARMTargetInfo::setCPU(const std::string &Name) { + if (Name != "generic") + setArchInfo(llvm::ARM::parseCPUArch(Name)); + + if (ArchKind == llvm::ARM::ArchKind::INVALID) + return false; + setAtomic(); + CPU = Name; + return true; +} + +bool ARMTargetInfo::setFPMath(StringRef Name) { + if (Name == "neon") { + FPMath = FP_Neon; + return true; + } else if (Name == "vfp" || Name == "vfp2" || Name == "vfp3" || + Name == "vfp4") { + FPMath = FP_VFP; + return true; + } + return false; +} + +void ARMTargetInfo::getTargetDefinesARMV81A(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__ARM_FEATURE_QRDMX", "1"); +} + +void ARMTargetInfo::getTargetDefinesARMV82A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Also include the ARMv8.1-A defines + getTargetDefinesARMV81A(Opts, Builder); +} + +void ARMTargetInfo::getTargetDefinesARMV83A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Also include the ARMv8.2-A defines + Builder.defineMacro("__ARM_FEATURE_COMPLEX", "1"); + getTargetDefinesARMV82A(Opts, Builder); +} + +void ARMTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Target identification. + Builder.defineMacro("__arm"); + Builder.defineMacro("__arm__"); + // For bare-metal none-eabi. + if (getTriple().getOS() == llvm::Triple::UnknownOS && + (getTriple().getEnvironment() == llvm::Triple::EABI || + getTriple().getEnvironment() == llvm::Triple::EABIHF)) + Builder.defineMacro("__ELF__"); + + // Target properties. + Builder.defineMacro("__REGISTER_PREFIX__", ""); + + // Unfortunately, __ARM_ARCH_7K__ is now more of an ABI descriptor. The CPU + // happens to be Cortex-A7 though, so it should still get __ARM_ARCH_7A__. + if (getTriple().isWatchABI()) + Builder.defineMacro("__ARM_ARCH_7K__", "2"); + + if (!CPUAttr.empty()) + Builder.defineMacro("__ARM_ARCH_" + CPUAttr + "__"); + + // ACLE 6.4.1 ARM/Thumb instruction set architecture + // __ARM_ARCH is defined as an integer value indicating the current ARM ISA + Builder.defineMacro("__ARM_ARCH", Twine(ArchVersion)); + + if (ArchVersion >= 8) { + // ACLE 6.5.7 Crypto Extension + // The __ARM_FEATURE_CRYPTO is deprecated in favor of finer grained + // feature macros for AES and SHA2 + if (SHA2 && AES) + Builder.defineMacro("__ARM_FEATURE_CRYPTO", "1"); + if (SHA2) + Builder.defineMacro("__ARM_FEATURE_SHA2", "1"); + if (AES) + Builder.defineMacro("__ARM_FEATURE_AES", "1"); + // ACLE 6.5.8 CRC32 Extension + if (CRC) + Builder.defineMacro("__ARM_FEATURE_CRC32", "1"); + // ACLE 6.5.10 Numeric Maximum and Minimum + Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN", "1"); + // ACLE 6.5.9 Directed Rounding + Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING", "1"); + } + + // __ARM_ARCH_ISA_ARM is defined to 1 if the core supports the ARM ISA. It + // is not defined for the M-profile. + // NOTE that the default profile is assumed to be 'A' + if (CPUProfile.empty() || ArchProfile != llvm::ARM::ProfileKind::M) + Builder.defineMacro("__ARM_ARCH_ISA_ARM", "1"); + + // __ARM_ARCH_ISA_THUMB is defined to 1 if the core supports the original + // Thumb ISA (including v6-M and v8-M Baseline). It is set to 2 if the + // core supports the Thumb-2 ISA as found in the v6T2 architecture and all + // v7 and v8 architectures excluding v8-M Baseline. + if (supportsThumb2()) + Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "2"); + else if (supportsThumb()) + Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "1"); + + // __ARM_32BIT_STATE is defined to 1 if code is being generated for a 32-bit + // instruction set such as ARM or Thumb. + Builder.defineMacro("__ARM_32BIT_STATE", "1"); + + // ACLE 6.4.2 Architectural Profile (A, R, M or pre-Cortex) + + // __ARM_ARCH_PROFILE is defined as 'A', 'R', 'M' or 'S', or unset. + if (!CPUProfile.empty()) + Builder.defineMacro("__ARM_ARCH_PROFILE", "'" + CPUProfile + "'"); + + // ACLE 6.4.3 Unaligned access supported in hardware + if (Unaligned) + Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1"); + + // ACLE 6.4.4 LDREX/STREX + if (LDREX) + Builder.defineMacro("__ARM_FEATURE_LDREX", "0x" + Twine::utohexstr(LDREX)); + + // ACLE 6.4.5 CLZ + if (ArchVersion == 5 || (ArchVersion == 6 && CPUProfile != "M") || + ArchVersion > 6) + Builder.defineMacro("__ARM_FEATURE_CLZ", "1"); + + // ACLE 6.5.1 Hardware Floating Point + if (HW_FP) + Builder.defineMacro("__ARM_FP", "0x" + Twine::utohexstr(HW_FP)); + + // ACLE predefines. + Builder.defineMacro("__ARM_ACLE", "200"); + + // FP16 support (we currently only support IEEE format). + Builder.defineMacro("__ARM_FP16_FORMAT_IEEE", "1"); + Builder.defineMacro("__ARM_FP16_ARGS", "1"); + + // ACLE 6.5.3 Fused multiply-accumulate (FMA) + if (ArchVersion >= 7 && (FPU & VFP4FPU)) + Builder.defineMacro("__ARM_FEATURE_FMA", "1"); + + // Subtarget options. + + // FIXME: It's more complicated than this and we don't really support + // interworking. + // Windows on ARM does not "support" interworking + if (5 <= ArchVersion && ArchVersion <= 8 && !getTriple().isOSWindows()) + Builder.defineMacro("__THUMB_INTERWORK__"); + + if (ABI == "aapcs" || ABI == "aapcs-linux" || ABI == "aapcs-vfp") { + // Embedded targets on Darwin follow AAPCS, but not EABI. + // Windows on ARM follows AAPCS VFP, but does not conform to EABI. + if (!getTriple().isOSBinFormatMachO() && !getTriple().isOSWindows()) + Builder.defineMacro("__ARM_EABI__"); + Builder.defineMacro("__ARM_PCS", "1"); + } + + if ((!SoftFloat && !SoftFloatABI) || ABI == "aapcs-vfp" || ABI == "aapcs16") + Builder.defineMacro("__ARM_PCS_VFP", "1"); + + if (SoftFloat) + Builder.defineMacro("__SOFTFP__"); + + // ACLE position independent code macros. + if (Opts.ROPI) + Builder.defineMacro("__ARM_ROPI", "1"); + if (Opts.RWPI) + Builder.defineMacro("__ARM_RWPI", "1"); + + if (ArchKind == llvm::ARM::ArchKind::XSCALE) + Builder.defineMacro("__XSCALE__"); + + if (isThumb()) { + Builder.defineMacro("__THUMBEL__"); + Builder.defineMacro("__thumb__"); + if (supportsThumb2()) + Builder.defineMacro("__thumb2__"); + } + + // ACLE 6.4.9 32-bit SIMD instructions + if ((CPUProfile != "M" && ArchVersion >= 6) || (CPUProfile == "M" && DSP)) + Builder.defineMacro("__ARM_FEATURE_SIMD32", "1"); + + // ACLE 6.4.10 Hardware Integer Divide + if (((HWDiv & HWDivThumb) && isThumb()) || + ((HWDiv & HWDivARM) && !isThumb())) { + Builder.defineMacro("__ARM_FEATURE_IDIV", "1"); + Builder.defineMacro("__ARM_ARCH_EXT_IDIV__", "1"); + } + + // Note, this is always on in gcc, even though it doesn't make sense. + Builder.defineMacro("__APCS_32__"); + + // __VFP_FP__ means that the floating-point format is VFP, not that a hardware + // FPU is present. Moreover, the VFP format is the only one supported by + // clang. For these reasons, this macro is always defined. + Builder.defineMacro("__VFP_FP__"); + + if (FPUModeIsVFP((FPUMode)FPU)) { + if (FPU & VFP2FPU) + Builder.defineMacro("__ARM_VFPV2__"); + if (FPU & VFP3FPU) + Builder.defineMacro("__ARM_VFPV3__"); + if (FPU & VFP4FPU) + Builder.defineMacro("__ARM_VFPV4__"); + if (FPU & FPARMV8) + Builder.defineMacro("__ARM_FPV5__"); + } + + // This only gets set when Neon instructions are actually available, unlike + // the VFP define, hence the soft float and arch check. This is subtly + // different from gcc, we follow the intent which was that it should be set + // when Neon instructions are actually available. + if ((FPU & NeonFPU) && !SoftFloat && ArchVersion >= 7) { + Builder.defineMacro("__ARM_NEON", "1"); + Builder.defineMacro("__ARM_NEON__"); + // current AArch32 NEON implementations do not support double-precision + // floating-point even when it is present in VFP. + Builder.defineMacro("__ARM_NEON_FP", + "0x" + Twine::utohexstr(HW_FP & ~HW_FP_DP)); + } + + if (hasMVE()) { + Builder.defineMacro("__ARM_FEATURE_MVE", hasMVEFloat() ? "3" : "1"); + } + + if (hasCDE()) { + Builder.defineMacro("__ARM_FEATURE_CDE", "1"); + Builder.defineMacro("__ARM_FEATURE_CDE_COPROC", + "0x" + Twine::utohexstr(getARMCDECoprocMask())); + } + + Builder.defineMacro("__ARM_SIZEOF_WCHAR_T", + Twine(Opts.WCharSize ? Opts.WCharSize : 4)); + + Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM", Opts.ShortEnums ? "1" : "4"); + + // CMSE + if (ArchVersion == 8 && ArchProfile == llvm::ARM::ProfileKind::M) + Builder.defineMacro("__ARM_FEATURE_CMSE", Opts.Cmse ? "3" : "1"); + + if (ArchVersion >= 6 && CPUAttr != "6M" && CPUAttr != "8M_BASE") { + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); + } + + // ACLE 6.4.7 DSP instructions + if (DSP) { + Builder.defineMacro("__ARM_FEATURE_DSP", "1"); + } + + // ACLE 6.4.8 Saturation instructions + bool SAT = false; + if ((ArchVersion == 6 && CPUProfile != "M") || ArchVersion > 6) { + Builder.defineMacro("__ARM_FEATURE_SAT", "1"); + SAT = true; + } + + // ACLE 6.4.6 Q (saturation) flag + if (DSP || SAT) + Builder.defineMacro("__ARM_FEATURE_QBIT", "1"); + + if (Opts.UnsafeFPMath) + Builder.defineMacro("__ARM_FP_FAST", "1"); + + // Armv8.2-A FP16 vector intrinsic + if ((FPU & NeonFPU) && HasLegalHalfType) + Builder.defineMacro("__ARM_FEATURE_FP16_VECTOR_ARITHMETIC", "1"); + + // Armv8.2-A FP16 scalar intrinsics + if (HasLegalHalfType) + Builder.defineMacro("__ARM_FEATURE_FP16_SCALAR_ARITHMETIC", "1"); + + // Armv8.2-A dot product intrinsics + if (DotProd) + Builder.defineMacro("__ARM_FEATURE_DOTPROD", "1"); + + if (HasMatMul) + Builder.defineMacro("__ARM_FEATURE_MATMUL_INT8", "1"); + + if (HasPAC) + Builder.defineMacro("__ARM_FEATURE_PAUTH", "1"); + + if (HasBTI) + Builder.defineMacro("__ARM_FEATURE_BTI", "1"); + + if (HasBFloat16) { + Builder.defineMacro("__ARM_FEATURE_BF16", "1"); + Builder.defineMacro("__ARM_FEATURE_BF16_VECTOR_ARITHMETIC", "1"); + Builder.defineMacro("__ARM_BF16_FORMAT_ALTERNATIVE", "1"); + } + + if (Opts.BranchTargetEnforcement) + Builder.defineMacro("__ARM_FEATURE_BTI_DEFAULT", "1"); + + if (Opts.hasSignReturnAddress()) { + unsigned Value = 1; + if (Opts.isSignReturnAddressScopeAll()) + Value |= 1 << 2; + Builder.defineMacro("__ARM_FEATURE_PAC_DEFAULT", Twine(Value)); + } + + switch (ArchKind) { + default: + break; + case llvm::ARM::ArchKind::ARMV8_1A: + getTargetDefinesARMV81A(Opts, Builder); + break; + case llvm::ARM::ArchKind::ARMV8_2A: + getTargetDefinesARMV82A(Opts, Builder); + break; + case llvm::ARM::ArchKind::ARMV8_3A: + case llvm::ARM::ArchKind::ARMV8_4A: + case llvm::ARM::ArchKind::ARMV8_5A: + case llvm::ARM::ArchKind::ARMV8_6A: + case llvm::ARM::ArchKind::ARMV8_8A: + case llvm::ARM::ArchKind::ARMV9A: + case llvm::ARM::ArchKind::ARMV9_1A: + case llvm::ARM::ArchKind::ARMV9_2A: + case llvm::ARM::ArchKind::ARMV9_3A: + getTargetDefinesARMV83A(Opts, Builder); + break; + } +} + +const Builtin::Info ARMTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsNEON.def" + +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define LANGBUILTIN(ID, TYPE, ATTRS, LANG) \ + {#ID, TYPE, ATTRS, nullptr, LANG, nullptr}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr}, +#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \ + {#ID, TYPE, ATTRS, HEADER, LANGS, FEATURE}, +#include "clang/Basic/BuiltinsARM.def" +}; + +ArrayRef<Builtin::Info> ARMTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::ARM::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} + +bool ARMTargetInfo::isCLZForZeroUndef() const { return false; } +TargetInfo::BuiltinVaListKind ARMTargetInfo::getBuiltinVaListKind() const { + return IsAAPCS + ? AAPCSABIBuiltinVaList + : (getTriple().isWatchABI() ? TargetInfo::CharPtrBuiltinVaList + : TargetInfo::VoidPtrBuiltinVaList); +} + +const char *const ARMTargetInfo::GCCRegNames[] = { + // Integer registers + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", + "r12", "sp", "lr", "pc", + + // Float registers + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", + "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22", + "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", + + // Double registers + "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", + "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21", "d22", + "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", + + // Quad registers + "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9", "q10", "q11", + "q12", "q13", "q14", "q15"}; + +ArrayRef<const char *> ARMTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +const TargetInfo::GCCRegAlias ARMTargetInfo::GCCRegAliases[] = { + {{"a1"}, "r0"}, {{"a2"}, "r1"}, {{"a3"}, "r2"}, {{"a4"}, "r3"}, + {{"v1"}, "r4"}, {{"v2"}, "r5"}, {{"v3"}, "r6"}, {{"v4"}, "r7"}, + {{"v5"}, "r8"}, {{"v6", "rfp"}, "r9"}, {{"sl"}, "r10"}, {{"fp"}, "r11"}, + {{"ip"}, "r12"}, {{"r13"}, "sp"}, {{"r14"}, "lr"}, {{"r15"}, "pc"}, + // The S, D and Q registers overlap, but aren't really aliases; we + // don't want to substitute one of these for a different-sized one. +}; + +ArrayRef<TargetInfo::GCCRegAlias> ARMTargetInfo::getGCCRegAliases() const { + return llvm::makeArrayRef(GCCRegAliases); +} + +bool ARMTargetInfo::validateAsmConstraint( + const char *&Name, TargetInfo::ConstraintInfo &Info) const { + switch (*Name) { + default: + break; + case 'l': // r0-r7 if thumb, r0-r15 if ARM + Info.setAllowsRegister(); + return true; + case 'h': // r8-r15, thumb only + if (isThumb()) { + Info.setAllowsRegister(); + return true; + } + break; + case 's': // An integer constant, but allowing only relocatable values. + return true; + case 't': // s0-s31, d0-d31, or q0-q15 + case 'w': // s0-s15, d0-d7, or q0-q3 + case 'x': // s0-s31, d0-d15, or q0-q7 + if (FPRegsDisabled) + return false; + Info.setAllowsRegister(); + return true; + case 'j': // An immediate integer between 0 and 65535 (valid for MOVW) + // only available in ARMv6T2 and above + if (CPUAttr.equals("6T2") || ArchVersion >= 7) { + Info.setRequiresImmediate(0, 65535); + return true; + } + break; + case 'I': + if (isThumb()) { + if (!supportsThumb2()) + Info.setRequiresImmediate(0, 255); + else + // FIXME: should check if immediate value would be valid for a Thumb2 + // data-processing instruction + Info.setRequiresImmediate(); + } else + // FIXME: should check if immediate value would be valid for an ARM + // data-processing instruction + Info.setRequiresImmediate(); + return true; + case 'J': + if (isThumb() && !supportsThumb2()) + Info.setRequiresImmediate(-255, -1); + else + Info.setRequiresImmediate(-4095, 4095); + return true; + case 'K': + if (isThumb()) { + if (!supportsThumb2()) + // FIXME: should check if immediate value can be obtained from shifting + // a value between 0 and 255 left by any amount + Info.setRequiresImmediate(); + else + // FIXME: should check if immediate value would be valid for a Thumb2 + // data-processing instruction when inverted + Info.setRequiresImmediate(); + } else + // FIXME: should check if immediate value would be valid for an ARM + // data-processing instruction when inverted + Info.setRequiresImmediate(); + return true; + case 'L': + if (isThumb()) { + if (!supportsThumb2()) + Info.setRequiresImmediate(-7, 7); + else + // FIXME: should check if immediate value would be valid for a Thumb2 + // data-processing instruction when negated + Info.setRequiresImmediate(); + } else + // FIXME: should check if immediate value would be valid for an ARM + // data-processing instruction when negated + Info.setRequiresImmediate(); + return true; + case 'M': + if (isThumb() && !supportsThumb2()) + // FIXME: should check if immediate value is a multiple of 4 between 0 and + // 1020 + Info.setRequiresImmediate(); + else + // FIXME: should check if immediate value is a power of two or a integer + // between 0 and 32 + Info.setRequiresImmediate(); + return true; + case 'N': + // Thumb1 only + if (isThumb() && !supportsThumb2()) { + Info.setRequiresImmediate(0, 31); + return true; + } + break; + case 'O': + // Thumb1 only + if (isThumb() && !supportsThumb2()) { + // FIXME: should check if immediate value is a multiple of 4 between -508 + // and 508 + Info.setRequiresImmediate(); + return true; + } + break; + case 'Q': // A memory address that is a single base register. + Info.setAllowsMemory(); + return true; + case 'T': + switch (Name[1]) { + default: + break; + case 'e': // Even general-purpose register + case 'o': // Odd general-purpose register + Info.setAllowsRegister(); + Name++; + return true; + } + break; + case 'U': // a memory reference... + switch (Name[1]) { + case 'q': // ...ARMV4 ldrsb + case 'v': // ...VFP load/store (reg+constant offset) + case 'y': // ...iWMMXt load/store + case 't': // address valid for load/store opaque types wider + // than 128-bits + case 'n': // valid address for Neon doubleword vector load/store + case 'm': // valid address for Neon element and structure load/store + case 's': // valid address for non-offset loads/stores of quad-word + // values in four ARM registers + Info.setAllowsMemory(); + Name++; + return true; + } + break; + } + return false; +} + +std::string ARMTargetInfo::convertConstraint(const char *&Constraint) const { + std::string R; + switch (*Constraint) { + case 'U': // Two-character constraint; add "^" hint for later parsing. + case 'T': + R = std::string("^") + std::string(Constraint, 2); + Constraint++; + break; + case 'p': // 'p' should be translated to 'r' by default. + R = std::string("r"); + break; + default: + return std::string(1, *Constraint); + } + return R; +} + +bool ARMTargetInfo::validateConstraintModifier( + StringRef Constraint, char Modifier, unsigned Size, + std::string &SuggestedModifier) const { + bool isOutput = (Constraint[0] == '='); + bool isInOut = (Constraint[0] == '+'); + + // Strip off constraint modifiers. + while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&') + Constraint = Constraint.substr(1); + + switch (Constraint[0]) { + default: + break; + case 'r': { + switch (Modifier) { + default: + return (isInOut || isOutput || Size <= 64); + case 'q': + // A register of size 32 cannot fit a vector type. + return false; + } + } + } + + return true; +} +const char *ARMTargetInfo::getClobbers() const { + // FIXME: Is this really right? + return ""; +} + +TargetInfo::CallingConvCheckResult +ARMTargetInfo::checkCallingConvention(CallingConv CC) const { + switch (CC) { + case CC_AAPCS: + case CC_AAPCS_VFP: + case CC_Swift: + case CC_SwiftAsync: + case CC_OpenCLKernel: + return CCCR_OK; + default: + return CCCR_Warning; + } +} + +int ARMTargetInfo::getEHDataRegisterNumber(unsigned RegNo) const { + if (RegNo == 0) + return 0; + if (RegNo == 1) + return 1; + return -1; +} + +bool ARMTargetInfo::hasSjLjLowering() const { return true; } + +ARMleTargetInfo::ARMleTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : ARMTargetInfo(Triple, Opts) {} + +void ARMleTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__ARMEL__"); + ARMTargetInfo::getTargetDefines(Opts, Builder); +} + +ARMbeTargetInfo::ARMbeTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : ARMTargetInfo(Triple, Opts) {} + +void ARMbeTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__ARMEB__"); + Builder.defineMacro("__ARM_BIG_ENDIAN"); + ARMTargetInfo::getTargetDefines(Opts, Builder); +} + +WindowsARMTargetInfo::WindowsARMTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : WindowsTargetInfo<ARMleTargetInfo>(Triple, Opts), Triple(Triple) { +} + +void WindowsARMTargetInfo::getVisualStudioDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + // FIXME: this is invalid for WindowsCE + Builder.defineMacro("_M_ARM_NT", "1"); + Builder.defineMacro("_M_ARMT", "_M_ARM"); + Builder.defineMacro("_M_THUMB", "_M_ARM"); + + assert((Triple.getArch() == llvm::Triple::arm || + Triple.getArch() == llvm::Triple::thumb) && + "invalid architecture for Windows ARM target info"); + unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6; + Builder.defineMacro("_M_ARM", Triple.getArchName().substr(Offset)); + + // TODO map the complete set of values + // 31: VFPv3 40: VFPv4 + Builder.defineMacro("_M_ARM_FP", "31"); +} + +TargetInfo::BuiltinVaListKind +WindowsARMTargetInfo::getBuiltinVaListKind() const { + return TargetInfo::CharPtrBuiltinVaList; +} + +TargetInfo::CallingConvCheckResult +WindowsARMTargetInfo::checkCallingConvention(CallingConv CC) const { + switch (CC) { + case CC_X86StdCall: + case CC_X86ThisCall: + case CC_X86FastCall: + case CC_X86VectorCall: + return CCCR_Ignore; + case CC_C: + case CC_OpenCLKernel: + case CC_PreserveMost: + case CC_PreserveAll: + case CC_Swift: + case CC_SwiftAsync: + return CCCR_OK; + default: + return CCCR_Warning; + } +} + +// Windows ARM + Itanium C++ ABI Target +ItaniumWindowsARMleTargetInfo::ItaniumWindowsARMleTargetInfo( + const llvm::Triple &Triple, const TargetOptions &Opts) + : WindowsARMTargetInfo(Triple, Opts) { + TheCXXABI.set(TargetCXXABI::GenericARM); +} + +void ItaniumWindowsARMleTargetInfo::getTargetDefines( + const LangOptions &Opts, MacroBuilder &Builder) const { + WindowsARMTargetInfo::getTargetDefines(Opts, Builder); + + if (Opts.MSVCCompat) + WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder); +} + +// Windows ARM, MS (C++) ABI +MicrosoftARMleTargetInfo::MicrosoftARMleTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : WindowsARMTargetInfo(Triple, Opts) { + TheCXXABI.set(TargetCXXABI::Microsoft); +} + +void MicrosoftARMleTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + WindowsARMTargetInfo::getTargetDefines(Opts, Builder); + WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder); +} + +MinGWARMTargetInfo::MinGWARMTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : WindowsARMTargetInfo(Triple, Opts) { + TheCXXABI.set(TargetCXXABI::GenericARM); +} + +void MinGWARMTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + WindowsARMTargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("_ARM_"); +} + +CygwinARMTargetInfo::CygwinARMTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : ARMleTargetInfo(Triple, Opts) { + this->WCharType = TargetInfo::UnsignedShort; + TLSSupported = false; + DoubleAlign = LongLongAlign = 64; + resetDataLayout("e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"); +} + +void CygwinARMTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + ARMleTargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("_ARM_"); + Builder.defineMacro("__CYGWIN__"); + Builder.defineMacro("__CYGWIN32__"); + DefineStd(Builder, "unix", Opts); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); +} + +DarwinARMTargetInfo::DarwinARMTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : DarwinTargetInfo<ARMleTargetInfo>(Triple, Opts) { + HasAlignMac68kSupport = true; + // iOS always has 64-bit atomic instructions. + // FIXME: This should be based off of the target features in + // ARMleTargetInfo. + MaxAtomicInlineWidth = 64; + + if (Triple.isWatchABI()) { + // Darwin on iOS uses a variant of the ARM C++ ABI. + TheCXXABI.set(TargetCXXABI::WatchOS); + + // BOOL should be a real boolean on the new ABI + UseSignedCharForObjCBool = false; + } else + TheCXXABI.set(TargetCXXABI::iOS); +} + +void DarwinARMTargetInfo::getOSDefines(const LangOptions &Opts, + const llvm::Triple &Triple, + MacroBuilder &Builder) const { + getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion); +} + +RenderScript32TargetInfo::RenderScript32TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : ARMleTargetInfo(llvm::Triple("armv7", Triple.getVendorName(), + Triple.getOSName(), + Triple.getEnvironmentName()), + Opts) { + IsRenderScriptTarget = true; + LongWidth = LongAlign = 64; +} + +void RenderScript32TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__RENDERSCRIPT__"); + ARMleTargetInfo::getTargetDefines(Opts, Builder); +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/ARM.h b/contrib/llvm-project/clang/lib/Basic/Targets/ARM.h new file mode 100644 index 000000000000..e85336b6e32f --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/ARM.h @@ -0,0 +1,297 @@ +//===--- ARM.h - Declare ARM target feature support -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares ARM TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_ARM_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_ARM_H + +#include "OSTargets.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ARMTargetParser.h" +#include "llvm/Support/TargetParser.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY ARMTargetInfo : public TargetInfo { + // Possible FPU choices. + enum FPUMode { + VFP2FPU = (1 << 0), + VFP3FPU = (1 << 1), + VFP4FPU = (1 << 2), + NeonFPU = (1 << 3), + FPARMV8 = (1 << 4) + }; + + enum MVEMode { + MVE_INT = (1 << 0), + MVE_FP = (1 << 1) + }; + + // Possible HWDiv features. + enum HWDivMode { HWDivThumb = (1 << 0), HWDivARM = (1 << 1) }; + + static bool FPUModeIsVFP(FPUMode Mode) { + return Mode & (VFP2FPU | VFP3FPU | VFP4FPU | NeonFPU | FPARMV8); + } + + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + static const char *const GCCRegNames[]; + + std::string ABI, CPU; + + StringRef CPUProfile; + StringRef CPUAttr; + + enum { FP_Default, FP_VFP, FP_Neon } FPMath; + + llvm::ARM::ISAKind ArchISA; + llvm::ARM::ArchKind ArchKind = llvm::ARM::ArchKind::ARMV4T; + llvm::ARM::ProfileKind ArchProfile; + unsigned ArchVersion; + + unsigned FPU : 5; + unsigned MVE : 2; + + unsigned IsAAPCS : 1; + unsigned HWDiv : 2; + + // Initialized via features. + unsigned SoftFloat : 1; + unsigned SoftFloatABI : 1; + + unsigned CRC : 1; + unsigned Crypto : 1; + unsigned SHA2 : 1; + unsigned AES : 1; + unsigned DSP : 1; + unsigned Unaligned : 1; + unsigned DotProd : 1; + unsigned HasMatMul : 1; + unsigned FPRegsDisabled : 1; + unsigned HasPAC : 1; + unsigned HasBTI : 1; + + enum { + LDREX_B = (1 << 0), /// byte (8-bit) + LDREX_H = (1 << 1), /// half (16-bit) + LDREX_W = (1 << 2), /// word (32-bit) + LDREX_D = (1 << 3), /// double (64-bit) + }; + + uint32_t LDREX; + + // ACLE 6.5.1 Hardware floating point + enum { + HW_FP_HP = (1 << 1), /// half (16-bit) + HW_FP_SP = (1 << 2), /// single (32-bit) + HW_FP_DP = (1 << 3), /// double (64-bit) + }; + uint32_t HW_FP; + + static const Builtin::Info BuiltinInfo[]; + + void setABIAAPCS(); + void setABIAPCS(bool IsAAPCS16); + + void setArchInfo(); + void setArchInfo(llvm::ARM::ArchKind Kind); + + void setAtomic(); + + bool isThumb() const; + bool supportsThumb() const; + bool supportsThumb2() const; + bool hasMVE() const; + bool hasMVEFloat() const; + bool hasCDE() const; + + StringRef getCPUAttr() const; + StringRef getCPUProfile() const; + +public: + ARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + + StringRef getABI() const override; + bool setABI(const std::string &Name) override; + + bool isBranchProtectionSupportedArch(StringRef Arch) const override; + bool validateBranchProtection(StringRef Spec, StringRef Arch, + BranchProtectionInfo &BPI, + StringRef &Err) const override; + + // FIXME: This should be based on Arch attributes, not CPU names. + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override; + + bool isValidFeatureName(StringRef Feature) const override { + // We pass soft-float-abi in as a -target-feature, but the backend figures + // this out through other means. + return Feature != "soft-float-abi"; + } + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override; + + bool hasFeature(StringRef Feature) const override; + + bool hasBFloat16Type() const override; + + bool isValidCPUName(StringRef Name) const override; + void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; + + bool setCPU(const std::string &Name) override; + + bool setFPMath(StringRef Name) override; + + bool useFP16ConversionIntrinsics() const override { + return false; + } + + void getTargetDefinesARMV81A(const LangOptions &Opts, + MacroBuilder &Builder) const; + void getTargetDefinesARMV82A(const LangOptions &Opts, + MacroBuilder &Builder) const; + void getTargetDefinesARMV83A(const LangOptions &Opts, + MacroBuilder &Builder) const; + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + bool isCLZForZeroUndef() const override; + BuiltinVaListKind getBuiltinVaListKind() const override; + + ArrayRef<const char *> getGCCRegNames() const override; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override; + std::string convertConstraint(const char *&Constraint) const override; + bool + validateConstraintModifier(StringRef Constraint, char Modifier, unsigned Size, + std::string &SuggestedModifier) const override; + const char *getClobbers() const override; + + StringRef getConstraintRegister(StringRef Constraint, + StringRef Expression) const override { + return Expression; + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override; + + int getEHDataRegisterNumber(unsigned RegNo) const override; + + bool hasSjLjLowering() const override; + + bool hasBitIntType() const override { return true; } + + const char *getBFloat16Mangling() const override { return "u6__bf16"; }; +}; + +class LLVM_LIBRARY_VISIBILITY ARMleTargetInfo : public ARMTargetInfo { +public: + ARMleTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +class LLVM_LIBRARY_VISIBILITY ARMbeTargetInfo : public ARMTargetInfo { +public: + ARMbeTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +class LLVM_LIBRARY_VISIBILITY WindowsARMTargetInfo + : public WindowsTargetInfo<ARMleTargetInfo> { + const llvm::Triple Triple; + +public: + WindowsARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + + void getVisualStudioDefines(const LangOptions &Opts, + MacroBuilder &Builder) const; + + BuiltinVaListKind getBuiltinVaListKind() const override; + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override; +}; + +// Windows ARM + Itanium C++ ABI Target +class LLVM_LIBRARY_VISIBILITY ItaniumWindowsARMleTargetInfo + : public WindowsARMTargetInfo { +public: + ItaniumWindowsARMleTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts); + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +// Windows ARM, MS (C++) ABI +class LLVM_LIBRARY_VISIBILITY MicrosoftARMleTargetInfo + : public WindowsARMTargetInfo { +public: + MicrosoftARMleTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts); + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +// ARM MinGW target +class LLVM_LIBRARY_VISIBILITY MinGWARMTargetInfo : public WindowsARMTargetInfo { +public: + MinGWARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +// ARM Cygwin target +class LLVM_LIBRARY_VISIBILITY CygwinARMTargetInfo : public ARMleTargetInfo { +public: + CygwinARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +class LLVM_LIBRARY_VISIBILITY DarwinARMTargetInfo + : public DarwinTargetInfo<ARMleTargetInfo> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override; + +public: + DarwinARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); +}; + +// 32-bit RenderScript is armv7 with width and align of 'long' set to 8-bytes +class LLVM_LIBRARY_VISIBILITY RenderScript32TargetInfo + : public ARMleTargetInfo { +public: + RenderScript32TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts); + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +} // namespace targets +} // namespace clang + +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_ARM_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/AVR.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/AVR.cpp new file mode 100644 index 000000000000..6266ed72cd5c --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/AVR.cpp @@ -0,0 +1,355 @@ +//===--- AVR.cpp - Implement AVR target feature support -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements AVR TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "AVR.h" +#include "clang/Basic/MacroBuilder.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +namespace clang { +namespace targets { + +/// Information about a specific microcontroller. +struct LLVM_LIBRARY_VISIBILITY MCUInfo { + const char *Name; + const char *DefineName; + const int NumFlashBanks; // -1 means the device does not support LPM/ELPM. +}; + +// This list should be kept up-to-date with AVRDevices.td in LLVM. +static MCUInfo AVRMcus[] = { + {"at90s1200", "__AVR_AT90S1200__", 0}, + {"attiny11", "__AVR_ATtiny11__", 0}, + {"attiny12", "__AVR_ATtiny12__", 0}, + {"attiny15", "__AVR_ATtiny15__", 0}, + {"attiny28", "__AVR_ATtiny28__", 0}, + {"at90s2313", "__AVR_AT90S2313__", 1}, + {"at90s2323", "__AVR_AT90S2323__", 1}, + {"at90s2333", "__AVR_AT90S2333__", 1}, + {"at90s2343", "__AVR_AT90S2343__", 1}, + {"attiny22", "__AVR_ATtiny22__", 1}, + {"attiny26", "__AVR_ATtiny26__", 1}, + {"at86rf401", "__AVR_AT86RF401__", 1}, + {"at90s4414", "__AVR_AT90S4414__", 1}, + {"at90s4433", "__AVR_AT90S4433__", 1}, + {"at90s4434", "__AVR_AT90S4434__", 1}, + {"at90s8515", "__AVR_AT90S8515__", 1}, + {"at90c8534", "__AVR_AT90c8534__", 1}, + {"at90s8535", "__AVR_AT90S8535__", 1}, + {"ata5272", "__AVR_ATA5272__", 1}, + {"attiny13", "__AVR_ATtiny13__", 1}, + {"attiny13a", "__AVR_ATtiny13A__", 1}, + {"attiny2313", "__AVR_ATtiny2313__", 1}, + {"attiny2313a", "__AVR_ATtiny2313A__", 1}, + {"attiny24", "__AVR_ATtiny24__", 1}, + {"attiny24a", "__AVR_ATtiny24A__", 1}, + {"attiny4313", "__AVR_ATtiny4313__", 1}, + {"attiny44", "__AVR_ATtiny44__", 1}, + {"attiny44a", "__AVR_ATtiny44A__", 1}, + {"attiny84", "__AVR_ATtiny84__", 1}, + {"attiny84a", "__AVR_ATtiny84A__", 1}, + {"attiny25", "__AVR_ATtiny25__", 1}, + {"attiny45", "__AVR_ATtiny45__", 1}, + {"attiny85", "__AVR_ATtiny85__", 1}, + {"attiny261", "__AVR_ATtiny261__", 1}, + {"attiny261a", "__AVR_ATtiny261A__", 1}, + {"attiny441", "__AVR_ATtiny441__", 1}, + {"attiny461", "__AVR_ATtiny461__", 1}, + {"attiny461a", "__AVR_ATtiny461A__", 1}, + {"attiny841", "__AVR_ATtiny841__", 1}, + {"attiny861", "__AVR_ATtiny861__", 1}, + {"attiny861a", "__AVR_ATtiny861A__", 1}, + {"attiny87", "__AVR_ATtiny87__", 1}, + {"attiny43u", "__AVR_ATtiny43U__", 1}, + {"attiny48", "__AVR_ATtiny48__", 1}, + {"attiny88", "__AVR_ATtiny88__", 1}, + {"attiny828", "__AVR_ATtiny828__", 1}, + {"at43usb355", "__AVR_AT43USB355__", 1}, + {"at76c711", "__AVR_AT76C711__", 1}, + {"atmega103", "__AVR_ATmega103__", 1}, + {"at43usb320", "__AVR_AT43USB320__", 1}, + {"attiny167", "__AVR_ATtiny167__", 1}, + {"at90usb82", "__AVR_AT90USB82__", 1}, + {"at90usb162", "__AVR_AT90USB162__", 1}, + {"ata5505", "__AVR_ATA5505__", 1}, + {"atmega8u2", "__AVR_ATmega8U2__", 1}, + {"atmega16u2", "__AVR_ATmega16U2__", 1}, + {"atmega32u2", "__AVR_ATmega32U2__", 1}, + {"attiny1634", "__AVR_ATtiny1634__", 1}, + {"atmega8", "__AVR_ATmega8__", 1}, + {"ata6289", "__AVR_ATA6289__", 1}, + {"atmega8a", "__AVR_ATmega8A__", 1}, + {"ata6285", "__AVR_ATA6285__", 1}, + {"ata6286", "__AVR_ATA6286__", 1}, + {"atmega48", "__AVR_ATmega48__", 1}, + {"atmega48a", "__AVR_ATmega48A__", 1}, + {"atmega48pa", "__AVR_ATmega48PA__", 1}, + {"atmega48pb", "__AVR_ATmega48PB__", 1}, + {"atmega48p", "__AVR_ATmega48P__", 1}, + {"atmega88", "__AVR_ATmega88__", 1}, + {"atmega88a", "__AVR_ATmega88A__", 1}, + {"atmega88p", "__AVR_ATmega88P__", 1}, + {"atmega88pa", "__AVR_ATmega88PA__", 1}, + {"atmega88pb", "__AVR_ATmega88PB__", 1}, + {"atmega8515", "__AVR_ATmega8515__", 1}, + {"atmega8535", "__AVR_ATmega8535__", 1}, + {"atmega8hva", "__AVR_ATmega8HVA__", 1}, + {"at90pwm1", "__AVR_AT90PWM1__", 1}, + {"at90pwm2", "__AVR_AT90PWM2__", 1}, + {"at90pwm2b", "__AVR_AT90PWM2B__", 1}, + {"at90pwm3", "__AVR_AT90PWM3__", 1}, + {"at90pwm3b", "__AVR_AT90PWM3B__", 1}, + {"at90pwm81", "__AVR_AT90PWM81__", 1}, + {"ata5790", "__AVR_ATA5790__", 1}, + {"ata5795", "__AVR_ATA5795__", 1}, + {"atmega16", "__AVR_ATmega16__", 1}, + {"atmega16a", "__AVR_ATmega16A__", 1}, + {"atmega161", "__AVR_ATmega161__", 1}, + {"atmega162", "__AVR_ATmega162__", 1}, + {"atmega163", "__AVR_ATmega163__", 1}, + {"atmega164a", "__AVR_ATmega164A__", 1}, + {"atmega164p", "__AVR_ATmega164P__", 1}, + {"atmega164pa", "__AVR_ATmega164PA__", 1}, + {"atmega165", "__AVR_ATmega165__", 1}, + {"atmega165a", "__AVR_ATmega165A__", 1}, + {"atmega165p", "__AVR_ATmega165P__", 1}, + {"atmega165pa", "__AVR_ATmega165PA__", 1}, + {"atmega168", "__AVR_ATmega168__", 1}, + {"atmega168a", "__AVR_ATmega168A__", 1}, + {"atmega168p", "__AVR_ATmega168P__", 1}, + {"atmega168pa", "__AVR_ATmega168PA__", 1}, + {"atmega168pb", "__AVR_ATmega168PB__", 1}, + {"atmega169", "__AVR_ATmega169__", 1}, + {"atmega169a", "__AVR_ATmega169A__", 1}, + {"atmega169p", "__AVR_ATmega169P__", 1}, + {"atmega169pa", "__AVR_ATmega169PA__", 1}, + {"atmega32", "__AVR_ATmega32__", 1}, + {"atmega32a", "__AVR_ATmega32A__", 1}, + {"atmega323", "__AVR_ATmega323__", 1}, + {"atmega324a", "__AVR_ATmega324A__", 1}, + {"atmega324p", "__AVR_ATmega324P__", 1}, + {"atmega324pa", "__AVR_ATmega324PA__", 1}, + {"atmega324pb", "__AVR_ATmega324PB__", 1}, + {"atmega325", "__AVR_ATmega325__", 1}, + {"atmega325a", "__AVR_ATmega325A__", 1}, + {"atmega325p", "__AVR_ATmega325P__", 1}, + {"atmega325pa", "__AVR_ATmega325PA__", 1}, + {"atmega3250", "__AVR_ATmega3250__", 1}, + {"atmega3250a", "__AVR_ATmega3250A__", 1}, + {"atmega3250p", "__AVR_ATmega3250P__", 1}, + {"atmega3250pa", "__AVR_ATmega3250PA__", 1}, + {"atmega328", "__AVR_ATmega328__", 1}, + {"atmega328p", "__AVR_ATmega328P__", 1}, + {"atmega328pb", "__AVR_ATmega328PB__", 1}, + {"atmega329", "__AVR_ATmega329__", 1}, + {"atmega329a", "__AVR_ATmega329A__", 1}, + {"atmega329p", "__AVR_ATmega329P__", 1}, + {"atmega329pa", "__AVR_ATmega329PA__", 1}, + {"atmega3290", "__AVR_ATmega3290__", 1}, + {"atmega3290a", "__AVR_ATmega3290A__", 1}, + {"atmega3290p", "__AVR_ATmega3290P__", 1}, + {"atmega3290pa", "__AVR_ATmega3290PA__", 1}, + {"atmega406", "__AVR_ATmega406__", 1}, + {"atmega64", "__AVR_ATmega64__", 1}, + {"atmega64a", "__AVR_ATmega64A__", 1}, + {"atmega640", "__AVR_ATmega640__", 1}, + {"atmega644", "__AVR_ATmega644__", 1}, + {"atmega644a", "__AVR_ATmega644A__", 1}, + {"atmega644p", "__AVR_ATmega644P__", 1}, + {"atmega644pa", "__AVR_ATmega644PA__", 1}, + {"atmega645", "__AVR_ATmega645__", 1}, + {"atmega645a", "__AVR_ATmega645A__", 1}, + {"atmega645p", "__AVR_ATmega645P__", 1}, + {"atmega649", "__AVR_ATmega649__", 1}, + {"atmega649a", "__AVR_ATmega649A__", 1}, + {"atmega649p", "__AVR_ATmega649P__", 1}, + {"atmega6450", "__AVR_ATmega6450__", 1}, + {"atmega6450a", "__AVR_ATmega6450A__", 1}, + {"atmega6450p", "__AVR_ATmega6450P__", 1}, + {"atmega6490", "__AVR_ATmega6490__", 1}, + {"atmega6490a", "__AVR_ATmega6490A__", 1}, + {"atmega6490p", "__AVR_ATmega6490P__", 1}, + {"atmega64rfr2", "__AVR_ATmega64RFR2__", 1}, + {"atmega644rfr2", "__AVR_ATmega644RFR2__", 1}, + {"atmega16hva", "__AVR_ATmega16HVA__", 1}, + {"atmega16hva2", "__AVR_ATmega16HVA2__", 1}, + {"atmega16hvb", "__AVR_ATmega16HVB__", 1}, + {"atmega16hvbrevb", "__AVR_ATmega16HVBREVB__", 1}, + {"atmega32hvb", "__AVR_ATmega32HVB__", 1}, + {"atmega32hvbrevb", "__AVR_ATmega32HVBREVB__", 1}, + {"atmega64hve", "__AVR_ATmega64HVE__", 1}, + {"at90can32", "__AVR_AT90CAN32__", 1}, + {"at90can64", "__AVR_AT90CAN64__", 1}, + {"at90pwm161", "__AVR_AT90PWM161__", 1}, + {"at90pwm216", "__AVR_AT90PWM216__", 1}, + {"at90pwm316", "__AVR_AT90PWM316__", 1}, + {"atmega32c1", "__AVR_ATmega32C1__", 1}, + {"atmega64c1", "__AVR_ATmega64C1__", 1}, + {"atmega16m1", "__AVR_ATmega16M1__", 1}, + {"atmega32m1", "__AVR_ATmega32M1__", 1}, + {"atmega64m1", "__AVR_ATmega64M1__", 1}, + {"atmega16u4", "__AVR_ATmega16U4__", 1}, + {"atmega32u4", "__AVR_ATmega32U4__", 1}, + {"atmega32u6", "__AVR_ATmega32U6__", 1}, + {"at90usb646", "__AVR_AT90USB646__", 1}, + {"at90usb647", "__AVR_AT90USB647__", 1}, + {"at90scr100", "__AVR_AT90SCR100__", 1}, + {"at94k", "__AVR_AT94K__", 1}, + {"m3000", "__AVR_AT000__", 1}, + {"atmega128", "__AVR_ATmega128__", 2}, + {"atmega128a", "__AVR_ATmega128A__", 2}, + {"atmega1280", "__AVR_ATmega1280__", 2}, + {"atmega1281", "__AVR_ATmega1281__", 2}, + {"atmega1284", "__AVR_ATmega1284__", 2}, + {"atmega1284p", "__AVR_ATmega1284P__", 2}, + {"atmega128rfa1", "__AVR_ATmega128RFA1__", 2}, + {"atmega128rfr2", "__AVR_ATmega128RFR2__", 2}, + {"atmega1284rfr2", "__AVR_ATmega1284RFR2__", 2}, + {"at90can128", "__AVR_AT90CAN128__", 2}, + {"at90usb1286", "__AVR_AT90USB1286__", 2}, + {"at90usb1287", "__AVR_AT90USB1287__", 2}, + {"atmega2560", "__AVR_ATmega2560__", 4}, + {"atmega2561", "__AVR_ATmega2561__", 4}, + {"atmega256rfr2", "__AVR_ATmega256RFR2__", 4}, + {"atmega2564rfr2", "__AVR_ATmega2564RFR2__", 4}, + {"atxmega16a4", "__AVR_ATxmega16A4__", 1}, + {"atxmega16a4u", "__AVR_ATxmega16A4U__", 1}, + {"atxmega16c4", "__AVR_ATxmega16C4__", 1}, + {"atxmega16d4", "__AVR_ATxmega16D4__", 1}, + {"atxmega32a4", "__AVR_ATxmega32A4__", 1}, + {"atxmega32a4u", "__AVR_ATxmega32A4U__", 1}, + {"atxmega32c4", "__AVR_ATxmega32C4__", 1}, + {"atxmega32d4", "__AVR_ATxmega32D4__", 1}, + {"atxmega32e5", "__AVR_ATxmega32E5__", 1}, + {"atxmega16e5", "__AVR_ATxmega16E5__", 1}, + {"atxmega8e5", "__AVR_ATxmega8E5__", 1}, + {"atxmega32x1", "__AVR_ATxmega32X1__", 1}, + {"atxmega64a3", "__AVR_ATxmega64A3__", 1}, + {"atxmega64a3u", "__AVR_ATxmega64A3U__", 1}, + {"atxmega64a4u", "__AVR_ATxmega64A4U__", 1}, + {"atxmega64b1", "__AVR_ATxmega64B1__", 1}, + {"atxmega64b3", "__AVR_ATxmega64B3__", 1}, + {"atxmega64c3", "__AVR_ATxmega64C3__", 1}, + {"atxmega64d3", "__AVR_ATxmega64D3__", 1}, + {"atxmega64d4", "__AVR_ATxmega64D4__", 1}, + {"atxmega64a1", "__AVR_ATxmega64A1__", 1}, + {"atxmega64a1u", "__AVR_ATxmega64A1U__", 1}, + {"atxmega128a3", "__AVR_ATxmega128A3__", 2}, + {"atxmega128a3u", "__AVR_ATxmega128A3U__", 2}, + {"atxmega128b1", "__AVR_ATxmega128B1__", 2}, + {"atxmega128b3", "__AVR_ATxmega128B3__", 2}, + {"atxmega128c3", "__AVR_ATxmega128C3__", 2}, + {"atxmega128d3", "__AVR_ATxmega128D3__", 2}, + {"atxmega128d4", "__AVR_ATxmega128D4__", 2}, + {"atxmega192a3", "__AVR_ATxmega192A3__", 3}, + {"atxmega192a3u", "__AVR_ATxmega192A3U__", 3}, + {"atxmega192c3", "__AVR_ATxmega192C3__", 3}, + {"atxmega192d3", "__AVR_ATxmega192D3__", 3}, + {"atxmega256a3", "__AVR_ATxmega256A3__", 4}, + {"atxmega256a3u", "__AVR_ATxmega256A3U__", 4}, + {"atxmega256a3b", "__AVR_ATxmega256A3B__", 4}, + {"atxmega256a3bu", "__AVR_ATxmega256A3BU__", 4}, + {"atxmega256c3", "__AVR_ATxmega256C3__", 4}, + {"atxmega256d3", "__AVR_ATxmega256D3__", 4}, + {"atxmega384c3", "__AVR_ATxmega384C3__", 6}, + {"atxmega384d3", "__AVR_ATxmega384D3__", 6}, + {"atxmega128a1", "__AVR_ATxmega128A1__", 2}, + {"atxmega128a1u", "__AVR_ATxmega128A1U__", 2}, + {"atxmega128a4u", "__AVR_ATxmega128A4U__", 2}, + {"attiny4", "__AVR_ATtiny4__", 0}, + {"attiny5", "__AVR_ATtiny5__", 0}, + {"attiny9", "__AVR_ATtiny9__", 0}, + {"attiny10", "__AVR_ATtiny10__", 0}, + {"attiny20", "__AVR_ATtiny20__", 0}, + {"attiny40", "__AVR_ATtiny40__", 0}, + {"attiny102", "__AVR_ATtiny102__", 0}, + {"attiny104", "__AVR_ATtiny104__", 0}, + {"attiny202", "__AVR_ATtiny202__", 1}, + {"attiny402", "__AVR_ATtiny402__", 1}, + {"attiny204", "__AVR_ATtiny204__", 1}, + {"attiny404", "__AVR_ATtiny404__", 1}, + {"attiny804", "__AVR_ATtiny804__", 1}, + {"attiny1604", "__AVR_ATtiny1604__", 1}, + {"attiny406", "__AVR_ATtiny406__", 1}, + {"attiny806", "__AVR_ATtiny806__", 1}, + {"attiny1606", "__AVR_ATtiny1606__", 1}, + {"attiny807", "__AVR_ATtiny807__", 1}, + {"attiny1607", "__AVR_ATtiny1607__", 1}, + {"attiny212", "__AVR_ATtiny212__", 1}, + {"attiny412", "__AVR_ATtiny412__", 1}, + {"attiny214", "__AVR_ATtiny214__", 1}, + {"attiny414", "__AVR_ATtiny414__", 1}, + {"attiny814", "__AVR_ATtiny814__", 1}, + {"attiny1614", "__AVR_ATtiny1614__", 1}, + {"attiny416", "__AVR_ATtiny416__", 1}, + {"attiny816", "__AVR_ATtiny816__", 1}, + {"attiny1616", "__AVR_ATtiny1616__", 1}, + {"attiny3216", "__AVR_ATtiny3216__", 1}, + {"attiny417", "__AVR_ATtiny417__", 1}, + {"attiny817", "__AVR_ATtiny817__", 1}, + {"attiny1617", "__AVR_ATtiny1617__", 1}, + {"attiny3217", "__AVR_ATtiny3217__", 1}, +}; + +} // namespace targets +} // namespace clang + +static constexpr llvm::StringLiteral ValidFamilyNames[] = { + "avr1", "avr2", "avr25", "avr3", "avr31", + "avr35", "avr4", "avr5", "avr51", "avr6", + "avrxmega1", "avrxmega2", "avrxmega3", "avrxmega4", "avrxmega5", + "avrxmega6", "avrxmega7", "avrtiny"}; + +bool AVRTargetInfo::isValidCPUName(StringRef Name) const { + bool IsFamily = llvm::is_contained(ValidFamilyNames, Name); + + bool IsMCU = llvm::any_of( + AVRMcus, [&](const MCUInfo &Info) { return Info.Name == Name; }); + return IsFamily || IsMCU; +} + +void AVRTargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const { + Values.append(std::begin(ValidFamilyNames), std::end(ValidFamilyNames)); + for (const MCUInfo &Info : AVRMcus) + Values.push_back(Info.Name); +} + +void AVRTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("AVR"); + Builder.defineMacro("__AVR"); + Builder.defineMacro("__AVR__"); + Builder.defineMacro("__ELF__"); + + if (!this->CPU.empty()) { + auto It = llvm::find_if( + AVRMcus, [&](const MCUInfo &Info) { return Info.Name == this->CPU; }); + + if (It != std::end(AVRMcus)) { + Builder.defineMacro(It->DefineName); + if (It->NumFlashBanks >= 1) + Builder.defineMacro("__flash", "__attribute__((address_space(1)))"); + if (It->NumFlashBanks >= 2) + Builder.defineMacro("__flash1", "__attribute__((address_space(2)))"); + if (It->NumFlashBanks >= 3) + Builder.defineMacro("__flash2", "__attribute__((address_space(3)))"); + if (It->NumFlashBanks >= 4) + Builder.defineMacro("__flash3", "__attribute__((address_space(4)))"); + if (It->NumFlashBanks >= 5) + Builder.defineMacro("__flash4", "__attribute__((address_space(5)))"); + if (It->NumFlashBanks >= 6) + Builder.defineMacro("__flash5", "__attribute__((address_space(6)))"); + } + } +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/AVR.h b/contrib/llvm-project/clang/lib/Basic/Targets/AVR.h new file mode 100644 index 000000000000..a281e2c2cd74 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/AVR.h @@ -0,0 +1,186 @@ +//===--- AVR.h - Declare AVR target feature support -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares AVR TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_AVR_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_AVR_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +// AVR Target +class LLVM_LIBRARY_VISIBILITY AVRTargetInfo : public TargetInfo { +public: + AVRTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + TLSSupported = false; + PointerWidth = 16; + PointerAlign = 8; + IntWidth = 16; + IntAlign = 8; + LongWidth = 32; + LongAlign = 8; + LongLongWidth = 64; + LongLongAlign = 8; + SuitableAlign = 8; + DefaultAlignForAttributeAligned = 8; + HalfWidth = 16; + HalfAlign = 8; + FloatWidth = 32; + FloatAlign = 8; + DoubleWidth = 32; + DoubleAlign = 8; + DoubleFormat = &llvm::APFloat::IEEEsingle(); + LongDoubleWidth = 32; + LongDoubleAlign = 8; + LongDoubleFormat = &llvm::APFloat::IEEEsingle(); + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + Char16Type = UnsignedInt; + WIntType = SignedInt; + Int16Type = SignedInt; + Char32Type = UnsignedLong; + SigAtomicType = SignedChar; + ProgramAddrSpace = 1; + resetDataLayout("e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + const char *getClobbers() const override { return ""; } + + ArrayRef<const char *> getGCCRegNames() const override { + static const char *const GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", + "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", + "r20", "r21", "r22", "r23", "r24", "r25", "X", "Y", "Z", "SP" + }; + return llvm::makeArrayRef(GCCRegNames); + } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; + } + + ArrayRef<TargetInfo::AddlRegName> getGCCAddlRegNames() const override { + static const TargetInfo::AddlRegName AddlRegNames[] = { + {{"r26", "r27"}, 26}, + {{"r28", "r29"}, 27}, + {{"r30", "r31"}, 28}, + {{"SPL", "SPH"}, 29}, + }; + return llvm::makeArrayRef(AddlRegNames); + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + // There aren't any multi-character AVR specific constraints. + if (StringRef(Name).size() > 1) + return false; + + switch (*Name) { + default: + return false; + case 'a': // Simple upper registers + case 'b': // Base pointer registers pairs + case 'd': // Upper register + case 'l': // Lower registers + case 'e': // Pointer register pairs + case 'q': // Stack pointer register + case 'r': // Any register + case 'w': // Special upper register pairs + case 't': // Temporary register + case 'x': + case 'X': // Pointer register pair X + case 'y': + case 'Y': // Pointer register pair Y + case 'z': + case 'Z': // Pointer register pair Z + Info.setAllowsRegister(); + return true; + case 'I': // 6-bit positive integer constant + Info.setRequiresImmediate(0, 63); + return true; + case 'J': // 6-bit negative integer constant + Info.setRequiresImmediate(-63, 0); + return true; + case 'K': // Integer constant (Range: 2) + Info.setRequiresImmediate(2); + return true; + case 'L': // Integer constant (Range: 0) + Info.setRequiresImmediate(0); + return true; + case 'M': // 8-bit integer constant + Info.setRequiresImmediate(0, 0xff); + return true; + case 'N': // Integer constant (Range: -1) + Info.setRequiresImmediate(-1); + return true; + case 'O': // Integer constant (Range: 8, 16, 24) + Info.setRequiresImmediate({8, 16, 24}); + return true; + case 'P': // Integer constant (Range: 1) + Info.setRequiresImmediate(1); + return true; + case 'R': // Integer constant (Range: -6 to 5) + Info.setRequiresImmediate(-6, 5); + return true; + case 'G': // Floating point constant + case 'Q': // A memory address based on Y or Z pointer with displacement. + return true; + } + + return false; + } + + IntType getIntTypeByWidth(unsigned BitWidth, bool IsSigned) const final { + // AVR prefers int for 16-bit integers. + return BitWidth == 16 ? (IsSigned ? SignedInt : UnsignedInt) + : TargetInfo::getIntTypeByWidth(BitWidth, IsSigned); + } + + IntType getLeastIntTypeByWidth(unsigned BitWidth, bool IsSigned) const final { + // AVR uses int for int_least16_t and int_fast16_t. + return BitWidth == 16 + ? (IsSigned ? SignedInt : UnsignedInt) + : TargetInfo::getLeastIntTypeByWidth(BitWidth, IsSigned); + } + + bool isValidCPUName(StringRef Name) const override; + void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; + bool setCPU(const std::string &Name) override { + bool isValid = isValidCPUName(Name); + if (isValid) + CPU = Name; + return isValid; + } + +protected: + std::string CPU; +}; + +} // namespace targets +} // namespace clang + +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_AVR_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/BPF.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/BPF.cpp new file mode 100644 index 000000000000..2dfe21564cc1 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/BPF.cpp @@ -0,0 +1,59 @@ +//===--- BPF.cpp - Implement BPF target feature support -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements BPF TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "BPF.h" +#include "Targets.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringRef.h" + +using namespace clang; +using namespace clang::targets; + +const Builtin::Info BPFTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsBPF.def" +}; + +void BPFTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__bpf__"); + Builder.defineMacro("__BPF__"); +} + +static constexpr llvm::StringLiteral ValidCPUNames[] = {"generic", "v1", "v2", + "v3", "probe"}; + +bool BPFTargetInfo::isValidCPUName(StringRef Name) const { + return llvm::is_contained(ValidCPUNames, Name); +} + +void BPFTargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const { + Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames)); +} + +ArrayRef<Builtin::Info> BPFTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::BPF::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} + +bool BPFTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) { + for (const auto &Feature : Features) { + if (Feature == "+alu32") { + HasAlu32 = true; + } + } + + return true; +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/BPF.h b/contrib/llvm-project/clang/lib/Basic/Targets/BPF.h new file mode 100644 index 000000000000..393a91ff53a5 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/BPF.h @@ -0,0 +1,118 @@ +//===--- BPF.h - Declare BPF target feature support -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares BPF TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_BPF_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_BPF_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo { + static const Builtin::Info BuiltinInfo[]; + bool HasAlu32 = false; + +public: + BPFTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + SizeType = UnsignedLong; + PtrDiffType = SignedLong; + IntPtrType = SignedLong; + IntMaxType = SignedLong; + Int64Type = SignedLong; + RegParmMax = 5; + if (Triple.getArch() == llvm::Triple::bpfeb) { + resetDataLayout("E-m:e-p:64:64-i64:64-i128:128-n32:64-S128"); + } else { + resetDataLayout("e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"); + } + MaxAtomicPromoteWidth = 64; + MaxAtomicInlineWidth = 64; + TLSSupported = false; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool hasFeature(StringRef Feature) const override { + return Feature == "bpf" || Feature == "alu32" || Feature == "dwarfris"; + } + + void setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name, + bool Enabled) const override { + Features[Name] = Enabled; + } + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + const char *getClobbers() const override { return ""; } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + bool isValidGCCRegisterName(StringRef Name) const override { return true; } + ArrayRef<const char *> getGCCRegNames() const override { return None; } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + switch (*Name) { + default: + break; + case 'w': + if (HasAlu32) { + Info.setAllowsRegister(); + } + break; + } + return true; + } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; + } + + bool allowDebugInfoForExternalRef() const override { return true; } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + switch (CC) { + default: + return CCCR_Warning; + case CC_C: + case CC_OpenCLKernel: + return CCCR_OK; + } + } + + bool isValidCPUName(StringRef Name) const override; + + void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; + + bool setCPU(const std::string &Name) override { + if (Name == "v3") { + HasAlu32 = true; + } + + StringRef CPUName(Name); + return isValidCPUName(CPUName); + } +}; +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_BPF_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/Hexagon.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/Hexagon.cpp new file mode 100644 index 000000000000..161369242926 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/Hexagon.cpp @@ -0,0 +1,244 @@ +//===--- Hexagon.cpp - Implement Hexagon target feature support -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements Hexagon TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "Hexagon.h" +#include "Targets.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +void HexagonTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__qdsp6__", "1"); + Builder.defineMacro("__hexagon__", "1"); + + Builder.defineMacro("__ELF__"); + + // The macro __HVXDBL__ is deprecated. + bool DefineHvxDbl = false; + + if (CPU == "hexagonv5") { + Builder.defineMacro("__HEXAGON_V5__"); + Builder.defineMacro("__HEXAGON_ARCH__", "5"); + if (Opts.HexagonQdsp6Compat) { + Builder.defineMacro("__QDSP6_V5__"); + Builder.defineMacro("__QDSP6_ARCH__", "5"); + } + } else if (CPU == "hexagonv55") { + Builder.defineMacro("__HEXAGON_V55__"); + Builder.defineMacro("__HEXAGON_ARCH__", "55"); + Builder.defineMacro("__QDSP6_V55__"); + Builder.defineMacro("__QDSP6_ARCH__", "55"); + } else if (CPU == "hexagonv60") { + DefineHvxDbl = true; + Builder.defineMacro("__HEXAGON_V60__"); + Builder.defineMacro("__HEXAGON_ARCH__", "60"); + Builder.defineMacro("__QDSP6_V60__"); + Builder.defineMacro("__QDSP6_ARCH__", "60"); + } else if (CPU == "hexagonv62") { + DefineHvxDbl = true; + Builder.defineMacro("__HEXAGON_V62__"); + Builder.defineMacro("__HEXAGON_ARCH__", "62"); + } else if (CPU == "hexagonv65") { + DefineHvxDbl = true; + Builder.defineMacro("__HEXAGON_V65__"); + Builder.defineMacro("__HEXAGON_ARCH__", "65"); + } else if (CPU == "hexagonv66") { + DefineHvxDbl = true; + Builder.defineMacro("__HEXAGON_V66__"); + Builder.defineMacro("__HEXAGON_ARCH__", "66"); + } else if (CPU == "hexagonv67") { + Builder.defineMacro("__HEXAGON_V67__"); + Builder.defineMacro("__HEXAGON_ARCH__", "67"); + } else if (CPU == "hexagonv67t") { + Builder.defineMacro("__HEXAGON_V67T__"); + Builder.defineMacro("__HEXAGON_ARCH__", "67"); + } else if (CPU == "hexagonv68") { + Builder.defineMacro("__HEXAGON_V68__"); + Builder.defineMacro("__HEXAGON_ARCH__", "68"); + } else if (CPU == "hexagonv69") { + Builder.defineMacro("__HEXAGON_V69__"); + Builder.defineMacro("__HEXAGON_ARCH__", "69"); + } + + if (hasFeature("hvx-length64b")) { + Builder.defineMacro("__HVX__"); + Builder.defineMacro("__HVX_ARCH__", HVXVersion); + Builder.defineMacro("__HVX_LENGTH__", "64"); + } + + if (hasFeature("hvx-length128b")) { + Builder.defineMacro("__HVX__"); + Builder.defineMacro("__HVX_ARCH__", HVXVersion); + Builder.defineMacro("__HVX_LENGTH__", "128"); + if (DefineHvxDbl) + Builder.defineMacro("__HVXDBL__"); + } + + if (hasFeature("audio")) { + Builder.defineMacro("__HEXAGON_AUDIO__"); + } + + std::string NumPhySlots = isTinyCore() ? "3" : "4"; + Builder.defineMacro("__HEXAGON_PHYSICAL_SLOTS__", NumPhySlots); +} + +bool HexagonTargetInfo::initFeatureMap( + llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, + const std::vector<std::string> &FeaturesVec) const { + if (isTinyCore()) + Features["audio"] = true; + + StringRef CPUFeature = CPU; + CPUFeature.consume_front("hexagon"); + CPUFeature.consume_back("t"); + if (!CPUFeature.empty()) + Features[CPUFeature] = true; + + Features["long-calls"] = false; + + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); +} + +bool HexagonTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) { + for (auto &F : Features) { + if (F == "+hvx-length64b") + HasHVX = HasHVX64B = true; + else if (F == "+hvx-length128b") + HasHVX = HasHVX128B = true; + else if (F.find("+hvxv") != std::string::npos) { + HasHVX = true; + HVXVersion = F.substr(std::string("+hvxv").length()); + } else if (F == "-hvx") + HasHVX = HasHVX64B = HasHVX128B = false; + else if (F == "+long-calls") + UseLongCalls = true; + else if (F == "-long-calls") + UseLongCalls = false; + else if (F == "+audio") + HasAudio = true; + } + if (CPU.compare("hexagonv68") >= 0) { + HasLegalHalfType = true; + HasFloat16 = true; + } + return true; +} + +const char *const HexagonTargetInfo::GCCRegNames[] = { + // Scalar registers: + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", + "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", + "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", + "r1:0", "r3:2", "r5:4", "r7:6", "r9:8", "r11:10", "r13:12", "r15:14", + "r17:16", "r19:18", "r21:20", "r23:22", "r25:24", "r27:26", "r29:28", + "r31:30", + // Predicate registers: + "p0", "p1", "p2", "p3", + // Control registers: + "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10", "c11", + "c12", "c13", "c14", "c15", "c16", "c17", "c18", "c19", "c20", "c21", + "c22", "c23", "c24", "c25", "c26", "c27", "c28", "c29", "c30", "c31", + "c1:0", "c3:2", "c5:4", "c7:6", "c9:8", "c11:10", "c13:12", "c15:14", + "c17:16", "c19:18", "c21:20", "c23:22", "c25:24", "c27:26", "c29:28", + "c31:30", + // Control register aliases: + "sa0", "lc0", "sa1", "lc1", "p3:0", "m0", "m1", "usr", "pc", "ugp", + "gp", "cs0", "cs1", "upcyclelo", "upcyclehi", "framelimit", "framekey", + "pktcountlo", "pktcounthi", "utimerlo", "utimerhi", + "upcycle", "pktcount", "utimer", + // HVX vector registers: + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", + "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", + "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", + "v1:0", "v3:2", "v5:4", "v7:6", "v9:8", "v11:10", "v13:12", "v15:14", + "v17:16", "v19:18", "v21:20", "v23:22", "v25:24", "v27:26", "v29:28", + "v31:30", + "v3:0", "v7:4", "v11:8", "v15:12", "v19:16", "v23:20", "v27:24", "v31:28", + // HVX vector predicates: + "q0", "q1", "q2", "q3", +}; + +ArrayRef<const char *> HexagonTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +const TargetInfo::GCCRegAlias HexagonTargetInfo::GCCRegAliases[] = { + {{"sp"}, "r29"}, + {{"fp"}, "r30"}, + {{"lr"}, "r31"}, +}; + +ArrayRef<TargetInfo::GCCRegAlias> HexagonTargetInfo::getGCCRegAliases() const { + return llvm::makeArrayRef(GCCRegAliases); +} + +const Builtin::Info HexagonTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, +#include "clang/Basic/BuiltinsHexagon.def" +}; + +bool HexagonTargetInfo::hasFeature(StringRef Feature) const { + std::string VS = "hvxv" + HVXVersion; + if (Feature == VS) + return true; + + return llvm::StringSwitch<bool>(Feature) + .Case("hexagon", true) + .Case("hvx", HasHVX) + .Case("hvx-length64b", HasHVX64B) + .Case("hvx-length128b", HasHVX128B) + .Case("long-calls", UseLongCalls) + .Case("audio", HasAudio) + .Default(false); +} + +struct CPUSuffix { + llvm::StringLiteral Name; + llvm::StringLiteral Suffix; +}; + +static constexpr CPUSuffix Suffixes[] = { + {{"hexagonv5"}, {"5"}}, {{"hexagonv55"}, {"55"}}, + {{"hexagonv60"}, {"60"}}, {{"hexagonv62"}, {"62"}}, + {{"hexagonv65"}, {"65"}}, {{"hexagonv66"}, {"66"}}, + {{"hexagonv67"}, {"67"}}, {{"hexagonv67t"}, {"67t"}}, + {{"hexagonv68"}, {"68"}}, {{"hexagonv69"}, {"69"}}, +}; + +const char *HexagonTargetInfo::getHexagonCPUSuffix(StringRef Name) { + const CPUSuffix *Item = llvm::find_if( + Suffixes, [Name](const CPUSuffix &S) { return S.Name == Name; }); + if (Item == std::end(Suffixes)) + return nullptr; + return Item->Suffix.data(); +} + +void HexagonTargetInfo::fillValidCPUList( + SmallVectorImpl<StringRef> &Values) const { + for (const CPUSuffix &Suffix : Suffixes) + Values.push_back(Suffix.Name); +} + +ArrayRef<Builtin::Info> HexagonTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::Hexagon::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/Hexagon.h b/contrib/llvm-project/clang/lib/Basic/Targets/Hexagon.h new file mode 100644 index 000000000000..94441998f355 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/Hexagon.h @@ -0,0 +1,146 @@ +//===--- Hexagon.h - Declare Hexagon target feature support -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares Hexagon TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_HEXAGON_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_HEXAGON_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +// Hexagon abstract base class +class LLVM_LIBRARY_VISIBILITY HexagonTargetInfo : public TargetInfo { + + static const Builtin::Info BuiltinInfo[]; + static const char *const GCCRegNames[]; + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + std::string CPU; + std::string HVXVersion; + bool HasHVX = false; + bool HasHVX64B = false; + bool HasHVX128B = false; + bool HasAudio = false; + bool UseLongCalls = false; + +public: + HexagonTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + // Specify the vector alignment explicitly. For v512x1, the calculated + // alignment would be 512*alignment(i1), which is 512 bytes, instead of + // the required minimum of 64 bytes. + resetDataLayout( + "e-m:e-p:32:32:32-a:0-n16:32-" + "i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-" + "v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048"); + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + + // {} in inline assembly are packet specifiers, not assembly variant + // specifiers. + NoAsmVariants = true; + + LargeArrayMinWidth = 64; + LargeArrayAlign = 64; + UseBitFieldTypeAlignment = true; + ZeroLengthBitfieldBoundary = 32; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + + // These are the default values anyway, but explicitly make sure + // that the size of the boolean type is 8 bits. Bool vectors are used + // for modeling predicate registers in HVX, and the bool -> byte + // correspondence matches the HVX architecture. + BoolWidth = BoolAlign = 8; + } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + switch (*Name) { + case 'v': + case 'q': + if (HasHVX) { + Info.setAllowsRegister(); + return true; + } + break; + case 'a': // Modifier register m0-m1. + Info.setAllowsRegister(); + return true; + case 's': + // Relocatable constant. + return true; + } + return false; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool isCLZForZeroUndef() const override { return false; } + + bool hasFeature(StringRef Feature) const override; + + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override; + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override; + + BuiltinVaListKind getBuiltinVaListKind() const override { + if (getTriple().isMusl()) + return TargetInfo::HexagonBuiltinVaList; + return TargetInfo::CharPtrBuiltinVaList; + } + + ArrayRef<const char *> getGCCRegNames() const override; + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; + + const char *getClobbers() const override { return ""; } + + static const char *getHexagonCPUSuffix(StringRef Name); + + bool isValidCPUName(StringRef Name) const override { + return getHexagonCPUSuffix(Name); + } + + void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; + + bool setCPU(const std::string &Name) override { + if (!isValidCPUName(Name)) + return false; + CPU = Name; + return true; + } + + int getEHDataRegisterNumber(unsigned RegNo) const override { + return RegNo < 2 ? RegNo : -1; + } + + bool isTinyCore() const { + // We can write more stricter checks later. + return CPU.find('t') != std::string::npos; + } + + bool hasBitIntType() const override { return true; } +}; +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_HEXAGON_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/Lanai.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/Lanai.cpp new file mode 100644 index 000000000000..bb1872083c09 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/Lanai.cpp @@ -0,0 +1,70 @@ +//===--- Lanai.cpp - Implement Lanai target feature support ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements Lanai TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "Lanai.h" +#include "clang/Basic/MacroBuilder.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +const char *const LanaiTargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", + "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", + "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" +}; + +ArrayRef<const char *> LanaiTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +const TargetInfo::GCCRegAlias LanaiTargetInfo::GCCRegAliases[] = { + {{"pc"}, "r2"}, {{"sp"}, "r4"}, {{"fp"}, "r5"}, {{"rv"}, "r8"}, + {{"rr1"}, "r10"}, {{"rr2"}, "r11"}, {{"rca"}, "r15"}, +}; + +ArrayRef<TargetInfo::GCCRegAlias> LanaiTargetInfo::getGCCRegAliases() const { + return llvm::makeArrayRef(GCCRegAliases); +} + +bool LanaiTargetInfo::isValidCPUName(StringRef Name) const { + return llvm::StringSwitch<bool>(Name).Case("v11", true).Default(false); +} +void LanaiTargetInfo::fillValidCPUList( + SmallVectorImpl<StringRef> &Values) const { + Values.emplace_back("v11"); +} + +bool LanaiTargetInfo::setCPU(const std::string &Name) { + CPU = llvm::StringSwitch<CPUKind>(Name).Case("v11", CK_V11).Default(CK_NONE); + + return CPU != CK_NONE; +} + +bool LanaiTargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature).Case("lanai", true).Default(false); +} + +void LanaiTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Define __lanai__ when building for target lanai. + Builder.defineMacro("__lanai__"); + + // Set define for the CPU specified. + switch (CPU) { + case CK_V11: + Builder.defineMacro("__LANAI_V11__"); + break; + case CK_NONE: + llvm_unreachable("Unhandled target CPU"); + } +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/Lanai.h b/contrib/llvm-project/clang/lib/Basic/Targets/Lanai.h new file mode 100644 index 000000000000..56c6cced938a --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/Lanai.h @@ -0,0 +1,95 @@ +//===--- Lanai.h - Declare Lanai target feature support ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares Lanai TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_LANAI_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_LANAI_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY LanaiTargetInfo : public TargetInfo { + // Class for Lanai (32-bit). + // The CPU profiles supported by the Lanai backend + enum CPUKind { + CK_NONE, + CK_V11, + } CPU; + + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + static const char *const GCCRegNames[]; + +public: + LanaiTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + // Description string has to be kept in sync with backend. + resetDataLayout("E" // Big endian + "-m:e" // ELF name manging + "-p:32:32" // 32 bit pointers, 32 bit aligned + "-i64:64" // 64 bit integers, 64 bit aligned + "-a:0:32" // 32 bit alignment of objects of aggregate type + "-n32" // 32 bit native integer width + "-S64" // 64 bit natural stack alignment + ); + + // Setting RegParmMax equal to what mregparm was set to in the old + // toolchain + RegParmMax = 4; + + // Set the default CPU to V11 + CPU = CK_V11; + + // Temporary approach to make everything at least word-aligned and allow for + // safely casting between pointers with different alignment requirements. + // TODO: Remove this when there are no more cast align warnings on the + // firmware. + MinGlobalAlign = 32; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool isValidCPUName(StringRef Name) const override; + + void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; + + bool setCPU(const std::string &Name) override; + + bool hasFeature(StringRef Feature) const override; + + ArrayRef<const char *> getGCCRegNames() const override; + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override { + return false; + } + + const char *getClobbers() const override { return ""; } + + bool hasBitIntType() const override { return true; } +}; +} // namespace targets +} // namespace clang + +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_LANAI_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/Le64.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/Le64.cpp new file mode 100644 index 000000000000..5c961ff81e05 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/Le64.cpp @@ -0,0 +1,31 @@ +//===--- Le64.cpp - Implement Le64 target feature support -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements Le64 TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "Le64.h" +#include "Targets.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" + +using namespace clang; +using namespace clang::targets; + +ArrayRef<Builtin::Info> Le64TargetInfo::getTargetBuiltins() const { + return {}; +} + +void Le64TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "unix", Opts); + defineCPUMacros(Builder, "le64", /*Tuning=*/false); + Builder.defineMacro("__ELF__"); +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/Le64.h b/contrib/llvm-project/clang/lib/Basic/Targets/Le64.h new file mode 100644 index 000000000000..13a0b04d9f09 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/Le64.h @@ -0,0 +1,62 @@ +//===--- Le64.h - Declare Le64 target feature support -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares Le64 TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_LE64_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_LE64_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY Le64TargetInfo : public TargetInfo { + +public: + Le64TargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + NoAsmVariants = true; + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + resetDataLayout("e-m:e-v128:32-v16:16-v32:32-v96:32-n8:16:32:64-S128"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::PNaClABIBuiltinVaList; + } + + const char *getClobbers() const override { return ""; } + + ArrayRef<const char *> getGCCRegNames() const override { return None; } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + return false; + } + + bool hasProtectedVisibility() const override { return false; } +}; + +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_LE64_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/M68k.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/M68k.cpp new file mode 100644 index 000000000000..ada5b97ed66d --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/M68k.cpp @@ -0,0 +1,236 @@ +//===--- M68k.cpp - Implement M68k targets feature support-------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements M68k TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "M68k.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/TargetParser.h" +#include <cstdint> +#include <cstring> +#include <limits> + +namespace clang { +namespace targets { + +M68kTargetInfo::M68kTargetInfo(const llvm::Triple &Triple, + const TargetOptions &) + : TargetInfo(Triple) { + + std::string Layout; + + // M68k is Big Endian + Layout += "E"; + + // FIXME how to wire it with the used object format? + Layout += "-m:e"; + + // M68k pointers are always 32 bit wide even for 16-bit CPUs + Layout += "-p:32:16:32"; + + // M68k integer data types + Layout += "-i8:8:8-i16:16:16-i32:16:32"; + + // FIXME no floats at the moment + + // The registers can hold 8, 16, 32 bits + Layout += "-n8:16:32"; + + // 16 bit alignment for both stack and aggregate + // in order to conform to ABI used by GCC + Layout += "-a:0:16-S16"; + + resetDataLayout(Layout); + + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; +} + +bool M68kTargetInfo::setCPU(const std::string &Name) { + StringRef N = Name; + CPU = llvm::StringSwitch<CPUKind>(N) + .Case("generic", CK_68000) + .Case("M68000", CK_68000) + .Case("M68010", CK_68010) + .Case("M68020", CK_68020) + .Case("M68030", CK_68030) + .Case("M68040", CK_68040) + .Case("M68060", CK_68060) + .Default(CK_Unknown); + return CPU != CK_Unknown; +} + +void M68kTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + using llvm::Twine; + + Builder.defineMacro("__m68k__"); + + Builder.defineMacro("mc68000"); + Builder.defineMacro("__mc68000"); + Builder.defineMacro("__mc68000__"); + + // For sub-architecture + switch (CPU) { + case CK_68010: + Builder.defineMacro("mc68010"); + Builder.defineMacro("__mc68010"); + Builder.defineMacro("__mc68010__"); + break; + case CK_68020: + Builder.defineMacro("mc68020"); + Builder.defineMacro("__mc68020"); + Builder.defineMacro("__mc68020__"); + break; + case CK_68030: + Builder.defineMacro("mc68030"); + Builder.defineMacro("__mc68030"); + Builder.defineMacro("__mc68030__"); + break; + case CK_68040: + Builder.defineMacro("mc68040"); + Builder.defineMacro("__mc68040"); + Builder.defineMacro("__mc68040__"); + break; + case CK_68060: + Builder.defineMacro("mc68060"); + Builder.defineMacro("__mc68060"); + Builder.defineMacro("__mc68060__"); + break; + default: + break; + } +} + +ArrayRef<Builtin::Info> M68kTargetInfo::getTargetBuiltins() const { + // FIXME: Implement. + return None; +} + +bool M68kTargetInfo::hasFeature(StringRef Feature) const { + // FIXME elaborate moar + return Feature == "M68000"; +} + +const char *const M68kTargetInfo::GCCRegNames[] = { + "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", + "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", + "pc"}; + +ArrayRef<const char *> M68kTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +ArrayRef<TargetInfo::GCCRegAlias> M68kTargetInfo::getGCCRegAliases() const { + // No aliases. + return None; +} + +bool M68kTargetInfo::validateAsmConstraint( + const char *&Name, TargetInfo::ConstraintInfo &info) const { + switch (*Name) { + case 'a': // address register + case 'd': // data register + info.setAllowsRegister(); + return true; + case 'I': // constant integer in the range [1,8] + info.setRequiresImmediate(1, 8); + return true; + case 'J': // constant signed 16-bit integer + info.setRequiresImmediate(std::numeric_limits<int16_t>::min(), + std::numeric_limits<int16_t>::max()); + return true; + case 'K': // constant that is NOT in the range of [-0x80, 0x80) + info.setRequiresImmediate(); + return true; + case 'L': // constant integer in the range [-8,-1] + info.setRequiresImmediate(-8, -1); + return true; + case 'M': // constant that is NOT in the range of [-0x100, 0x100] + info.setRequiresImmediate(); + return true; + case 'N': // constant integer in the range [24,31] + info.setRequiresImmediate(24, 31); + return true; + case 'O': // constant integer 16 + info.setRequiresImmediate(16); + return true; + case 'P': // constant integer in the range [8,15] + info.setRequiresImmediate(8, 15); + return true; + case 'C': + ++Name; + switch (*Name) { + case '0': // constant integer 0 + info.setRequiresImmediate(0); + return true; + case 'i': // constant integer + case 'j': // integer constant that doesn't fit in 16 bits + info.setRequiresImmediate(); + return true; + default: + break; + } + break; + default: + break; + } + return false; +} + +llvm::Optional<std::string> +M68kTargetInfo::handleAsmEscapedChar(char EscChar) const { + char C; + switch (EscChar) { + case '.': + case '#': + C = EscChar; + break; + case '/': + C = '%'; + break; + case '$': + C = 's'; + break; + case '&': + C = 'd'; + break; + default: + return llvm::None; + } + + return std::string(1, C); +} + +std::string M68kTargetInfo::convertConstraint(const char *&Constraint) const { + if (*Constraint == 'C') + // Two-character constraint; add "^" hint for later parsing + return std::string("^") + std::string(Constraint++, 2); + + return std::string(1, *Constraint); +} + +const char *M68kTargetInfo::getClobbers() const { + // FIXME: Is this really right? + return ""; +} + +TargetInfo::BuiltinVaListKind M68kTargetInfo::getBuiltinVaListKind() const { + return TargetInfo::VoidPtrBuiltinVaList; +} + +} // namespace targets +} // namespace clang diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/M68k.h b/contrib/llvm-project/clang/lib/Basic/Targets/M68k.h new file mode 100644 index 000000000000..a42ca674ef9c --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/M68k.h @@ -0,0 +1,59 @@ +//===--- M68k.h - Declare M68k target feature support -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares M68k TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_M68K_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_M68K_H + +#include "OSTargets.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY M68kTargetInfo : public TargetInfo { + static const char *const GCCRegNames[]; + + enum CPUKind { + CK_Unknown, + CK_68000, + CK_68010, + CK_68020, + CK_68030, + CK_68040, + CK_68060 + } CPU = CK_Unknown; + +public: + M68kTargetInfo(const llvm::Triple &Triple, const TargetOptions &); + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + bool hasFeature(StringRef Feature) const override; + ArrayRef<const char *> getGCCRegNames() const override; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; + std::string convertConstraint(const char *&Constraint) const override; + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override; + llvm::Optional<std::string> handleAsmEscapedChar(char EscChar) const override; + const char *getClobbers() const override; + BuiltinVaListKind getBuiltinVaListKind() const override; + bool setCPU(const std::string &Name) override; +}; + +} // namespace targets +} // namespace clang + +#endif diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/MSP430.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/MSP430.cpp new file mode 100644 index 000000000000..90890500ae27 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/MSP430.cpp @@ -0,0 +1,34 @@ +//===--- MSP430.cpp - Implement MSP430 target feature support -------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements MSP430 TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "MSP430.h" +#include "clang/Basic/MacroBuilder.h" + +using namespace clang; +using namespace clang::targets; + +const char *const MSP430TargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" +}; + +ArrayRef<const char *> MSP430TargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +void MSP430TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("MSP430"); + Builder.defineMacro("__MSP430__"); + Builder.defineMacro("__ELF__"); + // FIXME: defines for different 'flavours' of MCU +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/MSP430.h b/contrib/llvm-project/clang/lib/Basic/Targets/MSP430.h new file mode 100644 index 000000000000..9d42e4d4bb18 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/MSP430.h @@ -0,0 +1,103 @@ +//===--- MSP430.h - Declare MSP430 target feature support -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares MSP430 TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_MSP430_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_MSP430_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY MSP430TargetInfo : public TargetInfo { + static const char *const GCCRegNames[]; + +public: + MSP430TargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + TLSSupported = false; + IntWidth = 16; + IntAlign = 16; + LongWidth = 32; + LongLongWidth = 64; + LongAlign = LongLongAlign = 16; + FloatWidth = 32; + FloatAlign = 16; + DoubleWidth = LongDoubleWidth = 64; + DoubleAlign = LongDoubleAlign = 16; + PointerWidth = 16; + PointerAlign = 16; + SuitableAlign = 16; + SizeType = UnsignedInt; + IntMaxType = SignedLongLong; + IntPtrType = SignedInt; + PtrDiffType = SignedInt; + SigAtomicType = SignedLong; + resetDataLayout("e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16"); + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override { + // FIXME: Implement. + return None; + } + + bool allowsLargerPreferedTypeAlignment() const override { return false; } + + bool hasFeature(StringRef Feature) const override { + return Feature == "msp430"; + } + + ArrayRef<const char *> getGCCRegNames() const override; + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + // Make r0 - r3 be recognized by llc (f.e., in clobber list) + static const TargetInfo::GCCRegAlias GCCRegAliases[] = { + {{"r0"}, "pc"}, + {{"r1"}, "sp"}, + {{"r2"}, "sr"}, + {{"r3"}, "cg"}, + }; + return llvm::makeArrayRef(GCCRegAliases); + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override { + // FIXME: implement + switch (*Name) { + case 'K': // the constant 1 + case 'L': // constant -1^20 .. 1^19 + case 'M': // constant 1-4: + return true; + } + // No target constraints for now. + return false; + } + + const char *getClobbers() const override { + // FIXME: Is this really right? + return ""; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + // FIXME: implement + return TargetInfo::CharPtrBuiltinVaList; + } +}; + +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_MSP430_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/Mips.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/Mips.cpp new file mode 100644 index 000000000000..39246f650cce --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/Mips.cpp @@ -0,0 +1,298 @@ +//===--- Mips.cpp - Implement Mips target feature support -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements Mips TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "Mips.h" +#include "Targets.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +const Builtin::Info MipsTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsMips.def" +}; + +bool MipsTargetInfo::processorSupportsGPR64() const { + return llvm::StringSwitch<bool>(CPU) + .Case("mips3", true) + .Case("mips4", true) + .Case("mips5", true) + .Case("mips64", true) + .Case("mips64r2", true) + .Case("mips64r3", true) + .Case("mips64r5", true) + .Case("mips64r6", true) + .Case("octeon", true) + .Case("octeon+", true) + .Default(false); +} + +static constexpr llvm::StringLiteral ValidCPUNames[] = { + {"mips1"}, {"mips2"}, {"mips3"}, {"mips4"}, {"mips5"}, + {"mips32"}, {"mips32r2"}, {"mips32r3"}, {"mips32r5"}, {"mips32r6"}, + {"mips64"}, {"mips64r2"}, {"mips64r3"}, {"mips64r5"}, {"mips64r6"}, + {"octeon"}, {"octeon+"}, {"p5600"}}; + +bool MipsTargetInfo::isValidCPUName(StringRef Name) const { + return llvm::is_contained(ValidCPUNames, Name); +} + +void MipsTargetInfo::fillValidCPUList( + SmallVectorImpl<StringRef> &Values) const { + Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames)); +} + +unsigned MipsTargetInfo::getISARev() const { + return llvm::StringSwitch<unsigned>(getCPU()) + .Cases("mips32", "mips64", 1) + .Cases("mips32r2", "mips64r2", "octeon", "octeon+", 2) + .Cases("mips32r3", "mips64r3", 3) + .Cases("mips32r5", "mips64r5", 5) + .Cases("mips32r6", "mips64r6", 6) + .Default(0); +} + +void MipsTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + if (BigEndian) { + DefineStd(Builder, "MIPSEB", Opts); + Builder.defineMacro("_MIPSEB"); + } else { + DefineStd(Builder, "MIPSEL", Opts); + Builder.defineMacro("_MIPSEL"); + } + + Builder.defineMacro("__mips__"); + Builder.defineMacro("_mips"); + if (Opts.GNUMode) + Builder.defineMacro("mips"); + + if (ABI == "o32") { + Builder.defineMacro("__mips", "32"); + Builder.defineMacro("_MIPS_ISA", "_MIPS_ISA_MIPS32"); + } else { + Builder.defineMacro("__mips", "64"); + Builder.defineMacro("__mips64"); + Builder.defineMacro("__mips64__"); + Builder.defineMacro("_MIPS_ISA", "_MIPS_ISA_MIPS64"); + } + + const std::string ISARev = std::to_string(getISARev()); + + if (!ISARev.empty()) + Builder.defineMacro("__mips_isa_rev", ISARev); + + if (ABI == "o32") { + Builder.defineMacro("__mips_o32"); + Builder.defineMacro("_ABIO32", "1"); + Builder.defineMacro("_MIPS_SIM", "_ABIO32"); + } else if (ABI == "n32") { + Builder.defineMacro("__mips_n32"); + Builder.defineMacro("_ABIN32", "2"); + Builder.defineMacro("_MIPS_SIM", "_ABIN32"); + } else if (ABI == "n64") { + Builder.defineMacro("__mips_n64"); + Builder.defineMacro("_ABI64", "3"); + Builder.defineMacro("_MIPS_SIM", "_ABI64"); + } else + llvm_unreachable("Invalid ABI."); + + if (!IsNoABICalls) { + Builder.defineMacro("__mips_abicalls"); + if (CanUseBSDABICalls) + Builder.defineMacro("__ABICALLS__"); + } + + Builder.defineMacro("__REGISTER_PREFIX__", ""); + + switch (FloatABI) { + case HardFloat: + Builder.defineMacro("__mips_hard_float", Twine(1)); + break; + case SoftFloat: + Builder.defineMacro("__mips_soft_float", Twine(1)); + break; + } + + if (IsSingleFloat) + Builder.defineMacro("__mips_single_float", Twine(1)); + + switch (FPMode) { + case FPXX: + Builder.defineMacro("__mips_fpr", Twine(0)); + break; + case FP32: + Builder.defineMacro("__mips_fpr", Twine(32)); + break; + case FP64: + Builder.defineMacro("__mips_fpr", Twine(64)); + break; +} + + if (FPMode == FP64 || IsSingleFloat) + Builder.defineMacro("_MIPS_FPSET", Twine(32)); + else + Builder.defineMacro("_MIPS_FPSET", Twine(16)); + + if (IsMips16) + Builder.defineMacro("__mips16", Twine(1)); + + if (IsMicromips) + Builder.defineMacro("__mips_micromips", Twine(1)); + + if (IsNan2008) + Builder.defineMacro("__mips_nan2008", Twine(1)); + + if (IsAbs2008) + Builder.defineMacro("__mips_abs2008", Twine(1)); + + switch (DspRev) { + default: + break; + case DSP1: + Builder.defineMacro("__mips_dsp_rev", Twine(1)); + Builder.defineMacro("__mips_dsp", Twine(1)); + break; + case DSP2: + Builder.defineMacro("__mips_dsp_rev", Twine(2)); + Builder.defineMacro("__mips_dspr2", Twine(1)); + Builder.defineMacro("__mips_dsp", Twine(1)); + break; + } + + if (HasMSA) + Builder.defineMacro("__mips_msa", Twine(1)); + + if (DisableMadd4) + Builder.defineMacro("__mips_no_madd4", Twine(1)); + + Builder.defineMacro("_MIPS_SZPTR", Twine(getPointerWidth(0))); + Builder.defineMacro("_MIPS_SZINT", Twine(getIntWidth())); + Builder.defineMacro("_MIPS_SZLONG", Twine(getLongWidth())); + + Builder.defineMacro("_MIPS_ARCH", "\"" + CPU + "\""); + if (CPU == "octeon+") + Builder.defineMacro("_MIPS_ARCH_OCTEONP"); + else + Builder.defineMacro("_MIPS_ARCH_" + StringRef(CPU).upper()); + + if (StringRef(CPU).startswith("octeon")) + Builder.defineMacro("__OCTEON__"); + + // These shouldn't be defined for MIPS-I but there's no need to check + // for that since MIPS-I isn't supported. + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); + + // 32-bit MIPS processors don't have the necessary lld/scd instructions + // found in 64-bit processors. In the case of O32 on a 64-bit processor, + // the instructions exist but using them violates the ABI since they + // require 64-bit GPRs and O32 only supports 32-bit GPRs. + if (ABI == "n32" || ABI == "n64") + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); +} + +bool MipsTargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature) + .Case("mips", true) + .Case("dsp", DspRev >= DSP1) + .Case("dspr2", DspRev >= DSP2) + .Case("fp64", FPMode == FP64) + .Case("msa", HasMSA) + .Default(false); +} + +ArrayRef<Builtin::Info> MipsTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::Mips::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} + +unsigned MipsTargetInfo::getUnwindWordWidth() const { + return llvm::StringSwitch<unsigned>(ABI) + .Case("o32", 32) + .Case("n32", 64) + .Case("n64", 64) + .Default(getPointerWidth(0)); +} + +bool MipsTargetInfo::validateTarget(DiagnosticsEngine &Diags) const { + // microMIPS64R6 backend was removed. + if (getTriple().isMIPS64() && IsMicromips && (ABI == "n32" || ABI == "n64")) { + Diags.Report(diag::err_target_unsupported_cpu_for_micromips) << CPU; + return false; + } + // FIXME: It's valid to use O32 on a 64-bit CPU but the backend can't handle + // this yet. It's better to fail here than on the backend assertion. + if (processorSupportsGPR64() && ABI == "o32") { + Diags.Report(diag::err_target_unsupported_abi) << ABI << CPU; + return false; + } + + // 64-bit ABI's require 64-bit CPU's. + if (!processorSupportsGPR64() && (ABI == "n32" || ABI == "n64")) { + Diags.Report(diag::err_target_unsupported_abi) << ABI << CPU; + return false; + } + + // FIXME: It's valid to use O32 on a mips64/mips64el triple but the backend + // can't handle this yet. It's better to fail here than on the + // backend assertion. + if (getTriple().isMIPS64() && ABI == "o32") { + Diags.Report(diag::err_target_unsupported_abi_for_triple) + << ABI << getTriple().str(); + return false; + } + + // FIXME: It's valid to use N32/N64 on a mips/mipsel triple but the backend + // can't handle this yet. It's better to fail here than on the + // backend assertion. + if (getTriple().isMIPS32() && (ABI == "n32" || ABI == "n64")) { + Diags.Report(diag::err_target_unsupported_abi_for_triple) + << ABI << getTriple().str(); + return false; + } + + // -fpxx is valid only for the o32 ABI + if (FPMode == FPXX && (ABI == "n32" || ABI == "n64")) { + Diags.Report(diag::err_unsupported_abi_for_opt) << "-mfpxx" << "o32"; + return false; + } + + // -mfp32 and n32/n64 ABIs are incompatible + if (FPMode != FP64 && FPMode != FPXX && !IsSingleFloat && + (ABI == "n32" || ABI == "n64")) { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfpxx" << CPU; + return false; + } + // Mips revision 6 and -mfp32 are incompatible + if (FPMode != FP64 && FPMode != FPXX && (CPU == "mips32r6" || + CPU == "mips64r6")) { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfp32" << CPU; + return false; + } + // Option -mfp64 permitted on Mips32 iff revision 2 or higher is present + if (FPMode == FP64 && (CPU == "mips1" || CPU == "mips2" || + getISARev() < 2) && ABI == "o32") { + Diags.Report(diag::err_mips_fp64_req) << "-mfp64"; + return false; + } + + return true; +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/Mips.h b/contrib/llvm-project/clang/lib/Basic/Targets/Mips.h new file mode 100644 index 000000000000..b54d36e1c95f --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/Mips.h @@ -0,0 +1,414 @@ +//===--- Mips.h - Declare Mips target feature support -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares Mips TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_MIPS_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_MIPS_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public TargetInfo { + void setDataLayout() { + StringRef Layout; + + if (ABI == "o32") + Layout = "m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64"; + else if (ABI == "n32") + Layout = "m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32:64-S128"; + else if (ABI == "n64") + Layout = "m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128"; + else + llvm_unreachable("Invalid ABI"); + + if (BigEndian) + resetDataLayout(("E-" + Layout).str()); + else + resetDataLayout(("e-" + Layout).str()); + } + + static const Builtin::Info BuiltinInfo[]; + std::string CPU; + bool IsMips16; + bool IsMicromips; + bool IsNan2008; + bool IsAbs2008; + bool IsSingleFloat; + bool IsNoABICalls; + bool CanUseBSDABICalls; + enum MipsFloatABI { HardFloat, SoftFloat } FloatABI; + enum DspRevEnum { NoDSP, DSP1, DSP2 } DspRev; + bool HasMSA; + bool DisableMadd4; + bool UseIndirectJumpHazard; + +protected: + enum FPModeEnum { FPXX, FP32, FP64 } FPMode; + std::string ABI; + +public: + MipsTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple), IsMips16(false), IsMicromips(false), + IsNan2008(false), IsAbs2008(false), IsSingleFloat(false), + IsNoABICalls(false), CanUseBSDABICalls(false), FloatABI(HardFloat), + DspRev(NoDSP), HasMSA(false), DisableMadd4(false), + UseIndirectJumpHazard(false), FPMode(FPXX) { + TheCXXABI.set(TargetCXXABI::GenericMIPS); + + if (Triple.isMIPS32()) + setABI("o32"); + else if (Triple.getEnvironment() == llvm::Triple::GNUABIN32) + setABI("n32"); + else + setABI("n64"); + + CPU = ABI == "o32" ? "mips32r2" : "mips64r2"; + + CanUseBSDABICalls = Triple.isOSFreeBSD() || + Triple.isOSOpenBSD(); + } + + bool isIEEE754_2008Default() const { + return CPU == "mips32r6" || CPU == "mips64r6"; + } + + bool isFP64Default() const { + return CPU == "mips32r6" || ABI == "n32" || ABI == "n64" || ABI == "64"; + } + + bool isNan2008() const override { return IsNan2008; } + + bool processorSupportsGPR64() const; + + StringRef getABI() const override { return ABI; } + + bool setABI(const std::string &Name) override { + if (Name == "o32") { + setO32ABITypes(); + ABI = Name; + return true; + } + + if (Name == "n32") { + setN32ABITypes(); + ABI = Name; + return true; + } + if (Name == "n64") { + setN64ABITypes(); + ABI = Name; + return true; + } + return false; + } + + void setO32ABITypes() { + Int64Type = SignedLongLong; + IntMaxType = Int64Type; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + LongDoubleWidth = LongDoubleAlign = 64; + LongWidth = LongAlign = 32; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; + PointerWidth = PointerAlign = 32; + PtrDiffType = SignedInt; + SizeType = UnsignedInt; + SuitableAlign = 64; + } + + void setN32N64ABITypes() { + LongDoubleWidth = LongDoubleAlign = 128; + LongDoubleFormat = &llvm::APFloat::IEEEquad(); + if (getTriple().isOSFreeBSD()) { + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + } + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + SuitableAlign = 128; + } + + void setN64ABITypes() { + setN32N64ABITypes(); + if (getTriple().isOSOpenBSD()) { + Int64Type = SignedLongLong; + } else { + Int64Type = SignedLong; + } + IntMaxType = Int64Type; + LongWidth = LongAlign = 64; + PointerWidth = PointerAlign = 64; + PtrDiffType = SignedLong; + SizeType = UnsignedLong; + } + + void setN32ABITypes() { + setN32N64ABITypes(); + Int64Type = SignedLongLong; + IntMaxType = Int64Type; + LongWidth = LongAlign = 32; + PointerWidth = PointerAlign = 32; + PtrDiffType = SignedInt; + SizeType = UnsignedInt; + } + + bool isValidCPUName(StringRef Name) const override; + void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; + + bool setCPU(const std::string &Name) override { + CPU = Name; + return isValidCPUName(Name); + } + + const std::string &getCPU() const { return CPU; } + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override { + if (CPU.empty()) + CPU = getCPU(); + if (CPU == "octeon") + Features["mips64r2"] = Features["cnmips"] = true; + else if (CPU == "octeon+") + Features["mips64r2"] = Features["cnmips"] = Features["cnmipsp"] = true; + else + Features[CPU] = true; + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); + } + + unsigned getISARev() const; + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + bool hasFeature(StringRef Feature) const override; + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + ArrayRef<const char *> getGCCRegNames() const override { + static const char *const GCCRegNames[] = { + // CPU register names + // Must match second column of GCCRegAliases + "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", + "$11", "$12", "$13", "$14", "$15", "$16", "$17", "$18", "$19", "$20", + "$21", "$22", "$23", "$24", "$25", "$26", "$27", "$28", "$29", "$30", + "$31", + // Floating point register names + "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", + "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", "$f16", "$f17", "$f18", + "$f19", "$f20", "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", + "$f28", "$f29", "$f30", "$f31", + // Hi/lo and condition register names + "hi", "lo", "", "$fcc0", "$fcc1", "$fcc2", "$fcc3", "$fcc4", "$fcc5", + "$fcc6", "$fcc7", "$ac1hi", "$ac1lo", "$ac2hi", "$ac2lo", "$ac3hi", + "$ac3lo", + // MSA register names + "$w0", "$w1", "$w2", "$w3", "$w4", "$w5", "$w6", "$w7", "$w8", "$w9", + "$w10", "$w11", "$w12", "$w13", "$w14", "$w15", "$w16", "$w17", "$w18", + "$w19", "$w20", "$w21", "$w22", "$w23", "$w24", "$w25", "$w26", "$w27", + "$w28", "$w29", "$w30", "$w31", + // MSA control register names + "$msair", "$msacsr", "$msaaccess", "$msasave", "$msamodify", + "$msarequest", "$msamap", "$msaunmap" + }; + return llvm::makeArrayRef(GCCRegNames); + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + switch (*Name) { + default: + return false; + case 'r': // CPU registers. + case 'd': // Equivalent to "r" unless generating MIPS16 code. + case 'y': // Equivalent to "r", backward compatibility only. + case 'f': // floating-point registers. + case 'c': // $25 for indirect jumps + case 'l': // lo register + case 'x': // hilo register pair + Info.setAllowsRegister(); + return true; + case 'I': // Signed 16-bit constant + case 'J': // Integer 0 + case 'K': // Unsigned 16-bit constant + case 'L': // Signed 32-bit constant, lower 16-bit zeros (for lui) + case 'M': // Constants not loadable via lui, addiu, or ori + case 'N': // Constant -1 to -65535 + case 'O': // A signed 15-bit constant + case 'P': // A constant between 1 go 65535 + return true; + case 'R': // An address that can be used in a non-macro load or store + Info.setAllowsMemory(); + return true; + case 'Z': + if (Name[1] == 'C') { // An address usable by ll, and sc. + Info.setAllowsMemory(); + Name++; // Skip over 'Z'. + return true; + } + return false; + } + } + + std::string convertConstraint(const char *&Constraint) const override { + std::string R; + switch (*Constraint) { + case 'Z': // Two-character constraint; add "^" hint for later parsing. + if (Constraint[1] == 'C') { + R = std::string("^") + std::string(Constraint, 2); + Constraint++; + return R; + } + break; + } + return TargetInfo::convertConstraint(Constraint); + } + + const char *getClobbers() const override { + // In GCC, $1 is not widely used in generated code (it's used only in a few + // specific situations), so there is no real need for users to add it to + // the clobbers list if they want to use it in their inline assembly code. + // + // In LLVM, $1 is treated as a normal GPR and is always allocatable during + // code generation, so using it in inline assembly without adding it to the + // clobbers list can cause conflicts between the inline assembly code and + // the surrounding generated code. + // + // Another problem is that LLVM is allowed to choose $1 for inline assembly + // operands, which will conflict with the ".set at" assembler option (which + // we use only for inline assembly, in order to maintain compatibility with + // GCC) and will also conflict with the user's usage of $1. + // + // The easiest way to avoid these conflicts and keep $1 as an allocatable + // register for generated code is to automatically clobber $1 for all inline + // assembly code. + // + // FIXME: We should automatically clobber $1 only for inline assembly code + // which actually uses it. This would allow LLVM to use $1 for inline + // assembly operands if the user's assembly code doesn't use it. + return "~{$1}"; + } + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override { + IsMips16 = false; + IsMicromips = false; + IsNan2008 = isIEEE754_2008Default(); + IsAbs2008 = isIEEE754_2008Default(); + IsSingleFloat = false; + FloatABI = HardFloat; + DspRev = NoDSP; + FPMode = isFP64Default() ? FP64 : FPXX; + + for (const auto &Feature : Features) { + if (Feature == "+single-float") + IsSingleFloat = true; + else if (Feature == "+soft-float") + FloatABI = SoftFloat; + else if (Feature == "+mips16") + IsMips16 = true; + else if (Feature == "+micromips") + IsMicromips = true; + else if (Feature == "+dsp") + DspRev = std::max(DspRev, DSP1); + else if (Feature == "+dspr2") + DspRev = std::max(DspRev, DSP2); + else if (Feature == "+msa") + HasMSA = true; + else if (Feature == "+nomadd4") + DisableMadd4 = true; + else if (Feature == "+fp64") + FPMode = FP64; + else if (Feature == "-fp64") + FPMode = FP32; + else if (Feature == "+fpxx") + FPMode = FPXX; + else if (Feature == "+nan2008") + IsNan2008 = true; + else if (Feature == "-nan2008") + IsNan2008 = false; + else if (Feature == "+abs2008") + IsAbs2008 = true; + else if (Feature == "-abs2008") + IsAbs2008 = false; + else if (Feature == "+noabicalls") + IsNoABICalls = true; + else if (Feature == "+use-indirect-jump-hazard") + UseIndirectJumpHazard = true; + } + + setDataLayout(); + + return true; + } + + int getEHDataRegisterNumber(unsigned RegNo) const override { + if (RegNo == 0) + return 4; + if (RegNo == 1) + return 5; + return -1; + } + + bool isCLZForZeroUndef() const override { return false; } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + static const TargetInfo::GCCRegAlias O32RegAliases[] = { + {{"at"}, "$1"}, {{"v0"}, "$2"}, {{"v1"}, "$3"}, + {{"a0"}, "$4"}, {{"a1"}, "$5"}, {{"a2"}, "$6"}, + {{"a3"}, "$7"}, {{"t0"}, "$8"}, {{"t1"}, "$9"}, + {{"t2"}, "$10"}, {{"t3"}, "$11"}, {{"t4"}, "$12"}, + {{"t5"}, "$13"}, {{"t6"}, "$14"}, {{"t7"}, "$15"}, + {{"s0"}, "$16"}, {{"s1"}, "$17"}, {{"s2"}, "$18"}, + {{"s3"}, "$19"}, {{"s4"}, "$20"}, {{"s5"}, "$21"}, + {{"s6"}, "$22"}, {{"s7"}, "$23"}, {{"t8"}, "$24"}, + {{"t9"}, "$25"}, {{"k0"}, "$26"}, {{"k1"}, "$27"}, + {{"gp"}, "$28"}, {{"sp", "$sp"}, "$29"}, {{"fp", "$fp"}, "$30"}, + {{"ra"}, "$31"} + }; + static const TargetInfo::GCCRegAlias NewABIRegAliases[] = { + {{"at"}, "$1"}, {{"v0"}, "$2"}, {{"v1"}, "$3"}, + {{"a0"}, "$4"}, {{"a1"}, "$5"}, {{"a2"}, "$6"}, + {{"a3"}, "$7"}, {{"a4"}, "$8"}, {{"a5"}, "$9"}, + {{"a6"}, "$10"}, {{"a7"}, "$11"}, {{"t0"}, "$12"}, + {{"t1"}, "$13"}, {{"t2"}, "$14"}, {{"t3"}, "$15"}, + {{"s0"}, "$16"}, {{"s1"}, "$17"}, {{"s2"}, "$18"}, + {{"s3"}, "$19"}, {{"s4"}, "$20"}, {{"s5"}, "$21"}, + {{"s6"}, "$22"}, {{"s7"}, "$23"}, {{"t8"}, "$24"}, + {{"t9"}, "$25"}, {{"k0"}, "$26"}, {{"k1"}, "$27"}, + {{"gp"}, "$28"}, {{"sp", "$sp"}, "$29"}, {{"fp", "$fp"}, "$30"}, + {{"ra"}, "$31"} + }; + if (ABI == "o32") + return llvm::makeArrayRef(O32RegAliases); + return llvm::makeArrayRef(NewABIRegAliases); + } + + bool hasInt128Type() const override { + return (ABI == "n32" || ABI == "n64") || getTargetOpts().ForceEnableInt128; + } + + unsigned getUnwindWordWidth() const override; + + bool validateTarget(DiagnosticsEngine &Diags) const override; + bool hasBitIntType() const override { return true; } +}; +} // namespace targets +} // namespace clang + +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_MIPS_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/NVPTX.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/NVPTX.cpp new file mode 100644 index 000000000000..75e82d819900 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/NVPTX.cpp @@ -0,0 +1,269 @@ +//===--- NVPTX.cpp - Implement NVPTX target feature support ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements NVPTX TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "NVPTX.h" +#include "Targets.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +const Builtin::Info NVPTXTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, +#include "clang/Basic/BuiltinsNVPTX.def" +}; + +const char *const NVPTXTargetInfo::GCCRegNames[] = {"r0"}; + +NVPTXTargetInfo::NVPTXTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts, + unsigned TargetPointerWidth) + : TargetInfo(Triple) { + assert((TargetPointerWidth == 32 || TargetPointerWidth == 64) && + "NVPTX only supports 32- and 64-bit modes."); + + PTXVersion = 32; + for (const StringRef Feature : Opts.FeaturesAsWritten) { + if (!Feature.startswith("+ptx")) + continue; + PTXVersion = llvm::StringSwitch<unsigned>(Feature) + .Case("+ptx75", 75) + .Case("+ptx74", 74) + .Case("+ptx73", 73) + .Case("+ptx72", 72) + .Case("+ptx71", 71) + .Case("+ptx70", 70) + .Case("+ptx65", 65) + .Case("+ptx64", 64) + .Case("+ptx63", 63) + .Case("+ptx61", 61) + .Case("+ptx60", 60) + .Case("+ptx50", 50) + .Case("+ptx43", 43) + .Case("+ptx42", 42) + .Case("+ptx41", 41) + .Case("+ptx40", 40) + .Case("+ptx32", 32) + .Default(32); + } + + TLSSupported = false; + VLASupported = false; + AddrSpaceMap = &NVPTXAddrSpaceMap; + UseAddrSpaceMapMangling = true; + + // Define available target features + // These must be defined in sorted order! + NoAsmVariants = true; + GPU = CudaArch::SM_20; + + if (TargetPointerWidth == 32) + resetDataLayout("e-p:32:32-i64:64-i128:128-v16:16-v32:32-n16:32:64"); + else if (Opts.NVPTXUseShortPointers) + resetDataLayout( + "e-p3:32:32-p4:32:32-p5:32:32-i64:64-i128:128-v16:16-v32:32-n16:32:64"); + else + resetDataLayout("e-i64:64-i128:128-v16:16-v32:32-n16:32:64"); + + // If possible, get a TargetInfo for our host triple, so we can match its + // types. + llvm::Triple HostTriple(Opts.HostTriple); + if (!HostTriple.isNVPTX()) + HostTarget.reset(AllocateTarget(llvm::Triple(Opts.HostTriple), Opts)); + + // If no host target, make some guesses about the data layout and return. + if (!HostTarget) { + LongWidth = LongAlign = TargetPointerWidth; + PointerWidth = PointerAlign = TargetPointerWidth; + switch (TargetPointerWidth) { + case 32: + SizeType = TargetInfo::UnsignedInt; + PtrDiffType = TargetInfo::SignedInt; + IntPtrType = TargetInfo::SignedInt; + break; + case 64: + SizeType = TargetInfo::UnsignedLong; + PtrDiffType = TargetInfo::SignedLong; + IntPtrType = TargetInfo::SignedLong; + break; + default: + llvm_unreachable("TargetPointerWidth must be 32 or 64"); + } + return; + } + + // Copy properties from host target. + PointerWidth = HostTarget->getPointerWidth(/* AddrSpace = */ 0); + PointerAlign = HostTarget->getPointerAlign(/* AddrSpace = */ 0); + BoolWidth = HostTarget->getBoolWidth(); + BoolAlign = HostTarget->getBoolAlign(); + IntWidth = HostTarget->getIntWidth(); + IntAlign = HostTarget->getIntAlign(); + HalfWidth = HostTarget->getHalfWidth(); + HalfAlign = HostTarget->getHalfAlign(); + FloatWidth = HostTarget->getFloatWidth(); + FloatAlign = HostTarget->getFloatAlign(); + DoubleWidth = HostTarget->getDoubleWidth(); + DoubleAlign = HostTarget->getDoubleAlign(); + LongWidth = HostTarget->getLongWidth(); + LongAlign = HostTarget->getLongAlign(); + LongLongWidth = HostTarget->getLongLongWidth(); + LongLongAlign = HostTarget->getLongLongAlign(); + MinGlobalAlign = HostTarget->getMinGlobalAlign(/* TypeSize = */ 0); + NewAlign = HostTarget->getNewAlign(); + DefaultAlignForAttributeAligned = + HostTarget->getDefaultAlignForAttributeAligned(); + SizeType = HostTarget->getSizeType(); + IntMaxType = HostTarget->getIntMaxType(); + PtrDiffType = HostTarget->getPtrDiffType(/* AddrSpace = */ 0); + IntPtrType = HostTarget->getIntPtrType(); + WCharType = HostTarget->getWCharType(); + WIntType = HostTarget->getWIntType(); + Char16Type = HostTarget->getChar16Type(); + Char32Type = HostTarget->getChar32Type(); + Int64Type = HostTarget->getInt64Type(); + SigAtomicType = HostTarget->getSigAtomicType(); + ProcessIDType = HostTarget->getProcessIDType(); + + UseBitFieldTypeAlignment = HostTarget->useBitFieldTypeAlignment(); + UseZeroLengthBitfieldAlignment = HostTarget->useZeroLengthBitfieldAlignment(); + UseExplicitBitFieldAlignment = HostTarget->useExplicitBitFieldAlignment(); + ZeroLengthBitfieldBoundary = HostTarget->getZeroLengthBitfieldBoundary(); + + // This is a bit of a lie, but it controls __GCC_ATOMIC_XXX_LOCK_FREE, and + // we need those macros to be identical on host and device, because (among + // other things) they affect which standard library classes are defined, and + // we need all classes to be defined on both the host and device. + MaxAtomicInlineWidth = HostTarget->getMaxAtomicInlineWidth(); + + // Properties intentionally not copied from host: + // - LargeArrayMinWidth, LargeArrayAlign: Not visible across the + // host/device boundary. + // - SuitableAlign: Not visible across the host/device boundary, and may + // correctly be different on host/device, e.g. if host has wider vector + // types than device. + // - LongDoubleWidth, LongDoubleAlign: nvptx's long double type is the same + // as its double type, but that's not necessarily true on the host. + // TODO: nvcc emits a warning when using long double on device; we should + // do the same. +} + +ArrayRef<const char *> NVPTXTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +bool NVPTXTargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature) + .Cases("ptx", "nvptx", true) + .Default(false); +} + +void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__PTX__"); + Builder.defineMacro("__NVPTX__"); + if (Opts.CUDAIsDevice) { + // Set __CUDA_ARCH__ for the GPU specified. + std::string CUDAArchCode = [this] { + switch (GPU) { + case CudaArch::GFX600: + case CudaArch::GFX601: + case CudaArch::GFX602: + case CudaArch::GFX700: + case CudaArch::GFX701: + case CudaArch::GFX702: + case CudaArch::GFX703: + case CudaArch::GFX704: + case CudaArch::GFX705: + case CudaArch::GFX801: + case CudaArch::GFX802: + case CudaArch::GFX803: + case CudaArch::GFX805: + case CudaArch::GFX810: + case CudaArch::GFX900: + case CudaArch::GFX902: + case CudaArch::GFX904: + case CudaArch::GFX906: + case CudaArch::GFX908: + case CudaArch::GFX909: + case CudaArch::GFX90a: + case CudaArch::GFX90c: + case CudaArch::GFX1010: + case CudaArch::GFX1011: + case CudaArch::GFX1012: + case CudaArch::GFX1013: + case CudaArch::GFX1030: + case CudaArch::GFX1031: + case CudaArch::GFX1032: + case CudaArch::GFX1033: + case CudaArch::GFX1034: + case CudaArch::GFX1035: + case CudaArch::Generic: + case CudaArch::LAST: + break; + case CudaArch::UNUSED: + case CudaArch::UNKNOWN: + assert(false && "No GPU arch when compiling CUDA device code."); + return ""; + case CudaArch::SM_20: + return "200"; + case CudaArch::SM_21: + return "210"; + case CudaArch::SM_30: + return "300"; + case CudaArch::SM_32: + return "320"; + case CudaArch::SM_35: + return "350"; + case CudaArch::SM_37: + return "370"; + case CudaArch::SM_50: + return "500"; + case CudaArch::SM_52: + return "520"; + case CudaArch::SM_53: + return "530"; + case CudaArch::SM_60: + return "600"; + case CudaArch::SM_61: + return "610"; + case CudaArch::SM_62: + return "620"; + case CudaArch::SM_70: + return "700"; + case CudaArch::SM_72: + return "720"; + case CudaArch::SM_75: + return "750"; + case CudaArch::SM_80: + return "800"; + case CudaArch::SM_86: + return "860"; + } + llvm_unreachable("unhandled CudaArch"); + }(); + Builder.defineMacro("__CUDA_ARCH__", CUDAArchCode); + } +} + +ArrayRef<Builtin::Info> NVPTXTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::NVPTX::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/NVPTX.h b/contrib/llvm-project/clang/lib/Basic/Targets/NVPTX.h new file mode 100644 index 000000000000..589f24f4bb03 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/NVPTX.h @@ -0,0 +1,182 @@ +//===--- NVPTX.h - Declare NVPTX target feature support ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares NVPTX TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_NVPTX_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_NVPTX_H + +#include "clang/Basic/Cuda.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +static const unsigned NVPTXAddrSpaceMap[] = { + 0, // Default + 1, // opencl_global + 3, // opencl_local + 4, // opencl_constant + 0, // opencl_private + // FIXME: generic has to be added to the target + 0, // opencl_generic + 1, // opencl_global_device + 1, // opencl_global_host + 1, // cuda_device + 4, // cuda_constant + 3, // cuda_shared + 1, // sycl_global + 1, // sycl_global_device + 1, // sycl_global_host + 3, // sycl_local + 0, // sycl_private + 0, // ptr32_sptr + 0, // ptr32_uptr + 0 // ptr64 +}; + +/// The DWARF address class. Taken from +/// https://docs.nvidia.com/cuda/archive/10.0/ptx-writers-guide-to-interoperability/index.html#cuda-specific-dwarf +static const int NVPTXDWARFAddrSpaceMap[] = { + -1, // Default, opencl_private or opencl_generic - not defined + 5, // opencl_global + -1, + 8, // opencl_local or cuda_shared + 4, // opencl_constant or cuda_constant +}; + +class LLVM_LIBRARY_VISIBILITY NVPTXTargetInfo : public TargetInfo { + static const char *const GCCRegNames[]; + static const Builtin::Info BuiltinInfo[]; + CudaArch GPU; + uint32_t PTXVersion; + std::unique_ptr<TargetInfo> HostTarget; + +public: + NVPTXTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts, + unsigned TargetPointerWidth); + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override { + Features[CudaArchToString(GPU)] = true; + Features["ptx" + std::to_string(PTXVersion)] = true; + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); + } + + bool hasFeature(StringRef Feature) const override; + + ArrayRef<const char *> getGCCRegNames() const override; + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + // No aliases. + return None; + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + switch (*Name) { + default: + return false; + case 'c': + case 'h': + case 'r': + case 'l': + case 'f': + case 'd': + Info.setAllowsRegister(); + return true; + } + } + + const char *getClobbers() const override { + // FIXME: Is this really right? + return ""; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + // FIXME: implement + return TargetInfo::CharPtrBuiltinVaList; + } + + bool isValidCPUName(StringRef Name) const override { + return StringToCudaArch(Name) != CudaArch::UNKNOWN; + } + + void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override { + for (int i = static_cast<int>(CudaArch::SM_20); + i < static_cast<int>(CudaArch::Generic); ++i) + Values.emplace_back(CudaArchToString(static_cast<CudaArch>(i))); + } + + bool setCPU(const std::string &Name) override { + GPU = StringToCudaArch(Name); + return GPU != CudaArch::UNKNOWN; + } + + void setSupportedOpenCLOpts() override { + auto &Opts = getSupportedOpenCLOpts(); + Opts["cl_clang_storage_class_specifiers"] = true; + Opts["__cl_clang_function_pointers"] = true; + Opts["__cl_clang_variadic_functions"] = true; + Opts["__cl_clang_non_portable_kernel_param_types"] = true; + Opts["__cl_clang_bitfields"] = true; + + Opts["cl_khr_fp64"] = true; + Opts["__opencl_c_fp64"] = true; + Opts["cl_khr_byte_addressable_store"] = true; + Opts["cl_khr_global_int32_base_atomics"] = true; + Opts["cl_khr_global_int32_extended_atomics"] = true; + Opts["cl_khr_local_int32_base_atomics"] = true; + Opts["cl_khr_local_int32_extended_atomics"] = true; + } + + const llvm::omp::GV &getGridValue() const override { + return llvm::omp::NVPTXGridValues; + } + + /// \returns If a target requires an address within a target specific address + /// space \p AddressSpace to be converted in order to be used, then return the + /// corresponding target specific DWARF address space. + /// + /// \returns Otherwise return None and no conversion will be emitted in the + /// DWARF. + Optional<unsigned> + getDWARFAddressSpace(unsigned AddressSpace) const override { + if (AddressSpace >= llvm::array_lengthof(NVPTXDWARFAddrSpaceMap) || + NVPTXDWARFAddrSpaceMap[AddressSpace] < 0) + return llvm::None; + return NVPTXDWARFAddrSpaceMap[AddressSpace]; + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + // CUDA compilations support all of the host's calling conventions. + // + // TODO: We should warn if you apply a non-default CC to anything other than + // a host function. + if (HostTarget) + return HostTarget->checkCallingConvention(CC); + return CCCR_Warning; + } + + bool hasBitIntType() const override { return true; } +}; +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_NVPTX_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/OSTargets.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/OSTargets.cpp new file mode 100644 index 000000000000..f8f12daaa072 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/OSTargets.cpp @@ -0,0 +1,230 @@ +//===--- OSTargets.cpp - Implement OS target feature support --------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements OS specific TargetInfo types. +//===----------------------------------------------------------------------===// + +#include "OSTargets.h" +#include "clang/Basic/MacroBuilder.h" +#include "llvm/ADT/StringRef.h" + +using namespace clang; +using namespace clang::targets; + +namespace clang { +namespace targets { + +void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, + const llvm::Triple &Triple, StringRef &PlatformName, + VersionTuple &PlatformMinVersion) { + Builder.defineMacro("__APPLE_CC__", "6000"); + Builder.defineMacro("__APPLE__"); + Builder.defineMacro("__STDC_NO_THREADS__"); + + // AddressSanitizer doesn't play well with source fortification, which is on + // by default on Darwin. + if (Opts.Sanitize.has(SanitizerKind::Address)) + Builder.defineMacro("_FORTIFY_SOURCE", "0"); + + // Darwin defines __weak, __strong, and __unsafe_unretained even in C mode. + if (!Opts.ObjC) { + // __weak is always defined, for use in blocks and with objc pointers. + Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))"); + Builder.defineMacro("__strong", ""); + Builder.defineMacro("__unsafe_unretained", ""); + } + + if (Opts.Static) + Builder.defineMacro("__STATIC__"); + else + Builder.defineMacro("__DYNAMIC__"); + + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + + // Get the platform type and version number from the triple. + VersionTuple OsVersion; + if (Triple.isMacOSX()) { + Triple.getMacOSXVersion(OsVersion); + PlatformName = "macos"; + } else { + OsVersion = Triple.getOSVersion(); + PlatformName = llvm::Triple::getOSTypeName(Triple.getOS()); + if (PlatformName == "ios" && Triple.isMacCatalystEnvironment()) + PlatformName = "maccatalyst"; + } + + // If -target arch-pc-win32-macho option specified, we're + // generating code for Win32 ABI. No need to emit + // __ENVIRONMENT_XX_OS_VERSION_MIN_REQUIRED__. + if (PlatformName == "win32") { + PlatformMinVersion = OsVersion; + return; + } + + // Set the appropriate OS version define. + if (Triple.isiOS()) { + assert(OsVersion < VersionTuple(100) && "Invalid version!"); + char Str[7]; + if (OsVersion.getMajor() < 10) { + Str[0] = '0' + OsVersion.getMajor(); + Str[1] = '0' + (OsVersion.getMinor().getValueOr(0) / 10); + Str[2] = '0' + (OsVersion.getMinor().getValueOr(0) % 10); + Str[3] = '0' + (OsVersion.getSubminor().getValueOr(0) / 10); + Str[4] = '0' + (OsVersion.getSubminor().getValueOr(0) % 10); + Str[5] = '\0'; + } else { + // Handle versions >= 10. + Str[0] = '0' + (OsVersion.getMajor() / 10); + Str[1] = '0' + (OsVersion.getMajor() % 10); + Str[2] = '0' + (OsVersion.getMinor().getValueOr(0) / 10); + Str[3] = '0' + (OsVersion.getMinor().getValueOr(0) % 10); + Str[4] = '0' + (OsVersion.getSubminor().getValueOr(0) / 10); + Str[5] = '0' + (OsVersion.getSubminor().getValueOr(0) % 10); + Str[6] = '\0'; + } + if (Triple.isTvOS()) + Builder.defineMacro("__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__", Str); + else + Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", + Str); + + } else if (Triple.isWatchOS()) { + assert(OsVersion < VersionTuple(10) && "Invalid version!"); + char Str[6]; + Str[0] = '0' + OsVersion.getMajor(); + Str[1] = '0' + (OsVersion.getMinor().getValueOr(0) / 10); + Str[2] = '0' + (OsVersion.getMinor().getValueOr(0) % 10); + Str[3] = '0' + (OsVersion.getSubminor().getValueOr(0) / 10); + Str[4] = '0' + (OsVersion.getSubminor().getValueOr(0) % 10); + Str[5] = '\0'; + Builder.defineMacro("__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__", Str); + } else if (Triple.isMacOSX()) { + // Note that the Driver allows versions which aren't representable in the + // define (because we only get a single digit for the minor and micro + // revision numbers). So, we limit them to the maximum representable + // version. + assert(OsVersion < VersionTuple(100) && "Invalid version!"); + char Str[7]; + if (OsVersion < VersionTuple(10, 10)) { + Str[0] = '0' + (OsVersion.getMajor() / 10); + Str[1] = '0' + (OsVersion.getMajor() % 10); + Str[2] = '0' + std::min(OsVersion.getMinor().getValueOr(0), 9U); + Str[3] = '0' + std::min(OsVersion.getSubminor().getValueOr(0), 9U); + Str[4] = '\0'; + } else { + // Handle versions > 10.9. + Str[0] = '0' + (OsVersion.getMajor() / 10); + Str[1] = '0' + (OsVersion.getMajor() % 10); + Str[2] = '0' + (OsVersion.getMinor().getValueOr(0) / 10); + Str[3] = '0' + (OsVersion.getMinor().getValueOr(0) % 10); + Str[4] = '0' + (OsVersion.getSubminor().getValueOr(0) / 10); + Str[5] = '0' + (OsVersion.getSubminor().getValueOr(0) % 10); + Str[6] = '\0'; + } + Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", Str); + } + + // Tell users about the kernel if there is one. + if (Triple.isOSDarwin()) + Builder.defineMacro("__MACH__"); + + PlatformMinVersion = OsVersion; +} + +static void addMinGWDefines(const llvm::Triple &Triple, const LangOptions &Opts, + MacroBuilder &Builder) { + DefineStd(Builder, "WIN32", Opts); + DefineStd(Builder, "WINNT", Opts); + if (Triple.isArch64Bit()) { + DefineStd(Builder, "WIN64", Opts); + Builder.defineMacro("__MINGW64__"); + } + Builder.defineMacro("__MSVCRT__"); + Builder.defineMacro("__MINGW32__"); + addCygMingDefines(Opts, Builder); +} + +static void addVisualCDefines(const LangOptions &Opts, MacroBuilder &Builder) { + if (Opts.CPlusPlus) { + if (Opts.RTTIData) + Builder.defineMacro("_CPPRTTI"); + + if (Opts.CXXExceptions) + Builder.defineMacro("_CPPUNWIND"); + } + + if (Opts.Bool) + Builder.defineMacro("__BOOL_DEFINED"); + + if (!Opts.CharIsSigned) + Builder.defineMacro("_CHAR_UNSIGNED"); + + // FIXME: POSIXThreads isn't exactly the option this should be defined for, + // but it works for now. + if (Opts.POSIXThreads) + Builder.defineMacro("_MT"); + + if (Opts.MSCompatibilityVersion) { + Builder.defineMacro("_MSC_VER", + Twine(Opts.MSCompatibilityVersion / 100000)); + Builder.defineMacro("_MSC_FULL_VER", Twine(Opts.MSCompatibilityVersion)); + // FIXME We cannot encode the revision information into 32-bits + Builder.defineMacro("_MSC_BUILD", Twine(1)); + + if (Opts.CPlusPlus11 && Opts.isCompatibleWithMSVC(LangOptions::MSVC2015)) + Builder.defineMacro("_HAS_CHAR16_T_LANGUAGE_SUPPORT", Twine(1)); + + if (Opts.isCompatibleWithMSVC(LangOptions::MSVC2015)) { + if (Opts.CPlusPlus2b) + Builder.defineMacro("_MSVC_LANG", "202004L"); + else if (Opts.CPlusPlus20) + Builder.defineMacro("_MSVC_LANG", "202002L"); + else if (Opts.CPlusPlus17) + Builder.defineMacro("_MSVC_LANG", "201703L"); + else if (Opts.CPlusPlus14) + Builder.defineMacro("_MSVC_LANG", "201402L"); + } + } + + if (Opts.MicrosoftExt) { + Builder.defineMacro("_MSC_EXTENSIONS"); + + if (Opts.CPlusPlus11) { + Builder.defineMacro("_RVALUE_REFERENCES_V2_SUPPORTED"); + Builder.defineMacro("_RVALUE_REFERENCES_SUPPORTED"); + Builder.defineMacro("_NATIVE_NULLPTR_SUPPORTED"); + } + } + + Builder.defineMacro("_INTEGRAL_MAX_BITS", "64"); + Builder.defineMacro("__STDC_NO_THREADS__"); + + // Starting with VS 2022 17.1, MSVC predefines the below macro to inform + // users of the execution character set defined at compile time. + // The value given is the Windows Code Page Identifier: + // https://docs.microsoft.com/en-us/windows/win32/intl/code-page-identifiers + // + // Clang currently only supports UTF-8, so we'll use 65001 + Builder.defineMacro("_MSVC_EXECUTION_CHARACTER_SET", "65001"); +} + +void addWindowsDefines(const llvm::Triple &Triple, const LangOptions &Opts, + MacroBuilder &Builder) { + Builder.defineMacro("_WIN32"); + if (Triple.isArch64Bit()) + Builder.defineMacro("_WIN64"); + if (Triple.isWindowsGNUEnvironment()) + addMinGWDefines(Triple, Opts, Builder); + else if (Triple.isKnownWindowsMSVCEnvironment() || + (Triple.isWindowsItaniumEnvironment() && Opts.MSVCCompat)) + addVisualCDefines(Opts, Builder); +} + +} // namespace targets +} // namespace clang diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/OSTargets.h b/contrib/llvm-project/clang/lib/Basic/Targets/OSTargets.h new file mode 100644 index 000000000000..3c1830d5f8e8 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/OSTargets.h @@ -0,0 +1,982 @@ +//===--- OSTargets.h - Declare OS target feature support --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares OS specific TargetInfo types. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_OSTARGETS_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_OSTARGETS_H + +#include "Targets.h" + +namespace clang { +namespace targets { + +template <typename TgtInfo> +class LLVM_LIBRARY_VISIBILITY OSTargetInfo : public TgtInfo { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const = 0; + +public: + OSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : TgtInfo(Triple, Opts) {} + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + TgtInfo::getTargetDefines(Opts, Builder); + getOSDefines(Opts, TgtInfo::getTriple(), Builder); + } +}; + +// CloudABI Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY CloudABITargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + Builder.defineMacro("__CloudABI__"); + Builder.defineMacro("__ELF__"); + + // CloudABI uses ISO/IEC 10646:2012 for wchar_t, char16_t and char32_t. + Builder.defineMacro("__STDC_ISO_10646__", "201206L"); + Builder.defineMacro("__STDC_UTF_16__"); + Builder.defineMacro("__STDC_UTF_32__"); + } + +public: + CloudABITargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) {} +}; + +// Ananas target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY AnanasTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // Ananas defines + Builder.defineMacro("__Ananas__"); + Builder.defineMacro("__ELF__"); + } + +public: + AnanasTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) {} +}; + +void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, + const llvm::Triple &Triple, StringRef &PlatformName, + VersionTuple &PlatformMinVersion); + +template <typename Target> +class LLVM_LIBRARY_VISIBILITY DarwinTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + getDarwinDefines(Builder, Opts, Triple, this->PlatformName, + this->PlatformMinVersion); + } + +public: + DarwinTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + // By default, no TLS, and we list permitted architecture/OS + // combinations. + this->TLSSupported = false; + + if (Triple.isMacOSX()) + this->TLSSupported = !Triple.isMacOSXVersionLT(10, 7); + else if (Triple.isiOS()) { + // 64-bit iOS supported it from 8 onwards, 32-bit device from 9 onwards, + // 32-bit simulator from 10 onwards. + if (Triple.isArch64Bit()) + this->TLSSupported = !Triple.isOSVersionLT(8); + else if (Triple.isArch32Bit()) { + if (!Triple.isSimulatorEnvironment()) + this->TLSSupported = !Triple.isOSVersionLT(9); + else + this->TLSSupported = !Triple.isOSVersionLT(10); + } + } else if (Triple.isWatchOS()) { + if (!Triple.isSimulatorEnvironment()) + this->TLSSupported = !Triple.isOSVersionLT(2); + else + this->TLSSupported = !Triple.isOSVersionLT(3); + } + + this->MCountName = "\01mcount"; + } + + const char *getStaticInitSectionSpecifier() const override { + // FIXME: We should return 0 when building kexts. + return "__TEXT,__StaticInit,regular,pure_instructions"; + } + + /// Darwin does not support protected visibility. Darwin's "default" + /// is very similar to ELF's "protected"; Darwin requires a "weak" + /// attribute on declarations that can be dynamically replaced. + bool hasProtectedVisibility() const override { return false; } + + unsigned getExnObjectAlignment() const override { + // Older versions of libc++abi guarantee an alignment of only 8-bytes for + // exception objects because of a bug in __cxa_exception that was + // eventually fixed in r319123. + llvm::VersionTuple MinVersion; + const llvm::Triple &T = this->getTriple(); + + // Compute the earliest OS versions that have the fix to libc++abi. + switch (T.getOS()) { + case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: // Earliest supporting version is 10.14. + MinVersion = llvm::VersionTuple(10U, 14U); + break; + case llvm::Triple::IOS: + case llvm::Triple::TvOS: // Earliest supporting version is 12.0.0. + MinVersion = llvm::VersionTuple(12U); + break; + case llvm::Triple::WatchOS: // Earliest supporting version is 5.0.0. + MinVersion = llvm::VersionTuple(5U); + break; + default: + // Conservatively return 8 bytes if OS is unknown. + return 64; + } + + if (T.getOSVersion() < MinVersion) + return 64; + return OSTargetInfo<Target>::getExnObjectAlignment(); + } + + TargetInfo::IntType getLeastIntTypeByWidth(unsigned BitWidth, + bool IsSigned) const final { + // Darwin uses `long long` for `int_least64_t` and `int_fast64_t`. + return BitWidth == 64 + ? (IsSigned ? TargetInfo::SignedLongLong + : TargetInfo::UnsignedLongLong) + : TargetInfo::getLeastIntTypeByWidth(BitWidth, IsSigned); + } +}; + +// DragonFlyBSD Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY DragonFlyBSDTargetInfo + : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // DragonFly defines; list based off of gcc output + Builder.defineMacro("__DragonFly__"); + Builder.defineMacro("__DragonFly_cc_version", "100001"); + Builder.defineMacro("__ELF__"); + Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); + Builder.defineMacro("__tune_i386__"); + DefineStd(Builder, "unix", Opts); + if (this->HasFloat128) + Builder.defineMacro("__FLOAT128__"); + } + +public: + DragonFlyBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + switch (Triple.getArch()) { + default: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + this->HasFloat128 = true; + this->MCountName = ".mcount"; + break; + } + } +}; + +#ifndef FREEBSD_CC_VERSION +#define FREEBSD_CC_VERSION 0U +#endif + +// FreeBSD Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY FreeBSDTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // FreeBSD defines; list based off of gcc output + + unsigned Release = Triple.getOSMajorVersion(); + if (Release == 0U) + Release = 8U; + unsigned CCVersion = FREEBSD_CC_VERSION; + if (CCVersion == 0U) + CCVersion = Release * 100000U + 1U; + + Builder.defineMacro("__FreeBSD__", Twine(Release)); + Builder.defineMacro("__FreeBSD_cc_version", Twine(CCVersion)); + Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); + + // On FreeBSD, wchar_t contains the number of the code point as + // used by the character set of the locale. These character sets are + // not necessarily a superset of ASCII. + // + // FIXME: This is wrong; the macro refers to the numerical values + // of wchar_t *literals*, which are not locale-dependent. However, + // FreeBSD systems apparently depend on us getting this wrong, and + // setting this to 1 is conforming even if all the basic source + // character literals have the same encoding as char and wchar_t. + Builder.defineMacro("__STDC_MB_MIGHT_NEQ_WC__", "1"); + } + +public: + FreeBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + switch (Triple.getArch()) { + default: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + this->MCountName = ".mcount"; + break; + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::ppc: + case llvm::Triple::ppcle: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + this->MCountName = "_mcount"; + break; + case llvm::Triple::arm: + this->MCountName = "__mcount"; + break; + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + break; + } + } +}; + +// GNU/kFreeBSD Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY KFreeBSDTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // GNU/kFreeBSD defines; list based off of gcc output + + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__FreeBSD_kernel__"); + Builder.defineMacro("__GLIBC__"); + Builder.defineMacro("__ELF__"); + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + } + +public: + KFreeBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) {} +}; + +// Haiku Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY HaikuTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // Haiku defines; list based off of gcc output + Builder.defineMacro("__HAIKU__"); + Builder.defineMacro("__ELF__"); + DefineStd(Builder, "unix", Opts); + if (this->HasFloat128) + Builder.defineMacro("__FLOAT128__"); + } + +public: + HaikuTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->SizeType = TargetInfo::UnsignedLong; + this->IntPtrType = TargetInfo::SignedLong; + this->PtrDiffType = TargetInfo::SignedLong; + this->ProcessIDType = TargetInfo::SignedLong; + this->TLSSupported = false; + switch (Triple.getArch()) { + default: + break; + case llvm::Triple::x86: + case llvm::Triple::x86_64: + this->HasFloat128 = true; + break; + } + } +}; + +// Hurd target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY HurdTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // Hurd defines; list based off of gcc output. + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__GNU__"); + Builder.defineMacro("__gnu_hurd__"); + Builder.defineMacro("__MACH__"); + Builder.defineMacro("__GLIBC__"); + Builder.defineMacro("__ELF__"); + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + } +public: + HurdTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) {} +}; + +// Minix Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY MinixTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // Minix defines + + Builder.defineMacro("__minix", "3"); + Builder.defineMacro("_EM_WSIZE", "4"); + Builder.defineMacro("_EM_PSIZE", "4"); + Builder.defineMacro("_EM_SSIZE", "2"); + Builder.defineMacro("_EM_LSIZE", "4"); + Builder.defineMacro("_EM_FSIZE", "4"); + Builder.defineMacro("_EM_DSIZE", "8"); + Builder.defineMacro("__ELF__"); + DefineStd(Builder, "unix", Opts); + } + +public: + MinixTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) {} +}; + +// Linux target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY LinuxTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // Linux defines; list based off of gcc output + DefineStd(Builder, "unix", Opts); + DefineStd(Builder, "linux", Opts); + Builder.defineMacro("__ELF__"); + if (Triple.isAndroid()) { + Builder.defineMacro("__ANDROID__", "1"); + this->PlatformName = "android"; + this->PlatformMinVersion = Triple.getEnvironmentVersion(); + const unsigned Maj = this->PlatformMinVersion.getMajor(); + if (Maj) { + Builder.defineMacro("__ANDROID_MIN_SDK_VERSION__", Twine(Maj)); + // This historical but ambiguous name for the minSdkVersion macro. Keep + // defined for compatibility. + Builder.defineMacro("__ANDROID_API__", "__ANDROID_MIN_SDK_VERSION__"); + } + } else { + Builder.defineMacro("__gnu_linux__"); + } + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + if (this->HasFloat128) + Builder.defineMacro("__FLOAT128__"); + } + +public: + LinuxTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->WIntType = TargetInfo::UnsignedInt; + + switch (Triple.getArch()) { + default: + break; + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + case llvm::Triple::ppc: + case llvm::Triple::ppcle: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + this->MCountName = "_mcount"; + break; + case llvm::Triple::x86: + case llvm::Triple::x86_64: + this->HasFloat128 = true; + break; + } + } + + const char *getStaticInitSectionSpecifier() const override { + return ".text.startup"; + } +}; + +// NetBSD Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY NetBSDTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // NetBSD defines; list based off of gcc output + Builder.defineMacro("__NetBSD__"); + Builder.defineMacro("__unix__"); + Builder.defineMacro("__ELF__"); + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + } + +public: + NetBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->MCountName = "__mcount"; + } +}; + +// OpenBSD Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY OpenBSDTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // OpenBSD defines; list based off of gcc output + + Builder.defineMacro("__OpenBSD__"); + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + if (this->HasFloat128) + Builder.defineMacro("__FLOAT128__"); + + if (Opts.C11) + Builder.defineMacro("__STDC_NO_THREADS__"); + } + +public: + OpenBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->WCharType = this->WIntType = this->SignedInt; + this->IntMaxType = TargetInfo::SignedLongLong; + this->Int64Type = TargetInfo::SignedLongLong; + switch (Triple.getArch()) { + case llvm::Triple::x86: + case llvm::Triple::x86_64: + this->HasFloat128 = true; + LLVM_FALLTHROUGH; + default: + this->MCountName = "__mcount"; + break; + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + case llvm::Triple::sparcv9: + this->MCountName = "_mcount"; + break; + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + break; + } + } +}; + +// PSP Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY PSPTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // PSP defines; list based on the output of the pspdev gcc toolchain. + Builder.defineMacro("PSP"); + Builder.defineMacro("_PSP"); + Builder.defineMacro("__psp__"); + Builder.defineMacro("__ELF__"); + } + +public: + PSPTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) {} +}; + +// PS3 PPU Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY PS3PPUTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // PS3 PPU defines. + Builder.defineMacro("__PPC__"); + Builder.defineMacro("__PPU__"); + Builder.defineMacro("__CELLOS_LV2__"); + Builder.defineMacro("__ELF__"); + Builder.defineMacro("__LP32__"); + Builder.defineMacro("_ARCH_PPC64"); + Builder.defineMacro("__powerpc64__"); + } + +public: + PS3PPUTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->LongWidth = this->LongAlign = 32; + this->PointerWidth = this->PointerAlign = 32; + this->IntMaxType = TargetInfo::SignedLongLong; + this->Int64Type = TargetInfo::SignedLongLong; + this->SizeType = TargetInfo::UnsignedInt; + this->resetDataLayout("E-m:e-p:32:32-i64:64-n32:64"); + } +}; + +template <typename Target> +class LLVM_LIBRARY_VISIBILITY PS4OSTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + Builder.defineMacro("__FreeBSD__", "9"); + Builder.defineMacro("__FreeBSD_cc_version", "900001"); + Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); + Builder.defineMacro("__SCE__"); + Builder.defineMacro("__ORBIS__"); + } + +public: + PS4OSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->WCharType = TargetInfo::UnsignedShort; + + // On PS4, TLS variable cannot be aligned to more than 32 bytes (256 bits). + this->MaxTLSAlign = 256; + + // On PS4, do not honor explicit bit field alignment, + // as in "__attribute__((aligned(2))) int b : 1;". + this->UseExplicitBitFieldAlignment = false; + + switch (Triple.getArch()) { + default: + case llvm::Triple::x86_64: + this->MCountName = ".mcount"; + this->NewAlign = 256; + break; + } + } + TargetInfo::CallingConvCheckResult + checkCallingConvention(CallingConv CC) const override { + return (CC == CC_C) ? TargetInfo::CCCR_OK : TargetInfo::CCCR_Error; + } +}; + +// RTEMS Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY RTEMSTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // RTEMS defines; list based off of gcc output + + Builder.defineMacro("__rtems__"); + Builder.defineMacro("__ELF__"); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + } + +public: + RTEMSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + switch (Triple.getArch()) { + default: + case llvm::Triple::x86: + // this->MCountName = ".mcount"; + break; + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + // this->MCountName = "_mcount"; + break; + case llvm::Triple::arm: + // this->MCountName = "__mcount"; + break; + } + } +}; + +// Solaris target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY SolarisTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + DefineStd(Builder, "sun", Opts); + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); + Builder.defineMacro("__svr4__"); + Builder.defineMacro("__SVR4"); + // Solaris headers require _XOPEN_SOURCE to be set to 600 for C99 and + // newer, but to 500 for everything else. feature_test.h has a check to + // ensure that you are not using C99 with an old version of X/Open or C89 + // with a new version. + if (Opts.C99) + Builder.defineMacro("_XOPEN_SOURCE", "600"); + else + Builder.defineMacro("_XOPEN_SOURCE", "500"); + if (Opts.CPlusPlus) { + Builder.defineMacro("__C99FEATURES__"); + Builder.defineMacro("_FILE_OFFSET_BITS", "64"); + } + // GCC restricts the next two to C++. + Builder.defineMacro("_LARGEFILE_SOURCE"); + Builder.defineMacro("_LARGEFILE64_SOURCE"); + Builder.defineMacro("__EXTENSIONS__"); + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + if (this->HasFloat128) + Builder.defineMacro("__FLOAT128__"); + } + +public: + SolarisTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + if (this->PointerWidth == 64) { + this->WCharType = this->WIntType = this->SignedInt; + } else { + this->WCharType = this->WIntType = this->SignedLong; + } + switch (Triple.getArch()) { + default: + break; + case llvm::Triple::x86: + case llvm::Triple::x86_64: + this->HasFloat128 = true; + break; + } + } +}; + +// AIX Target +template <typename Target> +class AIXTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("_IBMR2"); + Builder.defineMacro("_POWER"); + Builder.defineMacro("__THW_BIG_ENDIAN__"); + + Builder.defineMacro("_AIX"); + Builder.defineMacro("__TOS_AIX__"); + Builder.defineMacro("__HOS_AIX__"); + + if (Opts.C11) { + Builder.defineMacro("__STDC_NO_ATOMICS__"); + Builder.defineMacro("__STDC_NO_THREADS__"); + } + + if (Opts.EnableAIXExtendedAltivecABI) + Builder.defineMacro("__EXTABI__"); + + VersionTuple OsVersion = Triple.getOSVersion(); + + // Define AIX OS-Version Macros. + // Includes logic for legacy versions of AIX; no specific intent to support. + if (OsVersion >= VersionTuple(3, 2)) + Builder.defineMacro("_AIX32"); + if (OsVersion >= VersionTuple(4, 1)) + Builder.defineMacro("_AIX41"); + if (OsVersion >= VersionTuple(4, 3)) + Builder.defineMacro("_AIX43"); + if (OsVersion >= VersionTuple(5, 0)) + Builder.defineMacro("_AIX50"); + if (OsVersion >= VersionTuple(5, 1)) + Builder.defineMacro("_AIX51"); + if (OsVersion >= VersionTuple(5, 2)) + Builder.defineMacro("_AIX52"); + if (OsVersion >= VersionTuple(5, 3)) + Builder.defineMacro("_AIX53"); + if (OsVersion >= VersionTuple(6, 1)) + Builder.defineMacro("_AIX61"); + if (OsVersion >= VersionTuple(7, 1)) + Builder.defineMacro("_AIX71"); + if (OsVersion >= VersionTuple(7, 2)) + Builder.defineMacro("_AIX72"); + if (OsVersion >= VersionTuple(7, 3)) + Builder.defineMacro("_AIX73"); + + // FIXME: Do not define _LONG_LONG when -fno-long-long is specified. + Builder.defineMacro("_LONG_LONG"); + + if (Opts.POSIXThreads) { + Builder.defineMacro("_THREAD_SAFE"); + } + + if (this->PointerWidth == 64) { + Builder.defineMacro("__64BIT__"); + } + + // Define _WCHAR_T when it is a fundamental type + // (i.e., for C++ without -fno-wchar). + if (Opts.CPlusPlus && Opts.WChar) { + Builder.defineMacro("_WCHAR_T"); + } + } + +public: + AIXTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->TheCXXABI.set(TargetCXXABI::XL); + + if (this->PointerWidth == 64) { + this->WCharType = this->UnsignedInt; + } else { + this->WCharType = this->UnsignedShort; + } + this->UseZeroLengthBitfieldAlignment = true; + } + + // AIX sets FLT_EVAL_METHOD to be 1. + unsigned getFloatEvalMethod() const override { return 1; } + + bool defaultsToAIXPowerAlignment() const override { return true; } +}; + +// z/OS target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY ZOSTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // FIXME: _LONG_LONG should not be defined under -std=c89. + Builder.defineMacro("_LONG_LONG"); + Builder.defineMacro("_OPEN_DEFAULT"); + // _UNIX03_WITHDRAWN is required to build libcxx. + Builder.defineMacro("_UNIX03_WITHDRAWN"); + Builder.defineMacro("__370__"); + Builder.defineMacro("__BFP__"); + // FIXME: __BOOL__ should not be defined under -std=c89. + Builder.defineMacro("__BOOL__"); + Builder.defineMacro("__LONGNAME__"); + Builder.defineMacro("__MVS__"); + Builder.defineMacro("__THW_370__"); + Builder.defineMacro("__THW_BIG_ENDIAN__"); + Builder.defineMacro("__TOS_390__"); + Builder.defineMacro("__TOS_MVS__"); + Builder.defineMacro("__XPLINK__"); + + if (this->PointerWidth == 64) + Builder.defineMacro("__64BIT__"); + + if (Opts.CPlusPlus) { + Builder.defineMacro("__DLL__"); + // _XOPEN_SOURCE=600 is required to build libcxx. + Builder.defineMacro("_XOPEN_SOURCE", "600"); + } + + if (Opts.GNUMode) { + Builder.defineMacro("_MI_BUILTIN"); + Builder.defineMacro("_EXT"); + } + + if (Opts.CPlusPlus && Opts.WChar) { + // Macro __wchar_t is defined so that the wchar_t data + // type is not declared as a typedef in system headers. + Builder.defineMacro("__wchar_t"); + } + + this->PlatformName = llvm::Triple::getOSTypeName(Triple.getOS()); + } + +public: + ZOSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->WCharType = TargetInfo::UnsignedInt; + this->MaxAlignedAttribute = 128; + this->UseBitFieldTypeAlignment = false; + this->UseZeroLengthBitfieldAlignment = true; + this->UseLeadingZeroLengthBitfield = false; + this->ZeroLengthBitfieldBoundary = 32; + } +}; + +void addWindowsDefines(const llvm::Triple &Triple, const LangOptions &Opts, + MacroBuilder &Builder); + +// Windows target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY WindowsTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + addWindowsDefines(Triple, Opts, Builder); + } + +public: + WindowsTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->WCharType = TargetInfo::UnsignedShort; + this->WIntType = TargetInfo::UnsignedShort; + } +}; + +template <typename Target> +class LLVM_LIBRARY_VISIBILITY NaClTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); + Builder.defineMacro("__native_client__"); + } + +public: + NaClTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->LongAlign = 32; + this->LongWidth = 32; + this->PointerAlign = 32; + this->PointerWidth = 32; + this->IntMaxType = TargetInfo::SignedLongLong; + this->Int64Type = TargetInfo::SignedLongLong; + this->DoubleAlign = 64; + this->LongDoubleWidth = 64; + this->LongDoubleAlign = 64; + this->LongLongWidth = 64; + this->LongLongAlign = 64; + this->SizeType = TargetInfo::UnsignedInt; + this->PtrDiffType = TargetInfo::SignedInt; + this->IntPtrType = TargetInfo::SignedInt; + // RegParmMax is inherited from the underlying architecture. + this->LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + if (Triple.getArch() == llvm::Triple::arm) { + // Handled in ARM's setABI(). + } else if (Triple.getArch() == llvm::Triple::x86) { + this->resetDataLayout("e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-" + "i64:64-n8:16:32-S128"); + } else if (Triple.getArch() == llvm::Triple::x86_64) { + this->resetDataLayout("e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-" + "i64:64-n8:16:32:64-S128"); + } else if (Triple.getArch() == llvm::Triple::mipsel) { + // Handled on mips' setDataLayout. + } else { + assert(Triple.getArch() == llvm::Triple::le32); + this->resetDataLayout("e-p:32:32-i64:64"); + } + } +}; + +// Fuchsia Target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY FuchsiaTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + Builder.defineMacro("__Fuchsia__"); + Builder.defineMacro("__ELF__"); + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + // Required by the libc++ locale support. + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + Builder.defineMacro("__Fuchsia_API_level__", Twine(Opts.FuchsiaAPILevel)); + this->PlatformName = "fuchsia"; + this->PlatformMinVersion = VersionTuple(Opts.FuchsiaAPILevel); + } + +public: + FuchsiaTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->MCountName = "__mcount"; + this->TheCXXABI.set(TargetCXXABI::Fuchsia); + } +}; + +// WebAssembly target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY WebAssemblyOSTargetInfo + : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // A common platform macro. + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + // Follow g++ convention and predefine _GNU_SOURCE for C++. + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + // Indicate that we have __float128. + Builder.defineMacro("__FLOAT128__"); + } + +public: + explicit WebAssemblyOSTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->MCountName = "__mcount"; + this->TheCXXABI.set(TargetCXXABI::WebAssembly); + this->HasFloat128 = true; + } +}; + +// WASI target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY WASITargetInfo + : public WebAssemblyOSTargetInfo<Target> { + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const final { + WebAssemblyOSTargetInfo<Target>::getOSDefines(Opts, Triple, Builder); + Builder.defineMacro("__wasi__"); + } + +public: + explicit WASITargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : WebAssemblyOSTargetInfo<Target>(Triple, Opts) {} +}; + +// Emscripten target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY EmscriptenTargetInfo + : public WebAssemblyOSTargetInfo<Target> { + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const final { + WebAssemblyOSTargetInfo<Target>::getOSDefines(Opts, Triple, Builder); + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__EMSCRIPTEN__"); + if (Opts.POSIXThreads) + Builder.defineMacro("__EMSCRIPTEN_PTHREADS__"); + } + +public: + explicit EmscriptenTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : WebAssemblyOSTargetInfo<Target>(Triple, Opts) { + // Keeping the alignment of long double to 8 bytes even though its size is + // 16 bytes allows emscripten to have an 8-byte-aligned max_align_t which + // in turn gives is a 8-byte aligned malloc. + // Emscripten's ABI is unstable and we may change this back to 128 to match + // the WebAssembly default in the future. + this->LongDoubleAlign = 64; + } +}; + +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_OSTARGETS_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/PNaCl.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/PNaCl.cpp new file mode 100644 index 000000000000..60e9467193a8 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/PNaCl.cpp @@ -0,0 +1,29 @@ +//===--- PNaCl.cpp - Implement PNaCl target feature support ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements PNaCl TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "PNaCl.h" +#include "clang/Basic/MacroBuilder.h" + +using namespace clang; +using namespace clang::targets; + +ArrayRef<const char *> PNaClTargetInfo::getGCCRegNames() const { return None; } + +ArrayRef<TargetInfo::GCCRegAlias> PNaClTargetInfo::getGCCRegAliases() const { + return None; +} + +void PNaClTargetInfo::getArchDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__le32__"); + Builder.defineMacro("__pnacl__"); +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/PNaCl.h b/contrib/llvm-project/clang/lib/Basic/Targets/PNaCl.h new file mode 100644 index 000000000000..b5cf73d73e95 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/PNaCl.h @@ -0,0 +1,88 @@ +//===--- PNaCl.h - Declare PNaCl target feature support ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares PNaCl TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_PNACL_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_PNACL_H + +#include "Mips.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY PNaClTargetInfo : public TargetInfo { +public: + PNaClTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : TargetInfo(Triple) { + this->LongAlign = 32; + this->LongWidth = 32; + this->PointerAlign = 32; + this->PointerWidth = 32; + this->IntMaxType = TargetInfo::SignedLongLong; + this->Int64Type = TargetInfo::SignedLongLong; + this->DoubleAlign = 64; + this->LongDoubleWidth = 64; + this->LongDoubleAlign = 64; + this->SizeType = TargetInfo::UnsignedInt; + this->PtrDiffType = TargetInfo::SignedInt; + this->IntPtrType = TargetInfo::SignedInt; + this->RegParmMax = 0; // Disallow regparm + } + + void getArchDefines(const LangOptions &Opts, MacroBuilder &Builder) const; + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + getArchDefines(Opts, Builder); + } + + bool hasFeature(StringRef Feature) const override { + return Feature == "pnacl"; + } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::PNaClABIBuiltinVaList; + } + + ArrayRef<const char *> getGCCRegNames() const override; + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + return false; + } + + const char *getClobbers() const override { return ""; } + + bool hasBitIntType() const override { return true; } +}; + +// We attempt to use PNaCl (le32) frontend and Mips32EL backend. +class LLVM_LIBRARY_VISIBILITY NaClMips32TargetInfo : public MipsTargetInfo { +public: + NaClMips32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : MipsTargetInfo(Triple, Opts) {} + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::PNaClABIBuiltinVaList; + } +}; +} // namespace targets +} // namespace clang + +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_PNACL_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/PPC.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/PPC.cpp new file mode 100644 index 000000000000..1eb0317af60b --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/PPC.cpp @@ -0,0 +1,830 @@ +//===--- PPC.cpp - Implement PPC target feature support -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements PPC TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "PPC.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" + +using namespace clang; +using namespace clang::targets; + +const Builtin::Info PPCTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsPPC.def" +}; + +/// handleTargetFeatures - Perform initialization based on the user +/// configured set of features. +bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) { + FloatABI = HardFloat; + for (const auto &Feature : Features) { + if (Feature == "+altivec") { + HasAltivec = true; + } else if (Feature == "+vsx") { + HasVSX = true; + } else if (Feature == "+bpermd") { + HasBPERMD = true; + } else if (Feature == "+extdiv") { + HasExtDiv = true; + } else if (Feature == "+power8-vector") { + HasP8Vector = true; + } else if (Feature == "+crypto") { + HasP8Crypto = true; + } else if (Feature == "+direct-move") { + HasDirectMove = true; + } else if (Feature == "+htm") { + HasHTM = true; + } else if (Feature == "+float128") { + HasFloat128 = true; + } else if (Feature == "+power9-vector") { + HasP9Vector = true; + } else if (Feature == "+power10-vector") { + HasP10Vector = true; + } else if (Feature == "+pcrelative-memops") { + HasPCRelativeMemops = true; + } else if (Feature == "+prefix-instrs") { + HasPrefixInstrs = true; + } else if (Feature == "+spe" || Feature == "+efpu2") { + HasStrictFP = false; + HasSPE = true; + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + } else if (Feature == "-hard-float") { + FloatABI = SoftFloat; + } else if (Feature == "+paired-vector-memops") { + PairedVectorMemops = true; + } else if (Feature == "+mma") { + HasMMA = true; + } else if (Feature == "+rop-protect") { + HasROPProtect = true; + } else if (Feature == "+privileged") { + HasPrivileged = true; + } else if (Feature == "+isa-v206-instructions") { + IsISA2_06 = true; + } else if (Feature == "+isa-v207-instructions") { + IsISA2_07 = true; + } else if (Feature == "+isa-v30-instructions") { + IsISA3_0 = true; + } else if (Feature == "+isa-v31-instructions") { + IsISA3_1 = true; + } + // TODO: Finish this list and add an assert that we've handled them + // all. + } + + return true; +} + +static void defineXLCompatMacros(MacroBuilder &Builder) { + Builder.defineMacro("__popcntb", "__builtin_ppc_popcntb"); + Builder.defineMacro("__poppar4", "__builtin_ppc_poppar4"); + Builder.defineMacro("__poppar8", "__builtin_ppc_poppar8"); + Builder.defineMacro("__eieio", "__builtin_ppc_eieio"); + Builder.defineMacro("__iospace_eieio", "__builtin_ppc_iospace_eieio"); + Builder.defineMacro("__isync", "__builtin_ppc_isync"); + Builder.defineMacro("__lwsync", "__builtin_ppc_lwsync"); + Builder.defineMacro("__iospace_lwsync", "__builtin_ppc_iospace_lwsync"); + Builder.defineMacro("__sync", "__builtin_ppc_sync"); + Builder.defineMacro("__iospace_sync", "__builtin_ppc_iospace_sync"); + Builder.defineMacro("__dcbfl", "__builtin_ppc_dcbfl"); + Builder.defineMacro("__dcbflp", "__builtin_ppc_dcbflp"); + Builder.defineMacro("__dcbst", "__builtin_ppc_dcbst"); + Builder.defineMacro("__dcbt", "__builtin_ppc_dcbt"); + Builder.defineMacro("__dcbtst", "__builtin_ppc_dcbtst"); + Builder.defineMacro("__dcbz", "__builtin_ppc_dcbz"); + Builder.defineMacro("__icbt", "__builtin_ppc_icbt"); + Builder.defineMacro("__compare_and_swap", "__builtin_ppc_compare_and_swap"); + Builder.defineMacro("__compare_and_swaplp", + "__builtin_ppc_compare_and_swaplp"); + Builder.defineMacro("__fetch_and_add", "__builtin_ppc_fetch_and_add"); + Builder.defineMacro("__fetch_and_addlp", "__builtin_ppc_fetch_and_addlp"); + Builder.defineMacro("__fetch_and_and", "__builtin_ppc_fetch_and_and"); + Builder.defineMacro("__fetch_and_andlp", "__builtin_ppc_fetch_and_andlp"); + Builder.defineMacro("__fetch_and_or", "__builtin_ppc_fetch_and_or"); + Builder.defineMacro("__fetch_and_orlp", "__builtin_ppc_fetch_and_orlp"); + Builder.defineMacro("__fetch_and_swap", "__builtin_ppc_fetch_and_swap"); + Builder.defineMacro("__fetch_and_swaplp", "__builtin_ppc_fetch_and_swaplp"); + Builder.defineMacro("__ldarx", "__builtin_ppc_ldarx"); + Builder.defineMacro("__lwarx", "__builtin_ppc_lwarx"); + Builder.defineMacro("__lharx", "__builtin_ppc_lharx"); + Builder.defineMacro("__lbarx", "__builtin_ppc_lbarx"); + Builder.defineMacro("__stfiw", "__builtin_ppc_stfiw"); + Builder.defineMacro("__stdcx", "__builtin_ppc_stdcx"); + Builder.defineMacro("__stwcx", "__builtin_ppc_stwcx"); + Builder.defineMacro("__sthcx", "__builtin_ppc_sthcx"); + Builder.defineMacro("__stbcx", "__builtin_ppc_stbcx"); + Builder.defineMacro("__tdw", "__builtin_ppc_tdw"); + Builder.defineMacro("__tw", "__builtin_ppc_tw"); + Builder.defineMacro("__trap", "__builtin_ppc_trap"); + Builder.defineMacro("__trapd", "__builtin_ppc_trapd"); + Builder.defineMacro("__fcfid", "__builtin_ppc_fcfid"); + Builder.defineMacro("__fcfud", "__builtin_ppc_fcfud"); + Builder.defineMacro("__fctid", "__builtin_ppc_fctid"); + Builder.defineMacro("__fctidz", "__builtin_ppc_fctidz"); + Builder.defineMacro("__fctiw", "__builtin_ppc_fctiw"); + Builder.defineMacro("__fctiwz", "__builtin_ppc_fctiwz"); + Builder.defineMacro("__fctudz", "__builtin_ppc_fctudz"); + Builder.defineMacro("__fctuwz", "__builtin_ppc_fctuwz"); + Builder.defineMacro("__cmpeqb", "__builtin_ppc_cmpeqb"); + Builder.defineMacro("__cmprb", "__builtin_ppc_cmprb"); + Builder.defineMacro("__setb", "__builtin_ppc_setb"); + Builder.defineMacro("__cmpb", "__builtin_ppc_cmpb"); + Builder.defineMacro("__mulhd", "__builtin_ppc_mulhd"); + Builder.defineMacro("__mulhdu", "__builtin_ppc_mulhdu"); + Builder.defineMacro("__mulhw", "__builtin_ppc_mulhw"); + Builder.defineMacro("__mulhwu", "__builtin_ppc_mulhwu"); + Builder.defineMacro("__maddhd", "__builtin_ppc_maddhd"); + Builder.defineMacro("__maddhdu", "__builtin_ppc_maddhdu"); + Builder.defineMacro("__maddld", "__builtin_ppc_maddld"); + Builder.defineMacro("__rlwnm", "__builtin_ppc_rlwnm"); + Builder.defineMacro("__rlwimi", "__builtin_ppc_rlwimi"); + Builder.defineMacro("__rldimi", "__builtin_ppc_rldimi"); + Builder.defineMacro("__load2r", "__builtin_ppc_load2r"); + Builder.defineMacro("__load4r", "__builtin_ppc_load4r"); + Builder.defineMacro("__load8r", "__builtin_ppc_load8r"); + Builder.defineMacro("__store2r", "__builtin_ppc_store2r"); + Builder.defineMacro("__store4r", "__builtin_ppc_store4r"); + Builder.defineMacro("__store8r", "__builtin_ppc_store8r"); + Builder.defineMacro("__extract_exp", "__builtin_ppc_extract_exp"); + Builder.defineMacro("__extract_sig", "__builtin_ppc_extract_sig"); + Builder.defineMacro("__mtfsb0", "__builtin_ppc_mtfsb0"); + Builder.defineMacro("__mtfsb1", "__builtin_ppc_mtfsb1"); + Builder.defineMacro("__mtfsf", "__builtin_ppc_mtfsf"); + Builder.defineMacro("__mtfsfi", "__builtin_ppc_mtfsfi"); + Builder.defineMacro("__insert_exp", "__builtin_ppc_insert_exp"); + Builder.defineMacro("__fmsub", "__builtin_ppc_fmsub"); + Builder.defineMacro("__fmsubs", "__builtin_ppc_fmsubs"); + Builder.defineMacro("__fnmadd", "__builtin_ppc_fnmadd"); + Builder.defineMacro("__fnmadds", "__builtin_ppc_fnmadds"); + Builder.defineMacro("__fnmsub", "__builtin_ppc_fnmsub"); + Builder.defineMacro("__fnmsubs", "__builtin_ppc_fnmsubs"); + Builder.defineMacro("__fre", "__builtin_ppc_fre"); + Builder.defineMacro("__fres", "__builtin_ppc_fres"); + Builder.defineMacro("__swdiv_nochk", "__builtin_ppc_swdiv_nochk"); + Builder.defineMacro("__swdivs_nochk", "__builtin_ppc_swdivs_nochk"); + Builder.defineMacro("__alloca", "__builtin_alloca"); + Builder.defineMacro("__vcipher", "__builtin_altivec_crypto_vcipher"); + Builder.defineMacro("__vcipherlast", "__builtin_altivec_crypto_vcipherlast"); + Builder.defineMacro("__vncipher", "__builtin_altivec_crypto_vncipher"); + Builder.defineMacro("__vncipherlast", + "__builtin_altivec_crypto_vncipherlast"); + Builder.defineMacro("__vpermxor", "__builtin_altivec_crypto_vpermxor"); + Builder.defineMacro("__vpmsumb", "__builtin_altivec_crypto_vpmsumb"); + Builder.defineMacro("__vpmsumd", "__builtin_altivec_crypto_vpmsumd"); + Builder.defineMacro("__vpmsumh", "__builtin_altivec_crypto_vpmsumh"); + Builder.defineMacro("__vpmsumw", "__builtin_altivec_crypto_vpmsumw"); + Builder.defineMacro("__divde", "__builtin_divde"); + Builder.defineMacro("__divwe", "__builtin_divwe"); + Builder.defineMacro("__divdeu", "__builtin_divdeu"); + Builder.defineMacro("__divweu", "__builtin_divweu"); + Builder.defineMacro("__alignx", "__builtin_ppc_alignx"); + Builder.defineMacro("__bcopy", "bcopy"); + Builder.defineMacro("__bpermd", "__builtin_bpermd"); + Builder.defineMacro("__cntlz4", "__builtin_clz"); + Builder.defineMacro("__cntlz8", "__builtin_clzll"); + Builder.defineMacro("__cmplx", "__builtin_complex"); + Builder.defineMacro("__cmplxf", "__builtin_complex"); + Builder.defineMacro("__cnttz4", "__builtin_ctz"); + Builder.defineMacro("__cnttz8", "__builtin_ctzll"); + Builder.defineMacro("__darn", "__builtin_darn"); + Builder.defineMacro("__darn_32", "__builtin_darn_32"); + Builder.defineMacro("__darn_raw", "__builtin_darn_raw"); + Builder.defineMacro("__dcbf", "__builtin_dcbf"); + Builder.defineMacro("__fmadd", "__builtin_fma"); + Builder.defineMacro("__fmadds", "__builtin_fmaf"); + Builder.defineMacro("__labs", "__builtin_labs"); + Builder.defineMacro("__llabs", "__builtin_llabs"); + Builder.defineMacro("__popcnt4", "__builtin_popcount"); + Builder.defineMacro("__popcnt8", "__builtin_popcountll"); + Builder.defineMacro("__readflm", "__builtin_readflm"); + Builder.defineMacro("__rotatel4", "__builtin_rotateleft32"); + Builder.defineMacro("__rotatel8", "__builtin_rotateleft64"); + Builder.defineMacro("__rdlam", "__builtin_ppc_rdlam"); + Builder.defineMacro("__setflm", "__builtin_setflm"); + Builder.defineMacro("__setrnd", "__builtin_setrnd"); + Builder.defineMacro("__dcbtstt", "__builtin_ppc_dcbtstt"); + Builder.defineMacro("__dcbtt", "__builtin_ppc_dcbtt"); + Builder.defineMacro("__mftbu", "__builtin_ppc_mftbu"); + Builder.defineMacro("__mfmsr", "__builtin_ppc_mfmsr"); + Builder.defineMacro("__mtmsr", "__builtin_ppc_mtmsr"); + Builder.defineMacro("__mfspr", "__builtin_ppc_mfspr"); + Builder.defineMacro("__mtspr", "__builtin_ppc_mtspr"); + Builder.defineMacro("__fric", "__builtin_ppc_fric"); + Builder.defineMacro("__frim", "__builtin_ppc_frim"); + Builder.defineMacro("__frims", "__builtin_ppc_frims"); + Builder.defineMacro("__frin", "__builtin_ppc_frin"); + Builder.defineMacro("__frins", "__builtin_ppc_frins"); + Builder.defineMacro("__frip", "__builtin_ppc_frip"); + Builder.defineMacro("__frips", "__builtin_ppc_frips"); + Builder.defineMacro("__friz", "__builtin_ppc_friz"); + Builder.defineMacro("__frizs", "__builtin_ppc_frizs"); + Builder.defineMacro("__fsel", "__builtin_ppc_fsel"); + Builder.defineMacro("__fsels", "__builtin_ppc_fsels"); + Builder.defineMacro("__frsqrte", "__builtin_ppc_frsqrte"); + Builder.defineMacro("__frsqrtes", "__builtin_ppc_frsqrtes"); + Builder.defineMacro("__fsqrt", "__builtin_ppc_fsqrt"); + Builder.defineMacro("__fsqrts", "__builtin_ppc_fsqrts"); + Builder.defineMacro("__addex", "__builtin_ppc_addex"); + Builder.defineMacro("__cmplxl", "__builtin_complex"); + Builder.defineMacro("__compare_exp_uo", "__builtin_ppc_compare_exp_uo"); + Builder.defineMacro("__compare_exp_lt", "__builtin_ppc_compare_exp_lt"); + Builder.defineMacro("__compare_exp_gt", "__builtin_ppc_compare_exp_gt"); + Builder.defineMacro("__compare_exp_eq", "__builtin_ppc_compare_exp_eq"); + Builder.defineMacro("__test_data_class", "__builtin_ppc_test_data_class"); + Builder.defineMacro("__swdiv", "__builtin_ppc_swdiv"); + Builder.defineMacro("__swdivs", "__builtin_ppc_swdivs"); +} + +/// PPCTargetInfo::getTargetDefines - Return a set of the PowerPC-specific +/// #defines that are not tied to a specific subtarget. +void PPCTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + + // We define the XLC compatibility macros only on AIX and Linux since XLC + // was never available on any other platforms. + if (getTriple().isOSAIX() || getTriple().isOSLinux()) + defineXLCompatMacros(Builder); + + // Target identification. + Builder.defineMacro("__ppc__"); + Builder.defineMacro("__PPC__"); + Builder.defineMacro("_ARCH_PPC"); + Builder.defineMacro("__powerpc__"); + Builder.defineMacro("__POWERPC__"); + if (PointerWidth == 64) { + Builder.defineMacro("_ARCH_PPC64"); + Builder.defineMacro("__powerpc64__"); + Builder.defineMacro("__ppc64__"); + Builder.defineMacro("__PPC64__"); + } else if (getTriple().isOSAIX()) { + // The XL compilers on AIX define _ARCH_PPC64 for both 32 and 64-bit modes. + Builder.defineMacro("_ARCH_PPC64"); + } + if (getTriple().isOSAIX()) { + Builder.defineMacro("__THW_PPC__"); + // Define __PPC and __powerpc for AIX XL C/C++ compatibility + Builder.defineMacro("__PPC"); + Builder.defineMacro("__powerpc"); + } + + // Target properties. + if (getTriple().getArch() == llvm::Triple::ppc64le || + getTriple().getArch() == llvm::Triple::ppcle) { + Builder.defineMacro("_LITTLE_ENDIAN"); + } else { + if (!getTriple().isOSNetBSD() && + !getTriple().isOSOpenBSD()) + Builder.defineMacro("_BIG_ENDIAN"); + } + + // ABI options. + if (ABI == "elfv1") + Builder.defineMacro("_CALL_ELF", "1"); + if (ABI == "elfv2") + Builder.defineMacro("_CALL_ELF", "2"); + + // This typically is only for a new enough linker (bfd >= 2.16.2 or gold), but + // our support post-dates this and it should work on all 64-bit ppc linux + // platforms. It is guaranteed to work on all elfv2 platforms. + if (getTriple().getOS() == llvm::Triple::Linux && PointerWidth == 64) + Builder.defineMacro("_CALL_LINUX", "1"); + + // Subtarget options. + if (!getTriple().isOSAIX()){ + Builder.defineMacro("__NATURAL_ALIGNMENT__"); + } + Builder.defineMacro("__REGISTER_PREFIX__", ""); + + // FIXME: Should be controlled by command line option. + if (LongDoubleWidth == 128) { + Builder.defineMacro("__LONG_DOUBLE_128__"); + Builder.defineMacro("__LONGDOUBLE128"); + if (Opts.PPCIEEELongDouble) + Builder.defineMacro("__LONG_DOUBLE_IEEE128__"); + else + Builder.defineMacro("__LONG_DOUBLE_IBM128__"); + } + + if (getTriple().isOSAIX() && Opts.LongDoubleSize == 64) { + assert(LongDoubleWidth == 64); + Builder.defineMacro("__LONGDOUBLE64"); + } + + // Define this for elfv2 (64-bit only) or 64-bit darwin. + if (ABI == "elfv2" || + (getTriple().getOS() == llvm::Triple::Darwin && PointerWidth == 64)) + Builder.defineMacro("__STRUCT_PARM_ALIGN__", "16"); + + if (ArchDefs & ArchDefineName) + Builder.defineMacro(Twine("_ARCH_", StringRef(CPU).upper())); + if (ArchDefs & ArchDefinePpcgr) + Builder.defineMacro("_ARCH_PPCGR"); + if (ArchDefs & ArchDefinePpcsq) + Builder.defineMacro("_ARCH_PPCSQ"); + if (ArchDefs & ArchDefine440) + Builder.defineMacro("_ARCH_440"); + if (ArchDefs & ArchDefine603) + Builder.defineMacro("_ARCH_603"); + if (ArchDefs & ArchDefine604) + Builder.defineMacro("_ARCH_604"); + if (ArchDefs & ArchDefinePwr4) + Builder.defineMacro("_ARCH_PWR4"); + if (ArchDefs & ArchDefinePwr5) + Builder.defineMacro("_ARCH_PWR5"); + if (ArchDefs & ArchDefinePwr5x) + Builder.defineMacro("_ARCH_PWR5X"); + if (ArchDefs & ArchDefinePwr6) + Builder.defineMacro("_ARCH_PWR6"); + if (ArchDefs & ArchDefinePwr6x) + Builder.defineMacro("_ARCH_PWR6X"); + if (ArchDefs & ArchDefinePwr7) + Builder.defineMacro("_ARCH_PWR7"); + if (ArchDefs & ArchDefinePwr8) + Builder.defineMacro("_ARCH_PWR8"); + if (ArchDefs & ArchDefinePwr9) + Builder.defineMacro("_ARCH_PWR9"); + if (ArchDefs & ArchDefinePwr10) + Builder.defineMacro("_ARCH_PWR10"); + if (ArchDefs & ArchDefineA2) + Builder.defineMacro("_ARCH_A2"); + if (ArchDefs & ArchDefineE500) + Builder.defineMacro("__NO_LWSYNC__"); + if (ArchDefs & ArchDefineFuture) + Builder.defineMacro("_ARCH_PWR_FUTURE"); + + if (HasAltivec) { + Builder.defineMacro("__VEC__", "10206"); + Builder.defineMacro("__ALTIVEC__"); + } + if (HasSPE) { + Builder.defineMacro("__SPE__"); + Builder.defineMacro("__NO_FPRS__"); + } + if (HasVSX) + Builder.defineMacro("__VSX__"); + if (HasP8Vector) + Builder.defineMacro("__POWER8_VECTOR__"); + if (HasP8Crypto) + Builder.defineMacro("__CRYPTO__"); + if (HasHTM) + Builder.defineMacro("__HTM__"); + if (HasFloat128) + Builder.defineMacro("__FLOAT128__"); + if (HasP9Vector) + Builder.defineMacro("__POWER9_VECTOR__"); + if (HasMMA) + Builder.defineMacro("__MMA__"); + if (HasROPProtect) + Builder.defineMacro("__ROP_PROTECT__"); + if (HasP10Vector) + Builder.defineMacro("__POWER10_VECTOR__"); + if (HasPCRelativeMemops) + Builder.defineMacro("__PCREL__"); + + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); + if (PointerWidth == 64) + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); + + // We have support for the bswap intrinsics so we can define this. + Builder.defineMacro("__HAVE_BSWAP__", "1"); + + // FIXME: The following are not yet generated here by Clang, but are + // generated by GCC: + // + // _SOFT_FLOAT_ + // __RECIP_PRECISION__ + // __APPLE_ALTIVEC__ + // __RECIP__ + // __RECIPF__ + // __RSQRTE__ + // __RSQRTEF__ + // _SOFT_DOUBLE_ + // __NO_LWSYNC__ + // __CMODEL_MEDIUM__ + // __CMODEL_LARGE__ + // _CALL_SYSV + // _CALL_DARWIN +} + +// Handle explicit options being passed to the compiler here: if we've +// explicitly turned off vsx and turned on any of: +// - power8-vector +// - direct-move +// - float128 +// - power9-vector +// - paired-vector-memops +// - mma +// - power10-vector +// then go ahead and error since the customer has expressed an incompatible +// set of options. +static bool ppcUserFeaturesCheck(DiagnosticsEngine &Diags, + const std::vector<std::string> &FeaturesVec) { + + // vsx was not explicitly turned off. + if (!llvm::is_contained(FeaturesVec, "-vsx")) + return true; + + auto FindVSXSubfeature = [&](StringRef Feature, StringRef Option) { + if (llvm::is_contained(FeaturesVec, Feature)) { + Diags.Report(diag::err_opt_not_valid_with_opt) << Option << "-mno-vsx"; + return true; + } + return false; + }; + + bool Found = FindVSXSubfeature("+power8-vector", "-mpower8-vector"); + Found |= FindVSXSubfeature("+direct-move", "-mdirect-move"); + Found |= FindVSXSubfeature("+float128", "-mfloat128"); + Found |= FindVSXSubfeature("+power9-vector", "-mpower9-vector"); + Found |= FindVSXSubfeature("+paired-vector-memops", "-mpaired-vector-memops"); + Found |= FindVSXSubfeature("+mma", "-mmma"); + Found |= FindVSXSubfeature("+power10-vector", "-mpower10-vector"); + + // Return false if any vsx subfeatures was found. + return !Found; +} + +bool PPCTargetInfo::initFeatureMap( + llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, + const std::vector<std::string> &FeaturesVec) const { + Features["altivec"] = llvm::StringSwitch<bool>(CPU) + .Case("7400", true) + .Case("g4", true) + .Case("7450", true) + .Case("g4+", true) + .Case("970", true) + .Case("g5", true) + .Case("pwr6", true) + .Case("pwr7", true) + .Case("pwr8", true) + .Case("pwr9", true) + .Case("ppc64", true) + .Case("ppc64le", true) + .Default(false); + + Features["power9-vector"] = (CPU == "pwr9"); + Features["crypto"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr9", true) + .Case("pwr8", true) + .Default(false); + Features["power8-vector"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr9", true) + .Case("pwr8", true) + .Default(false); + Features["bpermd"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr9", true) + .Case("pwr8", true) + .Case("pwr7", true) + .Default(false); + Features["extdiv"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr9", true) + .Case("pwr8", true) + .Case("pwr7", true) + .Default(false); + Features["direct-move"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr9", true) + .Case("pwr8", true) + .Default(false); + Features["vsx"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr9", true) + .Case("pwr8", true) + .Case("pwr7", true) + .Default(false); + Features["htm"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr9", true) + .Case("pwr8", true) + .Default(false); + + // ROP Protect is off by default. + Features["rop-protect"] = false; + // Privileged instructions are off by default. + Features["privileged"] = false; + + Features["spe"] = llvm::StringSwitch<bool>(CPU) + .Case("8548", true) + .Case("e500", true) + .Default(false); + + Features["isa-v206-instructions"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr9", true) + .Case("pwr8", true) + .Case("pwr7", true) + .Default(false); + + Features["isa-v207-instructions"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr9", true) + .Case("pwr8", true) + .Default(false); + + Features["isa-v30-instructions"] = + llvm::StringSwitch<bool>(CPU).Case("pwr9", true).Default(false); + + // Power10 includes all the same features as Power9 plus any features specific + // to the Power10 core. + if (CPU == "pwr10" || CPU == "power10") { + initFeatureMap(Features, Diags, "pwr9", FeaturesVec); + addP10SpecificFeatures(Features); + } + + // Future CPU should include all of the features of Power 10 as well as any + // additional features (yet to be determined) specific to it. + if (CPU == "future") { + initFeatureMap(Features, Diags, "pwr10", FeaturesVec); + addFutureSpecificFeatures(Features); + } + + if (!ppcUserFeaturesCheck(Diags, FeaturesVec)) + return false; + + if (!(ArchDefs & ArchDefinePwr7) && (ArchDefs & ArchDefinePpcgr) && + llvm::is_contained(FeaturesVec, "+float128")) { + // We have __float128 on PPC but not pre-VSX targets. + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfloat128" << CPU; + return false; + } + + if (!(ArchDefs & ArchDefinePwr10)) { + if (llvm::find(FeaturesVec, "+mma") != FeaturesVec.end()) { + // MMA operations are not available pre-Power10. + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mmma" << CPU; + return false; + } + if (llvm::find(FeaturesVec, "+pcrel") != FeaturesVec.end()) { + // PC-Relative instructions are not available pre-Power10, + // and these instructions also require prefixed instructions support. + Diags.Report(diag::err_opt_not_valid_without_opt) + << "-mpcrel" + << "-mcpu=pwr10 -mprefixed"; + return false; + } + if (llvm::find(FeaturesVec, "+prefixed") != FeaturesVec.end()) { + // Prefixed instructions are not available pre-Power10. + Diags.Report(diag::err_opt_not_valid_without_opt) << "-mprefixed" + << "-mcpu=pwr10"; + return false; + } + if (llvm::find(FeaturesVec, "+paired-vector-memops") != FeaturesVec.end()) { + // Paired vector memops are not available pre-Power10. + Diags.Report(diag::err_opt_not_valid_without_opt) + << "-mpaired-vector-memops" + << "-mcpu=pwr10"; + return false; + } + } + + if (!(ArchDefs & ArchDefinePwr8) && + llvm::is_contained(FeaturesVec, "+rop-protect")) { + // We can turn on ROP Protect on Power 8 and above. + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mrop-protect" << CPU; + return false; + } + + if (!(ArchDefs & ArchDefinePwr8) && + llvm::is_contained(FeaturesVec, "+privileged")) { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mprivileged" << CPU; + return false; + } + + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); +} + +// Add any Power10 specific features. +void PPCTargetInfo::addP10SpecificFeatures( + llvm::StringMap<bool> &Features) const { + Features["htm"] = false; // HTM was removed for P10. + Features["paired-vector-memops"] = true; + Features["mma"] = true; + Features["power10-vector"] = true; + Features["pcrelative-memops"] = true; + Features["prefix-instrs"] = true; + Features["isa-v31-instructions"] = true; +} + +// Add features specific to the "Future" CPU. +void PPCTargetInfo::addFutureSpecificFeatures( + llvm::StringMap<bool> &Features) const {} + +bool PPCTargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature) + .Case("powerpc", true) + .Case("altivec", HasAltivec) + .Case("vsx", HasVSX) + .Case("power8-vector", HasP8Vector) + .Case("crypto", HasP8Crypto) + .Case("direct-move", HasDirectMove) + .Case("htm", HasHTM) + .Case("bpermd", HasBPERMD) + .Case("extdiv", HasExtDiv) + .Case("float128", HasFloat128) + .Case("power9-vector", HasP9Vector) + .Case("paired-vector-memops", PairedVectorMemops) + .Case("power10-vector", HasP10Vector) + .Case("pcrelative-memops", HasPCRelativeMemops) + .Case("prefix-instrs", HasPrefixInstrs) + .Case("spe", HasSPE) + .Case("mma", HasMMA) + .Case("rop-protect", HasROPProtect) + .Case("privileged", HasPrivileged) + .Case("isa-v206-instructions", IsISA2_06) + .Case("isa-v207-instructions", IsISA2_07) + .Case("isa-v30-instructions", IsISA3_0) + .Case("isa-v31-instructions", IsISA3_1) + .Default(false); +} + +void PPCTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, + StringRef Name, bool Enabled) const { + if (Enabled) { + if (Name == "efpu2") + Features["spe"] = true; + // If we're enabling any of the vsx based features then enable vsx and + // altivec. We'll diagnose any problems later. + bool FeatureHasVSX = llvm::StringSwitch<bool>(Name) + .Case("vsx", true) + .Case("direct-move", true) + .Case("power8-vector", true) + .Case("power9-vector", true) + .Case("paired-vector-memops", true) + .Case("power10-vector", true) + .Case("float128", true) + .Case("mma", true) + .Default(false); + if (FeatureHasVSX) + Features["vsx"] = Features["altivec"] = true; + if (Name == "power9-vector") + Features["power8-vector"] = true; + else if (Name == "power10-vector") + Features["power8-vector"] = Features["power9-vector"] = true; + if (Name == "pcrel") + Features["pcrelative-memops"] = true; + else if (Name == "prefixed") + Features["prefix-instrs"] = true; + else + Features[Name] = true; + } else { + if (Name == "spe") + Features["efpu2"] = false; + // If we're disabling altivec or vsx go ahead and disable all of the vsx + // features. + if ((Name == "altivec") || (Name == "vsx")) + Features["vsx"] = Features["direct-move"] = Features["power8-vector"] = + Features["float128"] = Features["power9-vector"] = + Features["paired-vector-memops"] = Features["mma"] = + Features["power10-vector"] = false; + if (Name == "power8-vector") + Features["power9-vector"] = Features["paired-vector-memops"] = + Features["mma"] = Features["power10-vector"] = false; + else if (Name == "power9-vector") + Features["paired-vector-memops"] = Features["mma"] = + Features["power10-vector"] = false; + if (Name == "pcrel") + Features["pcrelative-memops"] = false; + else if (Name == "prefixed") + Features["prefix-instrs"] = false; + else + Features[Name] = false; + } +} + +const char *const PPCTargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", + "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", + "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", + "r27", "r28", "r29", "r30", "r31", "f0", "f1", "f2", "f3", + "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", + "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", + "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", + "f31", "mq", "lr", "ctr", "ap", "cr0", "cr1", "cr2", "cr3", + "cr4", "cr5", "cr6", "cr7", "xer", "v0", "v1", "v2", "v3", + "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", + "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", + "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", + "v31", "vrsave", "vscr", "spe_acc", "spefscr", "sfp" +}; + +ArrayRef<const char *> PPCTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +const TargetInfo::GCCRegAlias PPCTargetInfo::GCCRegAliases[] = { + // While some of these aliases do map to different registers + // they still share the same register name. + {{"0"}, "r0"}, {{"1", "sp"}, "r1"}, {{"2"}, "r2"}, + {{"3"}, "r3"}, {{"4"}, "r4"}, {{"5"}, "r5"}, + {{"6"}, "r6"}, {{"7"}, "r7"}, {{"8"}, "r8"}, + {{"9"}, "r9"}, {{"10"}, "r10"}, {{"11"}, "r11"}, + {{"12"}, "r12"}, {{"13"}, "r13"}, {{"14"}, "r14"}, + {{"15"}, "r15"}, {{"16"}, "r16"}, {{"17"}, "r17"}, + {{"18"}, "r18"}, {{"19"}, "r19"}, {{"20"}, "r20"}, + {{"21"}, "r21"}, {{"22"}, "r22"}, {{"23"}, "r23"}, + {{"24"}, "r24"}, {{"25"}, "r25"}, {{"26"}, "r26"}, + {{"27"}, "r27"}, {{"28"}, "r28"}, {{"29"}, "r29"}, + {{"30"}, "r30"}, {{"31"}, "r31"}, {{"fr0"}, "f0"}, + {{"fr1"}, "f1"}, {{"fr2"}, "f2"}, {{"fr3"}, "f3"}, + {{"fr4"}, "f4"}, {{"fr5"}, "f5"}, {{"fr6"}, "f6"}, + {{"fr7"}, "f7"}, {{"fr8"}, "f8"}, {{"fr9"}, "f9"}, + {{"fr10"}, "f10"}, {{"fr11"}, "f11"}, {{"fr12"}, "f12"}, + {{"fr13"}, "f13"}, {{"fr14"}, "f14"}, {{"fr15"}, "f15"}, + {{"fr16"}, "f16"}, {{"fr17"}, "f17"}, {{"fr18"}, "f18"}, + {{"fr19"}, "f19"}, {{"fr20"}, "f20"}, {{"fr21"}, "f21"}, + {{"fr22"}, "f22"}, {{"fr23"}, "f23"}, {{"fr24"}, "f24"}, + {{"fr25"}, "f25"}, {{"fr26"}, "f26"}, {{"fr27"}, "f27"}, + {{"fr28"}, "f28"}, {{"fr29"}, "f29"}, {{"fr30"}, "f30"}, + {{"fr31"}, "f31"}, {{"cc"}, "cr0"}, +}; + +ArrayRef<TargetInfo::GCCRegAlias> PPCTargetInfo::getGCCRegAliases() const { + return llvm::makeArrayRef(GCCRegAliases); +} + +// PPC ELFABIv2 DWARF Definitoin "Table 2.26. Mappings of Common Registers". +// vs0 ~ vs31 is mapping to 32 - 63, +// vs32 ~ vs63 is mapping to 77 - 108. +const TargetInfo::AddlRegName GCCAddlRegNames[] = { + // Table of additional register names to use in user input. + {{"vs0"}, 32}, {{"vs1"}, 33}, {{"vs2"}, 34}, {{"vs3"}, 35}, + {{"vs4"}, 36}, {{"vs5"}, 37}, {{"vs6"}, 38}, {{"vs7"}, 39}, + {{"vs8"}, 40}, {{"vs9"}, 41}, {{"vs10"}, 42}, {{"vs11"}, 43}, + {{"vs12"}, 44}, {{"vs13"}, 45}, {{"vs14"}, 46}, {{"vs15"}, 47}, + {{"vs16"}, 48}, {{"vs17"}, 49}, {{"vs18"}, 50}, {{"vs19"}, 51}, + {{"vs20"}, 52}, {{"vs21"}, 53}, {{"vs22"}, 54}, {{"vs23"}, 55}, + {{"vs24"}, 56}, {{"vs25"}, 57}, {{"vs26"}, 58}, {{"vs27"}, 59}, + {{"vs28"}, 60}, {{"vs29"}, 61}, {{"vs30"}, 62}, {{"vs31"}, 63}, + {{"vs32"}, 77}, {{"vs33"}, 78}, {{"vs34"}, 79}, {{"vs35"}, 80}, + {{"vs36"}, 81}, {{"vs37"}, 82}, {{"vs38"}, 83}, {{"vs39"}, 84}, + {{"vs40"}, 85}, {{"vs41"}, 86}, {{"vs42"}, 87}, {{"vs43"}, 88}, + {{"vs44"}, 89}, {{"vs45"}, 90}, {{"vs46"}, 91}, {{"vs47"}, 92}, + {{"vs48"}, 93}, {{"vs49"}, 94}, {{"vs50"}, 95}, {{"vs51"}, 96}, + {{"vs52"}, 97}, {{"vs53"}, 98}, {{"vs54"}, 99}, {{"vs55"}, 100}, + {{"vs56"}, 101}, {{"vs57"}, 102}, {{"vs58"}, 103}, {{"vs59"}, 104}, + {{"vs60"}, 105}, {{"vs61"}, 106}, {{"vs62"}, 107}, {{"vs63"}, 108}, +}; + +ArrayRef<TargetInfo::AddlRegName> PPCTargetInfo::getGCCAddlRegNames() const { + if (ABI == "elfv2") + return llvm::makeArrayRef(GCCAddlRegNames); + else + return TargetInfo::getGCCAddlRegNames(); +} + +static constexpr llvm::StringLiteral ValidCPUNames[] = { + {"generic"}, {"440"}, {"450"}, {"601"}, {"602"}, + {"603"}, {"603e"}, {"603ev"}, {"604"}, {"604e"}, + {"620"}, {"630"}, {"g3"}, {"7400"}, {"g4"}, + {"7450"}, {"g4+"}, {"750"}, {"8548"}, {"970"}, + {"g5"}, {"a2"}, {"e500"}, {"e500mc"}, {"e5500"}, + {"power3"}, {"pwr3"}, {"power4"}, {"pwr4"}, {"power5"}, + {"pwr5"}, {"power5x"}, {"pwr5x"}, {"power6"}, {"pwr6"}, + {"power6x"}, {"pwr6x"}, {"power7"}, {"pwr7"}, {"power8"}, + {"pwr8"}, {"power9"}, {"pwr9"}, {"power10"}, {"pwr10"}, + {"powerpc"}, {"ppc"}, {"ppc32"}, {"powerpc64"}, {"ppc64"}, + {"powerpc64le"}, {"ppc64le"}, {"future"}}; + +bool PPCTargetInfo::isValidCPUName(StringRef Name) const { + return llvm::is_contained(ValidCPUNames, Name); +} + +void PPCTargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const { + Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames)); +} + +void PPCTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) { + if (HasAltivec) + Opts.AltiVec = 1; + TargetInfo::adjust(Diags, Opts); + if (LongDoubleFormat != &llvm::APFloat::IEEEdouble()) + LongDoubleFormat = Opts.PPCIEEELongDouble + ? &llvm::APFloat::IEEEquad() + : &llvm::APFloat::PPCDoubleDouble(); + Opts.IEEE128 = 1; +} + +ArrayRef<Builtin::Info> PPCTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::PPC::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/PPC.h b/contrib/llvm-project/clang/lib/Basic/Targets/PPC.h new file mode 100644 index 000000000000..ac52eb219f54 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/PPC.h @@ -0,0 +1,515 @@ +//===--- PPC.h - Declare PPC target feature support -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares PPC TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_PPC_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_PPC_H + +#include "OSTargets.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +// PPC abstract base class +class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo { + + /// Flags for architecture specific defines. + typedef enum { + ArchDefineNone = 0, + ArchDefineName = 1 << 0, // <name> is substituted for arch name. + ArchDefinePpcgr = 1 << 1, + ArchDefinePpcsq = 1 << 2, + ArchDefine440 = 1 << 3, + ArchDefine603 = 1 << 4, + ArchDefine604 = 1 << 5, + ArchDefinePwr4 = 1 << 6, + ArchDefinePwr5 = 1 << 7, + ArchDefinePwr5x = 1 << 8, + ArchDefinePwr6 = 1 << 9, + ArchDefinePwr6x = 1 << 10, + ArchDefinePwr7 = 1 << 11, + ArchDefinePwr8 = 1 << 12, + ArchDefinePwr9 = 1 << 13, + ArchDefinePwr10 = 1 << 14, + ArchDefineFuture = 1 << 15, + ArchDefineA2 = 1 << 16, + ArchDefineE500 = 1 << 18 + } ArchDefineTypes; + + ArchDefineTypes ArchDefs = ArchDefineNone; + static const Builtin::Info BuiltinInfo[]; + static const char *const GCCRegNames[]; + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + std::string CPU; + enum PPCFloatABI { HardFloat, SoftFloat } FloatABI; + + // Target cpu features. + bool HasAltivec = false; + bool HasMMA = false; + bool HasROPProtect = false; + bool HasPrivileged = false; + bool HasVSX = false; + bool HasP8Vector = false; + bool HasP8Crypto = false; + bool HasDirectMove = false; + bool HasHTM = false; + bool HasBPERMD = false; + bool HasExtDiv = false; + bool HasP9Vector = false; + bool HasSPE = false; + bool PairedVectorMemops = false; + bool HasP10Vector = false; + bool HasPCRelativeMemops = false; + bool HasPrefixInstrs = false; + bool IsISA2_06 = false; + bool IsISA2_07 = false; + bool IsISA3_0 = false; + bool IsISA3_1 = false; + +protected: + std::string ABI; + +public: + PPCTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + SuitableAlign = 128; + SimdDefaultAlign = 128; + LongDoubleWidth = LongDoubleAlign = 128; + LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble(); + HasStrictFP = true; + HasIbm128 = true; + } + + // Set the language option for altivec based on our value. + void adjust(DiagnosticsEngine &Diags, LangOptions &Opts) override; + + // Note: GCC recognizes the following additional cpus: + // 401, 403, 405, 405fp, 440fp, 464, 464fp, 476, 476fp, 505, 740, 801, + // 821, 823, 8540, e300c2, e300c3, e500mc64, e6500, 860, cell, titan, rs64. + bool isValidCPUName(StringRef Name) const override; + void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; + + bool setCPU(const std::string &Name) override { + bool CPUKnown = isValidCPUName(Name); + if (CPUKnown) { + CPU = Name; + + // CPU identification. + ArchDefs = + (ArchDefineTypes)llvm::StringSwitch<int>(CPU) + .Case("440", ArchDefineName) + .Case("450", ArchDefineName | ArchDefine440) + .Case("601", ArchDefineName) + .Case("602", ArchDefineName | ArchDefinePpcgr) + .Case("603", ArchDefineName | ArchDefinePpcgr) + .Case("603e", ArchDefineName | ArchDefine603 | ArchDefinePpcgr) + .Case("603ev", ArchDefineName | ArchDefine603 | ArchDefinePpcgr) + .Case("604", ArchDefineName | ArchDefinePpcgr) + .Case("604e", ArchDefineName | ArchDefine604 | ArchDefinePpcgr) + .Case("620", ArchDefineName | ArchDefinePpcgr) + .Case("630", ArchDefineName | ArchDefinePpcgr) + .Case("7400", ArchDefineName | ArchDefinePpcgr) + .Case("7450", ArchDefineName | ArchDefinePpcgr) + .Case("750", ArchDefineName | ArchDefinePpcgr) + .Case("970", ArchDefineName | ArchDefinePwr4 | ArchDefinePpcgr | + ArchDefinePpcsq) + .Case("a2", ArchDefineA2) + .Cases("power3", "pwr3", ArchDefinePpcgr) + .Cases("power4", "pwr4", + ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) + .Cases("power5", "pwr5", + ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | + ArchDefinePpcsq) + .Cases("power5x", "pwr5x", + ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | + ArchDefinePpcgr | ArchDefinePpcsq) + .Cases("power6", "pwr6", + ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | + ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) + .Cases("power6x", "pwr6x", + ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x | + ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | + ArchDefinePpcsq) + .Cases("power7", "pwr7", + ArchDefinePwr7 | ArchDefinePwr6 | ArchDefinePwr5x | + ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | + ArchDefinePpcsq) + // powerpc64le automatically defaults to at least power8. + .Cases("power8", "pwr8", "ppc64le", + ArchDefinePwr8 | ArchDefinePwr7 | ArchDefinePwr6 | + ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | + ArchDefinePpcgr | ArchDefinePpcsq) + .Cases("power9", "pwr9", + ArchDefinePwr9 | ArchDefinePwr8 | ArchDefinePwr7 | + ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | + ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) + .Cases("power10", "pwr10", + ArchDefinePwr10 | ArchDefinePwr9 | ArchDefinePwr8 | + ArchDefinePwr7 | ArchDefinePwr6 | ArchDefinePwr5x | + ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | + ArchDefinePpcsq) + .Case("future", + ArchDefineFuture | ArchDefinePwr10 | ArchDefinePwr9 | + ArchDefinePwr8 | ArchDefinePwr7 | ArchDefinePwr6 | + ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | + ArchDefinePpcgr | ArchDefinePpcsq) + .Cases("8548", "e500", ArchDefineE500) + .Default(ArchDefineNone); + } + return CPUKnown; + } + + StringRef getABI() const override { return ABI; } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + bool isCLZForZeroUndef() const override { return false; } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override; + + void addP10SpecificFeatures(llvm::StringMap<bool> &Features) const; + void addFutureSpecificFeatures(llvm::StringMap<bool> &Features) const; + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override; + + bool hasFeature(StringRef Feature) const override; + + void setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name, + bool Enabled) const override; + + ArrayRef<const char *> getGCCRegNames() const override; + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; + + ArrayRef<TargetInfo::AddlRegName> getGCCAddlRegNames() const override; + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + switch (*Name) { + default: + return false; + case 'O': // Zero + break; + case 'f': // Floating point register + // Don't use floating point registers on soft float ABI. + if (FloatABI == SoftFloat) + return false; + LLVM_FALLTHROUGH; + case 'b': // Base register + Info.setAllowsRegister(); + break; + // FIXME: The following are added to allow parsing. + // I just took a guess at what the actions should be. + // Also, is more specific checking needed? I.e. specific registers? + case 'd': // Floating point register (containing 64-bit value) + case 'v': // Altivec vector register + // Don't use floating point and altivec vector registers + // on soft float ABI + if (FloatABI == SoftFloat) + return false; + Info.setAllowsRegister(); + break; + case 'w': + switch (Name[1]) { + case 'd': // VSX vector register to hold vector double data + case 'f': // VSX vector register to hold vector float data + case 's': // VSX vector register to hold scalar double data + case 'w': // VSX vector register to hold scalar double data + case 'a': // Any VSX register + case 'c': // An individual CR bit + case 'i': // FP or VSX register to hold 64-bit integers data + break; + default: + return false; + } + Info.setAllowsRegister(); + Name++; // Skip over 'w'. + break; + case 'h': // `MQ', `CTR', or `LINK' register + case 'q': // `MQ' register + case 'c': // `CTR' register + case 'l': // `LINK' register + case 'x': // `CR' register (condition register) number 0 + case 'y': // `CR' register (condition register) + case 'z': // `XER[CA]' carry bit (part of the XER register) + Info.setAllowsRegister(); + break; + case 'I': // Signed 16-bit constant + case 'J': // Unsigned 16-bit constant shifted left 16 bits + // (use `L' instead for SImode constants) + case 'K': // Unsigned 16-bit constant + case 'L': // Signed 16-bit constant shifted left 16 bits + case 'M': // Constant larger than 31 + case 'N': // Exact power of 2 + case 'P': // Constant whose negation is a signed 16-bit constant + case 'G': // Floating point constant that can be loaded into a + // register with one instruction per word + case 'H': // Integer/Floating point constant that can be loaded + // into a register using three instructions + break; + case 'm': // Memory operand. Note that on PowerPC targets, m can + // include addresses that update the base register. It + // is therefore only safe to use `m' in an asm statement + // if that asm statement accesses the operand exactly once. + // The asm statement must also use `%U<opno>' as a + // placeholder for the "update" flag in the corresponding + // load or store instruction. For example: + // asm ("st%U0 %1,%0" : "=m" (mem) : "r" (val)); + // is correct but: + // asm ("st %1,%0" : "=m" (mem) : "r" (val)); + // is not. Use es rather than m if you don't want the base + // register to be updated. + case 'e': + if (Name[1] != 's') + return false; + // es: A "stable" memory operand; that is, one which does not + // include any automodification of the base register. Unlike + // `m', this constraint can be used in asm statements that + // might access the operand several times, or that might not + // access it at all. + Info.setAllowsMemory(); + Name++; // Skip over 'e'. + break; + case 'Q': // Memory operand that is an offset from a register (it is + // usually better to use `m' or `es' in asm statements) + Info.setAllowsRegister(); + LLVM_FALLTHROUGH; + case 'Z': // Memory operand that is an indexed or indirect from a + // register (it is usually better to use `m' or `es' in + // asm statements) + Info.setAllowsMemory(); + break; + case 'R': // AIX TOC entry + case 'a': // Address operand that is an indexed or indirect from a + // register (`p' is preferable for asm statements) + case 'S': // Constant suitable as a 64-bit mask operand + case 'T': // Constant suitable as a 32-bit mask operand + case 'U': // System V Release 4 small data area reference + case 't': // AND masks that can be performed by two rldic{l, r} + // instructions + case 'W': // Vector constant that does not require memory + case 'j': // Vector constant that is all zeros. + break; + // End FIXME. + } + return true; + } + + std::string convertConstraint(const char *&Constraint) const override { + std::string R; + switch (*Constraint) { + case 'e': + case 'w': + // Two-character constraint; add "^" hint for later parsing. + R = std::string("^") + std::string(Constraint, 2); + Constraint++; + break; + default: + return TargetInfo::convertConstraint(Constraint); + } + return R; + } + + const char *getClobbers() const override { return ""; } + int getEHDataRegisterNumber(unsigned RegNo) const override { + if (RegNo == 0) + return 3; + if (RegNo == 1) + return 4; + return -1; + } + + bool hasSjLjLowering() const override { return true; } + + const char *getLongDoubleMangling() const override { + if (LongDoubleWidth == 64) + return "e"; + return LongDoubleFormat == &llvm::APFloat::PPCDoubleDouble() + ? "g" + : "u9__ieee128"; + } + const char *getFloat128Mangling() const override { return "u9__ieee128"; } + const char *getIbm128Mangling() const override { return "g"; } + + bool hasBitIntType() const override { return true; } + + bool isSPRegName(StringRef RegName) const override { + return RegName.equals("r1") || RegName.equals("x1"); + } +}; + +class LLVM_LIBRARY_VISIBILITY PPC32TargetInfo : public PPCTargetInfo { +public: + PPC32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : PPCTargetInfo(Triple, Opts) { + if (Triple.isOSAIX()) + resetDataLayout("E-m:a-p:32:32-i64:64-n32"); + else if (Triple.getArch() == llvm::Triple::ppcle) + resetDataLayout("e-m:e-p:32:32-i64:64-n32"); + else + resetDataLayout("E-m:e-p:32:32-i64:64-n32"); + + switch (getTriple().getOS()) { + case llvm::Triple::Linux: + case llvm::Triple::FreeBSD: + case llvm::Triple::NetBSD: + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + break; + case llvm::Triple::AIX: + SizeType = UnsignedLong; + PtrDiffType = SignedLong; + IntPtrType = SignedLong; + LongDoubleWidth = 64; + LongDoubleAlign = DoubleAlign = 32; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + break; + default: + break; + } + + if (Triple.isOSFreeBSD() || Triple.isOSNetBSD() || Triple.isOSOpenBSD() || + Triple.isMusl()) { + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + } + + // PPC32 supports atomics up to 4 bytes. + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + // This is the ELF definition, and is overridden by the Darwin sub-target + return TargetInfo::PowerABIBuiltinVaList; + } +}; + +// Note: ABI differences may eventually require us to have a separate +// TargetInfo for little endian. +class LLVM_LIBRARY_VISIBILITY PPC64TargetInfo : public PPCTargetInfo { +public: + PPC64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : PPCTargetInfo(Triple, Opts) { + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + IntMaxType = SignedLong; + Int64Type = SignedLong; + std::string DataLayout; + + if (Triple.isOSAIX()) { + // TODO: Set appropriate ABI for AIX platform. + DataLayout = "E-m:a-i64:64-n32:64"; + LongDoubleWidth = 64; + LongDoubleAlign = DoubleAlign = 32; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + } else if ((Triple.getArch() == llvm::Triple::ppc64le)) { + DataLayout = "e-m:e-i64:64-n32:64"; + ABI = "elfv2"; + } else { + DataLayout = "E-m:e-i64:64-n32:64"; + ABI = "elfv1"; + } + + if (Triple.isOSFreeBSD() || Triple.isOSOpenBSD() || Triple.isMusl()) { + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + } + + if (Triple.isOSAIX() || Triple.isOSLinux()) + DataLayout += "-S128-v256:256:256-v512:512:512"; + resetDataLayout(DataLayout); + + // PPC64 supports atomics up to 8 bytes. + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::CharPtrBuiltinVaList; + } + + // PPC64 Linux-specific ABI options. + bool setABI(const std::string &Name) override { + if (Name == "elfv1" || Name == "elfv2") { + ABI = Name; + return true; + } + return false; + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + switch (CC) { + case CC_Swift: + return CCCR_OK; + case CC_SwiftAsync: + return CCCR_Error; + default: + return CCCR_Warning; + } + } +}; + +class LLVM_LIBRARY_VISIBILITY DarwinPPC32TargetInfo + : public DarwinTargetInfo<PPC32TargetInfo> { +public: + DarwinPPC32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : DarwinTargetInfo<PPC32TargetInfo>(Triple, Opts) { + HasAlignMac68kSupport = true; + BoolWidth = BoolAlign = 32; // XXX support -mone-byte-bool? + PtrDiffType = SignedInt; // for http://llvm.org/bugs/show_bug.cgi?id=15726 + LongLongAlign = 32; + resetDataLayout("E-m:o-p:32:32-f64:32:64-n32", "_"); + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::CharPtrBuiltinVaList; + } +}; + +class LLVM_LIBRARY_VISIBILITY DarwinPPC64TargetInfo + : public DarwinTargetInfo<PPC64TargetInfo> { +public: + DarwinPPC64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : DarwinTargetInfo<PPC64TargetInfo>(Triple, Opts) { + HasAlignMac68kSupport = true; + resetDataLayout("E-m:o-i64:64-n32:64", "_"); + } +}; + +class LLVM_LIBRARY_VISIBILITY AIXPPC32TargetInfo : + public AIXTargetInfo<PPC32TargetInfo> { +public: + using AIXTargetInfo::AIXTargetInfo; + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::CharPtrBuiltinVaList; + } +}; + +class LLVM_LIBRARY_VISIBILITY AIXPPC64TargetInfo : + public AIXTargetInfo<PPC64TargetInfo> { +public: + using AIXTargetInfo::AIXTargetInfo; +}; + +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_PPC_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.cpp new file mode 100644 index 000000000000..0680cad5b07c --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.cpp @@ -0,0 +1,320 @@ +//===--- RISCV.cpp - Implement RISCV target feature support ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements RISCV TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "RISCV.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/TargetParser.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; +using namespace clang::targets; + +ArrayRef<const char *> RISCVTargetInfo::getGCCRegNames() const { + static const char *const GCCRegNames[] = { + // Integer registers + "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", + "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", + "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", + "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31", + + // Floating point registers + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", + + // Vector registers + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", + "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", + "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", + "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"}; + return llvm::makeArrayRef(GCCRegNames); +} + +ArrayRef<TargetInfo::GCCRegAlias> RISCVTargetInfo::getGCCRegAliases() const { + static const TargetInfo::GCCRegAlias GCCRegAliases[] = { + {{"zero"}, "x0"}, {{"ra"}, "x1"}, {{"sp"}, "x2"}, {{"gp"}, "x3"}, + {{"tp"}, "x4"}, {{"t0"}, "x5"}, {{"t1"}, "x6"}, {{"t2"}, "x7"}, + {{"s0"}, "x8"}, {{"s1"}, "x9"}, {{"a0"}, "x10"}, {{"a1"}, "x11"}, + {{"a2"}, "x12"}, {{"a3"}, "x13"}, {{"a4"}, "x14"}, {{"a5"}, "x15"}, + {{"a6"}, "x16"}, {{"a7"}, "x17"}, {{"s2"}, "x18"}, {{"s3"}, "x19"}, + {{"s4"}, "x20"}, {{"s5"}, "x21"}, {{"s6"}, "x22"}, {{"s7"}, "x23"}, + {{"s8"}, "x24"}, {{"s9"}, "x25"}, {{"s10"}, "x26"}, {{"s11"}, "x27"}, + {{"t3"}, "x28"}, {{"t4"}, "x29"}, {{"t5"}, "x30"}, {{"t6"}, "x31"}, + {{"ft0"}, "f0"}, {{"ft1"}, "f1"}, {{"ft2"}, "f2"}, {{"ft3"}, "f3"}, + {{"ft4"}, "f4"}, {{"ft5"}, "f5"}, {{"ft6"}, "f6"}, {{"ft7"}, "f7"}, + {{"fs0"}, "f8"}, {{"fs1"}, "f9"}, {{"fa0"}, "f10"}, {{"fa1"}, "f11"}, + {{"fa2"}, "f12"}, {{"fa3"}, "f13"}, {{"fa4"}, "f14"}, {{"fa5"}, "f15"}, + {{"fa6"}, "f16"}, {{"fa7"}, "f17"}, {{"fs2"}, "f18"}, {{"fs3"}, "f19"}, + {{"fs4"}, "f20"}, {{"fs5"}, "f21"}, {{"fs6"}, "f22"}, {{"fs7"}, "f23"}, + {{"fs8"}, "f24"}, {{"fs9"}, "f25"}, {{"fs10"}, "f26"}, {{"fs11"}, "f27"}, + {{"ft8"}, "f28"}, {{"ft9"}, "f29"}, {{"ft10"}, "f30"}, {{"ft11"}, "f31"}}; + return llvm::makeArrayRef(GCCRegAliases); +} + +bool RISCVTargetInfo::validateAsmConstraint( + const char *&Name, TargetInfo::ConstraintInfo &Info) const { + switch (*Name) { + default: + return false; + case 'I': + // A 12-bit signed immediate. + Info.setRequiresImmediate(-2048, 2047); + return true; + case 'J': + // Integer zero. + Info.setRequiresImmediate(0); + return true; + case 'K': + // A 5-bit unsigned immediate for CSR access instructions. + Info.setRequiresImmediate(0, 31); + return true; + case 'f': + // A floating-point register. + Info.setAllowsRegister(); + return true; + case 'A': + // An address that is held in a general-purpose register. + Info.setAllowsMemory(); + return true; + case 'S': // A symbolic address + Info.setAllowsRegister(); + return true; + case 'v': + // A vector register. + if (Name[1] == 'r' || Name[1] == 'm') { + Info.setAllowsRegister(); + Name += 1; + return true; + } + return false; + } +} + +std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const { + std::string R; + switch (*Constraint) { + case 'v': + R = std::string("^") + std::string(Constraint, 2); + Constraint += 1; + break; + default: + R = TargetInfo::convertConstraint(Constraint); + break; + } + return R; +} + +void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__ELF__"); + Builder.defineMacro("__riscv"); + bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64; + Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32"); + StringRef CodeModel = getTargetOpts().CodeModel; + unsigned FLen = ISAInfo->getFLen(); + unsigned MinVLen = ISAInfo->getMinVLen(); + unsigned MaxELen = ISAInfo->getMaxELen(); + unsigned MaxELenFp = ISAInfo->getMaxELenFp(); + if (CodeModel == "default") + CodeModel = "small"; + + if (CodeModel == "small") + Builder.defineMacro("__riscv_cmodel_medlow"); + else if (CodeModel == "medium") + Builder.defineMacro("__riscv_cmodel_medany"); + + StringRef ABIName = getABI(); + if (ABIName == "ilp32f" || ABIName == "lp64f") + Builder.defineMacro("__riscv_float_abi_single"); + else if (ABIName == "ilp32d" || ABIName == "lp64d") + Builder.defineMacro("__riscv_float_abi_double"); + else + Builder.defineMacro("__riscv_float_abi_soft"); + + if (ABIName == "ilp32e") + Builder.defineMacro("__riscv_abi_rve"); + + Builder.defineMacro("__riscv_arch_test"); + + for (auto &Extension : ISAInfo->getExtensions()) { + auto ExtName = Extension.first; + auto ExtInfo = Extension.second; + unsigned Version = + (ExtInfo.MajorVersion * 1000000) + (ExtInfo.MinorVersion * 1000); + + Builder.defineMacro(Twine("__riscv_", ExtName), Twine(Version)); + } + + if (ISAInfo->hasExtension("m")) { + Builder.defineMacro("__riscv_mul"); + Builder.defineMacro("__riscv_div"); + Builder.defineMacro("__riscv_muldiv"); + } + + if (ISAInfo->hasExtension("a")) { + Builder.defineMacro("__riscv_atomic"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); + if (Is64Bit) + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); + } + + if (FLen) { + Builder.defineMacro("__riscv_flen", Twine(FLen)); + Builder.defineMacro("__riscv_fdiv"); + Builder.defineMacro("__riscv_fsqrt"); + } + + if (MinVLen) { + Builder.defineMacro("__riscv_v_min_vlen", Twine(MinVLen)); + Builder.defineMacro("__riscv_v_elen", Twine(MaxELen)); + Builder.defineMacro("__riscv_v_elen_fp", Twine(MaxELenFp)); + } + + if (ISAInfo->hasExtension("c")) + Builder.defineMacro("__riscv_compressed"); + + if (ISAInfo->hasExtension("zve32x") || ISAInfo->hasExtension("v")) + Builder.defineMacro("__riscv_vector"); +} + +const Builtin::Info RISCVTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, +#include "clang/Basic/BuiltinsRISCVVector.def" +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, +#include "clang/Basic/BuiltinsRISCV.def" +}; + +ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::RISCV::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} + +bool RISCVTargetInfo::initFeatureMap( + llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, + const std::vector<std::string> &FeaturesVec) const { + + unsigned XLen = 32; + + if (getTriple().getArch() == llvm::Triple::riscv64) { + Features["64bit"] = true; + XLen = 64; + } + + auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesVec); + if (!ParseResult) { + std::string Buffer; + llvm::raw_string_ostream OutputErrMsg(Buffer); + handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) { + OutputErrMsg << ErrMsg.getMessage(); + }); + Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str(); + return false; + } + + return TargetInfo::initFeatureMap(Features, Diags, CPU, + (*ParseResult)->toFeatureVector()); +} + +/// Return true if has this feature, need to sync with handleTargetFeatures. +bool RISCVTargetInfo::hasFeature(StringRef Feature) const { + bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64; + auto Result = llvm::StringSwitch<Optional<bool>>(Feature) + .Case("riscv", true) + .Case("riscv32", !Is64Bit) + .Case("riscv64", Is64Bit) + .Case("64bit", Is64Bit) + .Default(None); + if (Result.hasValue()) + return Result.getValue(); + + if (ISAInfo->isSupportedExtensionFeature(Feature)) + return ISAInfo->hasExtension(Feature); + + return false; +} + +/// Perform initialization based on the user configured set of features. +bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) { + unsigned XLen = getTriple().isArch64Bit() ? 64 : 32; + auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features); + if (!ParseResult) { + std::string Buffer; + llvm::raw_string_ostream OutputErrMsg(Buffer); + handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) { + OutputErrMsg << ErrMsg.getMessage(); + }); + Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str(); + return false; + } else { + ISAInfo = std::move(*ParseResult); + } + + if (ABI.empty()) + ABI = llvm::RISCV::computeDefaultABIFromArch(*ISAInfo).str(); + + return true; +} + +bool RISCV32TargetInfo::isValidCPUName(StringRef Name) const { + return llvm::RISCV::checkCPUKind(llvm::RISCV::parseCPUKind(Name), + /*Is64Bit=*/false); +} + +void RISCV32TargetInfo::fillValidCPUList( + SmallVectorImpl<StringRef> &Values) const { + llvm::RISCV::fillValidCPUArchList(Values, false); +} + +bool RISCV32TargetInfo::isValidTuneCPUName(StringRef Name) const { + return llvm::RISCV::checkTuneCPUKind( + llvm::RISCV::parseTuneCPUKind(Name, false), + /*Is64Bit=*/false); +} + +void RISCV32TargetInfo::fillValidTuneCPUList( + SmallVectorImpl<StringRef> &Values) const { + llvm::RISCV::fillValidTuneCPUArchList(Values, false); +} + +bool RISCV64TargetInfo::isValidCPUName(StringRef Name) const { + return llvm::RISCV::checkCPUKind(llvm::RISCV::parseCPUKind(Name), + /*Is64Bit=*/true); +} + +void RISCV64TargetInfo::fillValidCPUList( + SmallVectorImpl<StringRef> &Values) const { + llvm::RISCV::fillValidCPUArchList(Values, true); +} + +bool RISCV64TargetInfo::isValidTuneCPUName(StringRef Name) const { + return llvm::RISCV::checkTuneCPUKind( + llvm::RISCV::parseTuneCPUKind(Name, true), + /*Is64Bit=*/true); +} + +void RISCV64TargetInfo::fillValidTuneCPUList( + SmallVectorImpl<StringRef> &Values) const { + llvm::RISCV::fillValidTuneCPUArchList(Values, true); +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.h b/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.h new file mode 100644 index 000000000000..5331ed4a50ae --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.h @@ -0,0 +1,162 @@ +//===--- RISCV.h - Declare RISCV target feature support ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares RISCV TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_RISCV_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_RISCV_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/RISCVISAInfo.h" + +namespace clang { +namespace targets { + +// RISC-V Target +class RISCVTargetInfo : public TargetInfo { +protected: + std::string ABI, CPU; + std::unique_ptr<llvm::RISCVISAInfo> ISAInfo; + static const Builtin::Info BuiltinInfo[]; + +public: + RISCVTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + LongDoubleWidth = 128; + LongDoubleAlign = 128; + LongDoubleFormat = &llvm::APFloat::IEEEquad(); + SuitableAlign = 128; + WCharType = SignedInt; + WIntType = UnsignedInt; + HasRISCVVTypes = true; + MCountName = "_mcount"; + HasFloat16 = true; + } + + bool setCPU(const std::string &Name) override { + if (!isValidCPUName(Name)) + return false; + CPU = Name; + return true; + } + + StringRef getABI() const override { return ABI; } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + const char *getClobbers() const override { return ""; } + + StringRef getConstraintRegister(StringRef Constraint, + StringRef Expression) const override { + return Expression; + } + + ArrayRef<const char *> getGCCRegNames() const override; + + int getEHDataRegisterNumber(unsigned RegNo) const override { + if (RegNo == 0) + return 10; + else if (RegNo == 1) + return 11; + else + return -1; + } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override; + + std::string convertConstraint(const char *&Constraint) const override; + + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override; + + bool hasFeature(StringRef Feature) const override; + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override; + + bool hasBitIntType() const override { return true; } +}; +class LLVM_LIBRARY_VISIBILITY RISCV32TargetInfo : public RISCVTargetInfo { +public: + RISCV32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : RISCVTargetInfo(Triple, Opts) { + IntPtrType = SignedInt; + PtrDiffType = SignedInt; + SizeType = UnsignedInt; + resetDataLayout("e-m:e-p:32:32-i64:64-n32-S128"); + } + + bool setABI(const std::string &Name) override { + if (Name == "ilp32" || Name == "ilp32f" || Name == "ilp32d") { + ABI = Name; + return true; + } + return false; + } + + bool isValidCPUName(StringRef Name) const override; + void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; + bool isValidTuneCPUName(StringRef Name) const override; + void fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) const override; + + void setMaxAtomicWidth() override { + MaxAtomicPromoteWidth = 128; + + if (ISAInfo->hasExtension("a")) + MaxAtomicInlineWidth = 32; + } +}; +class LLVM_LIBRARY_VISIBILITY RISCV64TargetInfo : public RISCVTargetInfo { +public: + RISCV64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : RISCVTargetInfo(Triple, Opts) { + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + IntMaxType = Int64Type = SignedLong; + resetDataLayout("e-m:e-p:64:64-i64:64-i128:128-n64-S128"); + } + + bool setABI(const std::string &Name) override { + if (Name == "lp64" || Name == "lp64f" || Name == "lp64d") { + ABI = Name; + return true; + } + return false; + } + + bool isValidCPUName(StringRef Name) const override; + void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; + bool isValidTuneCPUName(StringRef Name) const override; + void fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) const override; + + void setMaxAtomicWidth() override { + MaxAtomicPromoteWidth = 128; + + if (ISAInfo->hasExtension("a")) + MaxAtomicInlineWidth = 64; + } +}; +} // namespace targets +} // namespace clang + +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_RISCV_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/SPIR.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/SPIR.cpp new file mode 100644 index 000000000000..09d482a8b9ef --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/SPIR.cpp @@ -0,0 +1,51 @@ +//===--- SPIR.cpp - Implement SPIR and SPIR-V target feature support ------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements SPIR and SPIR-V TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "SPIR.h" +#include "Targets.h" + +using namespace clang; +using namespace clang::targets; + +void SPIRTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "SPIR", Opts); +} + +void SPIR32TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + SPIRTargetInfo::getTargetDefines(Opts, Builder); + DefineStd(Builder, "SPIR32", Opts); +} + +void SPIR64TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + SPIRTargetInfo::getTargetDefines(Opts, Builder); + DefineStd(Builder, "SPIR64", Opts); +} + +void SPIRVTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "SPIRV", Opts); +} + +void SPIRV32TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + SPIRVTargetInfo::getTargetDefines(Opts, Builder); + DefineStd(Builder, "SPIRV32", Opts); +} + +void SPIRV64TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + SPIRVTargetInfo::getTargetDefines(Opts, Builder); + DefineStd(Builder, "SPIRV64", Opts); +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/SPIR.h b/contrib/llvm-project/clang/lib/Basic/Targets/SPIR.h new file mode 100644 index 000000000000..a40d4b3ca27e --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/SPIR.h @@ -0,0 +1,278 @@ +//===--- SPIR.h - Declare SPIR and SPIR-V target feature support *- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares SPIR and SPIR-V TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +// Used by both the SPIR and SPIR-V targets. +static const unsigned SPIRDefIsPrivMap[] = { + 0, // Default + 1, // opencl_global + 3, // opencl_local + 2, // opencl_constant + 0, // opencl_private + 4, // opencl_generic + 5, // opencl_global_device + 6, // opencl_global_host + 0, // cuda_device + 0, // cuda_constant + 0, // cuda_shared + // SYCL address space values for this map are dummy + 0, // sycl_global + 0, // sycl_global_device + 0, // sycl_global_host + 0, // sycl_local + 0, // sycl_private + 0, // ptr32_sptr + 0, // ptr32_uptr + 0 // ptr64 +}; + +// Used by both the SPIR and SPIR-V targets. +static const unsigned SPIRDefIsGenMap[] = { + 4, // Default + // OpenCL address space values for this map are dummy and they can't be used + 0, // opencl_global + 0, // opencl_local + 0, // opencl_constant + 0, // opencl_private + 0, // opencl_generic + 0, // opencl_global_device + 0, // opencl_global_host + // cuda_* address space mapping is intended for HIPSPV (HIP to SPIR-V + // translation). This mapping is enabled when the language mode is HIP. + 1, // cuda_device + // cuda_constant pointer can be casted to default/"flat" pointer, but in + // SPIR-V casts between constant and generic pointers are not allowed. For + // this reason cuda_constant is mapped to SPIR-V CrossWorkgroup. + 1, // cuda_constant + 3, // cuda_shared + 1, // sycl_global + 5, // sycl_global_device + 6, // sycl_global_host + 3, // sycl_local + 0, // sycl_private + 0, // ptr32_sptr + 0, // ptr32_uptr + 0 // ptr64 +}; + +// Base class for SPIR and SPIR-V target info. +class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo { +protected: + BaseSPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + assert((Triple.isSPIR() || Triple.isSPIRV()) && + "Invalid architecture for SPIR or SPIR-V."); + assert(getTriple().getOS() == llvm::Triple::UnknownOS && + "SPIR(-V) target must use unknown OS"); + assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && + "SPIR(-V) target must use unknown environment type"); + TLSSupported = false; + VLASupported = false; + LongWidth = LongAlign = 64; + AddrSpaceMap = &SPIRDefIsPrivMap; + UseAddrSpaceMapMangling = true; + HasLegalHalfType = true; + HasFloat16 = true; + // Define available target features + // These must be defined in sorted order! + NoAsmVariants = true; + } + +public: + // SPIR supports the half type and the only llvm intrinsic allowed in SPIR is + // memcpy as per section 3 of the SPIR spec. + bool useFP16ConversionIntrinsics() const override { return false; } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } + + const char *getClobbers() const override { return ""; } + + ArrayRef<const char *> getGCCRegNames() const override { return None; } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override { + return true; + } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + Optional<unsigned> + getDWARFAddressSpace(unsigned AddressSpace) const override { + return AddressSpace; + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + return (CC == CC_SpirFunction || CC == CC_OpenCLKernel) ? CCCR_OK + : CCCR_Warning; + } + + CallingConv getDefaultCallingConv() const override { + return CC_SpirFunction; + } + + void setAddressSpaceMap(bool DefaultIsGeneric) { + AddrSpaceMap = DefaultIsGeneric ? &SPIRDefIsGenMap : &SPIRDefIsPrivMap; + } + + void adjust(DiagnosticsEngine &Diags, LangOptions &Opts) override { + TargetInfo::adjust(Diags, Opts); + // FIXME: SYCL specification considers unannotated pointers and references + // to be pointing to the generic address space. See section 5.9.3 of + // SYCL 2020 specification. + // Currently, there is no way of representing SYCL's and HIP's default + // address space language semantic along with the semantics of embedded C's + // default address space in the same address space map. Hence the map needs + // to be reset to allow mapping to the desired value of 'Default' entry for + // SYCL and HIP. + setAddressSpaceMap( + /*DefaultIsGeneric=*/Opts.SYCLIsDevice || + // The address mapping from HIP language for device code is only defined + // for SPIR-V. + (getTriple().isSPIRV() && Opts.HIP && Opts.CUDAIsDevice)); + } + + void setSupportedOpenCLOpts() override { + // Assume all OpenCL extensions and optional core features are supported + // for SPIR and SPIR-V since they are generic targets. + supportAllOpenCLOpts(); + } + + bool hasBitIntType() const override { return true; } + + bool hasInt128Type() const override { return false; } +}; + +class LLVM_LIBRARY_VISIBILITY SPIRTargetInfo : public BaseSPIRTargetInfo { +public: + SPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : BaseSPIRTargetInfo(Triple, Opts) { + assert(Triple.isSPIR() && "Invalid architecture for SPIR."); + assert(getTriple().getOS() == llvm::Triple::UnknownOS && + "SPIR target must use unknown OS"); + assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && + "SPIR target must use unknown environment type"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool hasFeature(StringRef Feature) const override { + return Feature == "spir"; + } +}; + +class LLVM_LIBRARY_VISIBILITY SPIR32TargetInfo : public SPIRTargetInfo { +public: + SPIR32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : SPIRTargetInfo(Triple, Opts) { + assert(Triple.getArch() == llvm::Triple::spir && + "Invalid architecture for 32-bit SPIR."); + PointerWidth = PointerAlign = 32; + SizeType = TargetInfo::UnsignedInt; + PtrDiffType = IntPtrType = TargetInfo::SignedInt; + resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-" + "v96:128-v192:256-v256:256-v512:512-v1024:1024"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +class LLVM_LIBRARY_VISIBILITY SPIR64TargetInfo : public SPIRTargetInfo { +public: + SPIR64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : SPIRTargetInfo(Triple, Opts) { + assert(Triple.getArch() == llvm::Triple::spir64 && + "Invalid architecture for 64-bit SPIR."); + PointerWidth = PointerAlign = 64; + SizeType = TargetInfo::UnsignedLong; + PtrDiffType = IntPtrType = TargetInfo::SignedLong; + resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-" + "v96:128-v192:256-v256:256-v512:512-v1024:1024"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +class LLVM_LIBRARY_VISIBILITY SPIRVTargetInfo : public BaseSPIRTargetInfo { +public: + SPIRVTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : BaseSPIRTargetInfo(Triple, Opts) { + assert(Triple.isSPIRV() && "Invalid architecture for SPIR-V."); + assert(getTriple().getOS() == llvm::Triple::UnknownOS && + "SPIR-V target must use unknown OS"); + assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && + "SPIR-V target must use unknown environment type"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool hasFeature(StringRef Feature) const override { + return Feature == "spirv"; + } +}; + +class LLVM_LIBRARY_VISIBILITY SPIRV32TargetInfo : public SPIRVTargetInfo { +public: + SPIRV32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : SPIRVTargetInfo(Triple, Opts) { + assert(Triple.getArch() == llvm::Triple::spirv32 && + "Invalid architecture for 32-bit SPIR-V."); + PointerWidth = PointerAlign = 32; + SizeType = TargetInfo::UnsignedInt; + PtrDiffType = IntPtrType = TargetInfo::SignedInt; + resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-" + "v96:128-v192:256-v256:256-v512:512-v1024:1024"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo : public SPIRVTargetInfo { +public: + SPIRV64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : SPIRVTargetInfo(Triple, Opts) { + assert(Triple.getArch() == llvm::Triple::spirv64 && + "Invalid architecture for 64-bit SPIR-V."); + PointerWidth = PointerAlign = 64; + SizeType = TargetInfo::UnsignedLong; + PtrDiffType = IntPtrType = TargetInfo::SignedLong; + resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-" + "v96:128-v192:256-v256:256-v512:512-v1024:1024"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/Sparc.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/Sparc.cpp new file mode 100644 index 000000000000..932102434801 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/Sparc.cpp @@ -0,0 +1,260 @@ +//===--- Sparc.cpp - Implement Sparc target feature support ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements Sparc TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "Sparc.h" +#include "Targets.h" +#include "clang/Basic/MacroBuilder.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +const char *const SparcTargetInfo::GCCRegNames[] = { + // Integer registers + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", + "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", + "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", + + // Floating-point registers + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", + "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", + "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", "f32", + "f34", "f36", "f38", "f40", "f42", "f44", "f46", "f48", "f50", "f52", "f54", + "f56", "f58", "f60", "f62", +}; + +ArrayRef<const char *> SparcTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +const TargetInfo::GCCRegAlias SparcTargetInfo::GCCRegAliases[] = { + {{"g0"}, "r0"}, {{"g1"}, "r1"}, {{"g2"}, "r2"}, {{"g3"}, "r3"}, + {{"g4"}, "r4"}, {{"g5"}, "r5"}, {{"g6"}, "r6"}, {{"g7"}, "r7"}, + {{"o0"}, "r8"}, {{"o1"}, "r9"}, {{"o2"}, "r10"}, {{"o3"}, "r11"}, + {{"o4"}, "r12"}, {{"o5"}, "r13"}, {{"o6", "sp"}, "r14"}, {{"o7"}, "r15"}, + {{"l0"}, "r16"}, {{"l1"}, "r17"}, {{"l2"}, "r18"}, {{"l3"}, "r19"}, + {{"l4"}, "r20"}, {{"l5"}, "r21"}, {{"l6"}, "r22"}, {{"l7"}, "r23"}, + {{"i0"}, "r24"}, {{"i1"}, "r25"}, {{"i2"}, "r26"}, {{"i3"}, "r27"}, + {{"i4"}, "r28"}, {{"i5"}, "r29"}, {{"i6", "fp"}, "r30"}, {{"i7"}, "r31"}, +}; + +ArrayRef<TargetInfo::GCCRegAlias> SparcTargetInfo::getGCCRegAliases() const { + return llvm::makeArrayRef(GCCRegAliases); +} + +bool SparcTargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature) + .Case("softfloat", SoftFloat) + .Case("sparc", true) + .Default(false); +} + +struct SparcCPUInfo { + llvm::StringLiteral Name; + SparcTargetInfo::CPUKind Kind; + SparcTargetInfo::CPUGeneration Generation; +}; + +static constexpr SparcCPUInfo CPUInfo[] = { + {{"v8"}, SparcTargetInfo::CK_V8, SparcTargetInfo::CG_V8}, + {{"supersparc"}, SparcTargetInfo::CK_SUPERSPARC, SparcTargetInfo::CG_V8}, + {{"sparclite"}, SparcTargetInfo::CK_SPARCLITE, SparcTargetInfo::CG_V8}, + {{"f934"}, SparcTargetInfo::CK_F934, SparcTargetInfo::CG_V8}, + {{"hypersparc"}, SparcTargetInfo::CK_HYPERSPARC, SparcTargetInfo::CG_V8}, + {{"sparclite86x"}, + SparcTargetInfo::CK_SPARCLITE86X, + SparcTargetInfo::CG_V8}, + {{"sparclet"}, SparcTargetInfo::CK_SPARCLET, SparcTargetInfo::CG_V8}, + {{"tsc701"}, SparcTargetInfo::CK_TSC701, SparcTargetInfo::CG_V8}, + {{"v9"}, SparcTargetInfo::CK_V9, SparcTargetInfo::CG_V9}, + {{"ultrasparc"}, SparcTargetInfo::CK_ULTRASPARC, SparcTargetInfo::CG_V9}, + {{"ultrasparc3"}, SparcTargetInfo::CK_ULTRASPARC3, SparcTargetInfo::CG_V9}, + {{"niagara"}, SparcTargetInfo::CK_NIAGARA, SparcTargetInfo::CG_V9}, + {{"niagara2"}, SparcTargetInfo::CK_NIAGARA2, SparcTargetInfo::CG_V9}, + {{"niagara3"}, SparcTargetInfo::CK_NIAGARA3, SparcTargetInfo::CG_V9}, + {{"niagara4"}, SparcTargetInfo::CK_NIAGARA4, SparcTargetInfo::CG_V9}, + {{"ma2100"}, SparcTargetInfo::CK_MYRIAD2100, SparcTargetInfo::CG_V8}, + {{"ma2150"}, SparcTargetInfo::CK_MYRIAD2150, SparcTargetInfo::CG_V8}, + {{"ma2155"}, SparcTargetInfo::CK_MYRIAD2155, SparcTargetInfo::CG_V8}, + {{"ma2450"}, SparcTargetInfo::CK_MYRIAD2450, SparcTargetInfo::CG_V8}, + {{"ma2455"}, SparcTargetInfo::CK_MYRIAD2455, SparcTargetInfo::CG_V8}, + {{"ma2x5x"}, SparcTargetInfo::CK_MYRIAD2x5x, SparcTargetInfo::CG_V8}, + {{"ma2080"}, SparcTargetInfo::CK_MYRIAD2080, SparcTargetInfo::CG_V8}, + {{"ma2085"}, SparcTargetInfo::CK_MYRIAD2085, SparcTargetInfo::CG_V8}, + {{"ma2480"}, SparcTargetInfo::CK_MYRIAD2480, SparcTargetInfo::CG_V8}, + {{"ma2485"}, SparcTargetInfo::CK_MYRIAD2485, SparcTargetInfo::CG_V8}, + {{"ma2x8x"}, SparcTargetInfo::CK_MYRIAD2x8x, SparcTargetInfo::CG_V8}, + // FIXME: the myriad2[.n] spellings are obsolete, + // but a grace period is needed to allow updating dependent builds. + {{"myriad2"}, SparcTargetInfo::CK_MYRIAD2x5x, SparcTargetInfo::CG_V8}, + {{"myriad2.1"}, SparcTargetInfo::CK_MYRIAD2100, SparcTargetInfo::CG_V8}, + {{"myriad2.2"}, SparcTargetInfo::CK_MYRIAD2x5x, SparcTargetInfo::CG_V8}, + {{"myriad2.3"}, SparcTargetInfo::CK_MYRIAD2x8x, SparcTargetInfo::CG_V8}, + {{"leon2"}, SparcTargetInfo::CK_LEON2, SparcTargetInfo::CG_V8}, + {{"at697e"}, SparcTargetInfo::CK_LEON2_AT697E, SparcTargetInfo::CG_V8}, + {{"at697f"}, SparcTargetInfo::CK_LEON2_AT697F, SparcTargetInfo::CG_V8}, + {{"leon3"}, SparcTargetInfo::CK_LEON3, SparcTargetInfo::CG_V8}, + {{"ut699"}, SparcTargetInfo::CK_LEON3_UT699, SparcTargetInfo::CG_V8}, + {{"gr712rc"}, SparcTargetInfo::CK_LEON3_GR712RC, SparcTargetInfo::CG_V8}, + {{"leon4"}, SparcTargetInfo::CK_LEON4, SparcTargetInfo::CG_V8}, + {{"gr740"}, SparcTargetInfo::CK_LEON4_GR740, SparcTargetInfo::CG_V8}, +}; + +SparcTargetInfo::CPUGeneration +SparcTargetInfo::getCPUGeneration(CPUKind Kind) const { + if (Kind == CK_GENERIC) + return CG_V8; + const SparcCPUInfo *Item = llvm::find_if( + CPUInfo, [Kind](const SparcCPUInfo &Info) { return Info.Kind == Kind; }); + if (Item == std::end(CPUInfo)) + llvm_unreachable("Unexpected CPU kind"); + return Item->Generation; +} + +SparcTargetInfo::CPUKind SparcTargetInfo::getCPUKind(StringRef Name) const { + const SparcCPUInfo *Item = llvm::find_if( + CPUInfo, [Name](const SparcCPUInfo &Info) { return Info.Name == Name; }); + + if (Item == std::end(CPUInfo)) + return CK_GENERIC; + return Item->Kind; +} + +void SparcTargetInfo::fillValidCPUList( + SmallVectorImpl<StringRef> &Values) const { + for (const SparcCPUInfo &Info : CPUInfo) + Values.push_back(Info.Name); +} + +void SparcTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "sparc", Opts); + Builder.defineMacro("__REGISTER_PREFIX__", ""); + + if (SoftFloat) + Builder.defineMacro("SOFT_FLOAT", "1"); +} + +void SparcV8TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + SparcTargetInfo::getTargetDefines(Opts, Builder); + if (getTriple().getOS() == llvm::Triple::Solaris) + Builder.defineMacro("__sparcv8"); + else { + switch (getCPUGeneration(CPU)) { + case CG_V8: + Builder.defineMacro("__sparcv8"); + Builder.defineMacro("__sparcv8__"); + break; + case CG_V9: + Builder.defineMacro("__sparc_v9__"); + break; + } + } + if (getTriple().getVendor() == llvm::Triple::Myriad) { + std::string MyriadArchValue, Myriad2Value; + Builder.defineMacro("__sparc_v8__"); + Builder.defineMacro("__leon__"); + switch (CPU) { + case CK_MYRIAD2100: + MyriadArchValue = "__ma2100"; + Myriad2Value = "1"; + break; + case CK_MYRIAD2150: + MyriadArchValue = "__ma2150"; + Myriad2Value = "2"; + break; + case CK_MYRIAD2155: + MyriadArchValue = "__ma2155"; + Myriad2Value = "2"; + break; + case CK_MYRIAD2450: + MyriadArchValue = "__ma2450"; + Myriad2Value = "2"; + break; + case CK_MYRIAD2455: + MyriadArchValue = "__ma2455"; + Myriad2Value = "2"; + break; + case CK_MYRIAD2x5x: + Myriad2Value = "2"; + break; + case CK_MYRIAD2080: + MyriadArchValue = "__ma2080"; + Myriad2Value = "3"; + break; + case CK_MYRIAD2085: + MyriadArchValue = "__ma2085"; + Myriad2Value = "3"; + break; + case CK_MYRIAD2480: + MyriadArchValue = "__ma2480"; + Myriad2Value = "3"; + break; + case CK_MYRIAD2485: + MyriadArchValue = "__ma2485"; + Myriad2Value = "3"; + break; + case CK_MYRIAD2x8x: + Myriad2Value = "3"; + break; + default: + MyriadArchValue = "__ma2100"; + Myriad2Value = "1"; + break; + } + if (!MyriadArchValue.empty()) { + Builder.defineMacro(MyriadArchValue, "1"); + Builder.defineMacro(MyriadArchValue + "__", "1"); + } + if (Myriad2Value == "2") { + Builder.defineMacro("__ma2x5x", "1"); + Builder.defineMacro("__ma2x5x__", "1"); + } else if (Myriad2Value == "3") { + Builder.defineMacro("__ma2x8x", "1"); + Builder.defineMacro("__ma2x8x__", "1"); + } + Builder.defineMacro("__myriad2__", Myriad2Value); + Builder.defineMacro("__myriad2", Myriad2Value); + } + if (getCPUGeneration(CPU) == CG_V9) { + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); + } +} + +void SparcV9TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + SparcTargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__sparcv9"); + Builder.defineMacro("__arch64__"); + // Solaris doesn't need these variants, but the BSDs do. + if (getTriple().getOS() != llvm::Triple::Solaris) { + Builder.defineMacro("__sparc64__"); + Builder.defineMacro("__sparc_v9__"); + Builder.defineMacro("__sparcv9__"); + } + + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); +} + +void SparcV9TargetInfo::fillValidCPUList( + SmallVectorImpl<StringRef> &Values) const { + for (const SparcCPUInfo &Info : CPUInfo) + if (Info.Generation == CG_V9) + Values.push_back(Info.Name); +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/Sparc.h b/contrib/llvm-project/clang/lib/Basic/Targets/Sparc.h new file mode 100644 index 000000000000..177a117520da --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/Sparc.h @@ -0,0 +1,236 @@ +//===--- Sparc.h - declare sparc target feature support ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares Sparc TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_SPARC_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_SPARC_H +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" +namespace clang { +namespace targets { +// Shared base class for SPARC v8 (32-bit) and SPARC v9 (64-bit). +class LLVM_LIBRARY_VISIBILITY SparcTargetInfo : public TargetInfo { + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + static const char *const GCCRegNames[]; + bool SoftFloat; + +public: + SparcTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple), SoftFloat(false) {} + + int getEHDataRegisterNumber(unsigned RegNo) const override { + if (RegNo == 0) + return 24; + if (RegNo == 1) + return 25; + return -1; + } + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override { + // Check if software floating point is enabled + if (llvm::is_contained(Features, "+soft-float")) + SoftFloat = true; + return true; + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool hasFeature(StringRef Feature) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override { + // FIXME: Implement! + return None; + } + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + ArrayRef<const char *> getGCCRegNames() const override; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override { + // FIXME: Implement! + switch (*Name) { + case 'I': // Signed 13-bit constant + case 'J': // Zero + case 'K': // 32-bit constant with the low 12 bits clear + case 'L': // A constant in the range supported by movcc (11-bit signed imm) + case 'M': // A constant in the range supported by movrcc (19-bit signed imm) + case 'N': // Same as 'K' but zext (required for SIMode) + case 'O': // The constant 4096 + return true; + + case 'f': + case 'e': + info.setAllowsRegister(); + return true; + } + return false; + } + const char *getClobbers() const override { + // FIXME: Implement! + return ""; + } + + // No Sparc V7 for now, the backend doesn't support it anyway. + enum CPUKind { + CK_GENERIC, + CK_V8, + CK_SUPERSPARC, + CK_SPARCLITE, + CK_F934, + CK_HYPERSPARC, + CK_SPARCLITE86X, + CK_SPARCLET, + CK_TSC701, + CK_V9, + CK_ULTRASPARC, + CK_ULTRASPARC3, + CK_NIAGARA, + CK_NIAGARA2, + CK_NIAGARA3, + CK_NIAGARA4, + CK_MYRIAD2100, + CK_MYRIAD2150, + CK_MYRIAD2155, + CK_MYRIAD2450, + CK_MYRIAD2455, + CK_MYRIAD2x5x, + CK_MYRIAD2080, + CK_MYRIAD2085, + CK_MYRIAD2480, + CK_MYRIAD2485, + CK_MYRIAD2x8x, + CK_LEON2, + CK_LEON2_AT697E, + CK_LEON2_AT697F, + CK_LEON3, + CK_LEON3_UT699, + CK_LEON3_GR712RC, + CK_LEON4, + CK_LEON4_GR740 + } CPU = CK_GENERIC; + + enum CPUGeneration { + CG_V8, + CG_V9, + }; + + CPUGeneration getCPUGeneration(CPUKind Kind) const; + + CPUKind getCPUKind(StringRef Name) const; + + bool isValidCPUName(StringRef Name) const override { + return getCPUKind(Name) != CK_GENERIC; + } + + void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; + + bool setCPU(const std::string &Name) override { + CPU = getCPUKind(Name); + return CPU != CK_GENERIC; + } +}; + +// SPARC v8 is the 32-bit mode selected by Triple::sparc. +class LLVM_LIBRARY_VISIBILITY SparcV8TargetInfo : public SparcTargetInfo { +public: + SparcV8TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : SparcTargetInfo(Triple, Opts) { + resetDataLayout("E-m:e-p:32:32-i64:64-f128:64-n32-S64"); + // NetBSD / OpenBSD use long (same as llvm default); everyone else uses int. + switch (getTriple().getOS()) { + default: + SizeType = UnsignedInt; + IntPtrType = SignedInt; + PtrDiffType = SignedInt; + break; + case llvm::Triple::NetBSD: + case llvm::Triple::OpenBSD: + SizeType = UnsignedLong; + IntPtrType = SignedLong; + PtrDiffType = SignedLong; + break; + } + // Up to 32 bits (V8) or 64 bits (V9) are lock-free atomic, but we're + // willing to do atomic ops on up to 64 bits. + MaxAtomicPromoteWidth = 64; + if (getCPUGeneration(CPU) == CG_V9) + MaxAtomicInlineWidth = 64; + else + // FIXME: This isn't correct for plain V8 which lacks CAS, + // only for LEON 3+ and Myriad. + MaxAtomicInlineWidth = 32; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool hasBitIntType() const override { return true; } +}; + +// SPARCV8el is the 32-bit little-endian mode selected by Triple::sparcel. +class LLVM_LIBRARY_VISIBILITY SparcV8elTargetInfo : public SparcV8TargetInfo { +public: + SparcV8elTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : SparcV8TargetInfo(Triple, Opts) { + resetDataLayout("e-m:e-p:32:32-i64:64-f128:64-n32-S64"); + } +}; + +// SPARC v9 is the 64-bit mode selected by Triple::sparcv9. +class LLVM_LIBRARY_VISIBILITY SparcV9TargetInfo : public SparcTargetInfo { +public: + SparcV9TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : SparcTargetInfo(Triple, Opts) { + // FIXME: Support Sparc quad-precision long double? + resetDataLayout("E-m:e-i64:64-n32:64-S128"); + // This is an LP64 platform. + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + + // OpenBSD uses long long for int64_t and intmax_t. + if (getTriple().isOSOpenBSD()) + IntMaxType = SignedLongLong; + else + IntMaxType = SignedLong; + Int64Type = IntMaxType; + + // The SPARCv8 System V ABI has long double 128-bits in size, but 64-bit + // aligned. The SPARCv9 SCD 2.4.1 says 16-byte aligned. + LongDoubleWidth = 128; + LongDoubleAlign = 128; + SuitableAlign = 128; + LongDoubleFormat = &llvm::APFloat::IEEEquad(); + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool isValidCPUName(StringRef Name) const override { + return getCPUGeneration(SparcTargetInfo::getCPUKind(Name)) == CG_V9; + } + + void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; + + bool setCPU(const std::string &Name) override { + if (!SparcTargetInfo::setCPU(Name)) + return false; + return getCPUGeneration(CPU) == CG_V9; + } + + bool hasBitIntType() const override { return true; } +}; +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_SPARC_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/SystemZ.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/SystemZ.cpp new file mode 100644 index 000000000000..e3e0da21f8d5 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/SystemZ.cpp @@ -0,0 +1,155 @@ +//===--- SystemZ.cpp - Implement SystemZ target feature support -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements SystemZ TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "SystemZ.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +const Builtin::Info SystemZTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, +#include "clang/Basic/BuiltinsSystemZ.def" +}; + +const char *const SystemZTargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "f0", "f2", "f4", "f6", "f1", "f3", "f5", "f7", + "f8", "f10", "f12", "f14", "f9", "f11", "f13", "f15", + /*ap*/"", "cc", /*fp*/"", /*rp*/"", "a0", "a1", + "v16", "v18", "v20", "v22", "v17", "v19", "v21", "v23", + "v24", "v26", "v28", "v30", "v25", "v27", "v29", "v31" +}; + +const TargetInfo::AddlRegName GCCAddlRegNames[] = { + {{"v0"}, 16}, {{"v2"}, 17}, {{"v4"}, 18}, {{"v6"}, 19}, + {{"v1"}, 20}, {{"v3"}, 21}, {{"v5"}, 22}, {{"v7"}, 23}, + {{"v8"}, 24}, {{"v10"}, 25}, {{"v12"}, 26}, {{"v14"}, 27}, + {{"v9"}, 28}, {{"v11"}, 29}, {{"v13"}, 30}, {{"v15"}, 31} +}; + +ArrayRef<const char *> SystemZTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +ArrayRef<TargetInfo::AddlRegName> SystemZTargetInfo::getGCCAddlRegNames() const { + return llvm::makeArrayRef(GCCAddlRegNames); +} + +bool SystemZTargetInfo::validateAsmConstraint( + const char *&Name, TargetInfo::ConstraintInfo &Info) const { + switch (*Name) { + default: + return false; + + case 'a': // Address register + case 'd': // Data register (equivalent to 'r') + case 'f': // Floating-point register + case 'v': // Vector register + Info.setAllowsRegister(); + return true; + + case 'I': // Unsigned 8-bit constant + case 'J': // Unsigned 12-bit constant + case 'K': // Signed 16-bit constant + case 'L': // Signed 20-bit displacement (on all targets we support) + case 'M': // 0x7fffffff + return true; + + case 'Q': // Memory with base and unsigned 12-bit displacement + case 'R': // Likewise, plus an index + case 'S': // Memory with base and signed 20-bit displacement + case 'T': // Likewise, plus an index + Info.setAllowsMemory(); + return true; + } +} + +struct ISANameRevision { + llvm::StringLiteral Name; + int ISARevisionID; +}; +static constexpr ISANameRevision ISARevisions[] = { + {{"arch8"}, 8}, {{"z10"}, 8}, + {{"arch9"}, 9}, {{"z196"}, 9}, + {{"arch10"}, 10}, {{"zEC12"}, 10}, + {{"arch11"}, 11}, {{"z13"}, 11}, + {{"arch12"}, 12}, {{"z14"}, 12}, + {{"arch13"}, 13}, {{"z15"}, 13}, + {{"arch14"}, 14} +}; + +int SystemZTargetInfo::getISARevision(StringRef Name) const { + const auto Rev = + llvm::find_if(ISARevisions, [Name](const ISANameRevision &CR) { + return CR.Name == Name; + }); + if (Rev == std::end(ISARevisions)) + return -1; + return Rev->ISARevisionID; +} + +void SystemZTargetInfo::fillValidCPUList( + SmallVectorImpl<StringRef> &Values) const { + for (const ISANameRevision &Rev : ISARevisions) + Values.push_back(Rev.Name); +} + +bool SystemZTargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature) + .Case("systemz", true) + .Case("arch8", ISARevision >= 8) + .Case("arch9", ISARevision >= 9) + .Case("arch10", ISARevision >= 10) + .Case("arch11", ISARevision >= 11) + .Case("arch12", ISARevision >= 12) + .Case("arch13", ISARevision >= 13) + .Case("arch14", ISARevision >= 14) + .Case("htm", HasTransactionalExecution) + .Case("vx", HasVector) + .Default(false); +} + +void SystemZTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__s390__"); + Builder.defineMacro("__s390x__"); + Builder.defineMacro("__zarch__"); + Builder.defineMacro("__LONG_DOUBLE_128__"); + + Builder.defineMacro("__ARCH__", Twine(ISARevision)); + + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); + + if (HasTransactionalExecution) + Builder.defineMacro("__HTM__"); + if (HasVector) + Builder.defineMacro("__VX__"); + if (Opts.ZVector) + Builder.defineMacro("__VEC__", "10304"); +} + +ArrayRef<Builtin::Info> SystemZTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::SystemZ::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/SystemZ.h b/contrib/llvm-project/clang/lib/Basic/Targets/SystemZ.h new file mode 100644 index 000000000000..92cefeea5d26 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/SystemZ.h @@ -0,0 +1,181 @@ +//===--- SystemZ.h - Declare SystemZ target feature support -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares SystemZ TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_SYSTEMZ_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_SYSTEMZ_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo { + + static const Builtin::Info BuiltinInfo[]; + static const char *const GCCRegNames[]; + std::string CPU; + int ISARevision; + bool HasTransactionalExecution; + bool HasVector; + bool SoftFloat; + +public: + SystemZTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple), CPU("z10"), ISARevision(8), + HasTransactionalExecution(false), HasVector(false), SoftFloat(false) { + IntMaxType = SignedLong; + Int64Type = SignedLong; + TLSSupported = true; + IntWidth = IntAlign = 32; + LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64; + PointerWidth = PointerAlign = 64; + LongDoubleWidth = 128; + LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEquad(); + DefaultAlignForAttributeAligned = 64; + MinGlobalAlign = 16; + if (Triple.isOSzOS()) { + // All vector types are default aligned on an 8-byte boundary, even if the + // vector facility is not available. That is different from Linux. + MaxVectorAlign = 64; + // Compared to Linux/ELF, the data layout differs only in some details: + // - name mangling is GOFF + // - 128 bit vector types are 64 bit aligned + resetDataLayout( + "E-m:l-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64"); + } else + resetDataLayout("E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64"); + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + HasStrictFP = true; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + ArrayRef<const char *> getGCCRegNames() const override; + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + // No aliases. + return None; + } + + ArrayRef<TargetInfo::AddlRegName> getGCCAddlRegNames() const override; + + bool isSPRegName(StringRef RegName) const override { + return RegName.equals("r15"); + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override; + + const char *getClobbers() const override { + // FIXME: Is this really right? + return ""; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::SystemZBuiltinVaList; + } + + int getISARevision(StringRef Name) const; + + bool isValidCPUName(StringRef Name) const override { + return getISARevision(Name) != -1; + } + + void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; + + bool setCPU(const std::string &Name) override { + CPU = Name; + ISARevision = getISARevision(CPU); + return ISARevision != -1; + } + + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override { + int ISARevision = getISARevision(CPU); + if (ISARevision >= 10) + Features["transactional-execution"] = true; + if (ISARevision >= 11) + Features["vector"] = true; + if (ISARevision >= 12) + Features["vector-enhancements-1"] = true; + if (ISARevision >= 13) + Features["vector-enhancements-2"] = true; + if (ISARevision >= 14) + Features["nnp-assist"] = true; + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); + } + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override { + HasTransactionalExecution = false; + HasVector = false; + SoftFloat = false; + for (const auto &Feature : Features) { + if (Feature == "+transactional-execution") + HasTransactionalExecution = true; + else if (Feature == "+vector") + HasVector = true; + else if (Feature == "+soft-float") + SoftFloat = true; + } + HasVector &= !SoftFloat; + + // If we use the vector ABI, vector types are 64-bit aligned. + if (HasVector && !getTriple().isOSzOS()) { + MaxVectorAlign = 64; + resetDataLayout("E-m:e-i1:8:16-i8:8:16-i64:64-f128:64" + "-v128:64-a:8:16-n32:64"); + } + return true; + } + + bool hasFeature(StringRef Feature) const override; + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + switch (CC) { + case CC_C: + case CC_Swift: + case CC_OpenCLKernel: + return CCCR_OK; + case CC_SwiftAsync: + return CCCR_Error; + default: + return CCCR_Warning; + } + } + + StringRef getABI() const override { + if (HasVector) + return "vector"; + return ""; + } + + const char *getLongDoubleMangling() const override { return "g"; } + + bool hasBitIntType() const override { return true; } + + int getEHDataRegisterNumber(unsigned RegNo) const override { + return RegNo < 4 ? 6 + RegNo : -1; + } +}; +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_SYSTEMZ_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/TCE.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/TCE.cpp new file mode 100644 index 000000000000..91194b568a09 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/TCE.cpp @@ -0,0 +1,34 @@ +//===--- TCE.cpp - Implement TCE target feature support -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements TCE TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "TCE.h" +#include "Targets.h" +#include "clang/Basic/MacroBuilder.h" + +using namespace clang; +using namespace clang::targets; + +void TCETargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "tce", Opts); + Builder.defineMacro("__TCE__"); + Builder.defineMacro("__TCE_V1__"); +} + +void TCELETargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "tcele", Opts); + Builder.defineMacro("__TCE__"); + Builder.defineMacro("__TCE_V1__"); + Builder.defineMacro("__TCELE__"); + Builder.defineMacro("__TCELE_V1__"); +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/TCE.h b/contrib/llvm-project/clang/lib/Basic/Targets/TCE.h new file mode 100644 index 000000000000..251b4d4b56f7 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/TCE.h @@ -0,0 +1,132 @@ +//===--- TCE.h - Declare TCE target feature support -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares TCE TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_TCE_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_TCE_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +// llvm and clang cannot be used directly to output native binaries for +// target, but is used to compile C code to llvm bitcode with correct +// type and alignment information. +// +// TCE uses the llvm bitcode as input and uses it for generating customized +// target processor and program binary. TCE co-design environment is +// publicly available in http://tce.cs.tut.fi + +static const unsigned TCEOpenCLAddrSpaceMap[] = { + 0, // Default + 3, // opencl_global + 4, // opencl_local + 5, // opencl_constant + 0, // opencl_private + 1, // opencl_global_device + 1, // opencl_global_host + // FIXME: generic has to be added to the target + 0, // opencl_generic + 0, // cuda_device + 0, // cuda_constant + 0, // cuda_shared + 0, // sycl_global + 0, // sycl_global_device + 0, // sycl_global_host + 0, // sycl_local + 0, // sycl_private + 0, // ptr32_sptr + 0, // ptr32_uptr + 0, // ptr64 +}; + +class LLVM_LIBRARY_VISIBILITY TCETargetInfo : public TargetInfo { +public: + TCETargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + TLSSupported = false; + IntWidth = 32; + LongWidth = LongLongWidth = 32; + PointerWidth = 32; + IntAlign = 32; + LongAlign = LongLongAlign = 32; + PointerAlign = 32; + SuitableAlign = 32; + SizeType = UnsignedInt; + IntMaxType = SignedLong; + IntPtrType = SignedInt; + PtrDiffType = SignedInt; + FloatWidth = 32; + FloatAlign = 32; + DoubleWidth = 32; + DoubleAlign = 32; + LongDoubleWidth = 32; + LongDoubleAlign = 32; + FloatFormat = &llvm::APFloat::IEEEsingle(); + DoubleFormat = &llvm::APFloat::IEEEsingle(); + LongDoubleFormat = &llvm::APFloat::IEEEsingle(); + resetDataLayout("E-p:32:32:32-i1:8:8-i8:8:32-" + "i16:16:32-i32:32:32-i64:32:32-" + "f32:32:32-f64:32:32-v64:32:32-" + "v128:32:32-v256:32:32-v512:32:32-" + "v1024:32:32-a0:0:32-n32"); + AddrSpaceMap = &TCEOpenCLAddrSpaceMap; + UseAddrSpaceMapMangling = true; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool hasFeature(StringRef Feature) const override { return Feature == "tce"; } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } + + const char *getClobbers() const override { return ""; } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + ArrayRef<const char *> getGCCRegNames() const override { return None; } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override { + return true; + } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; + } +}; + +class LLVM_LIBRARY_VISIBILITY TCELETargetInfo : public TCETargetInfo { +public: + TCELETargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : TCETargetInfo(Triple, Opts) { + BigEndian = false; + + resetDataLayout("e-p:32:32:32-i1:8:8-i8:8:32-" + "i16:16:32-i32:32:32-i64:32:32-" + "f32:32:32-f64:32:32-v64:32:32-" + "v128:32:32-v256:32:32-v512:32:32-" + "v1024:32:32-a0:0:32-n32"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_TCE_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/VE.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/VE.cpp new file mode 100644 index 000000000000..22223654e8ad --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/VE.cpp @@ -0,0 +1,39 @@ +//===--- VE.cpp - Implement VE target feature support ---------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements VE TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "VE.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" + +using namespace clang; +using namespace clang::targets; + +void VETargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("_LP64", "1"); + Builder.defineMacro("unix", "1"); + Builder.defineMacro("__unix__", "1"); + Builder.defineMacro("__linux__", "1"); + Builder.defineMacro("__ve", "1"); + Builder.defineMacro("__ve__", "1"); + Builder.defineMacro("__STDC_HOSTED__", "1"); + Builder.defineMacro("__STDC__", "1"); + Builder.defineMacro("__NEC__", "1"); + // FIXME: define __FAST_MATH__ 1 if -ffast-math is enabled + // FIXME: define __OPTIMIZE__ n if -On is enabled + // FIXME: define __VECTOR__ n 1 if automatic vectorization is enabled +} + +ArrayRef<Builtin::Info> VETargetInfo::getTargetBuiltins() const { + return ArrayRef<Builtin::Info>(); +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/VE.h b/contrib/llvm-project/clang/lib/Basic/Targets/VE.h new file mode 100644 index 000000000000..71d6fc08d859 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/VE.h @@ -0,0 +1,176 @@ +//===--- VE.h - Declare VE target feature support ---------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares VE TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_VE_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_VE_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY VETargetInfo : public TargetInfo { + static const Builtin::Info BuiltinInfo[]; + +public: + VETargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + NoAsmVariants = true; + LongDoubleWidth = 128; + LongDoubleAlign = 128; + LongDoubleFormat = &llvm::APFloat::IEEEquad(); + DoubleAlign = LongLongAlign = 64; + SuitableAlign = 64; + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + SizeType = UnsignedLong; + PtrDiffType = SignedLong; + IntPtrType = SignedLong; + IntMaxType = SignedLong; + Int64Type = SignedLong; + RegParmMax = 8; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + + WCharType = UnsignedInt; + WIntType = UnsignedInt; + UseZeroLengthBitfieldAlignment = true; + resetDataLayout( + "e-m:e-i64:64-n32:64-S128-v64:64:64-v128:64:64-v256:64:64-v512:64:64-" + "v1024:64:64-v2048:64:64-v4096:64:64-v8192:64:64-v16384:64:64"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool hasSjLjLowering() const override { return true; } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + switch (CC) { + default: + return CCCR_Warning; + case CC_C: + return CCCR_OK; + } + } + + const char *getClobbers() const override { return ""; } + + ArrayRef<const char *> getGCCRegNames() const override { + static const char *const GCCRegNames[] = { + // Regular registers + "sx0", "sx1", "sx2", "sx3", "sx4", "sx5", "sx6", "sx7", + "sx8", "sx9", "sx10", "sx11", "sx12", "sx13", "sx14", "sx15", + "sx16", "sx17", "sx18", "sx19", "sx20", "sx21", "sx22", "sx23", + "sx24", "sx25", "sx26", "sx27", "sx28", "sx29", "sx30", "sx31", + "sx32", "sx33", "sx34", "sx35", "sx36", "sx37", "sx38", "sx39", + "sx40", "sx41", "sx42", "sx43", "sx44", "sx45", "sx46", "sx47", + "sx48", "sx49", "sx50", "sx51", "sx52", "sx53", "sx54", "sx55", + "sx56", "sx57", "sx58", "sx59", "sx60", "sx61", "sx62", "sx63", + }; + return llvm::makeArrayRef(GCCRegNames); + } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + static const TargetInfo::GCCRegAlias GCCRegAliases[] = { + {{"s0"}, "sx0"}, + {{"s1"}, "sx1"}, + {{"s2"}, "sx2"}, + {{"s3"}, "sx3"}, + {{"s4"}, "sx4"}, + {{"s5"}, "sx5"}, + {{"s6"}, "sx6"}, + {{"s7"}, "sx7"}, + {{"s8", "sl"}, "sx8"}, + {{"s9", "fp"}, "sx9"}, + {{"s10", "lr"}, "sx10"}, + {{"s11", "sp"}, "sx11"}, + {{"s12", "outer"}, "sx12"}, + {{"s13"}, "sx13"}, + {{"s14", "tp"}, "sx14"}, + {{"s15", "got"}, "sx15"}, + {{"s16", "plt"}, "sx16"}, + {{"s17", "info"}, "sx17"}, + {{"s18"}, "sx18"}, + {{"s19"}, "sx19"}, + {{"s20"}, "sx20"}, + {{"s21"}, "sx21"}, + {{"s22"}, "sx22"}, + {{"s23"}, "sx23"}, + {{"s24"}, "sx24"}, + {{"s25"}, "sx25"}, + {{"s26"}, "sx26"}, + {{"s27"}, "sx27"}, + {{"s28"}, "sx28"}, + {{"s29"}, "sx29"}, + {{"s30"}, "sx30"}, + {{"s31"}, "sx31"}, + {{"s32"}, "sx32"}, + {{"s33"}, "sx33"}, + {{"s34"}, "sx34"}, + {{"s35"}, "sx35"}, + {{"s36"}, "sx36"}, + {{"s37"}, "sx37"}, + {{"s38"}, "sx38"}, + {{"s39"}, "sx39"}, + {{"s40"}, "sx40"}, + {{"s41"}, "sx41"}, + {{"s42"}, "sx42"}, + {{"s43"}, "sx43"}, + {{"s44"}, "sx44"}, + {{"s45"}, "sx45"}, + {{"s46"}, "sx46"}, + {{"s47"}, "sx47"}, + {{"s48"}, "sx48"}, + {{"s49"}, "sx49"}, + {{"s50"}, "sx50"}, + {{"s51"}, "sx51"}, + {{"s52"}, "sx52"}, + {{"s53"}, "sx53"}, + {{"s54"}, "sx54"}, + {{"s55"}, "sx55"}, + {{"s56"}, "sx56"}, + {{"s57"}, "sx57"}, + {{"s58"}, "sx58"}, + {{"s59"}, "sx59"}, + {{"s60"}, "sx60"}, + {{"s61"}, "sx61"}, + {{"s62"}, "sx62"}, + {{"s63"}, "sx63"}, + }; + return llvm::makeArrayRef(GCCRegAliases); + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + switch (*Name) { + default: + return false; + case 'v': + Info.setAllowsRegister(); + return true; + } + return false; + } + + bool allowsLargerPreferedTypeAlignment() const override { return false; } +}; +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_VE_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/WebAssembly.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/WebAssembly.cpp new file mode 100644 index 000000000000..2309997eb77b --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/WebAssembly.cpp @@ -0,0 +1,277 @@ +//===--- WebAssembly.cpp - Implement WebAssembly target feature support ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements WebAssembly TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "WebAssembly.h" +#include "Targets.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +const Builtin::Info WebAssemblyTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsWebAssembly.def" +}; + +static constexpr llvm::StringLiteral ValidCPUNames[] = { + {"mvp"}, {"bleeding-edge"}, {"generic"}}; + +StringRef WebAssemblyTargetInfo::getABI() const { return ABI; } + +bool WebAssemblyTargetInfo::setABI(const std::string &Name) { + if (Name != "mvp" && Name != "experimental-mv") + return false; + + ABI = Name; + return true; +} + +bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature) + .Case("simd128", SIMDLevel >= SIMD128) + .Case("relaxed-simd", SIMDLevel >= RelaxedSIMD) + .Case("nontrapping-fptoint", HasNontrappingFPToInt) + .Case("sign-ext", HasSignExt) + .Case("exception-handling", HasExceptionHandling) + .Case("bulk-memory", HasBulkMemory) + .Case("atomics", HasAtomics) + .Case("mutable-globals", HasMutableGlobals) + .Case("multivalue", HasMultivalue) + .Case("tail-call", HasTailCall) + .Case("reference-types", HasReferenceTypes) + .Default(false); +} + +bool WebAssemblyTargetInfo::isValidCPUName(StringRef Name) const { + return llvm::is_contained(ValidCPUNames, Name); +} + +void WebAssemblyTargetInfo::fillValidCPUList( + SmallVectorImpl<StringRef> &Values) const { + Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames)); +} + +void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + defineCPUMacros(Builder, "wasm", /*Tuning=*/false); + if (SIMDLevel >= SIMD128) + Builder.defineMacro("__wasm_simd128__"); + if (SIMDLevel >= RelaxedSIMD) + Builder.defineMacro("__wasm_relaxed_simd__"); + if (HasNontrappingFPToInt) + Builder.defineMacro("__wasm_nontrapping_fptoint__"); + if (HasSignExt) + Builder.defineMacro("__wasm_sign_ext__"); + if (HasExceptionHandling) + Builder.defineMacro("__wasm_exception_handling__"); + if (HasBulkMemory) + Builder.defineMacro("__wasm_bulk_memory__"); + if (HasAtomics) + Builder.defineMacro("__wasm_atomics__"); + if (HasMutableGlobals) + Builder.defineMacro("__wasm_mutable_globals__"); + if (HasMultivalue) + Builder.defineMacro("__wasm_multivalue__"); + if (HasTailCall) + Builder.defineMacro("__wasm_tail_call__"); + if (HasReferenceTypes) + Builder.defineMacro("__wasm_reference_types__"); +} + +void WebAssemblyTargetInfo::setSIMDLevel(llvm::StringMap<bool> &Features, + SIMDEnum Level, bool Enabled) { + if (Enabled) { + switch (Level) { + case RelaxedSIMD: + Features["relaxed-simd"] = true; + LLVM_FALLTHROUGH; + case SIMD128: + Features["simd128"] = true; + LLVM_FALLTHROUGH; + case NoSIMD: + break; + } + return; + } + + switch (Level) { + case NoSIMD: + case SIMD128: + Features["simd128"] = false; + LLVM_FALLTHROUGH; + case RelaxedSIMD: + Features["relaxed-simd"] = false; + break; + } +} + +void WebAssemblyTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, + StringRef Name, + bool Enabled) const { + if (Name == "simd128") + setSIMDLevel(Features, SIMD128, Enabled); + else if (Name == "relaxed-simd") + setSIMDLevel(Features, RelaxedSIMD, Enabled); + else + Features[Name] = Enabled; +} + +bool WebAssemblyTargetInfo::initFeatureMap( + llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, + const std::vector<std::string> &FeaturesVec) const { + if (CPU == "bleeding-edge") { + Features["nontrapping-fptoint"] = true; + Features["sign-ext"] = true; + Features["bulk-memory"] = true; + Features["atomics"] = true; + Features["mutable-globals"] = true; + Features["tail-call"] = true; + setSIMDLevel(Features, SIMD128, true); + } + + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); +} + +bool WebAssemblyTargetInfo::handleTargetFeatures( + std::vector<std::string> &Features, DiagnosticsEngine &Diags) { + for (const auto &Feature : Features) { + if (Feature == "+simd128") { + SIMDLevel = std::max(SIMDLevel, SIMD128); + continue; + } + if (Feature == "-simd128") { + SIMDLevel = std::min(SIMDLevel, SIMDEnum(SIMD128 - 1)); + continue; + } + if (Feature == "+relaxed-simd") { + SIMDLevel = std::max(SIMDLevel, RelaxedSIMD); + continue; + } + if (Feature == "-relaxed-simd") { + SIMDLevel = std::min(SIMDLevel, SIMDEnum(RelaxedSIMD - 1)); + continue; + } + if (Feature == "+nontrapping-fptoint") { + HasNontrappingFPToInt = true; + continue; + } + if (Feature == "-nontrapping-fptoint") { + HasNontrappingFPToInt = false; + continue; + } + if (Feature == "+sign-ext") { + HasSignExt = true; + continue; + } + if (Feature == "-sign-ext") { + HasSignExt = false; + continue; + } + if (Feature == "+exception-handling") { + HasExceptionHandling = true; + continue; + } + if (Feature == "-exception-handling") { + HasExceptionHandling = false; + continue; + } + if (Feature == "+bulk-memory") { + HasBulkMemory = true; + continue; + } + if (Feature == "-bulk-memory") { + HasBulkMemory = false; + continue; + } + if (Feature == "+atomics") { + HasAtomics = true; + continue; + } + if (Feature == "-atomics") { + HasAtomics = false; + continue; + } + if (Feature == "+mutable-globals") { + HasMutableGlobals = true; + continue; + } + if (Feature == "-mutable-globals") { + HasMutableGlobals = false; + continue; + } + if (Feature == "+multivalue") { + HasMultivalue = true; + continue; + } + if (Feature == "-multivalue") { + HasMultivalue = false; + continue; + } + if (Feature == "+tail-call") { + HasTailCall = true; + continue; + } + if (Feature == "-tail-call") { + HasTailCall = false; + continue; + } + if (Feature == "+reference-types") { + HasReferenceTypes = true; + continue; + } + if (Feature == "-reference-types") { + HasReferenceTypes = false; + continue; + } + + Diags.Report(diag::err_opt_not_valid_with_opt) + << Feature << "-target-feature"; + return false; + } + return true; +} + +ArrayRef<Builtin::Info> WebAssemblyTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::WebAssembly::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} + +void WebAssemblyTargetInfo::adjust(DiagnosticsEngine &Diags, + LangOptions &Opts) { + // If the Atomics feature isn't available, turn off POSIXThreads and + // ThreadModel, so that we don't predefine _REENTRANT or __STDCPP_THREADS__. + if (!HasAtomics) { + Opts.POSIXThreads = false; + Opts.setThreadModel(LangOptions::ThreadModelKind::Single); + Opts.ThreadsafeStatics = false; + } +} + +void WebAssembly32TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + WebAssemblyTargetInfo::getTargetDefines(Opts, Builder); + defineCPUMacros(Builder, "wasm32", /*Tuning=*/false); +} + +void WebAssembly64TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + WebAssemblyTargetInfo::getTargetDefines(Opts, Builder); + defineCPUMacros(Builder, "wasm64", /*Tuning=*/false); +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/WebAssembly.h b/contrib/llvm-project/clang/lib/Basic/Targets/WebAssembly.h new file mode 100644 index 000000000000..075486990558 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/WebAssembly.h @@ -0,0 +1,191 @@ +//=== WebAssembly.h - Declare WebAssembly target feature support *- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares WebAssembly TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_WEBASSEMBLY_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_WEBASSEMBLY_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo { + static const Builtin::Info BuiltinInfo[]; + + enum SIMDEnum { + NoSIMD, + SIMD128, + RelaxedSIMD, + } SIMDLevel = NoSIMD; + + bool HasNontrappingFPToInt = false; + bool HasSignExt = false; + bool HasExceptionHandling = false; + bool HasBulkMemory = false; + bool HasAtomics = false; + bool HasMutableGlobals = false; + bool HasMultivalue = false; + bool HasTailCall = false; + bool HasReferenceTypes = false; + + std::string ABI; + +public: + explicit WebAssemblyTargetInfo(const llvm::Triple &T, const TargetOptions &) + : TargetInfo(T) { + NoAsmVariants = true; + SuitableAlign = 128; + LargeArrayMinWidth = 128; + LargeArrayAlign = 128; + SimdDefaultAlign = 128; + SigAtomicType = SignedLong; + LongDoubleWidth = LongDoubleAlign = 128; + LongDoubleFormat = &llvm::APFloat::IEEEquad(); + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + // size_t being unsigned long for both wasm32 and wasm64 makes mangled names + // more consistent between the two. + SizeType = UnsignedLong; + PtrDiffType = SignedLong; + IntPtrType = SignedLong; + } + + StringRef getABI() const override; + bool setABI(const std::string &Name) override; + +protected: + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + +private: + static void setSIMDLevel(llvm::StringMap<bool> &Features, SIMDEnum Level, + bool Enabled); + + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override; + bool hasFeature(StringRef Feature) const final; + + void setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name, + bool Enabled) const final; + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) final; + + bool isValidCPUName(StringRef Name) const final; + void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const final; + + bool setCPU(const std::string &Name) final { return isValidCPUName(Name); } + + ArrayRef<Builtin::Info> getTargetBuiltins() const final; + + BuiltinVaListKind getBuiltinVaListKind() const final { + return VoidPtrBuiltinVaList; + } + + ArrayRef<const char *> getGCCRegNames() const final { return None; } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const final { + return None; + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const final { + return false; + } + + const char *getClobbers() const final { return ""; } + + bool isCLZForZeroUndef() const final { return false; } + + bool hasInt128Type() const final { return true; } + + IntType getIntTypeByWidth(unsigned BitWidth, bool IsSigned) const final { + // WebAssembly prefers long long for explicitly 64-bit integers. + return BitWidth == 64 ? (IsSigned ? SignedLongLong : UnsignedLongLong) + : TargetInfo::getIntTypeByWidth(BitWidth, IsSigned); + } + + IntType getLeastIntTypeByWidth(unsigned BitWidth, bool IsSigned) const final { + // WebAssembly uses long long for int_least64_t and int_fast64_t. + return BitWidth == 64 + ? (IsSigned ? SignedLongLong : UnsignedLongLong) + : TargetInfo::getLeastIntTypeByWidth(BitWidth, IsSigned); + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + switch (CC) { + case CC_C: + case CC_Swift: + return CCCR_OK; + case CC_SwiftAsync: + return CCCR_Error; + default: + return CCCR_Warning; + } + } + + bool hasBitIntType() const override { return true; } + + bool hasProtectedVisibility() const override { return false; } + + void adjust(DiagnosticsEngine &Diags, LangOptions &Opts) override; +}; + +class LLVM_LIBRARY_VISIBILITY WebAssembly32TargetInfo + : public WebAssemblyTargetInfo { +public: + explicit WebAssembly32TargetInfo(const llvm::Triple &T, + const TargetOptions &Opts) + : WebAssemblyTargetInfo(T, Opts) { + if (T.isOSEmscripten()) + resetDataLayout("e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-f128:64-n32:64-" + "S128-ni:1:10:20"); + else + resetDataLayout( + "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"); + } + +protected: + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +class LLVM_LIBRARY_VISIBILITY WebAssembly64TargetInfo + : public WebAssemblyTargetInfo { +public: + explicit WebAssembly64TargetInfo(const llvm::Triple &T, + const TargetOptions &Opts) + : WebAssemblyTargetInfo(T, Opts) { + LongAlign = LongWidth = 64; + PointerAlign = PointerWidth = 64; + SizeType = UnsignedLong; + PtrDiffType = SignedLong; + IntPtrType = SignedLong; + if (T.isOSEmscripten()) + resetDataLayout("e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-f128:64-n32:64-" + "S128-ni:1:10:20"); + else + resetDataLayout( + "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"); + } + +protected: + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_WEBASSEMBLY_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/X86.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/X86.cpp new file mode 100644 index 000000000000..5c4bd364b06a --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/X86.cpp @@ -0,0 +1,1540 @@ +//===--- X86.cpp - Implement X86 target feature support -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements X86 TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "X86.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/TargetBuiltins.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/X86TargetParser.h" + +namespace clang { +namespace targets { + +const Builtin::Info BuiltinInfoX86[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, +#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \ + {#ID, TYPE, ATTRS, HEADER, LANGS, FEATURE}, +#include "clang/Basic/BuiltinsX86.def" + +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, +#define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANGS, FEATURE) \ + {#ID, TYPE, ATTRS, HEADER, LANGS, FEATURE}, +#include "clang/Basic/BuiltinsX86_64.def" +}; + +static const char *const GCCRegNames[] = { + "ax", "dx", "cx", "bx", "si", "di", "bp", "sp", + "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", + "argp", "flags", "fpcr", "fpsr", "dirflag", "frame", "xmm0", "xmm1", + "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "mm0", "mm1", + "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", "r8", "r9", + "r10", "r11", "r12", "r13", "r14", "r15", "xmm8", "xmm9", + "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15", "ymm0", "ymm1", + "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", "ymm8", "ymm9", + "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15", "xmm16", "xmm17", + "xmm18", "xmm19", "xmm20", "xmm21", "xmm22", "xmm23", "xmm24", "xmm25", + "xmm26", "xmm27", "xmm28", "xmm29", "xmm30", "xmm31", "ymm16", "ymm17", + "ymm18", "ymm19", "ymm20", "ymm21", "ymm22", "ymm23", "ymm24", "ymm25", + "ymm26", "ymm27", "ymm28", "ymm29", "ymm30", "ymm31", "zmm0", "zmm1", + "zmm2", "zmm3", "zmm4", "zmm5", "zmm6", "zmm7", "zmm8", "zmm9", + "zmm10", "zmm11", "zmm12", "zmm13", "zmm14", "zmm15", "zmm16", "zmm17", + "zmm18", "zmm19", "zmm20", "zmm21", "zmm22", "zmm23", "zmm24", "zmm25", + "zmm26", "zmm27", "zmm28", "zmm29", "zmm30", "zmm31", "k0", "k1", + "k2", "k3", "k4", "k5", "k6", "k7", + "cr0", "cr2", "cr3", "cr4", "cr8", + "dr0", "dr1", "dr2", "dr3", "dr6", "dr7", + "bnd0", "bnd1", "bnd2", "bnd3", + "tmm0", "tmm1", "tmm2", "tmm3", "tmm4", "tmm5", "tmm6", "tmm7", +}; + +const TargetInfo::AddlRegName AddlRegNames[] = { + {{"al", "ah", "eax", "rax"}, 0}, + {{"bl", "bh", "ebx", "rbx"}, 3}, + {{"cl", "ch", "ecx", "rcx"}, 2}, + {{"dl", "dh", "edx", "rdx"}, 1}, + {{"esi", "rsi"}, 4}, + {{"edi", "rdi"}, 5}, + {{"esp", "rsp"}, 7}, + {{"ebp", "rbp"}, 6}, + {{"r8d", "r8w", "r8b"}, 38}, + {{"r9d", "r9w", "r9b"}, 39}, + {{"r10d", "r10w", "r10b"}, 40}, + {{"r11d", "r11w", "r11b"}, 41}, + {{"r12d", "r12w", "r12b"}, 42}, + {{"r13d", "r13w", "r13b"}, 43}, + {{"r14d", "r14w", "r14b"}, 44}, + {{"r15d", "r15w", "r15b"}, 45}, +}; + +} // namespace targets +} // namespace clang + +using namespace clang; +using namespace clang::targets; + +bool X86TargetInfo::setFPMath(StringRef Name) { + if (Name == "387") { + FPMath = FP_387; + return true; + } + if (Name == "sse") { + FPMath = FP_SSE; + return true; + } + return false; +} + +bool X86TargetInfo::initFeatureMap( + llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, + const std::vector<std::string> &FeaturesVec) const { + // FIXME: This *really* should not be here. + // X86_64 always has SSE2. + if (getTriple().getArch() == llvm::Triple::x86_64) + setFeatureEnabled(Features, "sse2", true); + + using namespace llvm::X86; + + SmallVector<StringRef, 16> CPUFeatures; + getFeaturesForCPU(CPU, CPUFeatures); + for (auto &F : CPUFeatures) + setFeatureEnabled(Features, F, true); + + std::vector<std::string> UpdatedFeaturesVec; + for (const auto &Feature : FeaturesVec) { + // Expand general-regs-only to -x86, -mmx and -sse + if (Feature == "+general-regs-only") { + UpdatedFeaturesVec.push_back("-x87"); + UpdatedFeaturesVec.push_back("-mmx"); + UpdatedFeaturesVec.push_back("-sse"); + continue; + } + + UpdatedFeaturesVec.push_back(Feature); + } + + if (!TargetInfo::initFeatureMap(Features, Diags, CPU, UpdatedFeaturesVec)) + return false; + + // Can't do this earlier because we need to be able to explicitly enable + // or disable these features and the things that they depend upon. + + // Enable popcnt if sse4.2 is enabled and popcnt is not explicitly disabled. + auto I = Features.find("sse4.2"); + if (I != Features.end() && I->getValue() && + !llvm::is_contained(UpdatedFeaturesVec, "-popcnt")) + Features["popcnt"] = true; + + // Additionally, if SSE is enabled and mmx is not explicitly disabled, + // then enable MMX. + I = Features.find("sse"); + if (I != Features.end() && I->getValue() && + !llvm::is_contained(UpdatedFeaturesVec, "-mmx")) + Features["mmx"] = true; + + // Enable xsave if avx is enabled and xsave is not explicitly disabled. + I = Features.find("avx"); + if (I != Features.end() && I->getValue() && + !llvm::is_contained(UpdatedFeaturesVec, "-xsave")) + Features["xsave"] = true; + + // Enable CRC32 if SSE4.2 is enabled and CRC32 is not explicitly disabled. + I = Features.find("sse4.2"); + if (I != Features.end() && I->getValue() && + !llvm::is_contained(UpdatedFeaturesVec, "-crc32")) + Features["crc32"] = true; + + return true; +} + +void X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, + StringRef Name, bool Enabled) const { + if (Name == "sse4") { + // We can get here via the __target__ attribute since that's not controlled + // via the -msse4/-mno-sse4 command line alias. Handle this the same way + // here - turn on the sse4.2 if enabled, turn off the sse4.1 level if + // disabled. + if (Enabled) + Name = "sse4.2"; + else + Name = "sse4.1"; + } + + Features[Name] = Enabled; + llvm::X86::updateImpliedFeatures(Name, Enabled, Features); +} + +/// handleTargetFeatures - Perform initialization based on the user +/// configured set of features. +bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) { + for (const auto &Feature : Features) { + if (Feature[0] != '+') + continue; + + if (Feature == "+aes") { + HasAES = true; + } else if (Feature == "+vaes") { + HasVAES = true; + } else if (Feature == "+pclmul") { + HasPCLMUL = true; + } else if (Feature == "+vpclmulqdq") { + HasVPCLMULQDQ = true; + } else if (Feature == "+lzcnt") { + HasLZCNT = true; + } else if (Feature == "+rdrnd") { + HasRDRND = true; + } else if (Feature == "+fsgsbase") { + HasFSGSBASE = true; + } else if (Feature == "+bmi") { + HasBMI = true; + } else if (Feature == "+bmi2") { + HasBMI2 = true; + } else if (Feature == "+popcnt") { + HasPOPCNT = true; + } else if (Feature == "+rtm") { + HasRTM = true; + } else if (Feature == "+prfchw") { + HasPRFCHW = true; + } else if (Feature == "+rdseed") { + HasRDSEED = true; + } else if (Feature == "+adx") { + HasADX = true; + } else if (Feature == "+tbm") { + HasTBM = true; + } else if (Feature == "+lwp") { + HasLWP = true; + } else if (Feature == "+fma") { + HasFMA = true; + } else if (Feature == "+f16c") { + HasF16C = true; + } else if (Feature == "+gfni") { + HasGFNI = true; + } else if (Feature == "+avx512cd") { + HasAVX512CD = true; + } else if (Feature == "+avx512vpopcntdq") { + HasAVX512VPOPCNTDQ = true; + } else if (Feature == "+avx512vnni") { + HasAVX512VNNI = true; + } else if (Feature == "+avx512bf16") { + HasAVX512BF16 = true; + } else if (Feature == "+avx512er") { + HasAVX512ER = true; + } else if (Feature == "+avx512fp16") { + HasAVX512FP16 = true; + HasFloat16 = true; + } else if (Feature == "+avx512pf") { + HasAVX512PF = true; + } else if (Feature == "+avx512dq") { + HasAVX512DQ = true; + } else if (Feature == "+avx512bitalg") { + HasAVX512BITALG = true; + } else if (Feature == "+avx512bw") { + HasAVX512BW = true; + } else if (Feature == "+avx512vl") { + HasAVX512VL = true; + } else if (Feature == "+avx512vbmi") { + HasAVX512VBMI = true; + } else if (Feature == "+avx512vbmi2") { + HasAVX512VBMI2 = true; + } else if (Feature == "+avx512ifma") { + HasAVX512IFMA = true; + } else if (Feature == "+avx512vp2intersect") { + HasAVX512VP2INTERSECT = true; + } else if (Feature == "+sha") { + HasSHA = true; + } else if (Feature == "+shstk") { + HasSHSTK = true; + } else if (Feature == "+movbe") { + HasMOVBE = true; + } else if (Feature == "+sgx") { + HasSGX = true; + } else if (Feature == "+cx8") { + HasCX8 = true; + } else if (Feature == "+cx16") { + HasCX16 = true; + } else if (Feature == "+fxsr") { + HasFXSR = true; + } else if (Feature == "+xsave") { + HasXSAVE = true; + } else if (Feature == "+xsaveopt") { + HasXSAVEOPT = true; + } else if (Feature == "+xsavec") { + HasXSAVEC = true; + } else if (Feature == "+xsaves") { + HasXSAVES = true; + } else if (Feature == "+mwaitx") { + HasMWAITX = true; + } else if (Feature == "+pku") { + HasPKU = true; + } else if (Feature == "+clflushopt") { + HasCLFLUSHOPT = true; + } else if (Feature == "+clwb") { + HasCLWB = true; + } else if (Feature == "+wbnoinvd") { + HasWBNOINVD = true; + } else if (Feature == "+prefetchwt1") { + HasPREFETCHWT1 = true; + } else if (Feature == "+clzero") { + HasCLZERO = true; + } else if (Feature == "+cldemote") { + HasCLDEMOTE = true; + } else if (Feature == "+rdpid") { + HasRDPID = true; + } else if (Feature == "+kl") { + HasKL = true; + } else if (Feature == "+widekl") { + HasWIDEKL = true; + } else if (Feature == "+retpoline-external-thunk") { + HasRetpolineExternalThunk = true; + } else if (Feature == "+sahf") { + HasLAHFSAHF = true; + } else if (Feature == "+waitpkg") { + HasWAITPKG = true; + } else if (Feature == "+movdiri") { + HasMOVDIRI = true; + } else if (Feature == "+movdir64b") { + HasMOVDIR64B = true; + } else if (Feature == "+pconfig") { + HasPCONFIG = true; + } else if (Feature == "+ptwrite") { + HasPTWRITE = true; + } else if (Feature == "+invpcid") { + HasINVPCID = true; + } else if (Feature == "+enqcmd") { + HasENQCMD = true; + } else if (Feature == "+hreset") { + HasHRESET = true; + } else if (Feature == "+amx-bf16") { + HasAMXBF16 = true; + } else if (Feature == "+amx-int8") { + HasAMXINT8 = true; + } else if (Feature == "+amx-tile") { + HasAMXTILE = true; + } else if (Feature == "+avxvnni") { + HasAVXVNNI = true; + } else if (Feature == "+serialize") { + HasSERIALIZE = true; + } else if (Feature == "+tsxldtrk") { + HasTSXLDTRK = true; + } else if (Feature == "+uintr") { + HasUINTR = true; + } else if (Feature == "+crc32") { + HasCRC32 = true; + } else if (Feature == "+x87") { + HasX87 = true; + } + + X86SSEEnum Level = llvm::StringSwitch<X86SSEEnum>(Feature) + .Case("+avx512f", AVX512F) + .Case("+avx2", AVX2) + .Case("+avx", AVX) + .Case("+sse4.2", SSE42) + .Case("+sse4.1", SSE41) + .Case("+ssse3", SSSE3) + .Case("+sse3", SSE3) + .Case("+sse2", SSE2) + .Case("+sse", SSE1) + .Default(NoSSE); + SSELevel = std::max(SSELevel, Level); + + MMX3DNowEnum ThreeDNowLevel = llvm::StringSwitch<MMX3DNowEnum>(Feature) + .Case("+3dnowa", AMD3DNowAthlon) + .Case("+3dnow", AMD3DNow) + .Case("+mmx", MMX) + .Default(NoMMX3DNow); + MMX3DNowLevel = std::max(MMX3DNowLevel, ThreeDNowLevel); + + XOPEnum XLevel = llvm::StringSwitch<XOPEnum>(Feature) + .Case("+xop", XOP) + .Case("+fma4", FMA4) + .Case("+sse4a", SSE4A) + .Default(NoXOP); + XOPLevel = std::max(XOPLevel, XLevel); + } + + // LLVM doesn't have a separate switch for fpmath, so only accept it if it + // matches the selected sse level. + if ((FPMath == FP_SSE && SSELevel < SSE1) || + (FPMath == FP_387 && SSELevel >= SSE1)) { + Diags.Report(diag::err_target_unsupported_fpmath) + << (FPMath == FP_SSE ? "sse" : "387"); + return false; + } + + SimdDefaultAlign = + hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128; + + // FIXME: We should allow long double type on 32-bits to match with GCC. + // This requires backend to be able to lower f80 without x87 first. + if (!HasX87 && LongDoubleFormat == &llvm::APFloat::x87DoubleExtended()) + HasLongDouble = false; + + return true; +} + +/// X86TargetInfo::getTargetDefines - Return the set of the X86-specific macro +/// definitions for this particular subtarget. +void X86TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Inline assembly supports X86 flag outputs. + Builder.defineMacro("__GCC_ASM_FLAG_OUTPUTS__"); + + std::string CodeModel = getTargetOpts().CodeModel; + if (CodeModel == "default") + CodeModel = "small"; + Builder.defineMacro("__code_model_" + CodeModel + "__"); + + // Target identification. + if (getTriple().getArch() == llvm::Triple::x86_64) { + Builder.defineMacro("__amd64__"); + Builder.defineMacro("__amd64"); + Builder.defineMacro("__x86_64"); + Builder.defineMacro("__x86_64__"); + if (getTriple().getArchName() == "x86_64h") { + Builder.defineMacro("__x86_64h"); + Builder.defineMacro("__x86_64h__"); + } + } else { + DefineStd(Builder, "i386", Opts); + } + + Builder.defineMacro("__SEG_GS"); + Builder.defineMacro("__SEG_FS"); + Builder.defineMacro("__seg_gs", "__attribute__((address_space(256)))"); + Builder.defineMacro("__seg_fs", "__attribute__((address_space(257)))"); + + // Subtarget options. + // FIXME: We are hard-coding the tune parameters based on the CPU, but they + // truly should be based on -mtune options. + using namespace llvm::X86; + switch (CPU) { + case CK_None: + break; + case CK_i386: + // The rest are coming from the i386 define above. + Builder.defineMacro("__tune_i386__"); + break; + case CK_i486: + case CK_WinChipC6: + case CK_WinChip2: + case CK_C3: + defineCPUMacros(Builder, "i486"); + break; + case CK_PentiumMMX: + Builder.defineMacro("__pentium_mmx__"); + Builder.defineMacro("__tune_pentium_mmx__"); + LLVM_FALLTHROUGH; + case CK_i586: + case CK_Pentium: + defineCPUMacros(Builder, "i586"); + defineCPUMacros(Builder, "pentium"); + break; + case CK_Pentium3: + case CK_PentiumM: + Builder.defineMacro("__tune_pentium3__"); + LLVM_FALLTHROUGH; + case CK_Pentium2: + case CK_C3_2: + Builder.defineMacro("__tune_pentium2__"); + LLVM_FALLTHROUGH; + case CK_PentiumPro: + case CK_i686: + defineCPUMacros(Builder, "i686"); + defineCPUMacros(Builder, "pentiumpro"); + break; + case CK_Pentium4: + defineCPUMacros(Builder, "pentium4"); + break; + case CK_Yonah: + case CK_Prescott: + case CK_Nocona: + defineCPUMacros(Builder, "nocona"); + break; + case CK_Core2: + case CK_Penryn: + defineCPUMacros(Builder, "core2"); + break; + case CK_Bonnell: + defineCPUMacros(Builder, "atom"); + break; + case CK_Silvermont: + defineCPUMacros(Builder, "slm"); + break; + case CK_Goldmont: + defineCPUMacros(Builder, "goldmont"); + break; + case CK_GoldmontPlus: + defineCPUMacros(Builder, "goldmont_plus"); + break; + case CK_Tremont: + defineCPUMacros(Builder, "tremont"); + break; + case CK_Nehalem: + case CK_Westmere: + case CK_SandyBridge: + case CK_IvyBridge: + case CK_Haswell: + case CK_Broadwell: + case CK_SkylakeClient: + case CK_SkylakeServer: + case CK_Cascadelake: + case CK_Cooperlake: + case CK_Cannonlake: + case CK_IcelakeClient: + case CK_Rocketlake: + case CK_IcelakeServer: + case CK_Tigerlake: + case CK_SapphireRapids: + case CK_Alderlake: + // FIXME: Historically, we defined this legacy name, it would be nice to + // remove it at some point. We've never exposed fine-grained names for + // recent primary x86 CPUs, and we should keep it that way. + defineCPUMacros(Builder, "corei7"); + break; + case CK_KNL: + defineCPUMacros(Builder, "knl"); + break; + case CK_KNM: + break; + case CK_Lakemont: + defineCPUMacros(Builder, "i586", /*Tuning*/false); + defineCPUMacros(Builder, "pentium", /*Tuning*/false); + Builder.defineMacro("__tune_lakemont__"); + break; + case CK_K6_2: + Builder.defineMacro("__k6_2__"); + Builder.defineMacro("__tune_k6_2__"); + LLVM_FALLTHROUGH; + case CK_K6_3: + if (CPU != CK_K6_2) { // In case of fallthrough + // FIXME: GCC may be enabling these in cases where some other k6 + // architecture is specified but -m3dnow is explicitly provided. The + // exact semantics need to be determined and emulated here. + Builder.defineMacro("__k6_3__"); + Builder.defineMacro("__tune_k6_3__"); + } + LLVM_FALLTHROUGH; + case CK_K6: + defineCPUMacros(Builder, "k6"); + break; + case CK_Athlon: + case CK_AthlonXP: + defineCPUMacros(Builder, "athlon"); + if (SSELevel != NoSSE) { + Builder.defineMacro("__athlon_sse__"); + Builder.defineMacro("__tune_athlon_sse__"); + } + break; + case CK_K8: + case CK_K8SSE3: + case CK_x86_64: + defineCPUMacros(Builder, "k8"); + break; + case CK_x86_64_v2: + case CK_x86_64_v3: + case CK_x86_64_v4: + break; + case CK_AMDFAM10: + defineCPUMacros(Builder, "amdfam10"); + break; + case CK_BTVER1: + defineCPUMacros(Builder, "btver1"); + break; + case CK_BTVER2: + defineCPUMacros(Builder, "btver2"); + break; + case CK_BDVER1: + defineCPUMacros(Builder, "bdver1"); + break; + case CK_BDVER2: + defineCPUMacros(Builder, "bdver2"); + break; + case CK_BDVER3: + defineCPUMacros(Builder, "bdver3"); + break; + case CK_BDVER4: + defineCPUMacros(Builder, "bdver4"); + break; + case CK_ZNVER1: + defineCPUMacros(Builder, "znver1"); + break; + case CK_ZNVER2: + defineCPUMacros(Builder, "znver2"); + break; + case CK_ZNVER3: + defineCPUMacros(Builder, "znver3"); + break; + case CK_Geode: + defineCPUMacros(Builder, "geode"); + break; + } + + // Target properties. + Builder.defineMacro("__REGISTER_PREFIX__", ""); + + // Define __NO_MATH_INLINES on linux/x86 so that we don't get inline + // functions in glibc header files that use FP Stack inline asm which the + // backend can't deal with (PR879). + Builder.defineMacro("__NO_MATH_INLINES"); + + if (HasAES) + Builder.defineMacro("__AES__"); + + if (HasVAES) + Builder.defineMacro("__VAES__"); + + if (HasPCLMUL) + Builder.defineMacro("__PCLMUL__"); + + if (HasVPCLMULQDQ) + Builder.defineMacro("__VPCLMULQDQ__"); + + // Note, in 32-bit mode, GCC does not define the macro if -mno-sahf. In LLVM, + // the feature flag only applies to 64-bit mode. + if (HasLAHFSAHF || getTriple().getArch() == llvm::Triple::x86) + Builder.defineMacro("__LAHF_SAHF__"); + + if (HasLZCNT) + Builder.defineMacro("__LZCNT__"); + + if (HasRDRND) + Builder.defineMacro("__RDRND__"); + + if (HasFSGSBASE) + Builder.defineMacro("__FSGSBASE__"); + + if (HasBMI) + Builder.defineMacro("__BMI__"); + + if (HasBMI2) + Builder.defineMacro("__BMI2__"); + + if (HasPOPCNT) + Builder.defineMacro("__POPCNT__"); + + if (HasRTM) + Builder.defineMacro("__RTM__"); + + if (HasPRFCHW) + Builder.defineMacro("__PRFCHW__"); + + if (HasRDSEED) + Builder.defineMacro("__RDSEED__"); + + if (HasADX) + Builder.defineMacro("__ADX__"); + + if (HasTBM) + Builder.defineMacro("__TBM__"); + + if (HasLWP) + Builder.defineMacro("__LWP__"); + + if (HasMWAITX) + Builder.defineMacro("__MWAITX__"); + + if (HasMOVBE) + Builder.defineMacro("__MOVBE__"); + + switch (XOPLevel) { + case XOP: + Builder.defineMacro("__XOP__"); + LLVM_FALLTHROUGH; + case FMA4: + Builder.defineMacro("__FMA4__"); + LLVM_FALLTHROUGH; + case SSE4A: + Builder.defineMacro("__SSE4A__"); + LLVM_FALLTHROUGH; + case NoXOP: + break; + } + + if (HasFMA) + Builder.defineMacro("__FMA__"); + + if (HasF16C) + Builder.defineMacro("__F16C__"); + + if (HasGFNI) + Builder.defineMacro("__GFNI__"); + + if (HasAVX512CD) + Builder.defineMacro("__AVX512CD__"); + if (HasAVX512VPOPCNTDQ) + Builder.defineMacro("__AVX512VPOPCNTDQ__"); + if (HasAVX512VNNI) + Builder.defineMacro("__AVX512VNNI__"); + if (HasAVX512BF16) + Builder.defineMacro("__AVX512BF16__"); + if (HasAVX512ER) + Builder.defineMacro("__AVX512ER__"); + if (HasAVX512FP16) + Builder.defineMacro("__AVX512FP16__"); + if (HasAVX512PF) + Builder.defineMacro("__AVX512PF__"); + if (HasAVX512DQ) + Builder.defineMacro("__AVX512DQ__"); + if (HasAVX512BITALG) + Builder.defineMacro("__AVX512BITALG__"); + if (HasAVX512BW) + Builder.defineMacro("__AVX512BW__"); + if (HasAVX512VL) + Builder.defineMacro("__AVX512VL__"); + if (HasAVX512VBMI) + Builder.defineMacro("__AVX512VBMI__"); + if (HasAVX512VBMI2) + Builder.defineMacro("__AVX512VBMI2__"); + if (HasAVX512IFMA) + Builder.defineMacro("__AVX512IFMA__"); + if (HasAVX512VP2INTERSECT) + Builder.defineMacro("__AVX512VP2INTERSECT__"); + if (HasSHA) + Builder.defineMacro("__SHA__"); + + if (HasFXSR) + Builder.defineMacro("__FXSR__"); + if (HasXSAVE) + Builder.defineMacro("__XSAVE__"); + if (HasXSAVEOPT) + Builder.defineMacro("__XSAVEOPT__"); + if (HasXSAVEC) + Builder.defineMacro("__XSAVEC__"); + if (HasXSAVES) + Builder.defineMacro("__XSAVES__"); + if (HasPKU) + Builder.defineMacro("__PKU__"); + if (HasCLFLUSHOPT) + Builder.defineMacro("__CLFLUSHOPT__"); + if (HasCLWB) + Builder.defineMacro("__CLWB__"); + if (HasWBNOINVD) + Builder.defineMacro("__WBNOINVD__"); + if (HasSHSTK) + Builder.defineMacro("__SHSTK__"); + if (HasSGX) + Builder.defineMacro("__SGX__"); + if (HasPREFETCHWT1) + Builder.defineMacro("__PREFETCHWT1__"); + if (HasCLZERO) + Builder.defineMacro("__CLZERO__"); + if (HasKL) + Builder.defineMacro("__KL__"); + if (HasWIDEKL) + Builder.defineMacro("__WIDEKL__"); + if (HasRDPID) + Builder.defineMacro("__RDPID__"); + if (HasCLDEMOTE) + Builder.defineMacro("__CLDEMOTE__"); + if (HasWAITPKG) + Builder.defineMacro("__WAITPKG__"); + if (HasMOVDIRI) + Builder.defineMacro("__MOVDIRI__"); + if (HasMOVDIR64B) + Builder.defineMacro("__MOVDIR64B__"); + if (HasPCONFIG) + Builder.defineMacro("__PCONFIG__"); + if (HasPTWRITE) + Builder.defineMacro("__PTWRITE__"); + if (HasINVPCID) + Builder.defineMacro("__INVPCID__"); + if (HasENQCMD) + Builder.defineMacro("__ENQCMD__"); + if (HasHRESET) + Builder.defineMacro("__HRESET__"); + if (HasAMXTILE) + Builder.defineMacro("__AMXTILE__"); + if (HasAMXINT8) + Builder.defineMacro("__AMXINT8__"); + if (HasAMXBF16) + Builder.defineMacro("__AMXBF16__"); + if (HasAVXVNNI) + Builder.defineMacro("__AVXVNNI__"); + if (HasSERIALIZE) + Builder.defineMacro("__SERIALIZE__"); + if (HasTSXLDTRK) + Builder.defineMacro("__TSXLDTRK__"); + if (HasUINTR) + Builder.defineMacro("__UINTR__"); + if (HasCRC32) + Builder.defineMacro("__CRC32__"); + + // Each case falls through to the previous one here. + switch (SSELevel) { + case AVX512F: + Builder.defineMacro("__AVX512F__"); + LLVM_FALLTHROUGH; + case AVX2: + Builder.defineMacro("__AVX2__"); + LLVM_FALLTHROUGH; + case AVX: + Builder.defineMacro("__AVX__"); + LLVM_FALLTHROUGH; + case SSE42: + Builder.defineMacro("__SSE4_2__"); + LLVM_FALLTHROUGH; + case SSE41: + Builder.defineMacro("__SSE4_1__"); + LLVM_FALLTHROUGH; + case SSSE3: + Builder.defineMacro("__SSSE3__"); + LLVM_FALLTHROUGH; + case SSE3: + Builder.defineMacro("__SSE3__"); + LLVM_FALLTHROUGH; + case SSE2: + Builder.defineMacro("__SSE2__"); + Builder.defineMacro("__SSE2_MATH__"); // -mfp-math=sse always implied. + LLVM_FALLTHROUGH; + case SSE1: + Builder.defineMacro("__SSE__"); + Builder.defineMacro("__SSE_MATH__"); // -mfp-math=sse always implied. + LLVM_FALLTHROUGH; + case NoSSE: + break; + } + + if (Opts.MicrosoftExt && getTriple().getArch() == llvm::Triple::x86) { + switch (SSELevel) { + case AVX512F: + case AVX2: + case AVX: + case SSE42: + case SSE41: + case SSSE3: + case SSE3: + case SSE2: + Builder.defineMacro("_M_IX86_FP", Twine(2)); + break; + case SSE1: + Builder.defineMacro("_M_IX86_FP", Twine(1)); + break; + default: + Builder.defineMacro("_M_IX86_FP", Twine(0)); + break; + } + } + + // Each case falls through to the previous one here. + switch (MMX3DNowLevel) { + case AMD3DNowAthlon: + Builder.defineMacro("__3dNOW_A__"); + LLVM_FALLTHROUGH; + case AMD3DNow: + Builder.defineMacro("__3dNOW__"); + LLVM_FALLTHROUGH; + case MMX: + Builder.defineMacro("__MMX__"); + LLVM_FALLTHROUGH; + case NoMMX3DNow: + break; + } + + if (CPU >= CK_i486 || CPU == CK_None) { + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); + } + if (HasCX8) + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); + if (HasCX16 && getTriple().getArch() == llvm::Triple::x86_64) + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16"); + + if (HasFloat128) + Builder.defineMacro("__SIZEOF_FLOAT128__", "16"); +} + +bool X86TargetInfo::isValidFeatureName(StringRef Name) const { + return llvm::StringSwitch<bool>(Name) + .Case("3dnow", true) + .Case("3dnowa", true) + .Case("adx", true) + .Case("aes", true) + .Case("amx-bf16", true) + .Case("amx-int8", true) + .Case("amx-tile", true) + .Case("avx", true) + .Case("avx2", true) + .Case("avx512f", true) + .Case("avx512cd", true) + .Case("avx512vpopcntdq", true) + .Case("avx512vnni", true) + .Case("avx512bf16", true) + .Case("avx512er", true) + .Case("avx512fp16", true) + .Case("avx512pf", true) + .Case("avx512dq", true) + .Case("avx512bitalg", true) + .Case("avx512bw", true) + .Case("avx512vl", true) + .Case("avx512vbmi", true) + .Case("avx512vbmi2", true) + .Case("avx512ifma", true) + .Case("avx512vp2intersect", true) + .Case("avxvnni", true) + .Case("bmi", true) + .Case("bmi2", true) + .Case("cldemote", true) + .Case("clflushopt", true) + .Case("clwb", true) + .Case("clzero", true) + .Case("crc32", true) + .Case("cx16", true) + .Case("enqcmd", true) + .Case("f16c", true) + .Case("fma", true) + .Case("fma4", true) + .Case("fsgsbase", true) + .Case("fxsr", true) + .Case("general-regs-only", true) + .Case("gfni", true) + .Case("hreset", true) + .Case("invpcid", true) + .Case("kl", true) + .Case("widekl", true) + .Case("lwp", true) + .Case("lzcnt", true) + .Case("mmx", true) + .Case("movbe", true) + .Case("movdiri", true) + .Case("movdir64b", true) + .Case("mwaitx", true) + .Case("pclmul", true) + .Case("pconfig", true) + .Case("pku", true) + .Case("popcnt", true) + .Case("prefetchwt1", true) + .Case("prfchw", true) + .Case("ptwrite", true) + .Case("rdpid", true) + .Case("rdrnd", true) + .Case("rdseed", true) + .Case("rtm", true) + .Case("sahf", true) + .Case("serialize", true) + .Case("sgx", true) + .Case("sha", true) + .Case("shstk", true) + .Case("sse", true) + .Case("sse2", true) + .Case("sse3", true) + .Case("ssse3", true) + .Case("sse4", true) + .Case("sse4.1", true) + .Case("sse4.2", true) + .Case("sse4a", true) + .Case("tbm", true) + .Case("tsxldtrk", true) + .Case("uintr", true) + .Case("vaes", true) + .Case("vpclmulqdq", true) + .Case("wbnoinvd", true) + .Case("waitpkg", true) + .Case("x87", true) + .Case("xop", true) + .Case("xsave", true) + .Case("xsavec", true) + .Case("xsaves", true) + .Case("xsaveopt", true) + .Default(false); +} + +bool X86TargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature) + .Case("adx", HasADX) + .Case("aes", HasAES) + .Case("amx-bf16", HasAMXBF16) + .Case("amx-int8", HasAMXINT8) + .Case("amx-tile", HasAMXTILE) + .Case("avxvnni", HasAVXVNNI) + .Case("avx", SSELevel >= AVX) + .Case("avx2", SSELevel >= AVX2) + .Case("avx512f", SSELevel >= AVX512F) + .Case("avx512cd", HasAVX512CD) + .Case("avx512vpopcntdq", HasAVX512VPOPCNTDQ) + .Case("avx512vnni", HasAVX512VNNI) + .Case("avx512bf16", HasAVX512BF16) + .Case("avx512er", HasAVX512ER) + .Case("avx512fp16", HasAVX512FP16) + .Case("avx512pf", HasAVX512PF) + .Case("avx512dq", HasAVX512DQ) + .Case("avx512bitalg", HasAVX512BITALG) + .Case("avx512bw", HasAVX512BW) + .Case("avx512vl", HasAVX512VL) + .Case("avx512vbmi", HasAVX512VBMI) + .Case("avx512vbmi2", HasAVX512VBMI2) + .Case("avx512ifma", HasAVX512IFMA) + .Case("avx512vp2intersect", HasAVX512VP2INTERSECT) + .Case("bmi", HasBMI) + .Case("bmi2", HasBMI2) + .Case("cldemote", HasCLDEMOTE) + .Case("clflushopt", HasCLFLUSHOPT) + .Case("clwb", HasCLWB) + .Case("clzero", HasCLZERO) + .Case("crc32", HasCRC32) + .Case("cx8", HasCX8) + .Case("cx16", HasCX16) + .Case("enqcmd", HasENQCMD) + .Case("f16c", HasF16C) + .Case("fma", HasFMA) + .Case("fma4", XOPLevel >= FMA4) + .Case("fsgsbase", HasFSGSBASE) + .Case("fxsr", HasFXSR) + .Case("gfni", HasGFNI) + .Case("hreset", HasHRESET) + .Case("invpcid", HasINVPCID) + .Case("kl", HasKL) + .Case("widekl", HasWIDEKL) + .Case("lwp", HasLWP) + .Case("lzcnt", HasLZCNT) + .Case("mm3dnow", MMX3DNowLevel >= AMD3DNow) + .Case("mm3dnowa", MMX3DNowLevel >= AMD3DNowAthlon) + .Case("mmx", MMX3DNowLevel >= MMX) + .Case("movbe", HasMOVBE) + .Case("movdiri", HasMOVDIRI) + .Case("movdir64b", HasMOVDIR64B) + .Case("mwaitx", HasMWAITX) + .Case("pclmul", HasPCLMUL) + .Case("pconfig", HasPCONFIG) + .Case("pku", HasPKU) + .Case("popcnt", HasPOPCNT) + .Case("prefetchwt1", HasPREFETCHWT1) + .Case("prfchw", HasPRFCHW) + .Case("ptwrite", HasPTWRITE) + .Case("rdpid", HasRDPID) + .Case("rdrnd", HasRDRND) + .Case("rdseed", HasRDSEED) + .Case("retpoline-external-thunk", HasRetpolineExternalThunk) + .Case("rtm", HasRTM) + .Case("sahf", HasLAHFSAHF) + .Case("serialize", HasSERIALIZE) + .Case("sgx", HasSGX) + .Case("sha", HasSHA) + .Case("shstk", HasSHSTK) + .Case("sse", SSELevel >= SSE1) + .Case("sse2", SSELevel >= SSE2) + .Case("sse3", SSELevel >= SSE3) + .Case("ssse3", SSELevel >= SSSE3) + .Case("sse4.1", SSELevel >= SSE41) + .Case("sse4.2", SSELevel >= SSE42) + .Case("sse4a", XOPLevel >= SSE4A) + .Case("tbm", HasTBM) + .Case("tsxldtrk", HasTSXLDTRK) + .Case("uintr", HasUINTR) + .Case("vaes", HasVAES) + .Case("vpclmulqdq", HasVPCLMULQDQ) + .Case("wbnoinvd", HasWBNOINVD) + .Case("waitpkg", HasWAITPKG) + .Case("x86", true) + .Case("x86_32", getTriple().getArch() == llvm::Triple::x86) + .Case("x86_64", getTriple().getArch() == llvm::Triple::x86_64) + .Case("x87", HasX87) + .Case("xop", XOPLevel >= XOP) + .Case("xsave", HasXSAVE) + .Case("xsavec", HasXSAVEC) + .Case("xsaves", HasXSAVES) + .Case("xsaveopt", HasXSAVEOPT) + .Default(false); +} + +// We can't use a generic validation scheme for the features accepted here +// versus subtarget features accepted in the target attribute because the +// bitfield structure that's initialized in the runtime only supports the +// below currently rather than the full range of subtarget features. (See +// X86TargetInfo::hasFeature for a somewhat comprehensive list). +bool X86TargetInfo::validateCpuSupports(StringRef FeatureStr) const { + return llvm::StringSwitch<bool>(FeatureStr) +#define X86_FEATURE_COMPAT(ENUM, STR, PRIORITY) .Case(STR, true) +#include "llvm/Support/X86TargetParser.def" + .Default(false); +} + +static llvm::X86::ProcessorFeatures getFeature(StringRef Name) { + return llvm::StringSwitch<llvm::X86::ProcessorFeatures>(Name) +#define X86_FEATURE_COMPAT(ENUM, STR, PRIORITY) \ + .Case(STR, llvm::X86::FEATURE_##ENUM) + +#include "llvm/Support/X86TargetParser.def" + ; + // Note, this function should only be used after ensuring the value is + // correct, so it asserts if the value is out of range. +} + +unsigned X86TargetInfo::multiVersionSortPriority(StringRef Name) const { + // Valid CPUs have a 'key feature' that compares just better than its key + // feature. + using namespace llvm::X86; + CPUKind Kind = parseArchX86(Name); + if (Kind != CK_None) { + ProcessorFeatures KeyFeature = getKeyFeature(Kind); + return (getFeaturePriority(KeyFeature) << 1) + 1; + } + + // Now we know we have a feature, so get its priority and shift it a few so + // that we have sufficient room for the CPUs (above). + return getFeaturePriority(getFeature(Name)) << 1; +} + +bool X86TargetInfo::validateCPUSpecificCPUDispatch(StringRef Name) const { + return llvm::StringSwitch<bool>(Name) +#define CPU_SPECIFIC(NAME, MANGLING, FEATURES) .Case(NAME, true) +#define CPU_SPECIFIC_ALIAS(NEW_NAME, NAME) .Case(NEW_NAME, true) +#include "llvm/Support/X86TargetParser.def" + .Default(false); +} + +static StringRef CPUSpecificCPUDispatchNameDealias(StringRef Name) { + return llvm::StringSwitch<StringRef>(Name) +#define CPU_SPECIFIC_ALIAS(NEW_NAME, NAME) .Case(NEW_NAME, NAME) +#include "llvm/Support/X86TargetParser.def" + .Default(Name); +} + +char X86TargetInfo::CPUSpecificManglingCharacter(StringRef Name) const { + return llvm::StringSwitch<char>(CPUSpecificCPUDispatchNameDealias(Name)) +#define CPU_SPECIFIC(NAME, MANGLING, FEATURES) .Case(NAME, MANGLING) +#include "llvm/Support/X86TargetParser.def" + .Default(0); +} + +void X86TargetInfo::getCPUSpecificCPUDispatchFeatures( + StringRef Name, llvm::SmallVectorImpl<StringRef> &Features) const { + StringRef WholeList = + llvm::StringSwitch<StringRef>(CPUSpecificCPUDispatchNameDealias(Name)) +#define CPU_SPECIFIC(NAME, MANGLING, FEATURES) .Case(NAME, FEATURES) +#include "llvm/Support/X86TargetParser.def" + .Default(""); + WholeList.split(Features, ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false); +} + +// We can't use a generic validation scheme for the cpus accepted here +// versus subtarget cpus accepted in the target attribute because the +// variables intitialized by the runtime only support the below currently +// rather than the full range of cpus. +bool X86TargetInfo::validateCpuIs(StringRef FeatureStr) const { + return llvm::StringSwitch<bool>(FeatureStr) +#define X86_VENDOR(ENUM, STRING) .Case(STRING, true) +#define X86_CPU_TYPE_ALIAS(ENUM, ALIAS) .Case(ALIAS, true) +#define X86_CPU_TYPE(ENUM, STR) .Case(STR, true) +#define X86_CPU_SUBTYPE(ENUM, STR) .Case(STR, true) +#include "llvm/Support/X86TargetParser.def" + .Default(false); +} + +static unsigned matchAsmCCConstraint(const char *&Name) { + auto RV = llvm::StringSwitch<unsigned>(Name) + .Case("@cca", 4) + .Case("@ccae", 5) + .Case("@ccb", 4) + .Case("@ccbe", 5) + .Case("@ccc", 4) + .Case("@cce", 4) + .Case("@ccz", 4) + .Case("@ccg", 4) + .Case("@ccge", 5) + .Case("@ccl", 4) + .Case("@ccle", 5) + .Case("@ccna", 5) + .Case("@ccnae", 6) + .Case("@ccnb", 5) + .Case("@ccnbe", 6) + .Case("@ccnc", 5) + .Case("@ccne", 5) + .Case("@ccnz", 5) + .Case("@ccng", 5) + .Case("@ccnge", 6) + .Case("@ccnl", 5) + .Case("@ccnle", 6) + .Case("@ccno", 5) + .Case("@ccnp", 5) + .Case("@ccns", 5) + .Case("@cco", 4) + .Case("@ccp", 4) + .Case("@ccs", 4) + .Default(0); + return RV; +} + +bool X86TargetInfo::validateAsmConstraint( + const char *&Name, TargetInfo::ConstraintInfo &Info) const { + switch (*Name) { + default: + return false; + // Constant constraints. + case 'e': // 32-bit signed integer constant for use with sign-extending x86_64 + // instructions. + case 'Z': // 32-bit unsigned integer constant for use with zero-extending + // x86_64 instructions. + case 's': + Info.setRequiresImmediate(); + return true; + case 'I': + Info.setRequiresImmediate(0, 31); + return true; + case 'J': + Info.setRequiresImmediate(0, 63); + return true; + case 'K': + Info.setRequiresImmediate(-128, 127); + return true; + case 'L': + Info.setRequiresImmediate({int(0xff), int(0xffff), int(0xffffffff)}); + return true; + case 'M': + Info.setRequiresImmediate(0, 3); + return true; + case 'N': + Info.setRequiresImmediate(0, 255); + return true; + case 'O': + Info.setRequiresImmediate(0, 127); + return true; + // Register constraints. + case 'Y': // 'Y' is the first character for several 2-character constraints. + // Shift the pointer to the second character of the constraint. + Name++; + switch (*Name) { + default: + return false; + case 'z': // First SSE register. + case '2': + case 't': // Any SSE register, when SSE2 is enabled. + case 'i': // Any SSE register, when SSE2 and inter-unit moves enabled. + case 'm': // Any MMX register, when inter-unit moves enabled. + case 'k': // AVX512 arch mask registers: k1-k7. + Info.setAllowsRegister(); + return true; + } + case 'f': // Any x87 floating point stack register. + // Constraint 'f' cannot be used for output operands. + if (Info.ConstraintStr[0] == '=') + return false; + Info.setAllowsRegister(); + return true; + case 'a': // eax. + case 'b': // ebx. + case 'c': // ecx. + case 'd': // edx. + case 'S': // esi. + case 'D': // edi. + case 'A': // edx:eax. + case 't': // Top of floating point stack. + case 'u': // Second from top of floating point stack. + case 'q': // Any register accessible as [r]l: a, b, c, and d. + case 'y': // Any MMX register. + case 'v': // Any {X,Y,Z}MM register (Arch & context dependent) + case 'x': // Any SSE register. + case 'k': // Any AVX512 mask register (same as Yk, additionally allows k0 + // for intermideate k reg operations). + case 'Q': // Any register accessible as [r]h: a, b, c, and d. + case 'R': // "Legacy" registers: ax, bx, cx, dx, di, si, sp, bp. + case 'l': // "Index" registers: any general register that can be used as an + // index in a base+index memory access. + Info.setAllowsRegister(); + return true; + // Floating point constant constraints. + case 'C': // SSE floating point constant. + case 'G': // x87 floating point constant. + return true; + case '@': + // CC condition changes. + if (auto Len = matchAsmCCConstraint(Name)) { + Name += Len - 1; + Info.setAllowsRegister(); + return true; + } + return false; + } +} + +// Below is based on the following information: +// +------------------------------------+-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------+ +// | Processor Name | Cache Line Size (Bytes) | Source | +// +------------------------------------+-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------+ +// | i386 | 64 | https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf | +// | i486 | 16 | "four doublewords" (doubleword = 32 bits, 4 bits * 32 bits = 16 bytes) https://en.wikichip.org/w/images/d/d3/i486_MICROPROCESSOR_HARDWARE_REFERENCE_MANUAL_%281990%29.pdf and http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.126.4216&rep=rep1&type=pdf (page 29) | +// | i586/Pentium MMX | 32 | https://www.7-cpu.com/cpu/P-MMX.html | +// | i686/Pentium | 32 | https://www.7-cpu.com/cpu/P6.html | +// | Netburst/Pentium4 | 64 | https://www.7-cpu.com/cpu/P4-180.html | +// | Atom | 64 | https://www.7-cpu.com/cpu/Atom.html | +// | Westmere | 64 | https://en.wikichip.org/wiki/intel/microarchitectures/sandy_bridge_(client) "Cache Architecture" | +// | Sandy Bridge | 64 | https://en.wikipedia.org/wiki/Sandy_Bridge and https://www.7-cpu.com/cpu/SandyBridge.html | +// | Ivy Bridge | 64 | https://blog.stuffedcow.net/2013/01/ivb-cache-replacement/ and https://www.7-cpu.com/cpu/IvyBridge.html | +// | Haswell | 64 | https://www.7-cpu.com/cpu/Haswell.html | +// | Boadwell | 64 | https://www.7-cpu.com/cpu/Broadwell.html | +// | Skylake (including skylake-avx512) | 64 | https://www.nas.nasa.gov/hecc/support/kb/skylake-processors_550.html "Cache Hierarchy" | +// | Cascade Lake | 64 | https://www.nas.nasa.gov/hecc/support/kb/cascade-lake-processors_579.html "Cache Hierarchy" | +// | Skylake | 64 | https://en.wikichip.org/wiki/intel/microarchitectures/kaby_lake "Memory Hierarchy" | +// | Ice Lake | 64 | https://www.7-cpu.com/cpu/Ice_Lake.html | +// | Knights Landing | 64 | https://software.intel.com/en-us/articles/intel-xeon-phi-processor-7200-family-memory-management-optimizations "The Intel® Xeon Phi™ Processor Architecture" | +// | Knights Mill | 64 | https://software.intel.com/sites/default/files/managed/9e/bc/64-ia-32-architectures-optimization-manual.pdf?countrylabel=Colombia "2.5.5.2 L1 DCache " | +// +------------------------------------+-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------+ +Optional<unsigned> X86TargetInfo::getCPUCacheLineSize() const { + using namespace llvm::X86; + switch (CPU) { + // i386 + case CK_i386: + // i486 + case CK_i486: + case CK_WinChipC6: + case CK_WinChip2: + case CK_C3: + // Lakemont + case CK_Lakemont: + return 16; + + // i586 + case CK_i586: + case CK_Pentium: + case CK_PentiumMMX: + // i686 + case CK_PentiumPro: + case CK_i686: + case CK_Pentium2: + case CK_Pentium3: + case CK_PentiumM: + case CK_C3_2: + // K6 + case CK_K6: + case CK_K6_2: + case CK_K6_3: + // Geode + case CK_Geode: + return 32; + + // Netburst + case CK_Pentium4: + case CK_Prescott: + case CK_Nocona: + // Atom + case CK_Bonnell: + case CK_Silvermont: + case CK_Goldmont: + case CK_GoldmontPlus: + case CK_Tremont: + + case CK_Westmere: + case CK_SandyBridge: + case CK_IvyBridge: + case CK_Haswell: + case CK_Broadwell: + case CK_SkylakeClient: + case CK_SkylakeServer: + case CK_Cascadelake: + case CK_Nehalem: + case CK_Cooperlake: + case CK_Cannonlake: + case CK_Tigerlake: + case CK_SapphireRapids: + case CK_IcelakeClient: + case CK_Rocketlake: + case CK_IcelakeServer: + case CK_Alderlake: + case CK_KNL: + case CK_KNM: + // K7 + case CK_Athlon: + case CK_AthlonXP: + // K8 + case CK_K8: + case CK_K8SSE3: + case CK_AMDFAM10: + // Bobcat + case CK_BTVER1: + case CK_BTVER2: + // Bulldozer + case CK_BDVER1: + case CK_BDVER2: + case CK_BDVER3: + case CK_BDVER4: + // Zen + case CK_ZNVER1: + case CK_ZNVER2: + case CK_ZNVER3: + // Deprecated + case CK_x86_64: + case CK_x86_64_v2: + case CK_x86_64_v3: + case CK_x86_64_v4: + case CK_Yonah: + case CK_Penryn: + case CK_Core2: + return 64; + + // The following currently have unknown cache line sizes (but they are probably all 64): + // Core + case CK_None: + return None; + } + llvm_unreachable("Unknown CPU kind"); +} + +bool X86TargetInfo::validateOutputSize(const llvm::StringMap<bool> &FeatureMap, + StringRef Constraint, + unsigned Size) const { + // Strip off constraint modifiers. + while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&') + Constraint = Constraint.substr(1); + + return validateOperandSize(FeatureMap, Constraint, Size); +} + +bool X86TargetInfo::validateInputSize(const llvm::StringMap<bool> &FeatureMap, + StringRef Constraint, + unsigned Size) const { + return validateOperandSize(FeatureMap, Constraint, Size); +} + +bool X86TargetInfo::validateOperandSize(const llvm::StringMap<bool> &FeatureMap, + StringRef Constraint, + unsigned Size) const { + switch (Constraint[0]) { + default: + break; + case 'k': + // Registers k0-k7 (AVX512) size limit is 64 bit. + case 'y': + return Size <= 64; + case 'f': + case 't': + case 'u': + return Size <= 128; + case 'Y': + // 'Y' is the first character for several 2-character constraints. + switch (Constraint[1]) { + default: + return false; + case 'm': + // 'Ym' is synonymous with 'y'. + case 'k': + return Size <= 64; + case 'z': + // XMM0/YMM/ZMM0 + if (hasFeatureEnabled(FeatureMap, "avx512f")) + // ZMM0 can be used if target supports AVX512F. + return Size <= 512U; + else if (hasFeatureEnabled(FeatureMap, "avx")) + // YMM0 can be used if target supports AVX. + return Size <= 256U; + else if (hasFeatureEnabled(FeatureMap, "sse")) + return Size <= 128U; + return false; + case 'i': + case 't': + case '2': + // 'Yi','Yt','Y2' are synonymous with 'x' when SSE2 is enabled. + if (SSELevel < SSE2) + return false; + break; + } + break; + case 'v': + case 'x': + if (hasFeatureEnabled(FeatureMap, "avx512f")) + // 512-bit zmm registers can be used if target supports AVX512F. + return Size <= 512U; + else if (hasFeatureEnabled(FeatureMap, "avx")) + // 256-bit ymm registers can be used if target supports AVX. + return Size <= 256U; + return Size <= 128U; + + } + + return true; +} + +std::string X86TargetInfo::convertConstraint(const char *&Constraint) const { + switch (*Constraint) { + case '@': + if (auto Len = matchAsmCCConstraint(Constraint)) { + std::string Converted = "{" + std::string(Constraint, Len) + "}"; + Constraint += Len - 1; + return Converted; + } + return std::string(1, *Constraint); + case 'a': + return std::string("{ax}"); + case 'b': + return std::string("{bx}"); + case 'c': + return std::string("{cx}"); + case 'd': + return std::string("{dx}"); + case 'S': + return std::string("{si}"); + case 'D': + return std::string("{di}"); + case 'p': // address + return std::string("im"); + case 't': // top of floating point stack. + return std::string("{st}"); + case 'u': // second from top of floating point stack. + return std::string("{st(1)}"); // second from top of floating point stack. + case 'Y': + switch (Constraint[1]) { + default: + // Break from inner switch and fall through (copy single char), + // continue parsing after copying the current constraint into + // the return string. + break; + case 'k': + case 'm': + case 'i': + case 't': + case 'z': + case '2': + // "^" hints llvm that this is a 2 letter constraint. + // "Constraint++" is used to promote the string iterator + // to the next constraint. + return std::string("^") + std::string(Constraint++, 2); + } + LLVM_FALLTHROUGH; + default: + return std::string(1, *Constraint); + } +} + +void X86TargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const { + bool Only64Bit = getTriple().getArch() != llvm::Triple::x86; + llvm::X86::fillValidCPUArchList(Values, Only64Bit); +} + +void X86TargetInfo::fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) const { + llvm::X86::fillValidTuneCPUList(Values); +} + +ArrayRef<const char *> X86TargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +ArrayRef<TargetInfo::AddlRegName> X86TargetInfo::getGCCAddlRegNames() const { + return llvm::makeArrayRef(AddlRegNames); +} + +ArrayRef<Builtin::Info> X86_32TargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfoX86, clang::X86::LastX86CommonBuiltin - + Builtin::FirstTSBuiltin + 1); +} + +ArrayRef<Builtin::Info> X86_64TargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfoX86, + X86::LastTSBuiltin - Builtin::FirstTSBuiltin); +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/X86.h b/contrib/llvm-project/clang/lib/Basic/Targets/X86.h new file mode 100644 index 000000000000..d1b66432e38b --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/X86.h @@ -0,0 +1,936 @@ +//===--- X86.h - Declare X86 target feature support -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares X86 TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_X86_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_X86_H + +#include "OSTargets.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/X86TargetParser.h" + +namespace clang { +namespace targets { + +static const unsigned X86AddrSpaceMap[] = { + 0, // Default + 0, // opencl_global + 0, // opencl_local + 0, // opencl_constant + 0, // opencl_private + 0, // opencl_generic + 0, // opencl_global_device + 0, // opencl_global_host + 0, // cuda_device + 0, // cuda_constant + 0, // cuda_shared + 0, // sycl_global + 0, // sycl_global_device + 0, // sycl_global_host + 0, // sycl_local + 0, // sycl_private + 270, // ptr32_sptr + 271, // ptr32_uptr + 272 // ptr64 +}; + +// X86 target abstract base class; x86-32 and x86-64 are very close, so +// most of the implementation can be shared. +class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo { + + enum X86SSEEnum { + NoSSE, + SSE1, + SSE2, + SSE3, + SSSE3, + SSE41, + SSE42, + AVX, + AVX2, + AVX512F + } SSELevel = NoSSE; + enum MMX3DNowEnum { + NoMMX3DNow, + MMX, + AMD3DNow, + AMD3DNowAthlon + } MMX3DNowLevel = NoMMX3DNow; + enum XOPEnum { NoXOP, SSE4A, FMA4, XOP } XOPLevel = NoXOP; + enum AddrSpace { ptr32_sptr = 270, ptr32_uptr = 271, ptr64 = 272 }; + + bool HasAES = false; + bool HasVAES = false; + bool HasPCLMUL = false; + bool HasVPCLMULQDQ = false; + bool HasGFNI = false; + bool HasLZCNT = false; + bool HasRDRND = false; + bool HasFSGSBASE = false; + bool HasBMI = false; + bool HasBMI2 = false; + bool HasPOPCNT = false; + bool HasRTM = false; + bool HasPRFCHW = false; + bool HasRDSEED = false; + bool HasADX = false; + bool HasTBM = false; + bool HasLWP = false; + bool HasFMA = false; + bool HasF16C = false; + bool HasAVX512CD = false; + bool HasAVX512VPOPCNTDQ = false; + bool HasAVX512VNNI = false; + bool HasAVX512FP16 = false; + bool HasAVX512BF16 = false; + bool HasAVX512ER = false; + bool HasAVX512PF = false; + bool HasAVX512DQ = false; + bool HasAVX512BITALG = false; + bool HasAVX512BW = false; + bool HasAVX512VL = false; + bool HasAVX512VBMI = false; + bool HasAVX512VBMI2 = false; + bool HasAVX512IFMA = false; + bool HasAVX512VP2INTERSECT = false; + bool HasSHA = false; + bool HasSHSTK = false; + bool HasSGX = false; + bool HasCX8 = false; + bool HasCX16 = false; + bool HasFXSR = false; + bool HasXSAVE = false; + bool HasXSAVEOPT = false; + bool HasXSAVEC = false; + bool HasXSAVES = false; + bool HasMWAITX = false; + bool HasCLZERO = false; + bool HasCLDEMOTE = false; + bool HasPCONFIG = false; + bool HasPKU = false; + bool HasCLFLUSHOPT = false; + bool HasCLWB = false; + bool HasMOVBE = false; + bool HasPREFETCHWT1 = false; + bool HasRDPID = false; + bool HasRetpolineExternalThunk = false; + bool HasLAHFSAHF = false; + bool HasWBNOINVD = false; + bool HasWAITPKG = false; + bool HasMOVDIRI = false; + bool HasMOVDIR64B = false; + bool HasPTWRITE = false; + bool HasINVPCID = false; + bool HasENQCMD = false; + bool HasKL = false; // For key locker + bool HasWIDEKL = false; // For wide key locker + bool HasHRESET = false; + bool HasAVXVNNI = false; + bool HasAMXTILE = false; + bool HasAMXINT8 = false; + bool HasAMXBF16 = false; + bool HasSERIALIZE = false; + bool HasTSXLDTRK = false; + bool HasUINTR = false; + bool HasCRC32 = false; + bool HasX87 = false; + +protected: + llvm::X86::CPUKind CPU = llvm::X86::CK_None; + + enum FPMathKind { FP_Default, FP_SSE, FP_387 } FPMath = FP_Default; + +public: + X86TargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + LongDoubleFormat = &llvm::APFloat::x87DoubleExtended(); + AddrSpaceMap = &X86AddrSpaceMap; + HasStrictFP = true; + + bool IsWinCOFF = + getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF(); + if (IsWinCOFF) + MaxVectorAlign = MaxTLSAlign = 8192u * getCharWidth(); + } + + const char *getLongDoubleMangling() const override { + return LongDoubleFormat == &llvm::APFloat::IEEEquad() ? "g" : "e"; + } + + unsigned getFloatEvalMethod() const override { + // X87 evaluates with 80 bits "long double" precision. + return SSELevel == NoSSE ? 2 : 0; + } + + ArrayRef<const char *> getGCCRegNames() const override; + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; + } + + ArrayRef<TargetInfo::AddlRegName> getGCCAddlRegNames() const override; + + bool isSPRegName(StringRef RegName) const override { + return RegName.equals("esp") || RegName.equals("rsp"); + } + + bool validateCpuSupports(StringRef Name) const override; + + bool validateCpuIs(StringRef Name) const override; + + bool validateCPUSpecificCPUDispatch(StringRef Name) const override; + + char CPUSpecificManglingCharacter(StringRef Name) const override; + + void getCPUSpecificCPUDispatchFeatures( + StringRef Name, + llvm::SmallVectorImpl<StringRef> &Features) const override; + + Optional<unsigned> getCPUCacheLineSize() const override; + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override; + + bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize, + bool &HasSizeMismatch) const override { + // esp and ebp are the only 32-bit registers the x86 backend can currently + // handle. + if (RegName.equals("esp") || RegName.equals("ebp")) { + // Check that the register size is 32-bit. + HasSizeMismatch = RegSize != 32; + return true; + } + + return false; + } + + bool validateOutputSize(const llvm::StringMap<bool> &FeatureMap, + StringRef Constraint, unsigned Size) const override; + + bool validateInputSize(const llvm::StringMap<bool> &FeatureMap, + StringRef Constraint, unsigned Size) const override; + + virtual bool + checkCFProtectionReturnSupported(DiagnosticsEngine &Diags) const override { + return true; + }; + + virtual bool + checkCFProtectionBranchSupported(DiagnosticsEngine &Diags) const override { + return true; + }; + + virtual bool validateOperandSize(const llvm::StringMap<bool> &FeatureMap, + StringRef Constraint, unsigned Size) const; + + std::string convertConstraint(const char *&Constraint) const override; + const char *getClobbers() const override { + return "~{dirflag},~{fpsr},~{flags}"; + } + + StringRef getConstraintRegister(StringRef Constraint, + StringRef Expression) const override { + StringRef::iterator I, E; + for (I = Constraint.begin(), E = Constraint.end(); I != E; ++I) { + if (isalpha(*I) || *I == '@') + break; + } + if (I == E) + return ""; + switch (*I) { + // For the register constraints, return the matching register name + case 'a': + return "ax"; + case 'b': + return "bx"; + case 'c': + return "cx"; + case 'd': + return "dx"; + case 'S': + return "si"; + case 'D': + return "di"; + // In case the constraint is 'r' we need to return Expression + case 'r': + return Expression; + // Double letters Y<x> constraints + case 'Y': + if ((++I != E) && ((*I == '0') || (*I == 'z'))) + return "xmm0"; + break; + default: + break; + } + return ""; + } + + bool useFP16ConversionIntrinsics() const override { + return false; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + void setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name, + bool Enabled) const final; + + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override; + + bool isValidFeatureName(StringRef Name) const override; + + bool hasFeature(StringRef Feature) const final; + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override; + + StringRef getABI() const override { + if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX512F) + return "avx512"; + if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX) + return "avx"; + if (getTriple().getArch() == llvm::Triple::x86 && + MMX3DNowLevel == NoMMX3DNow) + return "no-mmx"; + return ""; + } + + bool supportsTargetAttributeTune() const override { + return true; + } + + bool isValidCPUName(StringRef Name) const override { + bool Only64Bit = getTriple().getArch() != llvm::Triple::x86; + return llvm::X86::parseArchX86(Name, Only64Bit) != llvm::X86::CK_None; + } + + bool isValidTuneCPUName(StringRef Name) const override { + if (Name == "generic") + return true; + + // Allow 32-bit only CPUs regardless of 64-bit mode unlike isValidCPUName. + // NOTE: gcc rejects 32-bit mtune CPUs in 64-bit mode. But being lenient + // since mtune was ignored by clang for so long. + return llvm::X86::parseTuneCPU(Name) != llvm::X86::CK_None; + } + + void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; + void fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) const override; + + bool setCPU(const std::string &Name) override { + bool Only64Bit = getTriple().getArch() != llvm::Triple::x86; + CPU = llvm::X86::parseArchX86(Name, Only64Bit); + return CPU != llvm::X86::CK_None; + } + + unsigned multiVersionSortPriority(StringRef Name) const override; + + bool setFPMath(StringRef Name) override; + + bool supportsExtendIntArgs() const override { + return getTriple().getArch() != llvm::Triple::x86; + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + // Most of the non-ARM calling conventions are i386 conventions. + switch (CC) { + case CC_X86ThisCall: + case CC_X86FastCall: + case CC_X86StdCall: + case CC_X86VectorCall: + case CC_X86RegCall: + case CC_C: + case CC_PreserveMost: + case CC_Swift: + case CC_X86Pascal: + case CC_IntelOclBicc: + case CC_OpenCLKernel: + return CCCR_OK; + case CC_SwiftAsync: + return CCCR_Error; + default: + return CCCR_Warning; + } + } + + bool checkArithmeticFenceSupported() const override { return true; } + + CallingConv getDefaultCallingConv() const override { + return CC_C; + } + + bool hasSjLjLowering() const override { return true; } + + void setSupportedOpenCLOpts() override { supportAllOpenCLOpts(); } + + uint64_t getPointerWidthV(unsigned AddrSpace) const override { + if (AddrSpace == ptr32_sptr || AddrSpace == ptr32_uptr) + return 32; + if (AddrSpace == ptr64) + return 64; + return PointerWidth; + } + + uint64_t getPointerAlignV(unsigned AddrSpace) const override { + return getPointerWidthV(AddrSpace); + } +}; + +// X86-32 generic target +class LLVM_LIBRARY_VISIBILITY X86_32TargetInfo : public X86TargetInfo { +public: + X86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : X86TargetInfo(Triple, Opts) { + DoubleAlign = LongLongAlign = 32; + LongDoubleWidth = 96; + LongDoubleAlign = 32; + SuitableAlign = 128; + resetDataLayout( + Triple.isOSBinFormatMachO() + ? "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-" + "f80:32-n8:16:32-S128" + : "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-" + "f80:32-n8:16:32-S128", + Triple.isOSBinFormatMachO() ? "_" : ""); + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + RegParmMax = 3; + + // Use fpret for all types. + RealTypeUsesObjCFPRet = + ((1 << (int)FloatModeKind::Float) | (1 << (int)FloatModeKind::Double) | + (1 << (int)FloatModeKind::LongDouble)); + + // x86-32 has atomics up to 8 bytes + MaxAtomicPromoteWidth = 64; + MaxAtomicInlineWidth = 32; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::CharPtrBuiltinVaList; + } + + int getEHDataRegisterNumber(unsigned RegNo) const override { + if (RegNo == 0) + return 0; + if (RegNo == 1) + return 2; + return -1; + } + + bool validateOperandSize(const llvm::StringMap<bool> &FeatureMap, + StringRef Constraint, unsigned Size) const override { + switch (Constraint[0]) { + default: + break; + case 'R': + case 'q': + case 'Q': + case 'a': + case 'b': + case 'c': + case 'd': + case 'S': + case 'D': + return Size <= 32; + case 'A': + return Size <= 64; + } + + return X86TargetInfo::validateOperandSize(FeatureMap, Constraint, Size); + } + + void setMaxAtomicWidth() override { + if (hasFeature("cx8")) + MaxAtomicInlineWidth = 64; + } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + bool hasBitIntType() const override { return true; } +}; + +class LLVM_LIBRARY_VISIBILITY NetBSDI386TargetInfo + : public NetBSDTargetInfo<X86_32TargetInfo> { +public: + NetBSDI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : NetBSDTargetInfo<X86_32TargetInfo>(Triple, Opts) {} + + unsigned getFloatEvalMethod() const override { + VersionTuple OsVersion = getTriple().getOSVersion(); + // New NetBSD uses the default rounding mode. + if (OsVersion >= VersionTuple(6, 99, 26) || OsVersion.getMajor() == 0) + return X86_32TargetInfo::getFloatEvalMethod(); + // NetBSD before 6.99.26 defaults to "double" rounding. + return 1; + } +}; + +class LLVM_LIBRARY_VISIBILITY OpenBSDI386TargetInfo + : public OpenBSDTargetInfo<X86_32TargetInfo> { +public: + OpenBSDI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OpenBSDTargetInfo<X86_32TargetInfo>(Triple, Opts) { + SizeType = UnsignedLong; + IntPtrType = SignedLong; + PtrDiffType = SignedLong; + } +}; + +class LLVM_LIBRARY_VISIBILITY DarwinI386TargetInfo + : public DarwinTargetInfo<X86_32TargetInfo> { +public: + DarwinI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : DarwinTargetInfo<X86_32TargetInfo>(Triple, Opts) { + LongDoubleWidth = 128; + LongDoubleAlign = 128; + SuitableAlign = 128; + MaxVectorAlign = 256; + // The watchOS simulator uses the builtin bool type for Objective-C. + llvm::Triple T = llvm::Triple(Triple); + if (T.isWatchOS()) + UseSignedCharForObjCBool = false; + SizeType = UnsignedLong; + IntPtrType = SignedLong; + resetDataLayout("e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-" + "f80:128-n8:16:32-S128", "_"); + HasAlignMac68kSupport = true; + } + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override { + if (!DarwinTargetInfo<X86_32TargetInfo>::handleTargetFeatures(Features, + Diags)) + return false; + // We now know the features we have: we can decide how to align vectors. + MaxVectorAlign = + hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128; + return true; + } +}; + +// x86-32 Windows target +class LLVM_LIBRARY_VISIBILITY WindowsX86_32TargetInfo + : public WindowsTargetInfo<X86_32TargetInfo> { +public: + WindowsX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : WindowsTargetInfo<X86_32TargetInfo>(Triple, Opts) { + DoubleAlign = LongLongAlign = 64; + bool IsWinCOFF = + getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF(); + bool IsMSVC = getTriple().isWindowsMSVCEnvironment(); + std::string Layout = IsWinCOFF ? "e-m:x" : "e-m:e"; + Layout += "-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-"; + Layout += IsMSVC ? "f80:128" : "f80:32"; + Layout += "-n8:16:32-a:0:32-S32"; + resetDataLayout(Layout, IsWinCOFF ? "_" : ""); + } +}; + +// x86-32 Windows Visual Studio target +class LLVM_LIBRARY_VISIBILITY MicrosoftX86_32TargetInfo + : public WindowsX86_32TargetInfo { +public: + MicrosoftX86_32TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : WindowsX86_32TargetInfo(Triple, Opts) { + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder); + // The value of the following reflects processor type. + // 300=386, 400=486, 500=Pentium, 600=Blend (default) + // We lost the original triple, so we use the default. + Builder.defineMacro("_M_IX86", "600"); + } +}; + +// x86-32 MinGW target +class LLVM_LIBRARY_VISIBILITY MinGWX86_32TargetInfo + : public WindowsX86_32TargetInfo { +public: + MinGWX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : WindowsX86_32TargetInfo(Triple, Opts) { + HasFloat128 = true; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("_X86_"); + } +}; + +// x86-32 Cygwin target +class LLVM_LIBRARY_VISIBILITY CygwinX86_32TargetInfo : public X86_32TargetInfo { +public: + CygwinX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : X86_32TargetInfo(Triple, Opts) { + this->WCharType = TargetInfo::UnsignedShort; + DoubleAlign = LongLongAlign = 64; + resetDataLayout("e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:" + "32-n8:16:32-a:0:32-S32", + "_"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + X86_32TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("_X86_"); + Builder.defineMacro("__CYGWIN__"); + Builder.defineMacro("__CYGWIN32__"); + addCygMingDefines(Opts, Builder); + DefineStd(Builder, "unix", Opts); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + } +}; + +// x86-32 Haiku target +class LLVM_LIBRARY_VISIBILITY HaikuX86_32TargetInfo + : public HaikuTargetInfo<X86_32TargetInfo> { +public: + HaikuX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : HaikuTargetInfo<X86_32TargetInfo>(Triple, Opts) {} + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + HaikuTargetInfo<X86_32TargetInfo>::getTargetDefines(Opts, Builder); + Builder.defineMacro("__INTEL__"); + } +}; + +// X86-32 MCU target +class LLVM_LIBRARY_VISIBILITY MCUX86_32TargetInfo : public X86_32TargetInfo { +public: + MCUX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : X86_32TargetInfo(Triple, Opts) { + LongDoubleWidth = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + resetDataLayout("e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:32-f64:" + "32-f128:32-n8:16:32-a:0:32-S32"); + WIntType = UnsignedInt; + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + // On MCU we support only C calling convention. + return CC == CC_C ? CCCR_OK : CCCR_Warning; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + X86_32TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__iamcu"); + Builder.defineMacro("__iamcu__"); + } + + bool allowsLargerPreferedTypeAlignment() const override { return false; } +}; + +// x86-32 RTEMS target +class LLVM_LIBRARY_VISIBILITY RTEMSX86_32TargetInfo : public X86_32TargetInfo { +public: + RTEMSX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : X86_32TargetInfo(Triple, Opts) { + SizeType = UnsignedLong; + IntPtrType = SignedLong; + PtrDiffType = SignedLong; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + X86_32TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__INTEL__"); + Builder.defineMacro("__rtems__"); + } +}; + +// x86-64 generic target +class LLVM_LIBRARY_VISIBILITY X86_64TargetInfo : public X86TargetInfo { +public: + X86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : X86TargetInfo(Triple, Opts) { + const bool IsX32 = getTriple().isX32(); + bool IsWinCOFF = + getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF(); + LongWidth = LongAlign = PointerWidth = PointerAlign = IsX32 ? 32 : 64; + LongDoubleWidth = 128; + LongDoubleAlign = 128; + LargeArrayMinWidth = 128; + LargeArrayAlign = 128; + SuitableAlign = 128; + SizeType = IsX32 ? UnsignedInt : UnsignedLong; + PtrDiffType = IsX32 ? SignedInt : SignedLong; + IntPtrType = IsX32 ? SignedInt : SignedLong; + IntMaxType = IsX32 ? SignedLongLong : SignedLong; + Int64Type = IsX32 ? SignedLongLong : SignedLong; + RegParmMax = 6; + + // Pointers are 32-bit in x32. + resetDataLayout(IsX32 ? "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-" + "i64:64-f80:128-n8:16:32:64-S128" + : IsWinCOFF ? "e-m:w-p270:32:32-p271:32:32-p272:64:" + "64-i64:64-f80:128-n8:16:32:64-S128" + : "e-m:e-p270:32:32-p271:32:32-p272:64:" + "64-i64:64-f80:128-n8:16:32:64-S128"); + + // Use fpret only for long double. + RealTypeUsesObjCFPRet = (1 << (int)FloatModeKind::LongDouble); + + // Use fp2ret for _Complex long double. + ComplexLongDoubleUsesFP2Ret = true; + + // Make __builtin_ms_va_list available. + HasBuiltinMSVaList = true; + + // x86-64 has atomics up to 16 bytes. + MaxAtomicPromoteWidth = 128; + MaxAtomicInlineWidth = 64; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::X86_64ABIBuiltinVaList; + } + + int getEHDataRegisterNumber(unsigned RegNo) const override { + if (RegNo == 0) + return 0; + if (RegNo == 1) + return 1; + return -1; + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + switch (CC) { + case CC_C: + case CC_Swift: + case CC_SwiftAsync: + case CC_X86VectorCall: + case CC_IntelOclBicc: + case CC_Win64: + case CC_PreserveMost: + case CC_PreserveAll: + case CC_X86RegCall: + case CC_OpenCLKernel: + return CCCR_OK; + default: + return CCCR_Warning; + } + } + + CallingConv getDefaultCallingConv() const override { + return CC_C; + } + + // for x32 we need it here explicitly + bool hasInt128Type() const override { return true; } + + unsigned getUnwindWordWidth() const override { return 64; } + + unsigned getRegisterWidth() const override { return 64; } + + bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize, + bool &HasSizeMismatch) const override { + // rsp and rbp are the only 64-bit registers the x86 backend can currently + // handle. + if (RegName.equals("rsp") || RegName.equals("rbp")) { + // Check that the register size is 64-bit. + HasSizeMismatch = RegSize != 64; + return true; + } + + // Check if the register is a 32-bit register the backend can handle. + return X86TargetInfo::validateGlobalRegisterVariable(RegName, RegSize, + HasSizeMismatch); + } + + void setMaxAtomicWidth() override { + if (hasFeature("cx16")) + MaxAtomicInlineWidth = 128; + } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + bool hasBitIntType() const override { return true; } +}; + +// x86-64 Windows target +class LLVM_LIBRARY_VISIBILITY WindowsX86_64TargetInfo + : public WindowsTargetInfo<X86_64TargetInfo> { +public: + WindowsX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : WindowsTargetInfo<X86_64TargetInfo>(Triple, Opts) { + LongWidth = LongAlign = 32; + DoubleAlign = LongLongAlign = 64; + IntMaxType = SignedLongLong; + Int64Type = SignedLongLong; + SizeType = UnsignedLongLong; + PtrDiffType = SignedLongLong; + IntPtrType = SignedLongLong; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::CharPtrBuiltinVaList; + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + switch (CC) { + case CC_X86StdCall: + case CC_X86ThisCall: + case CC_X86FastCall: + return CCCR_Ignore; + case CC_C: + case CC_X86VectorCall: + case CC_IntelOclBicc: + case CC_PreserveMost: + case CC_PreserveAll: + case CC_X86_64SysV: + case CC_Swift: + case CC_SwiftAsync: + case CC_X86RegCall: + case CC_OpenCLKernel: + return CCCR_OK; + default: + return CCCR_Warning; + } + } +}; + +// x86-64 Windows Visual Studio target +class LLVM_LIBRARY_VISIBILITY MicrosoftX86_64TargetInfo + : public WindowsX86_64TargetInfo { +public: + MicrosoftX86_64TargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : WindowsX86_64TargetInfo(Triple, Opts) { + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("_M_X64", "100"); + Builder.defineMacro("_M_AMD64", "100"); + } + + TargetInfo::CallingConvKind + getCallingConvKind(bool ClangABICompat4) const override { + return CCK_MicrosoftWin64; + } +}; + +// x86-64 MinGW target +class LLVM_LIBRARY_VISIBILITY MinGWX86_64TargetInfo + : public WindowsX86_64TargetInfo { +public: + MinGWX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : WindowsX86_64TargetInfo(Triple, Opts) { + // Mingw64 rounds long double size and alignment up to 16 bytes, but sticks + // with x86 FP ops. Weird. + LongDoubleWidth = LongDoubleAlign = 128; + LongDoubleFormat = &llvm::APFloat::x87DoubleExtended(); + HasFloat128 = true; + } +}; + +// x86-64 Cygwin target +class LLVM_LIBRARY_VISIBILITY CygwinX86_64TargetInfo : public X86_64TargetInfo { +public: + CygwinX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : X86_64TargetInfo(Triple, Opts) { + this->WCharType = TargetInfo::UnsignedShort; + TLSSupported = false; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + X86_64TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__x86_64__"); + Builder.defineMacro("__CYGWIN__"); + Builder.defineMacro("__CYGWIN64__"); + addCygMingDefines(Opts, Builder); + DefineStd(Builder, "unix", Opts); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + } +}; + +class LLVM_LIBRARY_VISIBILITY DarwinX86_64TargetInfo + : public DarwinTargetInfo<X86_64TargetInfo> { +public: + DarwinX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : DarwinTargetInfo<X86_64TargetInfo>(Triple, Opts) { + Int64Type = SignedLongLong; + // The 64-bit iOS simulator uses the builtin bool type for Objective-C. + llvm::Triple T = llvm::Triple(Triple); + if (T.isiOS()) + UseSignedCharForObjCBool = false; + resetDataLayout("e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:" + "16:32:64-S128", "_"); + } + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override { + if (!DarwinTargetInfo<X86_64TargetInfo>::handleTargetFeatures(Features, + Diags)) + return false; + // We now know the features we have: we can decide how to align vectors. + MaxVectorAlign = + hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128; + return true; + } +}; + +class LLVM_LIBRARY_VISIBILITY OpenBSDX86_64TargetInfo + : public OpenBSDTargetInfo<X86_64TargetInfo> { +public: + OpenBSDX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OpenBSDTargetInfo<X86_64TargetInfo>(Triple, Opts) { + IntMaxType = SignedLongLong; + Int64Type = SignedLongLong; + } +}; + +// x86_32 Android target +class LLVM_LIBRARY_VISIBILITY AndroidX86_32TargetInfo + : public LinuxTargetInfo<X86_32TargetInfo> { +public: + AndroidX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : LinuxTargetInfo<X86_32TargetInfo>(Triple, Opts) { + SuitableAlign = 32; + LongDoubleWidth = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + } +}; + +// x86_64 Android target +class LLVM_LIBRARY_VISIBILITY AndroidX86_64TargetInfo + : public LinuxTargetInfo<X86_64TargetInfo> { +public: + AndroidX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : LinuxTargetInfo<X86_64TargetInfo>(Triple, Opts) { + LongDoubleFormat = &llvm::APFloat::IEEEquad(); + } +}; +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_X86_H diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/XCore.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/XCore.cpp new file mode 100644 index 000000000000..ba64f15f3394 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/XCore.cpp @@ -0,0 +1,38 @@ +//===--- XCore.cpp - Implement XCore target feature support ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements XCore TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "XCore.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" + +using namespace clang; +using namespace clang::targets; + +const Builtin::Info XCoreTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsXCore.def" +}; + +void XCoreTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__xcore__"); + Builder.defineMacro("__XS1B__"); +} + +ArrayRef<Builtin::Info> XCoreTargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::XCore::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/XCore.h b/contrib/llvm-project/clang/lib/Basic/Targets/XCore.h new file mode 100644 index 000000000000..25f20581839d --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/XCore.h @@ -0,0 +1,83 @@ +//===--- XCore.h - Declare XCore target feature support ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares XCore TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_XCORE_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_XCORE_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY XCoreTargetInfo : public TargetInfo { + static const Builtin::Info BuiltinInfo[]; + +public: + XCoreTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + NoAsmVariants = true; + LongLongAlign = 32; + SuitableAlign = 32; + DoubleAlign = LongDoubleAlign = 32; + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + WCharType = UnsignedChar; + WIntType = UnsignedInt; + UseZeroLengthBitfieldAlignment = true; + resetDataLayout("e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:32" + "-f64:32-a:0:32-n32"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + const char *getClobbers() const override { return ""; } + + ArrayRef<const char *> getGCCRegNames() const override { + static const char *const GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "cp", "dp", "sp", "lr" + }; + return llvm::makeArrayRef(GCCRegNames); + } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + return false; + } + + int getEHDataRegisterNumber(unsigned RegNo) const override { + // R0=ExceptionPointerRegister R1=ExceptionSelectorRegister + return (RegNo < 2) ? RegNo : -1; + } + + bool allowsLargerPreferedTypeAlignment() const override { return false; } + + bool hasBitIntType() const override { return true; } +}; +} // namespace targets +} // namespace clang +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_XCORE_H diff --git a/contrib/llvm-project/clang/lib/Basic/TokenKinds.cpp b/contrib/llvm-project/clang/lib/Basic/TokenKinds.cpp new file mode 100644 index 000000000000..d55e176c72c4 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/TokenKinds.cpp @@ -0,0 +1,67 @@ +//===--- TokenKinds.cpp - Token Kinds Support -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the TokenKind enum and support functions. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/TokenKinds.h" +#include "llvm/Support/ErrorHandling.h" +using namespace clang; + +static const char * const TokNames[] = { +#define TOK(X) #X, +#define KEYWORD(X,Y) #X, +#include "clang/Basic/TokenKinds.def" + nullptr +}; + +const char *tok::getTokenName(TokenKind Kind) { + if (Kind < tok::NUM_TOKENS) + return TokNames[Kind]; + llvm_unreachable("unknown TokenKind"); + return nullptr; +} + +const char *tok::getPunctuatorSpelling(TokenKind Kind) { + switch (Kind) { +#define PUNCTUATOR(X,Y) case X: return Y; +#include "clang/Basic/TokenKinds.def" + default: break; + } + return nullptr; +} + +const char *tok::getKeywordSpelling(TokenKind Kind) { + switch (Kind) { +#define KEYWORD(X,Y) case kw_ ## X: return #X; +#include "clang/Basic/TokenKinds.def" + default: break; + } + return nullptr; +} + +bool tok::isAnnotation(TokenKind Kind) { + switch (Kind) { +#define ANNOTATION(X) case annot_ ## X: return true; +#include "clang/Basic/TokenKinds.def" + default: + break; + } + return false; +} + +bool tok::isPragmaAnnotation(TokenKind Kind) { + switch (Kind) { +#define PRAGMA_ANNOTATION(X) case annot_ ## X: return true; +#include "clang/Basic/TokenKinds.def" + default: + break; + } + return false; +} diff --git a/contrib/llvm-project/clang/lib/Basic/TypeTraits.cpp b/contrib/llvm-project/clang/lib/Basic/TypeTraits.cpp new file mode 100644 index 000000000000..3b723afff70b --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/TypeTraits.cpp @@ -0,0 +1,86 @@ +//===--- TypeTraits.cpp - Type Traits Support -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the type traits support functions. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/TypeTraits.h" +#include "llvm/Support/ErrorHandling.h" +#include <cassert> +using namespace clang; + +static constexpr const char *TypeTraitNames[] = { +#define TYPE_TRAIT_1(Spelling, Name, Key) #Name, +#include "clang/Basic/TokenKinds.def" +#define TYPE_TRAIT_2(Spelling, Name, Key) #Name, +#include "clang/Basic/TokenKinds.def" +#define TYPE_TRAIT_N(Spelling, Name, Key) #Name, +#include "clang/Basic/TokenKinds.def" +}; + +static constexpr const char *TypeTraitSpellings[] = { +#define TYPE_TRAIT_1(Spelling, Name, Key) #Spelling, +#include "clang/Basic/TokenKinds.def" +#define TYPE_TRAIT_2(Spelling, Name, Key) #Spelling, +#include "clang/Basic/TokenKinds.def" +#define TYPE_TRAIT_N(Spelling, Name, Key) #Spelling, +#include "clang/Basic/TokenKinds.def" +}; + +static constexpr const char *ArrayTypeTraitNames[] = { +#define ARRAY_TYPE_TRAIT(Spelling, Name, Key) #Name, +#include "clang/Basic/TokenKinds.def" +}; + +static constexpr const char *ArrayTypeTraitSpellings[] = { +#define ARRAY_TYPE_TRAIT(Spelling, Name, Key) #Spelling, +#include "clang/Basic/TokenKinds.def" +}; + +static constexpr const char *UnaryExprOrTypeTraitNames[] = { +#define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) #Name, +#define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) #Name, +#include "clang/Basic/TokenKinds.def" +}; + +static constexpr const char *UnaryExprOrTypeTraitSpellings[] = { +#define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) #Spelling, +#define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) #Spelling, +#include "clang/Basic/TokenKinds.def" +}; + +const char *clang::getTraitName(TypeTrait T) { + assert(T <= TT_Last && "invalid enum value!"); + return TypeTraitNames[T]; +} + +const char *clang::getTraitName(ArrayTypeTrait T) { + assert(T <= ATT_Last && "invalid enum value!"); + return ArrayTypeTraitNames[T]; +} + +const char *clang::getTraitName(UnaryExprOrTypeTrait T) { + assert(T <= UETT_Last && "invalid enum value!"); + return UnaryExprOrTypeTraitNames[T]; +} + +const char *clang::getTraitSpelling(TypeTrait T) { + assert(T <= TT_Last && "invalid enum value!"); + return TypeTraitSpellings[T]; +} + +const char *clang::getTraitSpelling(ArrayTypeTrait T) { + assert(T <= ATT_Last && "invalid enum value!"); + return ArrayTypeTraitSpellings[T]; +} + +const char *clang::getTraitSpelling(UnaryExprOrTypeTrait T) { + assert(T <= UETT_Last && "invalid enum value!"); + return UnaryExprOrTypeTraitSpellings[T]; +} diff --git a/contrib/llvm-project/clang/lib/Basic/Version.cpp b/contrib/llvm-project/clang/lib/Basic/Version.cpp new file mode 100644 index 000000000000..e205da7adec1 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Version.cpp @@ -0,0 +1,126 @@ +//===- Version.cpp - Clang Version Number -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines several version-related utility functions for Clang. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Version.h" +#include "clang/Basic/LLVM.h" +#include "clang/Config/config.h" +#include "llvm/Support/raw_ostream.h" +#include <cstdlib> +#include <cstring> + +#include "VCSVersion.inc" + +namespace clang { + +std::string getClangRepositoryPath() { +#if defined(CLANG_REPOSITORY_STRING) + return CLANG_REPOSITORY_STRING; +#else +#ifdef CLANG_REPOSITORY + return CLANG_REPOSITORY; +#else + return ""; +#endif +#endif +} + +std::string getLLVMRepositoryPath() { +#ifdef LLVM_REPOSITORY + return LLVM_REPOSITORY; +#else + return ""; +#endif +} + +std::string getClangRevision() { +#ifdef CLANG_REVISION + return CLANG_REVISION; +#else + return ""; +#endif +} + +std::string getLLVMRevision() { +#ifdef LLVM_REVISION + return LLVM_REVISION; +#else + return ""; +#endif +} + +std::string getClangFullRepositoryVersion() { + std::string buf; + llvm::raw_string_ostream OS(buf); + std::string Path = getClangRepositoryPath(); + std::string Revision = getClangRevision(); + if (!Path.empty() || !Revision.empty()) { + OS << '('; + if (!Path.empty()) + OS << Path; + if (!Revision.empty()) { + if (!Path.empty()) + OS << ' '; + OS << Revision; + } + OS << ')'; + } + // Support LLVM in a separate repository. + std::string LLVMRev = getLLVMRevision(); + if (!LLVMRev.empty() && LLVMRev != Revision) { + OS << " ("; + std::string LLVMRepo = getLLVMRepositoryPath(); + if (!LLVMRepo.empty()) + OS << LLVMRepo << ' '; + OS << LLVMRev << ')'; + } + return buf; +} + +std::string getClangFullVersion() { + return getClangToolFullVersion("clang"); +} + +std::string getClangToolFullVersion(StringRef ToolName) { + std::string buf; + llvm::raw_string_ostream OS(buf); +#ifdef CLANG_VENDOR + OS << CLANG_VENDOR; +#endif + OS << ToolName << " version " CLANG_VERSION_STRING; + + std::string repo = getClangFullRepositoryVersion(); + if (!repo.empty()) { + OS << " " << repo; + } + + return buf; +} + +std::string getClangFullCPPVersion() { + // The version string we report in __VERSION__ is just a compacted version of + // the one we report on the command line. + std::string buf; + llvm::raw_string_ostream OS(buf); +#ifdef CLANG_VENDOR + OS << CLANG_VENDOR; +#endif + OS << "Clang " CLANG_VERSION_STRING; + + std::string repo = getClangFullRepositoryVersion(); + if (!repo.empty()) { + OS << " " << repo; + } + + return buf; +} + +} // end namespace clang diff --git a/contrib/llvm-project/clang/lib/Basic/Warnings.cpp b/contrib/llvm-project/clang/lib/Basic/Warnings.cpp new file mode 100644 index 000000000000..cc8c138233ca --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Warnings.cpp @@ -0,0 +1,233 @@ +//===--- Warnings.cpp - C-Language Front-end ------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Command line warning options handler. +// +//===----------------------------------------------------------------------===// +// +// This file is responsible for handling all warning options. This includes +// a number of -Wfoo options and their variants, which are driven by TableGen- +// generated data, and the special cases -pedantic, -pedantic-errors, -w, +// -Werror and -Wfatal-errors. +// +// Each warning option controls any number of actual warnings. +// Given a warning option 'foo', the following are valid: +// -Wfoo, -Wno-foo, -Werror=foo, -Wfatal-errors=foo +// +// Remark options are also handled here, analogously, except that they are much +// simpler because a remark can't be promoted to an error. +#include "clang/Basic/AllDiagnostics.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include <algorithm> +#include <cstring> +#include <utility> +using namespace clang; + +// EmitUnknownDiagWarning - Emit a warning and typo hint for unknown warning +// opts +static void EmitUnknownDiagWarning(DiagnosticsEngine &Diags, + diag::Flavor Flavor, StringRef Prefix, + StringRef Opt) { + StringRef Suggestion = DiagnosticIDs::getNearestOption(Flavor, Opt); + Diags.Report(diag::warn_unknown_diag_option) + << (Flavor == diag::Flavor::WarningOrError ? 0 : 1) + << (Prefix.str() += std::string(Opt)) << !Suggestion.empty() + << (Prefix.str() += std::string(Suggestion)); +} + +void clang::ProcessWarningOptions(DiagnosticsEngine &Diags, + const DiagnosticOptions &Opts, + bool ReportDiags) { + Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers + Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings); + Diags.setShowOverloads(Opts.getShowOverloads()); + + Diags.setElideType(Opts.ElideType); + Diags.setPrintTemplateTree(Opts.ShowTemplateTree); + Diags.setShowColors(Opts.ShowColors); + + // Handle -ferror-limit + if (Opts.ErrorLimit) + Diags.setErrorLimit(Opts.ErrorLimit); + if (Opts.TemplateBacktraceLimit) + Diags.setTemplateBacktraceLimit(Opts.TemplateBacktraceLimit); + if (Opts.ConstexprBacktraceLimit) + Diags.setConstexprBacktraceLimit(Opts.ConstexprBacktraceLimit); + + // If -pedantic or -pedantic-errors was specified, then we want to map all + // extension diagnostics onto WARNING or ERROR unless the user has futz'd + // around with them explicitly. + if (Opts.PedanticErrors) + Diags.setExtensionHandlingBehavior(diag::Severity::Error); + else if (Opts.Pedantic) + Diags.setExtensionHandlingBehavior(diag::Severity::Warning); + else + Diags.setExtensionHandlingBehavior(diag::Severity::Ignored); + + SmallVector<diag::kind, 10> _Diags; + const IntrusiveRefCntPtr< DiagnosticIDs > DiagIDs = + Diags.getDiagnosticIDs(); + // We parse the warning options twice. The first pass sets diagnostic state, + // while the second pass reports warnings/errors. This has the effect that + // we follow the more canonical "last option wins" paradigm when there are + // conflicting options. + for (unsigned Report = 0, ReportEnd = 2; Report != ReportEnd; ++Report) { + bool SetDiagnostic = (Report == 0); + + // If we've set the diagnostic state and are not reporting diagnostics then + // we're done. + if (!SetDiagnostic && !ReportDiags) + break; + + for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) { + const auto Flavor = diag::Flavor::WarningOrError; + StringRef Opt = Opts.Warnings[i]; + StringRef OrigOpt = Opts.Warnings[i]; + + // Treat -Wformat=0 as an alias for -Wno-format. + if (Opt == "format=0") + Opt = "no-format"; + + // Check to see if this warning starts with "no-", if so, this is a + // negative form of the option. + bool isPositive = true; + if (Opt.startswith("no-")) { + isPositive = false; + Opt = Opt.substr(3); + } + + // Figure out how this option affects the warning. If -Wfoo, map the + // diagnostic to a warning, if -Wno-foo, map it to ignore. + diag::Severity Mapping = + isPositive ? diag::Severity::Warning : diag::Severity::Ignored; + + // -Wsystem-headers is a special case, not driven by the option table. It + // cannot be controlled with -Werror. + if (Opt == "system-headers") { + if (SetDiagnostic) + Diags.setSuppressSystemWarnings(!isPositive); + continue; + } + + // -Weverything is a special case as well. It implicitly enables all + // warnings, including ones not explicitly in a warning group. + if (Opt == "everything") { + if (SetDiagnostic) { + if (isPositive) { + Diags.setEnableAllWarnings(true); + } else { + Diags.setEnableAllWarnings(false); + Diags.setSeverityForAll(Flavor, diag::Severity::Ignored); + } + } + continue; + } + + // -Werror/-Wno-error is a special case, not controlled by the option + // table. It also has the "specifier" form of -Werror=foo. GCC supports + // the deprecated -Werror-implicit-function-declaration which is used by + // a few projects. + if (Opt.startswith("error")) { + StringRef Specifier; + if (Opt.size() > 5) { // Specifier must be present. + if (Opt[5] != '=' && + Opt.substr(5) != "-implicit-function-declaration") { + if (Report) + Diags.Report(diag::warn_unknown_warning_specifier) + << "-Werror" << ("-W" + OrigOpt.str()); + continue; + } + Specifier = Opt.substr(6); + } + + if (Specifier.empty()) { + if (SetDiagnostic) + Diags.setWarningsAsErrors(isPositive); + continue; + } + + if (SetDiagnostic) { + // Set the warning as error flag for this specifier. + Diags.setDiagnosticGroupWarningAsError(Specifier, isPositive); + } else if (DiagIDs->getDiagnosticsInGroup(Flavor, Specifier, _Diags)) { + EmitUnknownDiagWarning(Diags, Flavor, "-Werror=", Specifier); + } + continue; + } + + // -Wfatal-errors is yet another special case. + if (Opt.startswith("fatal-errors")) { + StringRef Specifier; + if (Opt.size() != 12) { + if ((Opt[12] != '=' && Opt[12] != '-') || Opt.size() == 13) { + if (Report) + Diags.Report(diag::warn_unknown_warning_specifier) + << "-Wfatal-errors" << ("-W" + OrigOpt.str()); + continue; + } + Specifier = Opt.substr(13); + } + + if (Specifier.empty()) { + if (SetDiagnostic) + Diags.setErrorsAsFatal(isPositive); + continue; + } + + if (SetDiagnostic) { + // Set the error as fatal flag for this specifier. + Diags.setDiagnosticGroupErrorAsFatal(Specifier, isPositive); + } else if (DiagIDs->getDiagnosticsInGroup(Flavor, Specifier, _Diags)) { + EmitUnknownDiagWarning(Diags, Flavor, "-Wfatal-errors=", Specifier); + } + continue; + } + + if (Report) { + if (DiagIDs->getDiagnosticsInGroup(Flavor, Opt, _Diags)) + EmitUnknownDiagWarning(Diags, Flavor, isPositive ? "-W" : "-Wno-", + Opt); + } else { + Diags.setSeverityForGroup(Flavor, Opt, Mapping); + } + } + + for (unsigned i = 0, e = Opts.Remarks.size(); i != e; ++i) { + StringRef Opt = Opts.Remarks[i]; + const auto Flavor = diag::Flavor::Remark; + + // Check to see if this warning starts with "no-", if so, this is a + // negative form of the option. + bool IsPositive = !Opt.startswith("no-"); + if (!IsPositive) Opt = Opt.substr(3); + + auto Severity = IsPositive ? diag::Severity::Remark + : diag::Severity::Ignored; + + // -Reverything sets the state of all remarks. Note that all remarks are + // in remark groups, so we don't need a separate 'all remarks enabled' + // flag. + if (Opt == "everything") { + if (SetDiagnostic) + Diags.setSeverityForAll(Flavor, Severity); + continue; + } + + if (Report) { + if (DiagIDs->getDiagnosticsInGroup(Flavor, Opt, _Diags)) + EmitUnknownDiagWarning(Diags, Flavor, IsPositive ? "-R" : "-Rno-", + Opt); + } else { + Diags.setSeverityForGroup(Flavor, Opt, + IsPositive ? diag::Severity::Remark + : diag::Severity::Ignored); + } + } + } +} diff --git a/contrib/llvm-project/clang/lib/Basic/XRayInstr.cpp b/contrib/llvm-project/clang/lib/Basic/XRayInstr.cpp new file mode 100644 index 000000000000..822e14bbb622 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/XRayInstr.cpp @@ -0,0 +1,60 @@ +//===--- XRayInstr.cpp ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is part of XRay, a function call instrumentation system. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/XRayInstr.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringSwitch.h" + +namespace clang { + +XRayInstrMask parseXRayInstrValue(StringRef Value) { + XRayInstrMask ParsedKind = + llvm::StringSwitch<XRayInstrMask>(Value) + .Case("all", XRayInstrKind::All) + .Case("custom", XRayInstrKind::Custom) + .Case("function", + XRayInstrKind::FunctionEntry | XRayInstrKind::FunctionExit) + .Case("function-entry", XRayInstrKind::FunctionEntry) + .Case("function-exit", XRayInstrKind::FunctionExit) + .Case("typed", XRayInstrKind::Typed) + .Case("none", XRayInstrKind::None) + .Default(XRayInstrKind::None); + return ParsedKind; +} + +void serializeXRayInstrValue(XRayInstrSet Set, + SmallVectorImpl<StringRef> &Values) { + if (Set.Mask == XRayInstrKind::All) { + Values.push_back("all"); + return; + } + + if (Set.Mask == XRayInstrKind::None) { + Values.push_back("none"); + return; + } + + if (Set.has(XRayInstrKind::Custom)) + Values.push_back("custom"); + + if (Set.has(XRayInstrKind::Typed)) + Values.push_back("typed"); + + if (Set.has(XRayInstrKind::FunctionEntry) && + Set.has(XRayInstrKind::FunctionExit)) + Values.push_back("function"); + else if (Set.has(XRayInstrKind::FunctionEntry)) + Values.push_back("function-entry"); + else if (Set.has(XRayInstrKind::FunctionExit)) + Values.push_back("function-exit"); +} +} // namespace clang diff --git a/contrib/llvm-project/clang/lib/Basic/XRayLists.cpp b/contrib/llvm-project/clang/lib/Basic/XRayLists.cpp new file mode 100644 index 000000000000..6d34617d4795 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/XRayLists.cpp @@ -0,0 +1,77 @@ +//===-- XRayLists.cpp - XRay automatic-attribution ------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// User-provided filters for always/never XRay instrumenting certain functions. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/XRayLists.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Support/SpecialCaseList.h" + +using namespace clang; + +XRayFunctionFilter::XRayFunctionFilter( + ArrayRef<std::string> AlwaysInstrumentPaths, + ArrayRef<std::string> NeverInstrumentPaths, + ArrayRef<std::string> AttrListPaths, SourceManager &SM) + : AlwaysInstrument(llvm::SpecialCaseList::createOrDie( + AlwaysInstrumentPaths, SM.getFileManager().getVirtualFileSystem())), + NeverInstrument(llvm::SpecialCaseList::createOrDie( + NeverInstrumentPaths, SM.getFileManager().getVirtualFileSystem())), + AttrList(llvm::SpecialCaseList::createOrDie( + AttrListPaths, SM.getFileManager().getVirtualFileSystem())), + SM(SM) {} + +XRayFunctionFilter::~XRayFunctionFilter() = default; + +XRayFunctionFilter::ImbueAttribute +XRayFunctionFilter::shouldImbueFunction(StringRef FunctionName) const { + // First apply the always instrument list, than if it isn't an "always" see + // whether it's treated as a "never" instrument function. + // TODO: Remove these as they're deprecated; use the AttrList exclusively. + if (AlwaysInstrument->inSection("xray_always_instrument", "fun", FunctionName, + "arg1") || + AttrList->inSection("always", "fun", FunctionName, "arg1")) + return ImbueAttribute::ALWAYS_ARG1; + if (AlwaysInstrument->inSection("xray_always_instrument", "fun", + FunctionName) || + AttrList->inSection("always", "fun", FunctionName)) + return ImbueAttribute::ALWAYS; + + if (NeverInstrument->inSection("xray_never_instrument", "fun", + FunctionName) || + AttrList->inSection("never", "fun", FunctionName)) + return ImbueAttribute::NEVER; + + return ImbueAttribute::NONE; +} + +XRayFunctionFilter::ImbueAttribute +XRayFunctionFilter::shouldImbueFunctionsInFile(StringRef Filename, + StringRef Category) const { + if (AlwaysInstrument->inSection("xray_always_instrument", "src", Filename, + Category) || + AttrList->inSection("always", "src", Filename, Category)) + return ImbueAttribute::ALWAYS; + if (NeverInstrument->inSection("xray_never_instrument", "src", Filename, + Category) || + AttrList->inSection("never", "src", Filename, Category)) + return ImbueAttribute::NEVER; + return ImbueAttribute::NONE; +} + +XRayFunctionFilter::ImbueAttribute +XRayFunctionFilter::shouldImbueLocation(SourceLocation Loc, + StringRef Category) const { + if (!Loc.isValid()) + return ImbueAttribute::NONE; + return this->shouldImbueFunctionsInFile(SM.getFilename(SM.getFileLoc(Loc)), + Category); +} |