diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Basic')
76 files changed, 23272 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..9a8eb3d932cc --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Attributes.cpp @@ -0,0 +1,35 @@ +#include "clang/Basic/Attributes.h" +#include "clang/Basic/AttrSubjectMatchRules.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"; + +#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"); +} 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..d23c280d4758 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Builtins.cpp @@ -0,0 +1,194 @@ +//===--- 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(const char *Name) { + StringRef FuncName(Name); + 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 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 OclC1Unsupported = (LangOpts.OpenCLVersion / 100) != 1 && + (BuiltinInfo.Langs & ALL_OCLC_LANGUAGES ) == OCLC1X_LANG; + bool OclC2Unsupported = + (LangOpts.OpenCLVersion != 200 && !LangOpts.OpenCLCPlusPlus) && + (BuiltinInfo.Langs & ALL_OCLC_LANGUAGES) == OCLC20_LANG; + bool OclCUnsupported = !LangOpts.OpenCL && + (BuiltinInfo.Langs & ALL_OCLC_LANGUAGES); + bool OpenMPUnsupported = !LangOpts.OpenMP && BuiltinInfo.Langs == OMP_LANG; + bool CPlusPlusUnsupported = + !LangOpts.CPlusPlus && BuiltinInfo.Langs == CXX_LANG; + return !BuiltinsUnsupported && !MathBuiltinsUnsupported && !OclCUnsupported && + !OclC1Unsupported && !OclC2Unsupported && !OpenMPUnsupported && + !GnuModeUnsupported && !MSModeUnsupported && !ObjCUnsupported && + !CPlusPlusUnsupported; +} + +/// 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()); +} + +void Builtin::Context::forgetBuiltin(unsigned ID, IdentifierTable &Table) { + Table.get(getRecord(ID).Name).setBuiltinID(0); +} + +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/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..fa186380f109 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/CodeGenOptions.cpp @@ -0,0 +1,31 @@ +//===--- 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, "402*", 4); +} + +bool CodeGenOptions::isNoBuiltinFunc(const char *Name) const { + StringRef FuncName(Name); + for (unsigned i = 0, e = NoBuiltinFuncs.size(); i != e; ++i) + if (FuncName.equals(NoBuiltinFuncs[i])) + return true; + return false; +} + +} // 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..f2b6c8cd3ee9 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Cuda.cpp @@ -0,0 +1,401 @@ +#include "clang/Basic/Cuda.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.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"; + } + llvm_unreachable("invalid enum"); +} + +CudaVersion CudaStringToVersion(llvm::StringRef S) { + return llvm::StringSwitch<CudaVersion>(S) + .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); +} + +const char *CudaArchToString(CudaArch A) { + switch (A) { + case CudaArch::LAST: + break; + case CudaArch::UNKNOWN: + return "unknown"; + case CudaArch::SM_20: + return "sm_20"; + case CudaArch::SM_21: + return "sm_21"; + case CudaArch::SM_30: + return "sm_30"; + case CudaArch::SM_32: + return "sm_32"; + case CudaArch::SM_35: + return "sm_35"; + case CudaArch::SM_37: + return "sm_37"; + case CudaArch::SM_50: + return "sm_50"; + case CudaArch::SM_52: + return "sm_52"; + case CudaArch::SM_53: + return "sm_53"; + case CudaArch::SM_60: + return "sm_60"; + case CudaArch::SM_61: + return "sm_61"; + case CudaArch::SM_62: + return "sm_62"; + case CudaArch::SM_70: + return "sm_70"; + case CudaArch::SM_72: + return "sm_72"; + case CudaArch::SM_75: + return "sm_75"; + case CudaArch::GFX600: // tahiti + return "gfx600"; + case CudaArch::GFX601: // pitcairn, verde, oland,hainan + return "gfx601"; + case CudaArch::GFX700: // kaveri + return "gfx700"; + case CudaArch::GFX701: // hawaii + return "gfx701"; + case CudaArch::GFX702: // 290,290x,R390,R390x + return "gfx702"; + case CudaArch::GFX703: // kabini mullins + return "gfx703"; + case CudaArch::GFX704: // bonaire + return "gfx704"; + case CudaArch::GFX801: // carrizo + return "gfx801"; + case CudaArch::GFX802: // tonga,iceland + return "gfx802"; + case CudaArch::GFX803: // fiji,polaris10 + return "gfx803"; + case CudaArch::GFX810: // stoney + return "gfx810"; + case CudaArch::GFX900: // vega, instinct + return "gfx900"; + case CudaArch::GFX902: // TBA + return "gfx902"; + case CudaArch::GFX904: // TBA + return "gfx904"; + case CudaArch::GFX906: // TBA + return "gfx906"; + case CudaArch::GFX908: // TBA + return "gfx908"; + case CudaArch::GFX909: // TBA + return "gfx909"; + case CudaArch::GFX1010: // TBA + return "gfx1010"; + case CudaArch::GFX1011: // TBA + return "gfx1011"; + case CudaArch::GFX1012: // TBA + return "gfx1012"; + } + llvm_unreachable("invalid enum"); +} + +CudaArch StringToCudaArch(llvm::StringRef S) { + return llvm::StringSwitch<CudaArch>(S) + .Case("sm_20", CudaArch::SM_20) + .Case("sm_21", CudaArch::SM_21) + .Case("sm_30", CudaArch::SM_30) + .Case("sm_32", CudaArch::SM_32) + .Case("sm_35", CudaArch::SM_35) + .Case("sm_37", CudaArch::SM_37) + .Case("sm_50", CudaArch::SM_50) + .Case("sm_52", CudaArch::SM_52) + .Case("sm_53", CudaArch::SM_53) + .Case("sm_60", CudaArch::SM_60) + .Case("sm_61", CudaArch::SM_61) + .Case("sm_62", CudaArch::SM_62) + .Case("sm_70", CudaArch::SM_70) + .Case("sm_72", CudaArch::SM_72) + .Case("sm_75", CudaArch::SM_75) + .Case("gfx600", CudaArch::GFX600) + .Case("gfx601", CudaArch::GFX601) + .Case("gfx700", CudaArch::GFX700) + .Case("gfx701", CudaArch::GFX701) + .Case("gfx702", CudaArch::GFX702) + .Case("gfx703", CudaArch::GFX703) + .Case("gfx704", CudaArch::GFX704) + .Case("gfx801", CudaArch::GFX801) + .Case("gfx802", CudaArch::GFX802) + .Case("gfx803", CudaArch::GFX803) + .Case("gfx810", CudaArch::GFX810) + .Case("gfx900", CudaArch::GFX900) + .Case("gfx902", CudaArch::GFX902) + .Case("gfx904", CudaArch::GFX904) + .Case("gfx906", CudaArch::GFX906) + .Case("gfx908", CudaArch::GFX908) + .Case("gfx909", CudaArch::GFX909) + .Case("gfx1010", CudaArch::GFX1010) + .Case("gfx1011", CudaArch::GFX1011) + .Case("gfx1012", CudaArch::GFX1012) + .Default(CudaArch::UNKNOWN); +} + +const char *CudaVirtualArchToString(CudaVirtualArch A) { + switch (A) { + case CudaVirtualArch::UNKNOWN: + return "unknown"; + case CudaVirtualArch::COMPUTE_20: + return "compute_20"; + case CudaVirtualArch::COMPUTE_30: + return "compute_30"; + case CudaVirtualArch::COMPUTE_32: + return "compute_32"; + case CudaVirtualArch::COMPUTE_35: + return "compute_35"; + case CudaVirtualArch::COMPUTE_37: + return "compute_37"; + case CudaVirtualArch::COMPUTE_50: + return "compute_50"; + case CudaVirtualArch::COMPUTE_52: + return "compute_52"; + case CudaVirtualArch::COMPUTE_53: + return "compute_53"; + case CudaVirtualArch::COMPUTE_60: + return "compute_60"; + case CudaVirtualArch::COMPUTE_61: + return "compute_61"; + case CudaVirtualArch::COMPUTE_62: + return "compute_62"; + case CudaVirtualArch::COMPUTE_70: + return "compute_70"; + case CudaVirtualArch::COMPUTE_72: + return "compute_72"; + case CudaVirtualArch::COMPUTE_75: + return "compute_75"; + case CudaVirtualArch::COMPUTE_AMDGCN: + return "compute_amdgcn"; + } + llvm_unreachable("invalid enum"); +} + +CudaVirtualArch StringToCudaVirtualArch(llvm::StringRef S) { + return llvm::StringSwitch<CudaVirtualArch>(S) + .Case("compute_20", CudaVirtualArch::COMPUTE_20) + .Case("compute_30", CudaVirtualArch::COMPUTE_30) + .Case("compute_32", CudaVirtualArch::COMPUTE_32) + .Case("compute_35", CudaVirtualArch::COMPUTE_35) + .Case("compute_37", CudaVirtualArch::COMPUTE_37) + .Case("compute_50", CudaVirtualArch::COMPUTE_50) + .Case("compute_52", CudaVirtualArch::COMPUTE_52) + .Case("compute_53", CudaVirtualArch::COMPUTE_53) + .Case("compute_60", CudaVirtualArch::COMPUTE_60) + .Case("compute_61", CudaVirtualArch::COMPUTE_61) + .Case("compute_62", CudaVirtualArch::COMPUTE_62) + .Case("compute_70", CudaVirtualArch::COMPUTE_70) + .Case("compute_72", CudaVirtualArch::COMPUTE_72) + .Case("compute_75", CudaVirtualArch::COMPUTE_75) + .Case("compute_amdgcn", CudaVirtualArch::COMPUTE_AMDGCN) + .Default(CudaVirtualArch::UNKNOWN); +} + +CudaVirtualArch VirtualArchForCudaArch(CudaArch A) { + switch (A) { + case CudaArch::LAST: + break; + case CudaArch::UNKNOWN: + return CudaVirtualArch::UNKNOWN; + case CudaArch::SM_20: + case CudaArch::SM_21: + return CudaVirtualArch::COMPUTE_20; + case CudaArch::SM_30: + return CudaVirtualArch::COMPUTE_30; + case CudaArch::SM_32: + return CudaVirtualArch::COMPUTE_32; + case CudaArch::SM_35: + return CudaVirtualArch::COMPUTE_35; + case CudaArch::SM_37: + return CudaVirtualArch::COMPUTE_37; + case CudaArch::SM_50: + return CudaVirtualArch::COMPUTE_50; + case CudaArch::SM_52: + return CudaVirtualArch::COMPUTE_52; + case CudaArch::SM_53: + return CudaVirtualArch::COMPUTE_53; + case CudaArch::SM_60: + return CudaVirtualArch::COMPUTE_60; + case CudaArch::SM_61: + return CudaVirtualArch::COMPUTE_61; + case CudaArch::SM_62: + return CudaVirtualArch::COMPUTE_62; + case CudaArch::SM_70: + return CudaVirtualArch::COMPUTE_70; + case CudaArch::SM_72: + return CudaVirtualArch::COMPUTE_72; + case CudaArch::SM_75: + return CudaVirtualArch::COMPUTE_75; + case CudaArch::GFX600: + case CudaArch::GFX601: + case CudaArch::GFX700: + case CudaArch::GFX701: + case CudaArch::GFX702: + case CudaArch::GFX703: + case CudaArch::GFX704: + case CudaArch::GFX801: + case CudaArch::GFX802: + case CudaArch::GFX803: + case CudaArch::GFX810: + case CudaArch::GFX900: + case CudaArch::GFX902: + case CudaArch::GFX904: + case CudaArch::GFX906: + case CudaArch::GFX908: + case CudaArch::GFX909: + case CudaArch::GFX1010: + case CudaArch::GFX1011: + case CudaArch::GFX1012: + return CudaVirtualArch::COMPUTE_AMDGCN; + } + llvm_unreachable("invalid enum"); +} + +CudaVersion MinVersionForCudaArch(CudaArch A) { + switch (A) { + case CudaArch::LAST: + break; + case CudaArch::UNKNOWN: + return CudaVersion::UNKNOWN; + 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::GFX600: + case CudaArch::GFX601: + case CudaArch::GFX700: + case CudaArch::GFX701: + case CudaArch::GFX702: + case CudaArch::GFX703: + case CudaArch::GFX704: + case CudaArch::GFX801: + case CudaArch::GFX802: + case CudaArch::GFX803: + case CudaArch::GFX810: + case CudaArch::GFX900: + case CudaArch::GFX902: + case CudaArch::GFX904: + case CudaArch::GFX906: + case CudaArch::GFX908: + case CudaArch::GFX909: + case CudaArch::GFX1010: + case CudaArch::GFX1011: + case CudaArch::GFX1012: + return CudaVersion::CUDA_70; + } + llvm_unreachable("invalid enum"); +} + +CudaVersion MaxVersionForCudaArch(CudaArch A) { + switch (A) { + case CudaArch::UNKNOWN: + return CudaVersion::UNKNOWN; + case CudaArch::SM_20: + case CudaArch::SM_21: + case CudaArch::GFX600: + case CudaArch::GFX601: + case CudaArch::GFX700: + case CudaArch::GFX701: + case CudaArch::GFX702: + case CudaArch::GFX703: + case CudaArch::GFX704: + case CudaArch::GFX801: + case CudaArch::GFX802: + case CudaArch::GFX803: + case CudaArch::GFX810: + case CudaArch::GFX900: + case CudaArch::GFX902: + case CudaArch::GFX1010: + case CudaArch::GFX1011: + case CudaArch::GFX1012: + return CudaVersion::CUDA_80; + default: + return CudaVersion::LATEST; + } +} + +static 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; + 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/Diagnostic.cpp b/contrib/llvm-project/clang/lib/Basic/Diagnostic.cpp new file mode 100644 index 000000000000..c82f74413ec1 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Diagnostic.cpp @@ -0,0 +1,1149 @@ +//===- 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 DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &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; + } + + DB.AddString(string); + 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) { + if (DelayedDiagID) + return; + + DelayedDiagID = DiagID; + DelayedDiagArg1 = Arg1.str(); + DelayedDiagArg2 = Arg2.str(); +} + +void DiagnosticsEngine::ReportDelayed() { + unsigned ID = DelayedDiagID; + DelayedDiagID = 0; + Report(ID) << DelayedDiagArg1 << DelayedDiagArg2; +} + +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.getBuffer(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); + + // 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::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(); + NumDiagArgs = 0; + + DiagRanges.clear(); + DiagRanges.append(storedDiag.range_begin(), storedDiag.range_end()); + + DiagFixItHints.clear(); + DiagFixItHints.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; + SmallVector<char, 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: { + int 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: { + unsigned 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_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::StorageAllocator::StorageAllocator() { + for (unsigned I = 0; I != NumCached; ++I) + FreeList[I] = Cached + I; + NumFreeListEntries = NumCached; +} + +PartialDiagnostic::StorageAllocator::~StorageAllocator() { + // 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..e30e3753d193 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/DiagnosticIDs.cpp @@ -0,0 +1,748 @@ +//===--- 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 { + +// Diagnostic classes. +enum { + CLASS_NOTE = 0x01, + CLASS_REMARK = 0x02, + CLASS_WARNING = 0x03, + CLASS_EXTENSION = 0x04, + CLASS_ERROR = 0x05 +}; + +struct StaticDiagInfoRec { + uint16_t DiagID; + unsigned DefaultSeverity : 3; + unsigned Class : 3; + unsigned SFINAE : 2; + unsigned WarnNoWerror : 1; + unsigned WarnShowInSystemHeader : 1; + unsigned Category : 6; + + uint16_t OptionGroupIndex; + + uint16_t DescriptionLen; + const char *DescriptionStr; + + unsigned getOptionGroupIndex() const { + return OptionGroupIndex; + } + + StringRef getDescription() const { + return StringRef(DescriptionStr, 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(SEMA) +VALIDATE_DIAG_SIZE(ANALYSIS) +VALIDATE_DIAG_SIZE(REFACTORING) +#undef VALIDATE_DIAG_SIZE +#undef STRINGIFY_NAME + +} // namespace anonymous + +static const StaticDiagInfoRec StaticDiagInfo[] = { +#define DIAG(ENUM, CLASS, DEFAULT_SEVERITY, DESC, GROUP, SFINAE, NOWERROR, \ + SHOWINSYSHEADER, CATEGORY) \ + { \ + diag::ENUM, DEFAULT_SEVERITY, CLASS, DiagnosticIDs::SFINAE, NOWERROR, \ + SHOWINSYSHEADER, CATEGORY, GROUP, STR_SIZE(DESC, uint16_t), DESC \ + } \ + , +#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" +#undef DIAG +}; + +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; +} + +/// 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, 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; + + 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 GET_DIAG_TABLE +#include "clang/Basic/DiagnosticGroups.inc" +#undef GET_DIAG_TABLE +}; + +/// 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 OptionTable[Info->getOptionGroupIndex()].getName(); + 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; // Sanity 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/FileManager.cpp b/contrib/llvm-project/clang/lib/Basic/FileManager.cpp new file mode 100644 index 000000000000..b6a7fde09f35 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/FileManager.cpp @@ -0,0 +1,520 @@ +//===--- 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/SmallString.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/ADT/STLExtras.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; + +//===----------------------------------------------------------------------===// +// Common logic. +//===----------------------------------------------------------------------===// + +FileManager::FileManager(const FileSystemOptions &FSO, + IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) + : FS(std::move(FS)), FileSystemOpts(FSO), SeenDirEntries(64), + SeenFileEntries(64), NextFileUID(0) { + NumDirLookups = NumFileLookups = 0; + NumDirCacheMisses = NumFileCacheMisses = 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 const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr, + StringRef Filename, + bool CacheFailure) { + if (Filename.empty()) + return nullptr; + + if (llvm::sys::path::is_separator(Filename[Filename.size() - 1])) + return nullptr; // If Filename 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.getDirectory(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, nullptr}).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 = llvm::make_unique<DirectoryEntry>(); + UDE->Name = NamedDirEnt.first(); + NamedDirEnt.second = UDE.get(); + VirtualDirectoryEntries.push_back(std::move(UDE)); + + // Recursively add the other ancestors. + addAncestorsAsVirtualDirs(DirName); +} + +const DirectoryEntry *FileManager::getDirectory(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); +#ifdef _WIN32 + // Fixing a problem with "clang C:test.c" on Windows. + // Stat("C:") does not recognize "C:" as a valid directory + std::string DirNameStr; + if (DirName.size() > 1 && DirName.back() == ':' && + DirName.equals_lower(llvm::sys::path::root_name(DirName))) { + DirNameStr = DirName.str() + '.'; + DirName = DirNameStr; + } +#endif + + ++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, nullptr}); + if (!SeenDirInsertResult.second) + return SeenDirInsertResult.first->second; + + // 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; + if (getStatValue(InterndDirName, Status, false, nullptr /*directory lookup*/)) { + // There's no real directory at the given path. + if (!CacheFailure) + SeenDirEntries.erase(DirName); + return nullptr; + } + + // 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 &UDE; +} + +const FileEntry *FileManager::getFile(StringRef Filename, bool openFile, + bool CacheFailure) { + ++NumFileLookups; + + // See if there is already an entry in the map. + auto SeenFileInsertResult = SeenFileEntries.insert({Filename, nullptr}); + if (!SeenFileInsertResult.second) + return SeenFileInsertResult.first->second; + + // 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. + const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename, + CacheFailure); + if (DirInfo == nullptr) { // Directory doesn't exist, file can't exist. + if (!CacheFailure) + SeenFileEntries.erase(Filename); + + return nullptr; + } + + // 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; + if (getStatValue(InterndFileName, Status, true, openFile ? &F : nullptr)) { + // There's no real file at the given path. + if (!CacheFailure) + SeenFileEntries.erase(Filename); + + return nullptr; + } + + 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()]; + + NamedFileEnt.second = &UFE; + + // If the name returned by getStatValue is different than Filename, re-intern + // the name. + if (Status.getName() != Filename) { + auto &NamedFileEnt = + *SeenFileEntries.insert({Status.getName(), &UFE}).first; + assert(NamedFileEnt.second == &UFE && + "filename from getStatValue() refers to wrong file"); + InterndFileName = NamedFileEnt.first().data(); + } + + 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 != UFE.Dir && Status.IsVFSMapped) + UFE.Dir = DirInfo; + + // Always update the name to use the last name by which a file was accessed. + // FIXME: Neither this nor always using the first name 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. + UFE.Name = InterndFileName; + + return &UFE; + } + + // Otherwise, we don't have this file yet, add it. + UFE.Name = InterndFileName; + UFE.Size = Status.getSize(); + UFE.ModTime = llvm::sys::toTimeT(Status.getLastModificationTime()); + UFE.Dir = DirInfo; + 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 &UFE; +} + +const FileEntry * +FileManager::getVirtualFile(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, nullptr}).first; + if (NamedFileEnt.second) + return NamedFileEnt.second; + + // 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. + const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, 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) == 0) { + 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 = UFE; + + // 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. + if (UFE->isValid()) + return UFE; + + UFE->UniqueID = Status.getUniqueID(); + UFE->IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file; + fillRealPathName(UFE, Status.getName()); + } else { + VirtualFileEntries.push_back(llvm::make_unique<FileEntry>()); + UFE = VirtualFileEntries.back().get(); + NamedFileEnt.second = UFE; + } + + UFE->Name = InterndFileName; + UFE->Size = Size; + UFE->ModTime = ModificationTime; + UFE->Dir = DirInfo; + UFE->UID = NextFileUID++; + UFE->IsValid = true; + UFE->File.reset(); + return UFE; +} + +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 = AbsPath.str(); +} + +llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> +FileManager::getBufferForFile(const FileEntry *Entry, bool isVolatile, + bool ShouldCloseOpenFile) { + 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) + 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=*/true, isVolatile); + // FIXME: we need a set of APIs that can make guarantees about whether a + // FileEntry is open or not. + if (ShouldCloseOpenFile) + Entry->closeFile(); + return Result; + } + + // Otherwise, open the file. + + if (FileSystemOpts.WorkingDir.empty()) + return FS->getBufferForFile(Filename, FileSize, + /*RequiresNullTerminator=*/true, isVolatile); + + SmallString<128> FilePath(Entry->getName()); + FixupRelativePath(FilePath); + return FS->getBufferForFile(FilePath, FileSize, + /*RequiresNullTerminator=*/true, isVolatile); +} + +llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> +FileManager::getBufferForFile(StringRef Filename, bool isVolatile) { + if (FileSystemOpts.WorkingDir.empty()) + return FS->getBufferForFile(Filename, -1, true, isVolatile); + + SmallString<128> FilePath(Filename); + FixupRelativePath(FilePath); + return FS->getBufferForFile(FilePath.c_str(), -1, true, 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. +bool 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 bool(FileSystemStatCache::get(Path, Status, isFile, F, + StatCache.get(), *FS)); + + SmallString<128> FilePath(Path); + FixupRelativePath(FilePath); + + return bool(FileSystemStatCache::get(FilePath.c_str(), Status, isFile, F, + StatCache.get(), *FS)); +} + +bool 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 true; + Result = *S; + return false; +} + +void FileManager::invalidateCache(const FileEntry *Entry) { + assert(Entry && "Cannot invalidate a NULL FileEntry"); + + SeenFileEntries.erase(Entry->getName()); + + // FileEntry invalidation should not block future optimizations in the file + // caches. Possible alternatives are cache truncation (invalidate last N) or + // invalidation of the whole cache. + // + // FIXME: This is broken. We sometimes have the same FileEntry* shared + // betweeen multiple SeenFileEntries, so this can leave dangling pointers. + UniqueRealFiles.erase(Entry->getUniqueID()); +} + +void FileManager::GetUniqueIDMapping( + SmallVectorImpl<const FileEntry *> &UIDToFiles) const { + UIDToFiles.clear(); + UIDToFiles.resize(NextFileUID); + + // Map file entries + for (llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator>::const_iterator + FE = SeenFileEntries.begin(), FEEnd = SeenFileEntries.end(); + FE != FEEnd; ++FE) + if (FE->getValue()) + UIDToFiles[FE->getValue()->getUID()] = FE->getValue(); + + // Map virtual file entries + for (const auto &VFE : VirtualFileEntries) + UIDToFiles[VFE->getUID()] = VFE.get(); +} + +void FileManager::modifyFileEntry(FileEntry *File, + off_t Size, time_t ModificationTime) { + File->Size = Size; + File->ModTime = ModificationTime; +} + +StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) { + // FIXME: use llvm::sys::fs::canonical() when it gets implemented + llvm::DenseMap<const DirectoryEntry *, llvm::StringRef>::iterator Known + = CanonicalDirNames.find(Dir); + if (Known != CanonicalDirNames.end()) + return Known->second; + + StringRef CanonicalName(Dir->getName()); + + SmallString<4096> CanonicalNameBuf; + if (!FS->getRealPath(Dir->getName(), CanonicalNameBuf)) + CanonicalName = StringRef(CanonicalNameBuf).copy(CanonicalNameStorage); + + CanonicalDirNames.insert({Dir, 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/FixedPoint.cpp b/contrib/llvm-project/clang/lib/Basic/FixedPoint.cpp new file mode 100644 index 000000000000..05600dfc6d21 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/FixedPoint.cpp @@ -0,0 +1,258 @@ +//===- FixedPoint.cpp - Fixed point constant handling -----------*- 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 the implementation for the fixed point number interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/FixedPoint.h" + +namespace clang { + +APFixedPoint APFixedPoint::convert(const FixedPointSemantics &DstSema, + bool *Overflow) const { + llvm::APSInt NewVal = Val; + unsigned DstWidth = DstSema.getWidth(); + unsigned DstScale = DstSema.getScale(); + bool Upscaling = DstScale > getScale(); + if (Overflow) + *Overflow = false; + + if (Upscaling) { + NewVal = NewVal.extend(NewVal.getBitWidth() + DstScale - getScale()); + NewVal <<= (DstScale - getScale()); + } else { + NewVal >>= (getScale() - DstScale); + } + + auto Mask = llvm::APInt::getBitsSetFrom( + NewVal.getBitWidth(), + std::min(DstScale + DstSema.getIntegralBits(), NewVal.getBitWidth())); + llvm::APInt Masked(NewVal & Mask); + + // Change in the bits above the sign + if (!(Masked == Mask || Masked == 0)) { + // Found overflow in the bits above the sign + if (DstSema.isSaturated()) + NewVal = NewVal.isNegative() ? Mask : ~Mask; + else if (Overflow) + *Overflow = true; + } + + // If the dst semantics are unsigned, but our value is signed and negative, we + // clamp to zero. + if (!DstSema.isSigned() && NewVal.isSigned() && NewVal.isNegative()) { + // Found negative overflow for unsigned result + if (DstSema.isSaturated()) + NewVal = 0; + else if (Overflow) + *Overflow = true; + } + + NewVal = NewVal.extOrTrunc(DstWidth); + NewVal.setIsSigned(DstSema.isSigned()); + return APFixedPoint(NewVal, DstSema); +} + +int APFixedPoint::compare(const APFixedPoint &Other) const { + llvm::APSInt ThisVal = getValue(); + llvm::APSInt OtherVal = Other.getValue(); + bool ThisSigned = Val.isSigned(); + bool OtherSigned = OtherVal.isSigned(); + unsigned OtherScale = Other.getScale(); + unsigned OtherWidth = OtherVal.getBitWidth(); + + unsigned CommonWidth = std::max(Val.getBitWidth(), OtherWidth); + + // Prevent overflow in the event the widths are the same but the scales differ + CommonWidth += getScale() >= OtherScale ? getScale() - OtherScale + : OtherScale - getScale(); + + ThisVal = ThisVal.extOrTrunc(CommonWidth); + OtherVal = OtherVal.extOrTrunc(CommonWidth); + + unsigned CommonScale = std::max(getScale(), OtherScale); + ThisVal = ThisVal.shl(CommonScale - getScale()); + OtherVal = OtherVal.shl(CommonScale - OtherScale); + + if (ThisSigned && OtherSigned) { + if (ThisVal.sgt(OtherVal)) + return 1; + else if (ThisVal.slt(OtherVal)) + return -1; + } else if (!ThisSigned && !OtherSigned) { + if (ThisVal.ugt(OtherVal)) + return 1; + else if (ThisVal.ult(OtherVal)) + return -1; + } else if (ThisSigned && !OtherSigned) { + if (ThisVal.isSignBitSet()) + return -1; + else if (ThisVal.ugt(OtherVal)) + return 1; + else if (ThisVal.ult(OtherVal)) + return -1; + } else { + // !ThisSigned && OtherSigned + if (OtherVal.isSignBitSet()) + return 1; + else if (ThisVal.ugt(OtherVal)) + return 1; + else if (ThisVal.ult(OtherVal)) + return -1; + } + + return 0; +} + +APFixedPoint APFixedPoint::getMax(const FixedPointSemantics &Sema) { + bool IsUnsigned = !Sema.isSigned(); + auto Val = llvm::APSInt::getMaxValue(Sema.getWidth(), IsUnsigned); + if (IsUnsigned && Sema.hasUnsignedPadding()) + Val = Val.lshr(1); + return APFixedPoint(Val, Sema); +} + +APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) { + auto Val = llvm::APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned()); + return APFixedPoint(Val, Sema); +} + +FixedPointSemantics FixedPointSemantics::getCommonSemantics( + const FixedPointSemantics &Other) const { + unsigned CommonScale = std::max(getScale(), Other.getScale()); + unsigned CommonWidth = + std::max(getIntegralBits(), Other.getIntegralBits()) + CommonScale; + + bool ResultIsSigned = isSigned() || Other.isSigned(); + bool ResultIsSaturated = isSaturated() || Other.isSaturated(); + bool ResultHasUnsignedPadding = false; + if (!ResultIsSigned) { + // Both are unsigned. + ResultHasUnsignedPadding = hasUnsignedPadding() && + Other.hasUnsignedPadding() && !ResultIsSaturated; + } + + // If the result is signed, add an extra bit for the sign. Otherwise, if it is + // unsigned and has unsigned padding, we only need to add the extra padding + // bit back if we are not saturating. + if (ResultIsSigned || ResultHasUnsignedPadding) + CommonWidth++; + + return FixedPointSemantics(CommonWidth, CommonScale, ResultIsSigned, + ResultIsSaturated, ResultHasUnsignedPadding); +} + +APFixedPoint APFixedPoint::add(const APFixedPoint &Other, + bool *Overflow) const { + auto CommonFXSema = Sema.getCommonSemantics(Other.getSemantics()); + APFixedPoint ConvertedThis = convert(CommonFXSema); + APFixedPoint ConvertedOther = Other.convert(CommonFXSema); + llvm::APSInt ThisVal = ConvertedThis.getValue(); + llvm::APSInt OtherVal = ConvertedOther.getValue(); + bool Overflowed = false; + + llvm::APSInt Result; + if (CommonFXSema.isSaturated()) { + Result = CommonFXSema.isSigned() ? ThisVal.sadd_sat(OtherVal) + : ThisVal.uadd_sat(OtherVal); + } else { + Result = ThisVal.isSigned() ? ThisVal.sadd_ov(OtherVal, Overflowed) + : ThisVal.uadd_ov(OtherVal, Overflowed); + } + + if (Overflow) + *Overflow = Overflowed; + + return APFixedPoint(Result, CommonFXSema); +} + +void APFixedPoint::toString(llvm::SmallVectorImpl<char> &Str) const { + llvm::APSInt Val = getValue(); + unsigned Scale = getScale(); + + if (Val.isSigned() && Val.isNegative() && Val != -Val) { + Val = -Val; + Str.push_back('-'); + } + + llvm::APSInt IntPart = Val >> Scale; + + // Add 4 digits to hold the value after multiplying 10 (the radix) + unsigned Width = Val.getBitWidth() + 4; + llvm::APInt FractPart = Val.zextOrTrunc(Scale).zext(Width); + llvm::APInt FractPartMask = llvm::APInt::getAllOnesValue(Scale).zext(Width); + llvm::APInt RadixInt = llvm::APInt(Width, 10); + + IntPart.toString(Str, /*Radix=*/10); + Str.push_back('.'); + do { + (FractPart * RadixInt) + .lshr(Scale) + .toString(Str, /*Radix=*/10, Val.isSigned()); + FractPart = (FractPart * RadixInt) & FractPartMask; + } while (FractPart != 0); +} + +APFixedPoint APFixedPoint::negate(bool *Overflow) const { + if (!isSaturated()) { + if (Overflow) + *Overflow = + (!isSigned() && Val != 0) || (isSigned() && Val.isMinSignedValue()); + return APFixedPoint(-Val, Sema); + } + + // We never overflow for saturation + if (Overflow) + *Overflow = false; + + if (isSigned()) + return Val.isMinSignedValue() ? getMax(Sema) : APFixedPoint(-Val, Sema); + else + return APFixedPoint(Sema); +} + +llvm::APSInt APFixedPoint::convertToInt(unsigned DstWidth, bool DstSign, + bool *Overflow) const { + llvm::APSInt Result = getIntPart(); + unsigned SrcWidth = getWidth(); + + llvm::APSInt DstMin = llvm::APSInt::getMinValue(DstWidth, !DstSign); + llvm::APSInt DstMax = llvm::APSInt::getMaxValue(DstWidth, !DstSign); + + if (SrcWidth < DstWidth) { + Result = Result.extend(DstWidth); + } else if (SrcWidth > DstWidth) { + DstMin = DstMin.extend(SrcWidth); + DstMax = DstMax.extend(SrcWidth); + } + + if (Overflow) { + if (Result.isSigned() && !DstSign) { + *Overflow = Result.isNegative() || Result.ugt(DstMax); + } else if (Result.isUnsigned() && DstSign) { + *Overflow = Result.ugt(DstMax); + } else { + *Overflow = Result < DstMin || Result > DstMax; + } + } + + Result.setIsSigned(DstSign); + return Result.extOrTrunc(DstWidth); +} + +APFixedPoint APFixedPoint::getFromIntValue(const llvm::APSInt &Value, + const FixedPointSemantics &DstFXSema, + bool *Overflow) { + FixedPointSemantics IntFXSema = FixedPointSemantics::GetIntegerSemantics( + Value.getBitWidth(), Value.isSigned()); + return APFixedPoint(Value, IntFXSema).convert(DstFXSema, Overflow); +} + +} // namespace clang 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..ca9c71287ab7 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/IdentifierTable.cpp @@ -0,0 +1,697 @@ +//===- 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/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; + +//===----------------------------------------------------------------------===// +// 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, + KEYCXX2A = 0x200000, + KEYOPENCLCXX = 0x400000, + KEYMSCOMPAT = 0x800000, + KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX2A, + KEYALL = (0xffffff & ~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.CPlusPlus2a && (Flags & KEYCXX2A)) 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.ConceptsTS && (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; + 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); + + // 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.CPlusPlus2a = false; + return !isKeyword(LangOptsNoCPP); +} + +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, 'i', 'c', include); + CASE( 7, 'w', 'r', warning); + + 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. + +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 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 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::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..516b1ff1b7e2 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/LangOptions.cpp @@ -0,0 +1,49 @@ +//===- 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" + +using namespace clang; + +LangOptions::LangOptions() { +#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 = Default; +#include "clang/Basic/LangOptions.def" + + // These options do not affect AST generation. + SanitizerBlacklistFiles.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; + return VersionTuple(Ver / 100, (Ver % 100) / 10); +} 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..f394f26e550c --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Module.cpp @@ -0,0 +1,655 @@ +//===- 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), IsMissingRequirement(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) { + if (!Parent->isAvailable()) + IsAvailable = false; + if (Parent->IsSystem) + IsSystem = true; + if (Parent->IsExternC) + IsExternC = true; + if (Parent->NoUndeclaredIncludes) + NoUndeclaredIncludes = true; + if (Parent->ModuleMapIsPrivate) + ModuleMapIsPrivate = true; + IsMissingRequirement = Parent->IsMissingRequirement; + + 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 = std::find(LangOpts.ModuleFeatures.begin(), + LangOpts.ModuleFeatures.end(), + Feature) != LangOpts.ModuleFeatures.end(); + return HasFeature; +} + +bool Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target, + Requirement &Req, + UnresolvedHeaderDirective &MissingHeader, + Module *&ShadowingModule) const { + if (IsAvailable) + return true; + + for (const Module *Current = this; Current; Current = Current->Parent) { + if (Current->ShadowingModule) { + ShadowingModule = Current->ShadowingModule; + return false; + } + 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 false; + } + } + 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 { + const Module *This = this; + do { + if (This == Other) + return true; + + This = This->Parent; + } while (This); + + 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 || isValidIdentifier(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, Umbrella.dyn_cast<const DirectoryEntry *>()}; +} + +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 (const FileEntry *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(Feature, RequiredState)); + + // If this feature is currently available, we're done. + if (hasFeature(Feature, LangOpts, Target) == RequiredState) + return; + + markUnavailable(/*MissingRequirement*/true); +} + +void Module::markUnavailable(bool MissingRequirement) { + auto needUpdate = [MissingRequirement](Module *M) { + return M->IsAvailable || (!M->IsMissingRequirement && MissingRequirement); + }; + + 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->IsMissingRequirement |= MissingRequirement; + 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) 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); + + 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"; + } + + 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()); +} + +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 recurse to unavailable submodules. + if (E->isAvailable()) + 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}); +} 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/OpenMPKinds.cpp b/contrib/llvm-project/clang/lib/Basic/OpenMPKinds.cpp new file mode 100644 index 000000000000..82e193efef32 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/OpenMPKinds.cpp @@ -0,0 +1,1067 @@ +//===--- 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; + +OpenMPDirectiveKind clang::getOpenMPDirectiveKind(StringRef Str) { + return llvm::StringSwitch<OpenMPDirectiveKind>(Str) +#define OPENMP_DIRECTIVE(Name) .Case(#Name, OMPD_##Name) +#define OPENMP_DIRECTIVE_EXT(Name, Str) .Case(Str, OMPD_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPD_unknown); +} + +const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) { + assert(Kind <= OMPD_unknown); + switch (Kind) { + case OMPD_unknown: + return "unknown"; +#define OPENMP_DIRECTIVE(Name) \ + case OMPD_##Name: \ + return #Name; +#define OPENMP_DIRECTIVE_EXT(Name, Str) \ + case OMPD_##Name: \ + return Str; +#include "clang/Basic/OpenMPKinds.def" + break; + } + llvm_unreachable("Invalid OpenMP directive kind"); +} + +OpenMPClauseKind clang::getOpenMPClauseKind(StringRef Str) { + // 'flush' clause cannot be specified explicitly, because this is an implicit + // clause for 'flush' directive. If the 'flush' clause is explicitly specified + // the Parser should generate a warning about extra tokens at the end of the + // directive. + if (Str == "flush") + return OMPC_unknown; + return llvm::StringSwitch<OpenMPClauseKind>(Str) +#define OPENMP_CLAUSE(Name, Class) .Case(#Name, OMPC_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Case("uniform", OMPC_uniform) + .Default(OMPC_unknown); +} + +const char *clang::getOpenMPClauseName(OpenMPClauseKind Kind) { + assert(Kind <= OMPC_unknown); + switch (Kind) { + case OMPC_unknown: + return "unknown"; +#define OPENMP_CLAUSE(Name, Class) \ + case OMPC_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + case OMPC_uniform: + return "uniform"; + case OMPC_threadprivate: + return "threadprivate or thread local"; + } + llvm_unreachable("Invalid OpenMP clause kind"); +} + +unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, + StringRef Str) { + switch (Kind) { + case OMPC_default: + return llvm::StringSwitch<OpenMPDefaultClauseKind>(Str) +#define OPENMP_DEFAULT_KIND(Name) .Case(#Name, OMPC_DEFAULT_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_DEFAULT_unknown); + case OMPC_proc_bind: + return llvm::StringSwitch<OpenMPProcBindClauseKind>(Str) +#define OPENMP_PROC_BIND_KIND(Name) .Case(#Name, OMPC_PROC_BIND_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_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: + return 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); + case OMPC_to: + return llvm::StringSwitch<unsigned>(Str) +#define OPENMP_TO_MODIFIER_KIND(Name) \ + .Case(#Name, static_cast<unsigned>(OMPC_TO_MODIFIER_##Name)) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_TO_MODIFIER_unknown); + case OMPC_from: + return llvm::StringSwitch<unsigned>(Str) +#define OPENMP_FROM_MODIFIER_KIND(Name) \ + .Case(#Name, static_cast<unsigned>(OMPC_FROM_MODIFIER_##Name)) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_FROM_MODIFIER_unknown); + 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_unknown: + case OMPC_threadprivate: + case OMPC_if: + case OMPC_final: + case OMPC_num_threads: + case OMPC_safelen: + case OMPC_simdlen: + case OMPC_allocator: + case OMPC_allocate: + case OMPC_collapse: + case OMPC_private: + case OMPC_firstprivate: + case OMPC_lastprivate: + case OMPC_shared: + case OMPC_reduction: + 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_read: + case OMPC_write: + case OMPC_update: + case OMPC_capture: + case OMPC_seq_cst: + case OMPC_device: + 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_is_device_ptr: + case OMPC_unified_address: + case OMPC_unified_shared_memory: + case OMPC_reverse_offload: + case OMPC_dynamic_allocators: + break; + } + llvm_unreachable("Invalid OpenMP simple clause kind"); +} + +const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, + unsigned Type) { + switch (Kind) { + case OMPC_default: + switch (Type) { + case OMPC_DEFAULT_unknown: + return "unknown"; +#define OPENMP_DEFAULT_KIND(Name) \ + case OMPC_DEFAULT_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'default' clause type"); + case OMPC_proc_bind: + switch (Type) { + case OMPC_PROC_BIND_unknown: + return "unknown"; +#define OPENMP_PROC_BIND_KIND(Name) \ + case OMPC_PROC_BIND_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.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: + switch (Type) { + case OMPC_TO_MODIFIER_unknown: + return "unknown"; +#define OPENMP_TO_MODIFIER_KIND(Name) \ + case OMPC_TO_MODIFIER_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + llvm_unreachable("Invalid OpenMP 'to' clause type"); + case OMPC_from: + switch (Type) { + case OMPC_FROM_MODIFIER_unknown: + return "unknown"; +#define OPENMP_FROM_MODIFIER_KIND(Name) \ + case OMPC_FROM_MODIFIER_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + llvm_unreachable("Invalid OpenMP '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_unknown: + case OMPC_threadprivate: + case OMPC_if: + case OMPC_final: + case OMPC_num_threads: + case OMPC_safelen: + case OMPC_simdlen: + case OMPC_allocator: + case OMPC_allocate: + case OMPC_collapse: + case OMPC_private: + case OMPC_firstprivate: + case OMPC_lastprivate: + case OMPC_shared: + case OMPC_reduction: + 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_read: + case OMPC_write: + case OMPC_update: + case OMPC_capture: + case OMPC_seq_cst: + case OMPC_device: + 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_is_device_ptr: + case OMPC_unified_address: + case OMPC_unified_shared_memory: + case OMPC_reverse_offload: + case OMPC_dynamic_allocators: + break; + } + llvm_unreachable("Invalid OpenMP simple clause kind"); +} + +bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, + OpenMPClauseKind CKind) { + assert(DKind <= OMPD_unknown); + assert(CKind <= OMPC_unknown); + switch (DKind) { + case OMPD_parallel: + switch (CKind) { +#define OPENMP_PARALLEL_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_simd: + switch (CKind) { +#define OPENMP_SIMD_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_for: + switch (CKind) { +#define OPENMP_FOR_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_for_simd: + switch (CKind) { +#define OPENMP_FOR_SIMD_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_sections: + switch (CKind) { +#define OPENMP_SECTIONS_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_single: + switch (CKind) { +#define OPENMP_SINGLE_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_parallel_for: + switch (CKind) { +#define OPENMP_PARALLEL_FOR_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_parallel_for_simd: + switch (CKind) { +#define OPENMP_PARALLEL_FOR_SIMD_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_parallel_sections: + switch (CKind) { +#define OPENMP_PARALLEL_SECTIONS_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_task: + switch (CKind) { +#define OPENMP_TASK_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_flush: + return CKind == OMPC_flush; + break; + case OMPD_atomic: + switch (CKind) { +#define OPENMP_ATOMIC_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_target: + switch (CKind) { +#define OPENMP_TARGET_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_requires: + switch (CKind) { +#define OPENMP_REQUIRES_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_target_data: + switch (CKind) { +#define OPENMP_TARGET_DATA_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_target_enter_data: + switch (CKind) { +#define OPENMP_TARGET_ENTER_DATA_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_target_exit_data: + switch (CKind) { +#define OPENMP_TARGET_EXIT_DATA_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_target_parallel: + switch (CKind) { +#define OPENMP_TARGET_PARALLEL_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_target_parallel_for: + switch (CKind) { +#define OPENMP_TARGET_PARALLEL_FOR_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_target_update: + switch (CKind) { +#define OPENMP_TARGET_UPDATE_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_teams: + switch (CKind) { +#define OPENMP_TEAMS_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_declare_simd: + break; + case OMPD_cancel: + switch (CKind) { +#define OPENMP_CANCEL_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_ordered: + switch (CKind) { +#define OPENMP_ORDERED_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_taskloop: + switch (CKind) { +#define OPENMP_TASKLOOP_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_taskloop_simd: + switch (CKind) { +#define OPENMP_TASKLOOP_SIMD_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_critical: + switch (CKind) { +#define OPENMP_CRITICAL_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_distribute: + switch (CKind) { +#define OPENMP_DISTRIBUTE_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_distribute_parallel_for: + switch (CKind) { +#define OPENMP_DISTRIBUTE_PARALLEL_FOR_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_distribute_parallel_for_simd: + switch (CKind) { +#define OPENMP_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_distribute_simd: + switch (CKind) { +#define OPENMP_DISTRIBUTE_SIMD_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_target_parallel_for_simd: + switch (CKind) { +#define OPENMP_TARGET_PARALLEL_FOR_SIMD_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_target_simd: + switch (CKind) { +#define OPENMP_TARGET_SIMD_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_teams_distribute: + switch (CKind) { +#define OPENMP_TEAMS_DISTRIBUTE_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_teams_distribute_simd: + switch (CKind) { +#define OPENMP_TEAMS_DISTRIBUTE_SIMD_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_teams_distribute_parallel_for_simd: + switch (CKind) { +#define OPENMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_teams_distribute_parallel_for: + switch (CKind) { +#define OPENMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_target_teams: + switch (CKind) { +#define OPENMP_TARGET_TEAMS_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_target_teams_distribute: + switch (CKind) { +#define OPENMP_TARGET_TEAMS_DISTRIBUTE_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_target_teams_distribute_parallel_for: + switch (CKind) { +#define OPENMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_target_teams_distribute_parallel_for_simd: + switch (CKind) { +#define OPENMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_target_teams_distribute_simd: + switch (CKind) { +#define OPENMP_TARGET_TEAMS_DISTRIBUTE_SIMD_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_taskgroup: + switch (CKind) { +#define OPENMP_TASKGROUP_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_declare_mapper: + switch (CKind) { +#define OPENMP_DECLARE_MAPPER_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_allocate: + switch (CKind) { +#define OPENMP_ALLOCATE_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_declare_target: + case OMPD_end_declare_target: + case OMPD_unknown: + case OMPD_threadprivate: + case OMPD_section: + case OMPD_master: + case OMPD_taskyield: + case OMPD_barrier: + case OMPD_taskwait: + case OMPD_cancellation_point: + case OMPD_declare_reduction: + break; + } + return false; +} + +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_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; +} + +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; +} + +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; +} + +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_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::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; +} + +void clang::getOpenMPCaptureRegions( + SmallVectorImpl<OpenMPDirectiveKind> &CaptureRegions, + OpenMPDirectiveKind DKind) { + assert(DKind <= OMPD_unknown); + switch (DKind) { + case OMPD_parallel: + case OMPD_parallel_for: + case OMPD_parallel_for_simd: + 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: + 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_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: + CaptureRegions.push_back(OMPD_unknown); + 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_declare_reduction: + case OMPD_declare_mapper: + case OMPD_declare_simd: + case OMPD_declare_target: + case OMPD_end_declare_target: + case OMPD_requires: + llvm_unreachable("OpenMP Directive is not allowed"); + case OMPD_unknown: + 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/SanitizerBlacklist.cpp b/contrib/llvm-project/clang/lib/Basic/SanitizerBlacklist.cpp new file mode 100644 index 000000000000..aec35c7d9864 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/SanitizerBlacklist.cpp @@ -0,0 +1,50 @@ +//===--- SanitizerBlacklist.cpp - Blacklist 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 blacklist used to disable/alter instrumentation done in +// sanitizers. +// +//===----------------------------------------------------------------------===// +#include "clang/Basic/SanitizerBlacklist.h" + +using namespace clang; + +SanitizerBlacklist::SanitizerBlacklist( + const std::vector<std::string> &BlacklistPaths, SourceManager &SM) + : SSCL(SanitizerSpecialCaseList::createOrDie(BlacklistPaths)), SM(SM) {} + +bool SanitizerBlacklist::isBlacklistedGlobal(SanitizerMask Mask, + StringRef GlobalName, + StringRef Category) const { + return SSCL->inSection(Mask, "global", GlobalName, Category); +} + +bool SanitizerBlacklist::isBlacklistedType(SanitizerMask Mask, + StringRef MangledTypeName, + StringRef Category) const { + return SSCL->inSection(Mask, "type", MangledTypeName, Category); +} + +bool SanitizerBlacklist::isBlacklistedFunction(SanitizerMask Mask, + StringRef FunctionName) const { + return SSCL->inSection(Mask, "fun", FunctionName); +} + +bool SanitizerBlacklist::isBlacklistedFile(SanitizerMask Mask, + StringRef FileName, + StringRef Category) const { + return SSCL->inSection(Mask, "src", FileName, Category); +} + +bool SanitizerBlacklist::isBlacklistedLocation(SanitizerMask Mask, + SourceLocation Loc, + StringRef Category) const { + return Loc.isValid() && + isBlacklistedFile(Mask, SM.getFilename(SM.getFileLoc(Loc)), Category); +} + 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..5fb0f9660b15 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/SanitizerSpecialCaseList.cpp @@ -0,0 +1,63 @@ +//===--- 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, + std::string &Error) { + std::unique_ptr<clang::SanitizerSpecialCaseList> SSCL( + new SanitizerSpecialCaseList()); + if (SSCL->createInternal(Paths, Error)) { + SSCL->createSanitizerSections(); + return SSCL; + } + return nullptr; +} + +std::unique_ptr<SanitizerSpecialCaseList> +SanitizerSpecialCaseList::createOrDie(const std::vector<std::string> &Paths) { + std::string Error; + if (auto SSCL = create(Paths, 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..f5f81b5fb3e5 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Sanitizers.cpp @@ -0,0 +1,54 @@ +//===- 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/StringSwitch.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; +} + +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 { +llvm::hash_code hash_value(const clang::SanitizerMask &Arg) { + return Arg.hash_value(); +} +} // 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..c1fa406909fe --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/SourceLocation.cpp @@ -0,0 +1,253 @@ +//===- 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/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 +//===----------------------------------------------------------------------===// + +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 OS.str(); +} + +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 OS.str(); +} + +//===----------------------------------------------------------------------===// +// 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->getBuffer(SrcMgr->getFileID(*this), Invalid)->getBuffer(); +} + +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..12b0305e707c --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/SourceManager.cpp @@ -0,0 +1,2270 @@ +//===- 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/Optional.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Capacity.h" +#include "llvm/Support/Compiler.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 +//===----------------------------------------------------------------------===// + +ContentCache::~ContentCache() { + if (shouldFreeBuffer()) + delete Buffer.getPointer(); +} + +/// 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.getPointer() ? Buffer.getPointer()->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 { + assert(Buffer.getPointer()); + + // Should be unreachable, but keep for sanity. + if (!Buffer.getPointer()) + return llvm::MemoryBuffer::MemoryBuffer_Malloc; + + const llvm::MemoryBuffer *buf = Buffer.getPointer(); + return buf->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.getPointer() ? (unsigned) Buffer.getPointer()->getBufferSize() + : (unsigned) ContentsEntry->getSize(); +} + +void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B, bool DoNotFree) { + if (B && B == Buffer.getPointer()) { + assert(0 && "Replacing with the same buffer"); + Buffer.setInt(DoNotFree? DoNotFreeFlag : 0); + return; + } + + if (shouldFreeBuffer()) + delete Buffer.getPointer(); + Buffer.setPointer(B); + Buffer.setInt((B && DoNotFree) ? DoNotFreeFlag : 0); +} + +const llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag, + const SourceManager &SM, + SourceLocation Loc, + bool *Invalid) const { + // Lazily create the Buffer for ContentCaches that wrap files. If we already + // computed it, just return what we have. + if (Buffer.getPointer() || !ContentsEntry) { + if (Invalid) + *Invalid = isBufferInvalid(); + + return Buffer.getPointer(); + } + + // 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. + if ((uint64_t)ContentsEntry->getSize() >= + std::numeric_limits<unsigned>::max()) { + // We can't make a memory buffer of the required size, so just make a small + // one. We should never hit a situation where we've already parsed to a + // later offset of the file, so it shouldn't matter that the buffer is + // smaller than the file. + Buffer.setPointer( + llvm::MemoryBuffer::getMemBuffer("", ContentsEntry->getName()) + .release()); + if (Diag.isDiagnosticInFlight()) + Diag.SetDelayedDiagnostic(diag::err_file_too_large, + ContentsEntry->getName()); + else + Diag.Report(Loc, diag::err_file_too_large) + << ContentsEntry->getName(); + + Buffer.setInt(Buffer.getInt() | InvalidFlag); + if (Invalid) *Invalid = true; + return Buffer.getPointer(); + } + + bool isVolatile = SM.userFilesAreVolatile() && !IsSystemFile; + auto BufferOrError = + SM.getFileManager().getBufferForFile(ContentsEntry, isVolatile); + + // 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. + // + // FIXME: This is definitely not ideal, but our immediate clients can't + // currently handle returning a null entry here. Ideally we should detect + // that we are in an inconsistent situation and error out as quickly as + // possible. + if (!BufferOrError) { + StringRef FillStr("<<<MISSING SOURCE FILE>>>\n"); + auto BackupBuffer = llvm::WritableMemoryBuffer::getNewUninitMemBuffer( + ContentsEntry->getSize(), "<invalid>"); + char *Ptr = BackupBuffer->getBufferStart(); + for (unsigned i = 0, e = ContentsEntry->getSize(); i != e; ++i) + Ptr[i] = FillStr[i % FillStr.size()]; + Buffer.setPointer(BackupBuffer.release()); + + 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(); + + Buffer.setInt(Buffer.getInt() | InvalidFlag); + + if (Invalid) *Invalid = true; + return Buffer.getPointer(); + } + + Buffer.setPointer(BufferOrError->release()); + + // Check that the file's size is the same as in the file entry (which may + // have come from a stat cache). + if (getRawBuffer()->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(); + + Buffer.setInt(Buffer.getInt() | InvalidFlag); + if (Invalid) *Invalid = true; + return Buffer.getPointer(); + } + + // 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.getPointer()->getBuffer(); + 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); + + if (InvalidBOM) { + Diag.Report(Loc, diag::err_unsupported_bom) + << InvalidBOM << ContentsEntry->getName(); + Buffer.setInt(Buffer.getInt() | InvalidFlag); + } + + if (Invalid) + *Invalid = isBufferInvalid(); + + return Buffer.getPointer(); +} + +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]; + + // An unspecified FilenameID means use the last filename if available, or the + // main source file otherwise. + if (FilenameID == -1 && !Entries.empty()) + FilenameID = Entries.back().FilenameID; + + assert((Entries.empty() || Entries.back().FileOffset < Offset) && + "Adding line entries out of order!"); + + unsigned IncludeOffset = 0; + if (EntryExit == 0) { // No #include stack change. + IncludeOffset = Entries.empty() ? 0 : Entries.back().IncludeOffset; + } else if (EntryExit == 1) { + IncludeOffset = Offset-1; + } else if (EntryExit == 2) { + assert(!Entries.empty() && Entries.back().IncludeOffset && + "PPDirectives should have caught case when popping empty include stack"); + + // Get the include loc of the last entries' include loc as our include loc. + IncludeOffset = 0; + if (const LineEntry *PrevEntry = + FindNearestLineEntry(FID, Entries.back().IncludeOffset)) + IncludeOffset = PrevEntry->IncludeOffset; + } + + 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); +} + +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->IsSystemFile = Cache->IsSystemFile; + Clone->IsTransient = Cache->IsTransient; + Clone->replaceBuffer(Cache->getRawBuffer(), /*DoNotFree*/true); + 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); + } +} + +/// getOrCreateContentCache - Create or return a cached ContentCache for the +/// specified file. +const ContentCache * +SourceManager::getOrCreateContentCache(const FileEntry *FileEnt, + bool isSystemFile) { + assert(FileEnt && "Didn't specify a file entry to use?"); + + // 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->IsSystemFile = isSystemFile; + Entry->IsTransient = FilesAreTransient; + + return Entry; +} + +/// Create a new ContentCache for the specified memory buffer. +/// This does no caching. +const ContentCache * +SourceManager::createMemBufferContentCache(const llvm::MemoryBuffer *Buffer, + bool DoNotFree) { + // Add a new ContentCache to the MemBufferInfos list and return it. + ContentCache *Entry = ContentCacheAlloc.Allocate<ContentCache>(); + new (Entry) ContentCache(); + MemBufferInfos.push_back(Entry); + Entry->replaceBuffer(Buffer, DoNotFree); + 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. + LoadedSLocEntryTable[Index] = SLocEntry::get(0, + FileInfo::get(SourceLocation(), + getFakeContentCacheForRecovery(), + SrcMgr::C_User)); + } + } + + return LoadedSLocEntryTable[Index]; +} + +std::pair<int, unsigned> +SourceManager::AllocateLoadedSLocEntries(unsigned NumSLocEntries, + unsigned 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::MemoryBuffer *SourceManager::getFakeBufferForRecovery() const { + if (!FakeBufferForRecovery) + FakeBufferForRecovery = + llvm::MemoryBuffer::getMemBuffer("<<<INVALID BUFFER>>"); + + return FakeBufferForRecovery.get(); +} + +/// As part of recovering from missing or changed content, produce a +/// fake content cache. +const SrcMgr::ContentCache * +SourceManager::getFakeContentCacheForRecovery() const { + if (!FakeContentCacheForRecovery) { + FakeContentCacheForRecovery = llvm::make_unique<SrcMgr::ContentCache>(); + FakeContentCacheForRecovery->replaceBuffer(getFakeBufferForRecovery(), + /*DoNotFree=*/true); + } + return FakeContentCacheForRecovery.get(); +} + +/// 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. +//===----------------------------------------------------------------------===// + +/// 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::createFileID(const ContentCache *File, + SourceLocation IncludePos, + SrcMgr::CharacteristicKind FileCharacter, + int LoadedID, unsigned 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)); + SLocEntryLoaded[Index] = true; + return FileID::get(LoadedID); + } + LocalSLocEntryTable.push_back(SLocEntry::get(NextLocalOffset, + FileInfo::get(IncludePos, File, + FileCharacter))); + unsigned FileSize = File->getSize(); + assert(NextLocalOffset + FileSize + 1 > NextLocalOffset && + NextLocalOffset + FileSize + 1 <= CurrentLoadedOffset && + "Ran out of source locations!"); + // 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, + unsigned 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, + unsigned 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)); +} + +const llvm::MemoryBuffer * +SourceManager::getMemoryBufferForFile(const FileEntry *File, bool *Invalid) { + const SrcMgr::ContentCache *IR = getOrCreateContentCache(File); + assert(IR && "getOrCreateContentCache() cannot return NULL"); + return IR->getBuffer(Diag, *this, SourceLocation(), Invalid); +} + +void SourceManager::overrideFileContents(const FileEntry *SourceFile, + llvm::MemoryBuffer *Buffer, + bool DoNotFree) { + const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile); + assert(IR && "getOrCreateContentCache() cannot return NULL"); + + const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(Buffer, DoNotFree); + const_cast<SrcMgr::ContentCache *>(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; +} + +void SourceManager::disableFileContentsOverride(const FileEntry *File) { + if (!isFileOverridden(File)) + return; + + const SrcMgr::ContentCache *IR = getOrCreateContentCache(File); + const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(nullptr); + const_cast<SrcMgr::ContentCache *>(IR)->ContentsEntry = IR->OrigEntry; + + assert(OverriddenFilesInfo); + OverriddenFilesInfo->OverriddenFiles.erase(File); + OverriddenFilesInfo->OverriddenFilesWithBuffer.erase(File); +} + +void SourceManager::setFileIsTransient(const FileEntry *File) { + const SrcMgr::ContentCache *CC = getOrCreateContentCache(File); + const_cast<SrcMgr::ContentCache *>(CC)->IsTransient = true; +} + +StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const { + bool MyInvalid = false; + const SLocEntry &SLoc = getSLocEntry(FID, &MyInvalid); + if (!SLoc.isFile() || MyInvalid) { + if (Invalid) + *Invalid = true; + return "<<<<<INVALID SOURCE LOCATION>>>>>"; + } + + const llvm::MemoryBuffer *Buf = SLoc.getFile().getContentCache()->getBuffer( + Diag, *this, SourceLocation(), &MyInvalid); + if (Invalid) + *Invalid = MyInvalid; + + if (MyInvalid) + return "<<<<<INVALID SOURCE LOCATION>>>>>"; + + return Buf->getBuffer(); +} + +//===----------------------------------------------------------------------===// +// 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(unsigned 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(unsigned 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())); + + // If this isn't an expansion, remember it. We have good locality across + // FileID lookups. + if (!I->isExpansion()) + 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) { + bool Invalid = false; + unsigned MiddleIndex = (GreaterIndex-LessIndex)/2+LessIndex; + unsigned MidOffset = getLocalSLocEntry(MiddleIndex, &Invalid).getOffset(); + if (Invalid) + return FileID::get(0); + + ++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. + // FIXME: This could be made faster by using a function that's aware of + // being in the local area. + if (isOffsetInFileID(FileID::get(MiddleIndex), SLocOffset)) { + FileID Res = FileID::get(MiddleIndex); + + // If this isn't a macro expansion, remember it. We have good locality + // across FileID lookups. + if (!LocalSLocEntryTable[MiddleIndex].isExpansion()) + 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(unsigned SLocOffset) const { + // Sanity checking, otherwise a bug may lead to hanging in release build. + 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); + + if (!E.isExpansion()) + 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) { + // Sanity checking, otherwise a bug may lead to hanging in release build. + 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); + if (!E.isExpansion()) + LastFileIDLookup = Res; + NumBinaryProbes += NumProbes; + return Res; + } + + // Sanity checking, otherwise a bug may lead to hanging in release build. + 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); +} + +/// 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>>>>"; + } + const llvm::MemoryBuffer *Buffer = + Entry.getFile().getContentCache()->getBuffer( + Diag, *this, SourceLocation(), &CharDataInvalid); + if (Invalid) + *Invalid = CharDataInvalid; + return Buffer->getBufferStart() + (CharDataInvalid? 0 : LocInfo.second); +} + +/// 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 { + bool MyInvalid = false; + const llvm::MemoryBuffer *MemBuf = getBuffer(FID, &MyInvalid); + if (Invalid) + *Invalid = MyInvalid; + + if (MyInvalid) + 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 != nullptr && + LastLineNoResult < LastLineNoContentCache->NumLines) { + unsigned *SourceLineCache = LastLineNoContentCache->SourceLineCache; + 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(); +} + +#ifdef __SSE2__ +#include <emmintrin.h> +#endif + +static LLVM_ATTRIBUTE_NOINLINE void +ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI, + llvm::BumpPtrAllocator &Alloc, + const SourceManager &SM, bool &Invalid); +static void ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI, + llvm::BumpPtrAllocator &Alloc, + const SourceManager &SM, bool &Invalid) { + // Note that calling 'getBuffer()' may lazily page in the file. + const MemoryBuffer *Buffer = + FI->getBuffer(Diag, SM, SourceLocation(), &Invalid); + if (Invalid) + return; + + // 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(); + unsigned I = 0; + while (true) { + // Skip over the contents of the line. + while (Buf[I] != '\n' && Buf[I] != '\r' && Buf[I] != '\0') + ++I; + + if (Buf[I] == '\n' || Buf[I] == '\r') { + // If this is \r\n, skip both characters. + if (Buf[I] == '\r' && Buf[I+1] == '\n') + ++I; + ++I; + LineOffsets.push_back(I); + } else { + // Otherwise, this is a NUL. If end of file, exit. + if (Buf+I == End) break; + ++I; + } + } + + // Copy the offsets into the FileInfo structure. + FI->NumLines = LineOffsets.size(); + FI->SourceLineCache = Alloc.Allocate<unsigned>(LineOffsets.size()); + std::copy(LineOffsets.begin(), LineOffsets.end(), FI->SourceLineCache); +} + +/// 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; + } + + 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 = const_cast<ContentCache*>(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) { + bool MyInvalid = false; + ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid); + if (Invalid) + *Invalid = MyInvalid; + if (MyInvalid) + return 1; + } 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. + unsigned *SourceLineCache = Content->SourceLineCache; + unsigned *SourceLineCacheStart = SourceLineCache; + unsigned *SourceLineCacheEnd = SourceLineCache + Content->NumLines; + + 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->NumLines) + SourceLineCacheEnd = SourceLineCache+LastLineNoResult+1; + } + } + + 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); + bool Invalid = false; + const SLocEntry &SEntry = getSLocEntry(LocInfo.first, &Invalid); + if (Invalid || !SEntry.isFile()) + 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>"; + + return getBuffer(getFileID(Loc), Invalid)->getBufferIdentifier(); +} + +/// 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 + Filename = C->getBuffer(Diag, *this)->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); + + bool Invalid = false; + const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid); + if (Invalid || !Entry.isFile()) + 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; + unsigned 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. +//===----------------------------------------------------------------------===// + +/// Retrieve the inode for the given file entry, if possible. +/// +/// This routine involves a system call, and therefore should only be used +/// in non-performance-critical code. +static Optional<llvm::sys::fs::UniqueID> +getActualFileUID(const FileEntry *File) { + if (!File) + return None; + + llvm::sys::fs::UniqueID ID; + if (llvm::sys::fs::getUniqueID(File->getName(), ID)) + return None; + + return ID; +} + +/// 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!"); + + // Find the first file ID that corresponds to the given file. + FileID FirstFID; + + // First, check the main file ID, since it is common to look for a + // location in the main file. + Optional<llvm::sys::fs::UniqueID> SourceFileUID; + Optional<StringRef> SourceFileName; + if (MainFileID.isValid()) { + bool Invalid = false; + const SLocEntry &MainSLoc = getSLocEntry(MainFileID, &Invalid); + if (Invalid) + return FileID(); + + if (MainSLoc.isFile()) { + const ContentCache *MainContentCache + = MainSLoc.getFile().getContentCache(); + if (!MainContentCache || !MainContentCache->OrigEntry) { + // Can't do anything + } else if (MainContentCache->OrigEntry == SourceFile) { + FirstFID = MainFileID; + } else { + // Fall back: check whether we have the same base name and inode + // as the main file. + const FileEntry *MainFile = MainContentCache->OrigEntry; + SourceFileName = llvm::sys::path::filename(SourceFile->getName()); + if (*SourceFileName == llvm::sys::path::filename(MainFile->getName())) { + SourceFileUID = getActualFileUID(SourceFile); + if (SourceFileUID) { + if (Optional<llvm::sys::fs::UniqueID> MainFileUID = + getActualFileUID(MainFile)) { + if (*SourceFileUID == *MainFileUID) { + FirstFID = MainFileID; + SourceFile = MainFile; + } + } + } + } + } + } + } + + if (FirstFID.isInvalid()) { + // 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) { + bool Invalid = false; + const SLocEntry &SLoc = getLocalSLocEntry(I, &Invalid); + if (Invalid) + return FileID(); + + if (SLoc.isFile() && + SLoc.getFile().getContentCache() && + SLoc.getFile().getContentCache()->OrigEntry == SourceFile) { + FirstFID = FileID::get(I); + break; + } + } + // If that still didn't help, try the modules. + if (FirstFID.isInvalid()) { + for (unsigned I = 0, N = loaded_sloc_entry_size(); I != N; ++I) { + const SLocEntry &SLoc = getLoadedSLocEntry(I); + if (SLoc.isFile() && + SLoc.getFile().getContentCache() && + SLoc.getFile().getContentCache()->OrigEntry == SourceFile) { + FirstFID = FileID::get(-int(I) - 2); + break; + } + } + } + } + + // If we haven't found what we want yet, try again, but this time stat() + // each of the files in case the files have changed since we originally + // parsed the file. + if (FirstFID.isInvalid() && + (SourceFileName || + (SourceFileName = llvm::sys::path::filename(SourceFile->getName()))) && + (SourceFileUID || (SourceFileUID = getActualFileUID(SourceFile)))) { + bool Invalid = false; + for (unsigned I = 0, N = local_sloc_entry_size(); I != N; ++I) { + FileID IFileID; + IFileID.ID = I; + const SLocEntry &SLoc = getSLocEntry(IFileID, &Invalid); + if (Invalid) + return FileID(); + + if (SLoc.isFile()) { + const ContentCache *FileContentCache + = SLoc.getFile().getContentCache(); + const FileEntry *Entry = FileContentCache ? FileContentCache->OrigEntry + : nullptr; + if (Entry && + *SourceFileName == llvm::sys::path::filename(Entry->getName())) { + if (Optional<llvm::sys::fs::UniqueID> EntryUID = + getActualFileUID(Entry)) { + if (*SourceFileUID == *EntryUID) { + FirstFID = FileID::get(I); + SourceFile = Entry; + break; + } + } + } + } + } + } + + (void) SourceFile; + return FirstFID; +} + +/// 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; + + ContentCache *Content + = const_cast<ContentCache *>(Entry.getFile().getContentCache()); + if (!Content) + return SourceLocation(); + + // If this is the first use of line information for this buffer, compute the + // SourceLineCache for it on demand. + if (!Content->SourceLineCache) { + bool MyInvalid = false; + ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid); + if (MyInvalid) + return SourceLocation(); + } + + if (Line > Content->NumLines) { + unsigned Size = Content->getBuffer(Diag, *this)->getBufferSize(); + if (Size > 0) + --Size; + return FileLoc.getLocWithOffset(Size); + } + + const llvm::MemoryBuffer *Buffer = Content->getBuffer(Diag, *this); + 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()) { + SourceLocation IncludeLoc = Entry.getFile().getIncludeLoc(); + if (IncludeLoc.isInvalid()) + continue; + if (!isInFileID(IncludeLoc, FID)) + return; // No more files/macros that may be "contained" in this file. + + // 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; + } + + 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()) { + unsigned SpellBeginOffs = SpellLoc.getOffset(); + unsigned 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); + unsigned SpellFIDBeginOffs = Entry.getOffset(); + unsigned SpellFIDSize = getFileIDSize(SpellFID); + unsigned 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 = llvm::make_unique<MacroArgsMap>(); + computeMacroArgsCache(*MacroArgsCache, FID); + } + + assert(!MacroArgsCache->empty()); + MacroArgsMap::iterator I = MacroArgsCache->upper_bound(Offset); + --I; + + unsigned 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 = getBuffer(LOffs.first)->getBufferIdentifier(); + StringRef RB = getBuffer(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 += I->second->SourceLineCache != nullptr; + 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<unsigned> 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"; + if (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<unsigned> 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 = + llvm::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 = llvm::make_unique<DiagnosticsEngine>( + IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), + new DiagnosticOptions); + SourceMgr = llvm::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/TargetInfo.cpp b/contrib/llvm-project/clang/lib/Basic/TargetInfo.cpp new file mode 100644 index 000000000000..a9dfe69b90c5 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/TargetInfo.cpp @@ -0,0 +1,815 @@ +//===--- 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) : TargetOpts(), 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; + HasFloat16 = 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. + if (T.isGNUEnvironment() || T.isWindowsMSVCEnvironment() || T.isAndroid()) + NewAlign = Triple.isArch64Bit() ? 128 : Triple.isArch32Bit() ? 64 : 0; + 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; + 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; + SigAtomicType = SignedInt; + ProcessIDType = SignedInt; + UseSignedCharForObjCBool = true; + UseBitFieldTypeAlignment = true; + UseZeroLengthBitfieldAlignment = false; + UseExplicitBitFieldAlignment = true; + ZeroLengthBitfieldBoundary = 0; + HalfFormat = &llvm::APFloat::IEEEhalf(); + FloatFormat = &llvm::APFloat::IEEEsingle(); + DoubleFormat = &llvm::APFloat::IEEEdouble(); + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + Float128Format = &llvm::APFloat::IEEEquad(); + MCountName = "mcount"; + RegParmMax = 0; + SSERegParmMax = 0; + HasAlignMac68kSupport = false; + HasBuiltinMSVaList = false; + IsRenderScriptTarget = false; + + // 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(); +} + +// Out of line virtual dtor for TargetInfo. +TargetInfo::~TargetInfo() {} + +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; +} + +TargetInfo::RealType TargetInfo::getRealTypeByWidth(unsigned BitWidth) const { + if (getFloatWidth() == BitWidth) + return Float; + if (getDoubleWidth() == BitWidth) + return Double; + + switch (BitWidth) { + case 96: + if (&getLongDoubleFormat() == &llvm::APFloat::x87DoubleExtended()) + return LongDouble; + break; + case 128: + if (&getLongDoubleFormat() == &llvm::APFloat::PPCDoubleDouble() || + &getLongDoubleFormat() == &llvm::APFloat::IEEEquad()) + return LongDouble; + if (hasFloat128Type()) + return Float128; + break; + } + + return 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(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(); + } + + 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(); +} + +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"); +} + +/// 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..63a64ed2931a --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets.cpp @@ -0,0 +1,675 @@ +//===--- 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/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/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: + return new HexagonTargetInfo(Triple, Opts); + + case llvm::Triple::lanai: + return new LanaiTargetInfo(Triple, Opts); + + 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::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::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::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::NetBSD: + return new NetBSDTargetInfo<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::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::OpenBSD: + return new OpenBSDTargetInfo<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::OpenBSD: + return new OpenBSDTargetInfo<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); + 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::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 (Triple.getOS() != llvm::Triple::UnknownOS || + Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) + return nullptr; + return new SPIR32TargetInfo(Triple, Opts); + } + case llvm::Triple::spir64: { + if (Triple.getOS() != llvm::Triple::UnknownOS || + Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) + return nullptr; + return new SPIR64TargetInfo(Triple, Opts); + } + case llvm::Triple::wasm32: + if (Triple.getSubArch() != llvm::Triple::NoSubArch || + Triple.getVendor() != llvm::Triple::UnknownVendor || + !Triple.isOSBinFormatWasm()) + return nullptr; + switch (Triple.getOS()) { + 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 (Triple.getOS()) { + 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); + } +} +} // 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; + } + + // 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. + llvm::StringMap<bool> Features; + if (!Target->initFeatureMap(Features, Diags, Opts->CPU, + Opts->FeaturesAsWritten)) + return nullptr; + + // Add the features to the compile options. + Opts->Features.clear(); + for (const auto &F : Features) + 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->setOpenCLExtensionOpts(); + Target->setMaxAtomicWidth(); + + if (!Target->validateTarget(Diags)) + return nullptr; + + Target->CheckFixedPointBits(); + + return Target.release(); +} 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..25f2b7b35f41 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/AArch64.cpp @@ -0,0 +1,659 @@ +//===--- 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/TargetBuiltins.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringExtras.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}, +#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" +}; + +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; + + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + MaxVectorAlign = 128; + MaxAtomicInlineWidth = 128; + MaxAtomicPromoteWidth = 128; + + LongDoubleWidth = LongDoubleAlign = SuitableAlign = 128; + LongDoubleFormat = &llvm::APFloat::IEEEquad(); + + // Make __builtin_ms_va_list available. + HasBuiltinMSVaList = 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::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"); +} + +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_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 + // FIXME: Armv8.4 makes some extensions mandatory. Handle them here. + getTargetDefinesARMV83A(Opts, Builder); +} + +void AArch64TargetInfo::getTargetDefinesARMV85A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Also include the Armv8.4 defines + // FIXME: Armv8.5 makes some extensions mandatory. Handle them here. + getTargetDefinesARMV84A(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()) { + Builder.defineMacro("_LP64"); + Builder.defineMacro("__LP64__"); + } + + // ACLE predefines. Many can only have one possible value on v8 AArch64. + Builder.defineMacro("__ARM_ACLE", "200"); + Builder.defineMacro("__ARM_ARCH", "8"); + Builder.defineMacro("__ARM_ARCH_PROFILE", "'A'"); + + 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 (HasCRC) + Builder.defineMacro("__ARM_FEATURE_CRC32", "1"); + + if (HasCrypto) + Builder.defineMacro("__ARM_FEATURE_CRYPTO", "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 ((FPU & NeonMode) && HasFP16FML) + Builder.defineMacro("__ARM_FEATURE_FP16FML", "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; + } + + // 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"); +} + +ArrayRef<Builtin::Info> AArch64TargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::AArch64::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} + +bool AArch64TargetInfo::hasFeature(StringRef Feature) const { + return Feature == "aarch64" || Feature == "arm64" || Feature == "arm" || + (Feature == "neon" && (FPU & NeonMode)) || + (Feature == "sve" && (FPU & SveMode)); +} + +bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) { + FPU = FPUMode; + HasCRC = false; + HasCrypto = false; + HasUnaligned = true; + HasFullFP16 = false; + HasDotProd = false; + HasFP16FML = false; + HasMTE = false; + ArchKind = llvm::AArch64::ArchKind::ARMV8A; + + for (const auto &Feature : Features) { + if (Feature == "+neon") + FPU |= NeonMode; + if (Feature == "+sve") + FPU |= SveMode; + if (Feature == "+crc") + HasCRC = true; + if (Feature == "+crypto") + HasCrypto = true; + if (Feature == "+strict-align") + HasUnaligned = false; + 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 == "+fullfp16") + HasFullFP16 = true; + if (Feature == "+dotprod") + HasDotProd = true; + if (Feature == "+fp16fml") + HasFP16FML = true; + if (Feature == "+mte") + HasMTE = true; + } + + setDataLayout(); + + return true; +} + +TargetInfo::CallingConvCheckResult +AArch64TargetInfo::checkCallingConvention(CallingConv CC) const { + switch (CC) { + case CC_C: + case CC_Swift: + 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': + // 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. + llvm_unreachable("FIXME: Unimplemented support for U* constraints."); + case 'z': // Zero register, wzr or xzr + Info.setAllowsRegister(); + return true; + case 'x': // Floating point and SIMD registers (V0-V15) + 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; + + 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; +} + +AArch64leTargetInfo::AArch64leTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : AArch64TargetInfo(Triple, Opts) {} + +void AArch64leTargetInfo::setDataLayout() { + if (getTriple().isOSBinFormatMachO()) + 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("e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128"); +} + +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_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; + UseSignedCharForObjCBool = false; + + LongDoubleWidth = LongDoubleAlign = SuitableAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + + TheCXXABI.set(TargetCXXABI::iOS64); +} + +void DarwinAArch64TargetInfo::getOSDefines(const LangOptions &Opts, + const llvm::Triple &Triple, + MacroBuilder &Builder) const { + Builder.defineMacro("__AARCH64_SIMD__"); + 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"); + + 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..5833c146003b --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/AArch64.h @@ -0,0 +1,184 @@ +//===--- 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/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 HasUnaligned; + bool HasFullFP16; + bool HasDotProd; + bool HasFP16FML; + bool HasMTE; + + llvm::AArch64::ArchKind ArchKind; + + static const Builtin::Info BuiltinInfo[]; + + std::string ABI; + +public: + AArch64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); + + StringRef getABI() const override; + bool setABI(const std::string &Name) 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 getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() 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; + 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; +}; + +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..b5c82e288570 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/AMDGPU.cpp @@ -0,0 +1,350 @@ +//===--- 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"; + +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" + "-ni:7"; + +const LangASMap AMDGPUTargetInfo::AMDGPUDefIsGenMap = { + Generic, // Default + Global, // opencl_global + Local, // opencl_local + Constant, // opencl_constant + Private, // opencl_private + Generic, // opencl_generic + Global, // cuda_device + Constant, // cuda_constant + Local // cuda_shared +}; + +const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = { + Private, // Default + Global, // opencl_global + Local, // opencl_local + Constant, // opencl_constant + Private, // opencl_private + Generic, // opencl_generic + Global, // cuda_device + Constant, // cuda_constant + Local // cuda_shared +}; +} // 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" +}; + +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())) { + if (CPU.empty()) + CPU = "gfx600"; + + switch (llvm::AMDGPU::parseArchAMDGCN(CPU)) { + case GK_GFX1012: + case GK_GFX1011: + Features["dot1-insts"] = true; + Features["dot2-insts"] = true; + Features["dot5-insts"] = true; + Features["dot6-insts"] = true; + LLVM_FALLTHROUGH; + case GK_GFX1010: + Features["dl-insts"] = true; + Features["ci-insts"] = 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; + break; + case GK_GFX908: + Features["dot3-insts"] = true; + Features["dot4-insts"] = true; + Features["dot5-insts"] = true; + Features["dot6-insts"] = true; + LLVM_FALLTHROUGH; + case GK_GFX906: + Features["dl-insts"] = true; + Features["dot1-insts"] = true; + Features["dot2-insts"] = true; + LLVM_FALLTHROUGH; + case GK_GFX909: + case GK_GFX904: + case GK_GFX902: + case GK_GFX900: + Features["gfx9-insts"] = true; + LLVM_FALLTHROUGH; + case GK_GFX810: + 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_GFX704: + case GK_GFX703: + case GK_GFX702: + case GK_GFX701: + case GK_GFX700: + Features["ci-insts"] = true; + LLVM_FALLTHROUGH; + case GK_GFX601: + case GK_GFX600: + break; + case GK_NONE: + return false; + 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::adjustTargetOptions(const CodeGenOptions &CGOpts, + TargetOptions &TargetOpts) const { + bool hasFP32Denormals = false; + bool hasFP64Denormals = false; + + for (auto &I : TargetOpts.FeaturesAsWritten) { + if (I == "+fp32-denormals" || I == "-fp32-denormals") + hasFP32Denormals = true; + if (I == "+fp64-fp16-denormals" || I == "-fp64-fp16-denormals") + hasFP64Denormals = true; + } + if (!hasFP32Denormals) + TargetOpts.Features.push_back( + (Twine(hasFastFMAF() && hasFullRateDenormalsF32() && !CGOpts.FlushDenorm + ? '+' : '-') + Twine("fp32-denormals")) + .str()); + // Always do not flush fp64 or fp16 denorms. + if (!hasFP64Denormals && hasFP64()) + TargetOpts.Features.push_back("+fp64-fp16-denormals"); +} + +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); + assert(DataLayout->getAllocaAddrSpace() == Private); + + setAddressSpaceMap(Triple.getOS() == llvm::Triple::Mesa3D || + !isAMDGCN(Triple)); + UseAddrSpaceMapMangling = true; + + HasLegalHalfType = true; + HasFloat16 = true; + + // Set pointer width and alignment for target address space 0. + PointerWidth = PointerAlign = DataLayout->getPointerSizeInBits(); + if (getMaxPointerWidth() == 64) { + LongWidth = LongAlign = 64; + SizeType = UnsignedLong; + PtrDiffType = SignedLong; + IntPtrType = SignedLong; + } + + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; +} + +void AMDGPUTargetInfo::adjust(LangOptions &Opts) { + TargetInfo::adjust(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("__")); + } + + // 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"); +} + +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; +} 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..456cb2ebb8b5 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/AMDGPU.h @@ -0,0 +1,360 @@ +//===--- 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/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; + + 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(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 + /// {vn}, {v[n]} + /// {sn}, {s[n]} + /// {S} , where S is a special register name + ////{v[n:m]} + /// {s[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", + }); + + StringRef S(Name); + bool HasLeftParen = false; + if (S.front() == '{') { + HasLeftParen = true; + S = S.drop_front(); + } + if (S.empty()) + return false; + if (S.front() != 'v' && S.front() != 's') { + 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 or v. + 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}, {v[n]}, {s[n]}, {v[n:m]}, or {s[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 { + 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; + + void adjustTargetOptions(const CodeGenOptions &CGOpts, + TargetOptions &TargetOpts) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; + + 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.support("cl_clang_storage_class_specifiers"); + Opts.support("cl_khr_icd"); + + bool IsAMDGCN = isAMDGCN(getTriple()); + + if (hasFP64()) + Opts.support("cl_khr_fp64"); + + if (IsAMDGCN || GPUKind >= llvm::AMDGPU::GK_CEDAR) { + Opts.support("cl_khr_byte_addressable_store"); + Opts.support("cl_khr_global_int32_base_atomics"); + Opts.support("cl_khr_global_int32_extended_atomics"); + Opts.support("cl_khr_local_int32_base_atomics"); + Opts.support("cl_khr_local_int32_extended_atomics"); + } + + if (IsAMDGCN) { + Opts.support("cl_khr_fp16"); + Opts.support("cl_khr_int64_base_atomics"); + Opts.support("cl_khr_int64_extended_atomics"); + Opts.support("cl_khr_mipmap_image"); + Opts.support("cl_khr_subgroups"); + Opts.support("cl_khr_3d_image_writes"); + Opts.support("cl_amd_media_ops"); + Opts.support("cl_amd_media_ops2"); + } + } + + 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 { + return LangAS::Default; + } + + llvm::Optional<LangAS> getConstantAddressSpace() const override { + return getLangASFromTargetAS(Constant); + } + + /// \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 { + return AS == LangAS::opencl_local ? ~0 : 0; + } + + void setAuxTarget(const TargetInfo *Aux) override; +}; + +} // 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..c43a39984edb --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/ARC.h @@ -0,0 +1,73 @@ +//===--- 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; + } +}; + +} // 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..31b7085f6ce2 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/ARM.cpp @@ -0,0 +1,1171 @@ +//===--- 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; + 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; + + 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 = 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::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::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) + if (IsAAPCS && (Triple.getEnvironment() != llvm::Triple::Android)) + 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 + ? "\01__gnu_mcount_nc" + : "\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; +} + +// 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 + unsigned 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; + DSP = 0; + Unaligned = 1; + SoftFloat = false; + // Note that SoftFloatABI is initialized in our constructor. + HWDiv = 0; + DotProd = 0; + HasFloat16 = true; + + // 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 == "+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") { + DSP = 1; + MVE |= MVE_INT; + } else if (Feature == "+mve.fp") { + DSP = 1; + HasLegalHalfType = true; + FPU |= FPARMV8; + MVE |= MVE_INT | MVE_FP; + HW_FP |= HW_FP_SP | HW_FP_HP; + } + } + + 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: + 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::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::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 + if (Crypto) + Builder.defineMacro("__ARM_FEATURE_CRYPTO", "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__"); + + if (FPUModeIsVFP((FPUMode)FPU)) { + Builder.defineMacro("__VFP_FP__"); + 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"); + } + + 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"); + + switch (ArchKind) { + default: + break; + case llvm::ARM::ArchKind::ARMV8_1A: + getTargetDefinesARMV81A(Opts, Builder); + break; + case llvm::ARM::ArchKind::ARMV8_2A: + getTargetDefinesARMV82A(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 + case 'h': // r8-r15 + case 't': // VFP Floating point register single precision + case 'w': // VFP Floating point register double precision + Info.setAllowsRegister(); + return true; + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + // FIXME + return true; + 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_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: + 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..ce87a6265934 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/ARM.h @@ -0,0 +1,277 @@ +//===--- 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/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 DSP : 1; + unsigned Unaligned : 1; + unsigned DotProd : 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; + + 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; + + // 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 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 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; +}; + +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..d865676700b5 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/AVR.cpp @@ -0,0 +1,311 @@ +//===--- 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; +}; + +// This list should be kept up-to-date with AVRDevices.td in LLVM. +static MCUInfo AVRMcus[] = { + {"at90s1200", "__AVR_AT90S1200__"}, + {"attiny11", "__AVR_ATtiny11__"}, + {"attiny12", "__AVR_ATtiny12__"}, + {"attiny15", "__AVR_ATtiny15__"}, + {"attiny28", "__AVR_ATtiny28__"}, + {"at90s2313", "__AVR_AT90S2313__"}, + {"at90s2323", "__AVR_AT90S2323__"}, + {"at90s2333", "__AVR_AT90S2333__"}, + {"at90s2343", "__AVR_AT90S2343__"}, + {"attiny22", "__AVR_ATtiny22__"}, + {"attiny26", "__AVR_ATtiny26__"}, + {"at86rf401", "__AVR_AT86RF401__"}, + {"at90s4414", "__AVR_AT90S4414__"}, + {"at90s4433", "__AVR_AT90S4433__"}, + {"at90s4434", "__AVR_AT90S4434__"}, + {"at90s8515", "__AVR_AT90S8515__"}, + {"at90c8534", "__AVR_AT90c8534__"}, + {"at90s8535", "__AVR_AT90S8535__"}, + {"ata5272", "__AVR_ATA5272__"}, + {"attiny13", "__AVR_ATtiny13__"}, + {"attiny13a", "__AVR_ATtiny13A__"}, + {"attiny2313", "__AVR_ATtiny2313__"}, + {"attiny2313a", "__AVR_ATtiny2313A__"}, + {"attiny24", "__AVR_ATtiny24__"}, + {"attiny24a", "__AVR_ATtiny24A__"}, + {"attiny4313", "__AVR_ATtiny4313__"}, + {"attiny44", "__AVR_ATtiny44__"}, + {"attiny44a", "__AVR_ATtiny44A__"}, + {"attiny84", "__AVR_ATtiny84__"}, + {"attiny84a", "__AVR_ATtiny84A__"}, + {"attiny25", "__AVR_ATtiny25__"}, + {"attiny45", "__AVR_ATtiny45__"}, + {"attiny85", "__AVR_ATtiny85__"}, + {"attiny261", "__AVR_ATtiny261__"}, + {"attiny261a", "__AVR_ATtiny261A__"}, + {"attiny461", "__AVR_ATtiny461__"}, + {"attiny461a", "__AVR_ATtiny461A__"}, + {"attiny861", "__AVR_ATtiny861__"}, + {"attiny861a", "__AVR_ATtiny861A__"}, + {"attiny87", "__AVR_ATtiny87__"}, + {"attiny43u", "__AVR_ATtiny43U__"}, + {"attiny48", "__AVR_ATtiny48__"}, + {"attiny88", "__AVR_ATtiny88__"}, + {"attiny828", "__AVR_ATtiny828__"}, + {"at43usb355", "__AVR_AT43USB355__"}, + {"at76c711", "__AVR_AT76C711__"}, + {"atmega103", "__AVR_ATmega103__"}, + {"at43usb320", "__AVR_AT43USB320__"}, + {"attiny167", "__AVR_ATtiny167__"}, + {"at90usb82", "__AVR_AT90USB82__"}, + {"at90usb162", "__AVR_AT90USB162__"}, + {"ata5505", "__AVR_ATA5505__"}, + {"atmega8u2", "__AVR_ATmega8U2__"}, + {"atmega16u2", "__AVR_ATmega16U2__"}, + {"atmega32u2", "__AVR_ATmega32U2__"}, + {"attiny1634", "__AVR_ATtiny1634__"}, + {"atmega8", "__AVR_ATmega8__"}, + {"ata6289", "__AVR_ATA6289__"}, + {"atmega8a", "__AVR_ATmega8A__"}, + {"ata6285", "__AVR_ATA6285__"}, + {"ata6286", "__AVR_ATA6286__"}, + {"atmega48", "__AVR_ATmega48__"}, + {"atmega48a", "__AVR_ATmega48A__"}, + {"atmega48pa", "__AVR_ATmega48PA__"}, + {"atmega48p", "__AVR_ATmega48P__"}, + {"atmega88", "__AVR_ATmega88__"}, + {"atmega88a", "__AVR_ATmega88A__"}, + {"atmega88p", "__AVR_ATmega88P__"}, + {"atmega88pa", "__AVR_ATmega88PA__"}, + {"atmega8515", "__AVR_ATmega8515__"}, + {"atmega8535", "__AVR_ATmega8535__"}, + {"atmega8hva", "__AVR_ATmega8HVA__"}, + {"at90pwm1", "__AVR_AT90PWM1__"}, + {"at90pwm2", "__AVR_AT90PWM2__"}, + {"at90pwm2b", "__AVR_AT90PWM2B__"}, + {"at90pwm3", "__AVR_AT90PWM3__"}, + {"at90pwm3b", "__AVR_AT90PWM3B__"}, + {"at90pwm81", "__AVR_AT90PWM81__"}, + {"ata5790", "__AVR_ATA5790__"}, + {"ata5795", "__AVR_ATA5795__"}, + {"atmega16", "__AVR_ATmega16__"}, + {"atmega16a", "__AVR_ATmega16A__"}, + {"atmega161", "__AVR_ATmega161__"}, + {"atmega162", "__AVR_ATmega162__"}, + {"atmega163", "__AVR_ATmega163__"}, + {"atmega164a", "__AVR_ATmega164A__"}, + {"atmega164p", "__AVR_ATmega164P__"}, + {"atmega164pa", "__AVR_ATmega164PA__"}, + {"atmega165", "__AVR_ATmega165__"}, + {"atmega165a", "__AVR_ATmega165A__"}, + {"atmega165p", "__AVR_ATmega165P__"}, + {"atmega165pa", "__AVR_ATmega165PA__"}, + {"atmega168", "__AVR_ATmega168__"}, + {"atmega168a", "__AVR_ATmega168A__"}, + {"atmega168p", "__AVR_ATmega168P__"}, + {"atmega168pa", "__AVR_ATmega168PA__"}, + {"atmega169", "__AVR_ATmega169__"}, + {"atmega169a", "__AVR_ATmega169A__"}, + {"atmega169p", "__AVR_ATmega169P__"}, + {"atmega169pa", "__AVR_ATmega169PA__"}, + {"atmega32", "__AVR_ATmega32__"}, + {"atmega32a", "__AVR_ATmega32A__"}, + {"atmega323", "__AVR_ATmega323__"}, + {"atmega324a", "__AVR_ATmega324A__"}, + {"atmega324p", "__AVR_ATmega324P__"}, + {"atmega324pa", "__AVR_ATmega324PA__"}, + {"atmega325", "__AVR_ATmega325__"}, + {"atmega325a", "__AVR_ATmega325A__"}, + {"atmega325p", "__AVR_ATmega325P__"}, + {"atmega325pa", "__AVR_ATmega325PA__"}, + {"atmega3250", "__AVR_ATmega3250__"}, + {"atmega3250a", "__AVR_ATmega3250A__"}, + {"atmega3250p", "__AVR_ATmega3250P__"}, + {"atmega3250pa", "__AVR_ATmega3250PA__"}, + {"atmega328", "__AVR_ATmega328__"}, + {"atmega328p", "__AVR_ATmega328P__"}, + {"atmega329", "__AVR_ATmega329__"}, + {"atmega329a", "__AVR_ATmega329A__"}, + {"atmega329p", "__AVR_ATmega329P__"}, + {"atmega329pa", "__AVR_ATmega329PA__"}, + {"atmega3290", "__AVR_ATmega3290__"}, + {"atmega3290a", "__AVR_ATmega3290A__"}, + {"atmega3290p", "__AVR_ATmega3290P__"}, + {"atmega3290pa", "__AVR_ATmega3290PA__"}, + {"atmega406", "__AVR_ATmega406__"}, + {"atmega64", "__AVR_ATmega64__"}, + {"atmega64a", "__AVR_ATmega64A__"}, + {"atmega640", "__AVR_ATmega640__"}, + {"atmega644", "__AVR_ATmega644__"}, + {"atmega644a", "__AVR_ATmega644A__"}, + {"atmega644p", "__AVR_ATmega644P__"}, + {"atmega644pa", "__AVR_ATmega644PA__"}, + {"atmega645", "__AVR_ATmega645__"}, + {"atmega645a", "__AVR_ATmega645A__"}, + {"atmega645p", "__AVR_ATmega645P__"}, + {"atmega649", "__AVR_ATmega649__"}, + {"atmega649a", "__AVR_ATmega649A__"}, + {"atmega649p", "__AVR_ATmega649P__"}, + {"atmega6450", "__AVR_ATmega6450__"}, + {"atmega6450a", "__AVR_ATmega6450A__"}, + {"atmega6450p", "__AVR_ATmega6450P__"}, + {"atmega6490", "__AVR_ATmega6490__"}, + {"atmega6490a", "__AVR_ATmega6490A__"}, + {"atmega6490p", "__AVR_ATmega6490P__"}, + {"atmega64rfr2", "__AVR_ATmega64RFR2__"}, + {"atmega644rfr2", "__AVR_ATmega644RFR2__"}, + {"atmega16hva", "__AVR_ATmega16HVA__"}, + {"atmega16hva2", "__AVR_ATmega16HVA2__"}, + {"atmega16hvb", "__AVR_ATmega16HVB__"}, + {"atmega16hvbrevb", "__AVR_ATmega16HVBREVB__"}, + {"atmega32hvb", "__AVR_ATmega32HVB__"}, + {"atmega32hvbrevb", "__AVR_ATmega32HVBREVB__"}, + {"atmega64hve", "__AVR_ATmega64HVE__"}, + {"at90can32", "__AVR_AT90CAN32__"}, + {"at90can64", "__AVR_AT90CAN64__"}, + {"at90pwm161", "__AVR_AT90PWM161__"}, + {"at90pwm216", "__AVR_AT90PWM216__"}, + {"at90pwm316", "__AVR_AT90PWM316__"}, + {"atmega32c1", "__AVR_ATmega32C1__"}, + {"atmega64c1", "__AVR_ATmega64C1__"}, + {"atmega16m1", "__AVR_ATmega16M1__"}, + {"atmega32m1", "__AVR_ATmega32M1__"}, + {"atmega64m1", "__AVR_ATmega64M1__"}, + {"atmega16u4", "__AVR_ATmega16U4__"}, + {"atmega32u4", "__AVR_ATmega32U4__"}, + {"atmega32u6", "__AVR_ATmega32U6__"}, + {"at90usb646", "__AVR_AT90USB646__"}, + {"at90usb647", "__AVR_AT90USB647__"}, + {"at90scr100", "__AVR_AT90SCR100__"}, + {"at94k", "__AVR_AT94K__"}, + {"m3000", "__AVR_AT000__"}, + {"atmega128", "__AVR_ATmega128__"}, + {"atmega128a", "__AVR_ATmega128A__"}, + {"atmega1280", "__AVR_ATmega1280__"}, + {"atmega1281", "__AVR_ATmega1281__"}, + {"atmega1284", "__AVR_ATmega1284__"}, + {"atmega1284p", "__AVR_ATmega1284P__"}, + {"atmega128rfa1", "__AVR_ATmega128RFA1__"}, + {"atmega128rfr2", "__AVR_ATmega128RFR2__"}, + {"atmega1284rfr2", "__AVR_ATmega1284RFR2__"}, + {"at90can128", "__AVR_AT90CAN128__"}, + {"at90usb1286", "__AVR_AT90USB1286__"}, + {"at90usb1287", "__AVR_AT90USB1287__"}, + {"atmega2560", "__AVR_ATmega2560__"}, + {"atmega2561", "__AVR_ATmega2561__"}, + {"atmega256rfr2", "__AVR_ATmega256RFR2__"}, + {"atmega2564rfr2", "__AVR_ATmega2564RFR2__"}, + {"atxmega16a4", "__AVR_ATxmega16A4__"}, + {"atxmega16a4u", "__AVR_ATxmega16a4U__"}, + {"atxmega16c4", "__AVR_ATxmega16C4__"}, + {"atxmega16d4", "__AVR_ATxmega16D4__"}, + {"atxmega32a4", "__AVR_ATxmega32A4__"}, + {"atxmega32a4u", "__AVR_ATxmega32A4U__"}, + {"atxmega32c4", "__AVR_ATxmega32C4__"}, + {"atxmega32d4", "__AVR_ATxmega32D4__"}, + {"atxmega32e5", "__AVR_ATxmega32E5__"}, + {"atxmega16e5", "__AVR_ATxmega16E5__"}, + {"atxmega8e5", "__AVR_ATxmega8E5__"}, + {"atxmega32x1", "__AVR_ATxmega32X1__"}, + {"atxmega64a3", "__AVR_ATxmega64A3__"}, + {"atxmega64a3u", "__AVR_ATxmega64A3U__"}, + {"atxmega64a4u", "__AVR_ATxmega64A4U__"}, + {"atxmega64b1", "__AVR_ATxmega64B1__"}, + {"atxmega64b3", "__AVR_ATxmega64B3__"}, + {"atxmega64c3", "__AVR_ATxmega64C3__"}, + {"atxmega64d3", "__AVR_ATxmega64D3__"}, + {"atxmega64d4", "__AVR_ATxmega64D4__"}, + {"atxmega64a1", "__AVR_ATxmega64A1__"}, + {"atxmega64a1u", "__AVR_ATxmega64A1U__"}, + {"atxmega128a3", "__AVR_ATxmega128A3__"}, + {"atxmega128a3u", "__AVR_ATxmega128A3U__"}, + {"atxmega128b1", "__AVR_ATxmega128B1__"}, + {"atxmega128b3", "__AVR_ATxmega128B3__"}, + {"atxmega128c3", "__AVR_ATxmega128C3__"}, + {"atxmega128d3", "__AVR_ATxmega128D3__"}, + {"atxmega128d4", "__AVR_ATxmega128D4__"}, + {"atxmega192a3", "__AVR_ATxmega192A3__"}, + {"atxmega192a3u", "__AVR_ATxmega192A3U__"}, + {"atxmega192c3", "__AVR_ATxmega192C3__"}, + {"atxmega192d3", "__AVR_ATxmega192D3__"}, + {"atxmega256a3", "__AVR_ATxmega256A3__"}, + {"atxmega256a3u", "__AVR_ATxmega256A3U__"}, + {"atxmega256a3b", "__AVR_ATxmega256A3B__"}, + {"atxmega256a3bu", "__AVR_ATxmega256A3BU__"}, + {"atxmega256c3", "__AVR_ATxmega256C3__"}, + {"atxmega256d3", "__AVR_ATxmega256D3__"}, + {"atxmega384c3", "__AVR_ATxmega384C3__"}, + {"atxmega384d3", "__AVR_ATxmega384D3__"}, + {"atxmega128a1", "__AVR_ATxmega128A1__"}, + {"atxmega128a1u", "__AVR_ATxmega128A1U__"}, + {"atxmega128a4u", "__AVR_ATxmega128a4U__"}, + {"attiny4", "__AVR_ATtiny4__"}, + {"attiny5", "__AVR_ATtiny5__"}, + {"attiny9", "__AVR_ATtiny9__"}, + {"attiny10", "__AVR_ATtiny10__"}, + {"attiny20", "__AVR_ATtiny20__"}, + {"attiny40", "__AVR_ATtiny40__"}, + {"attiny102", "__AVR_ATtiny102__"}, + {"attiny104", "__AVR_ATtiny104__"}, +}; + +} // 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::find(ValidFamilyNames, Name) != std::end(ValidFamilyNames); + + bool IsMCU = + llvm::find_if(AVRMcus, [&](const MCUInfo &Info) { + return Info.Name == Name; + }) != std::end(AVRMcus); + 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__"); + + 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); + } +} 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..94f006ee1b8a --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/AVR.h @@ -0,0 +1,184 @@ +//===--- 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; + Char32Type = UnsignedLong; + SigAtomicType = SignedChar; + 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..0cf55a58a951 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/BPF.cpp @@ -0,0 +1,36 @@ +//===--- 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 "llvm/ADT/StringRef.h" + +using namespace clang; +using namespace clang::targets; + +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::find(ValidCPUNames, Name) != std::end(ValidCPUNames); +} + +void BPFTargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const { + Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames)); +} 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..79abd8828a2c --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/BPF.h @@ -0,0 +1,98 @@ +//===--- 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 { +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-n32:64-S128"); + } else { + resetDataLayout("e-m:e-p:64:64-i64:64-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; + } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } + + 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 { + return true; + } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; + } + + 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 { + 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..be23fd2536e0 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/Hexagon.cpp @@ -0,0 +1,170 @@ +//===--- 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"); + + 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") { + Builder.defineMacro("__HEXAGON_V60__"); + Builder.defineMacro("__HEXAGON_ARCH__", "60"); + Builder.defineMacro("__QDSP6_V60__"); + Builder.defineMacro("__QDSP6_ARCH__", "60"); + } else if (CPU == "hexagonv62") { + Builder.defineMacro("__HEXAGON_V62__"); + Builder.defineMacro("__HEXAGON_ARCH__", "62"); + } else if (CPU == "hexagonv65") { + Builder.defineMacro("__HEXAGON_V65__"); + Builder.defineMacro("__HEXAGON_ARCH__", "65"); + } else if (CPU == "hexagonv66") { + Builder.defineMacro("__HEXAGON_V66__"); + Builder.defineMacro("__HEXAGON_ARCH__", "66"); + } + + 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"); + // FIXME: This macro is deprecated. + Builder.defineMacro("__HVXDBL__"); + } +} + +bool HexagonTargetInfo::initFeatureMap( + llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, + const std::vector<std::string> &FeaturesVec) const { + 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; + } + return true; +} + +const char *const HexagonTargetInfo::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", "p0", "p1", "p2", "p3", + "sa0", "lc0", "sa1", "lc1", "m0", "m1", "usr", "ugp" +}; + +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}, +#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) + .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"}}, +}; + +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..25a78c181580 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/Hexagon.h @@ -0,0 +1,129 @@ +//===--- 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 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; + } + + 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 { + 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; + } +}; +} // 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..e119606384c7 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/Lanai.h @@ -0,0 +1,93 @@ +//===--- 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 ""; } +}; +} // 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..cacd10dc8936 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/Le64.cpp @@ -0,0 +1,38 @@ +//===--- 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; + +const Builtin::Info Le64TargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsLe64.def" +}; + +ArrayRef<Builtin::Info> Le64TargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef(BuiltinInfo, clang::Le64::LastTSBuiltin - + Builtin::FirstTSBuiltin); +} + +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..253d5681abc2 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/Le64.h @@ -0,0 +1,63 @@ +//===--- 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 { + static const Builtin::Info BuiltinInfo[]; + +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/MSP430.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/MSP430.cpp new file mode 100644 index 000000000000..ef53ee352c32 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/MSP430.cpp @@ -0,0 +1,33 @@ +//===--- 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__"); + // 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..620f12d2b8e3 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/MSP430.h @@ -0,0 +1,97 @@ +//===--- 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 { + // No aliases. + return None; + } + + 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..b9ab80df6194 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/Mips.cpp @@ -0,0 +1,296 @@ +//===--- 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); + return 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::find(ValidCPUNames, Name) != std::end(ValidCPUNames); +} + +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("fp64", FPMode == FP64) + .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..224ec0783edf --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/Mips.h @@ -0,0 +1,413 @@ +//===--- 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; +}; +} // 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..f69e9d84c701 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/NVPTX.cpp @@ -0,0 +1,244 @@ +//===--- 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("+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::GFX700: + case CudaArch::GFX701: + case CudaArch::GFX702: + case CudaArch::GFX703: + case CudaArch::GFX704: + case CudaArch::GFX801: + case CudaArch::GFX802: + case CudaArch::GFX803: + case CudaArch::GFX810: + case CudaArch::GFX900: + case CudaArch::GFX902: + case CudaArch::GFX904: + case CudaArch::GFX906: + case CudaArch::GFX908: + case CudaArch::GFX909: + case CudaArch::GFX1010: + case CudaArch::GFX1011: + case CudaArch::GFX1012: + case CudaArch::LAST: + break; + 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"; + } + 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..2cdd37ca1b07 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/NVPTX.h @@ -0,0 +1,163 @@ +//===--- 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, // cuda_device + 4, // cuda_constant + 3, // cuda_shared +}; + +/// 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::LAST); ++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.support("cl_clang_storage_class_specifiers"); + Opts.support("cl_khr_gl_sharing"); + Opts.support("cl_khr_icd"); + + Opts.support("cl_khr_fp64"); + Opts.support("cl_khr_byte_addressable_store"); + Opts.support("cl_khr_global_int32_base_atomics"); + Opts.support("cl_khr_global_int32_extended_atomics"); + Opts.support("cl_khr_local_int32_base_atomics"); + Opts.support("cl_khr_local_int32_extended_atomics"); + } + + /// \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; + } +}; +} // 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..72fdb0e7dde8 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/OSTargets.cpp @@ -0,0 +1,217 @@ +//===--- 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__"); + Builder.defineMacro("OBJC_NEW_PROPERTIES"); + // 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. + unsigned Maj, Min, Rev; + if (Triple.isMacOSX()) { + Triple.getMacOSXVersion(Maj, Min, Rev); + PlatformName = "macos"; + } else { + Triple.getOSVersion(Maj, Min, Rev); + PlatformName = llvm::Triple::getOSTypeName(Triple.getOS()); + } + + // 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 = VersionTuple(Maj, Min, Rev); + return; + } + + // Set the appropriate OS version define. + if (Triple.isiOS()) { + assert(Maj < 100 && Min < 100 && Rev < 100 && "Invalid version!"); + char Str[7]; + if (Maj < 10) { + Str[0] = '0' + Maj; + Str[1] = '0' + (Min / 10); + Str[2] = '0' + (Min % 10); + Str[3] = '0' + (Rev / 10); + Str[4] = '0' + (Rev % 10); + Str[5] = '\0'; + } else { + // Handle versions >= 10. + Str[0] = '0' + (Maj / 10); + Str[1] = '0' + (Maj % 10); + Str[2] = '0' + (Min / 10); + Str[3] = '0' + (Min % 10); + Str[4] = '0' + (Rev / 10); + Str[5] = '0' + (Rev % 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(Maj < 10 && Min < 100 && Rev < 100 && "Invalid version!"); + char Str[6]; + Str[0] = '0' + Maj; + Str[1] = '0' + (Min / 10); + Str[2] = '0' + (Min % 10); + Str[3] = '0' + (Rev / 10); + Str[4] = '0' + (Rev % 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(Maj < 100 && Min < 100 && Rev < 100 && "Invalid version!"); + char Str[7]; + if (Maj < 10 || (Maj == 10 && Min < 10)) { + Str[0] = '0' + (Maj / 10); + Str[1] = '0' + (Maj % 10); + Str[2] = '0' + std::min(Min, 9U); + Str[3] = '0' + std::min(Rev, 9U); + Str[4] = '\0'; + } else { + // Handle versions > 10.9. + Str[0] = '0' + (Maj / 10); + Str[1] = '0' + (Maj % 10); + Str[2] = '0' + (Min / 10); + Str[3] = '0' + (Min % 10); + Str[4] = '0' + (Rev / 10); + Str[5] = '0' + (Rev % 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 = VersionTuple(Maj, Min, Rev); +} + +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.CPlusPlus2a) + Builder.defineMacro("_MSVC_LANG", "201704L"); + 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"); +} + +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..c0373ffaa444 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/OSTargets.h @@ -0,0 +1,867 @@ +//===--- 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" +#include "llvm/MC/MCSectionMachO.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 whitelist 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"; + } + + std::string isValidSectionSpecifier(StringRef SR) const override { + // Let MCSectionMachO validate this. + StringRef Segment, Section; + unsigned TAA, StubSize; + bool HasTAA; + return llvm::MCSectionMachO::ParseSectionSpecifier(SR, Segment, Section, + TAA, HasTAA, StubSize); + } + + 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: + llvm_unreachable("Unexpected OS"); + } + + unsigned Major, Minor, Micro; + T.getOSVersion(Major, Minor, Micro); + if (llvm::VersionTuple(Major, Minor, Micro) < 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); + } + +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->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::ppc64: + case llvm::Triple::ppc64le: + this->MCountName = "_mcount"; + break; + case llvm::Triple::arm: + this->MCountName = "__mcount"; + 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"); + unsigned Maj, Min, Rev; + Triple.getEnvironmentVersion(Maj, Min, Rev); + this->PlatformName = "android"; + this->PlatformMinVersion = VersionTuple(Maj, Min, Rev); + if (Maj) + Builder.defineMacro("__ANDROID_API__", Twine(Maj)); + } 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::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__"); + } + +public: + OpenBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + 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::sparcv9: + this->MCountName = "_mcount"; + 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("__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; + } + } +}; + +// 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("_AIX"); + + unsigned Major, Minor, Micro; + Triple.getOSVersion(Major, Minor, Micro); + + // Define AIX OS-Version Macros. + // Includes logic for legacy versions of AIX; no specific intent to support. + std::pair<int, int> OsVersion = {Major, Minor}; + if (OsVersion >= std::make_pair(3, 2)) Builder.defineMacro("_AIX32"); + if (OsVersion >= std::make_pair(4, 1)) Builder.defineMacro("_AIX41"); + if (OsVersion >= std::make_pair(4, 3)) Builder.defineMacro("_AIX43"); + if (OsVersion >= std::make_pair(5, 0)) Builder.defineMacro("_AIX50"); + if (OsVersion >= std::make_pair(5, 1)) Builder.defineMacro("_AIX51"); + if (OsVersion >= std::make_pair(5, 2)) Builder.defineMacro("_AIX52"); + if (OsVersion >= std::make_pair(5, 3)) Builder.defineMacro("_AIX53"); + if (OsVersion >= std::make_pair(6, 1)) Builder.defineMacro("_AIX61"); + if (OsVersion >= std::make_pair(7, 1)) Builder.defineMacro("_AIX71"); + if (OsVersion >= std::make_pair(7, 2)) Builder.defineMacro("_AIX72"); + + // 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) { + 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 hasInt128Type() const override { return false; } +}; + +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-i64:64-n8:16:32-S128"); + } else if (Triple.getArch() == llvm::Triple::x86_64) { + this->resetDataLayout("e-m:e-p:32:32-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"); + } + +public: + FuchsiaTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) { + this->MCountName = "__mcount"; + } +}; + +// 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 { + // 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); + Builder.defineMacro("__EMSCRIPTEN__"); + } + +public: + explicit EmscriptenTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : WebAssemblyOSTargetInfo<Target>(Triple, Opts) {} +}; + +} // 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..ab4abf9fc567 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/PNaCl.h @@ -0,0 +1,86 @@ +//===--- 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 ""; } +}; + +// 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..a40991048873 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/PPC.cpp @@ -0,0 +1,485 @@ +//===--- 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 == "+qpx") { + HasQPX = true; + } else if (Feature == "+htm") { + HasHTM = true; + } else if (Feature == "+float128") { + HasFloat128 = true; + } else if (Feature == "+power9-vector") { + HasP9Vector = true; + } else if (Feature == "+spe") { + HasSPE = true; + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + } else if (Feature == "-hard-float") { + FloatABI = SoftFloat; + } + // TODO: Finish this list and add an assert that we've handled them + // all. + } + + return true; +} + +/// 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 { + // 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__"); + } + + // Target properties. + if (getTriple().getArch() == llvm::Triple::ppc64le) { + Builder.defineMacro("_LITTLE_ENDIAN"); + } else { + if (!getTriple().isOSNetBSD() && + !getTriple().isOSOpenBSD()) + Builder.defineMacro("_BIG_ENDIAN"); + } + + // ABI options. + if (ABI == "elfv1" || ABI == "elfv1-qpx") + 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"); + } + + // 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 & ArchDefineA2) + Builder.defineMacro("_ARCH_A2"); + if (ArchDefs & ArchDefineA2q) { + Builder.defineMacro("_ARCH_A2Q"); + Builder.defineMacro("_ARCH_QP"); + } + + if (getTriple().getVendor() == llvm::Triple::BGQ) { + Builder.defineMacro("__bg__"); + Builder.defineMacro("__THW_BLUEGENE__"); + Builder.defineMacro("__bgq__"); + Builder.defineMacro("__TOS_BGQ__"); + } + + 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__"); + + 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 +// 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) { + + if (llvm::find(FeaturesVec, "-vsx") != FeaturesVec.end()) { + if (llvm::find(FeaturesVec, "+power8-vector") != FeaturesVec.end()) { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mpower8-vector" + << "-mno-vsx"; + return false; + } + + if (llvm::find(FeaturesVec, "+direct-move") != FeaturesVec.end()) { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mdirect-move" + << "-mno-vsx"; + return false; + } + + if (llvm::find(FeaturesVec, "+float128") != FeaturesVec.end()) { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfloat128" + << "-mno-vsx"; + return false; + } + + if (llvm::find(FeaturesVec, "+power9-vector") != FeaturesVec.end()) { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mpower9-vector" + << "-mno-vsx"; + return false; + } + } + + return true; +} + +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["qpx"] = (CPU == "a2q"); + 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); + + if (!ppcUserFeaturesCheck(Diags, FeaturesVec)) + return false; + + if (!(ArchDefs & ArchDefinePwr9) && (ArchDefs & ArchDefinePpcgr) && + llvm::find(FeaturesVec, "+float128") != FeaturesVec.end()) { + // We have __float128 on PPC but not power 9 and above. + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfloat128" << CPU; + return false; + } + + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); +} + +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("qpx", HasQPX) + .Case("htm", HasHTM) + .Case("bpermd", HasBPERMD) + .Case("extdiv", HasExtDiv) + .Case("float128", HasFloat128) + .Case("power9-vector", HasP9Vector) + .Case("spe", HasSPE) + .Default(false); +} + +void PPCTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, + StringRef Name, bool Enabled) const { + if (Enabled) { + // 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("float128", true) + .Default(false); + if (FeatureHasVSX) + Features["vsx"] = Features["altivec"] = true; + if (Name == "power9-vector") + Features["power8-vector"] = true; + Features[Name] = true; + } else { + // 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"] = false; + if (Name == "power8-vector") + Features["power9-vector"] = false; + 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"}, "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"}, {"970"}, {"g5"}, + {"a2"}, {"a2q"}, {"e500mc"}, {"e5500"}, {"power3"}, + {"pwr3"}, {"power4"}, {"pwr4"}, {"power5"}, {"pwr5"}, + {"power5x"}, {"pwr5x"}, {"power6"}, {"pwr6"}, {"power6x"}, + {"pwr6x"}, {"power7"}, {"pwr7"}, {"power8"}, {"pwr8"}, + {"power9"}, {"pwr9"}, {"powerpc"}, {"ppc"}, {"powerpc64"}, + {"ppc64"}, {"powerpc64le"}, {"ppc64le"}, +}; + +bool PPCTargetInfo::isValidCPUName(StringRef Name) const { + return llvm::find(ValidCPUNames, Name) != std::end(ValidCPUNames); +} + +void PPCTargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const { + Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames)); +} + +void PPCTargetInfo::adjust(LangOptions &Opts) { + if (HasAltivec) + Opts.AltiVec = 1; + TargetInfo::adjust(Opts); + if (LongDoubleFormat != &llvm::APFloat::IEEEdouble()) + LongDoubleFormat = Opts.PPCIEEELongDouble + ? &llvm::APFloat::IEEEquad() + : &llvm::APFloat::PPCDoubleDouble(); +} + +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..6c6421c28e23 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/PPC.h @@ -0,0 +1,466 @@ +//===--- 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, + ArchDefineA2 = 1 << 14, + ArchDefineA2q = 1 << 15 + } 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 HasVSX = false; + bool HasP8Vector = false; + bool HasP8Crypto = false; + bool HasDirectMove = false; + bool HasQPX = false; + bool HasHTM = false; + bool HasBPERMD = false; + bool HasExtDiv = false; + bool HasP9Vector = false; + bool HasSPE = 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(); + } + + // Set the language option for altivec based on our value. + void adjust(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, 8548, 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) + .Case("a2q", ArchDefineName | ArchDefineA2 | ArchDefineA2q) + .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) + .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; + + 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) + 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(); + Info.setAllowsRegister(); + 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"; } +}; + +class LLVM_LIBRARY_VISIBILITY PPC32TargetInfo : public PPCTargetInfo { +public: + PPC32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : PPCTargetInfo(Triple, Opts) { + 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; + SuitableAlign = 64; + break; + default: + break; + } + + if (Triple.isOSFreeBSD() || Triple.isOSNetBSD() || Triple.isOSOpenBSD() || + Triple.getOS() == llvm::Triple::AIX || 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; + + if ((Triple.getArch() == llvm::Triple::ppc64le)) { + resetDataLayout("e-m:e-i64:64-n32:64"); + ABI = "elfv2"; + } else { + resetDataLayout("E-m:e-i64:64-n32:64"); + ABI = Triple.getEnvironment() == llvm::Triple::ELFv2 ? "elfv2" : "elfv1"; + } + + if (Triple.getOS() == llvm::Triple::AIX) + SuitableAlign = 64; + + if (Triple.isOSFreeBSD() || Triple.getOS() == llvm::Triple::AIX || + Triple.isMusl()) { + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble(); + } + + // 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 == "elfv1-qpx" || Name == "elfv2") { + ABI = Name; + return true; + } + return false; + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + switch (CC) { + case CC_Swift: + return CCCR_OK; + 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..930b825e94d2 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.cpp @@ -0,0 +1,140 @@ +//===--- 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/MacroBuilder.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +ArrayRef<const char *> RISCVTargetInfo::getGCCRegNames() const { + static const char *const GCCRegNames[] = { + "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"}; + 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"}}; + 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; + } +} + +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"); + // TODO: modify when more code models are supported. + Builder.defineMacro("__riscv_cmodel_medlow"); + + 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 if (ABIName == "ilp32e") + Builder.defineMacro("__riscv_abi_rve"); + else + Builder.defineMacro("__riscv_float_abi_soft"); + + if (HasM) { + Builder.defineMacro("__riscv_mul"); + Builder.defineMacro("__riscv_div"); + Builder.defineMacro("__riscv_muldiv"); + } + + if (HasA) + Builder.defineMacro("__riscv_atomic"); + + if (HasF || HasD) { + Builder.defineMacro("__riscv_flen", HasD ? "64" : "32"); + Builder.defineMacro("__riscv_fdiv"); + Builder.defineMacro("__riscv_fsqrt"); + } + + if (HasC) + Builder.defineMacro("__riscv_compressed"); +} + +/// Return true if has this feature, need to sync with handleTargetFeatures. +bool RISCVTargetInfo::hasFeature(StringRef Feature) const { + bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64; + return llvm::StringSwitch<bool>(Feature) + .Case("riscv", true) + .Case("riscv32", !Is64Bit) + .Case("riscv64", Is64Bit) + .Case("m", HasM) + .Case("a", HasA) + .Case("f", HasF) + .Case("d", HasD) + .Case("c", HasC) + .Default(false); +} + +/// Perform initialization based on the user configured set of features. +bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) { + for (const auto &Feature : Features) { + if (Feature == "+m") + HasM = true; + else if (Feature == "+a") + HasA = true; + else if (Feature == "+f") + HasF = true; + else if (Feature == "+d") + HasD = true; + else if (Feature == "+c") + HasC = true; + } + + return 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..9118494a87ab --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.h @@ -0,0 +1,131 @@ +//===--- 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" + +namespace clang { +namespace targets { + +// RISC-V Target +class RISCVTargetInfo : public TargetInfo { +protected: + std::string ABI; + bool HasM; + bool HasA; + bool HasF; + bool HasD; + bool HasC; + +public: + RISCVTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple), HasM(false), HasA(false), HasF(false), + HasD(false), HasC(false) { + LongDoubleWidth = 128; + LongDoubleAlign = 128; + LongDoubleFormat = &llvm::APFloat::IEEEquad(); + SuitableAlign = 128; + WCharType = SignedInt; + WIntType = UnsignedInt; + } + + StringRef getABI() const override { return ABI; } + 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; + + 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; + + bool hasFeature(StringRef Feature) const override; + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override; +}; +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; + } + + void setMaxAtomicWidth() override { + MaxAtomicPromoteWidth = 128; + + if (HasA) + 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; + } + + void setMaxAtomicWidth() override { + MaxAtomicPromoteWidth = 128; + + if (HasA) + 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..a9b815d13bc1 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/SPIR.cpp @@ -0,0 +1,32 @@ +//===--- SPIR.cpp - Implement SPIR 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 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 { + DefineStd(Builder, "SPIR32", Opts); +} + +void SPIR64TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "SPIR64", 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..802ccf8b671e --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/SPIR.h @@ -0,0 +1,132 @@ +//===--- SPIR.h - Declare SPIR 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 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 { + +static const unsigned SPIRAddrSpaceMap[] = { + 0, // Default + 1, // opencl_global + 3, // opencl_local + 2, // opencl_constant + 0, // opencl_private + 4, // opencl_generic + 0, // cuda_device + 0, // cuda_constant + 0 // cuda_shared +}; + +class LLVM_LIBRARY_VISIBILITY SPIRTargetInfo : public TargetInfo { +public: + SPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + 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"); + TLSSupported = false; + VLASupported = false; + LongWidth = LongAlign = 64; + AddrSpaceMap = &SPIRAddrSpaceMap; + UseAddrSpaceMapMangling = true; + HasLegalHalfType = true; + HasFloat16 = true; + // Define available target features + // These must be defined in sorted order! + NoAsmVariants = true; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool hasFeature(StringRef Feature) const override { + return Feature == "spir"; + } + + // 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; + } + + 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 setSupportedOpenCLOpts() override { + // Assume all OpenCL extensions and optional core features are supported + // for SPIR since it is a generic target. + getSupportedOpenCLOpts().supportAll(); + } +}; +class LLVM_LIBRARY_VISIBILITY SPIR32TargetInfo : public SPIRTargetInfo { +public: + SPIR32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : SPIRTargetInfo(Triple, Opts) { + 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) { + 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..13aa964d4716 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/Sparc.cpp @@ -0,0 +1,250 @@ +//===--- 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); + switch (getCPUGeneration(CPU)) { + case CG_V8: + Builder.defineMacro("__sparcv8"); + if (getTriple().getOS() != llvm::Triple::Solaris) + Builder.defineMacro("__sparcv8__"); + break; + case CG_V9: + Builder.defineMacro("__sparcv9"); + if (getTriple().getOS() != llvm::Triple::Solaris) { + Builder.defineMacro("__sparcv9__"); + 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); + } +} + +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__"); + } +} + +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..963192a4634f --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/Sparc.h @@ -0,0 +1,232 @@ +//===--- 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 + auto Feature = llvm::find(Features, "+soft-float"); + if (Feature != Features.end()) { + SoftFloat = true; + } + return true; + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool hasFeature(StringRef Feature) const override; + + bool hasSjLjLowering() const override { return true; } + + 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 are lock-free atomic, but we're willing to do atomic ops + // on up to 64 bits. + MaxAtomicPromoteWidth = 64; + MaxAtomicInlineWidth = 32; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool hasSjLjLowering() 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; + 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; + } +}; +} // 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..d86928a6333b --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/SystemZ.cpp @@ -0,0 +1,153 @@ +//===--- 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}, +}; + +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("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__", "10303"); +} + +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..e751806f4747 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/SystemZ.h @@ -0,0 +1,150 @@ +//===--- 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; + +public: + SystemZTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple), CPU("z10"), ISARevision(8), + HasTransactionalExecution(false), HasVector(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; + resetDataLayout("E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64"); + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + } + + 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 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; + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); + } + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override { + HasTransactionalExecution = false; + HasVector = false; + for (const auto &Feature : Features) { + if (Feature == "+transactional-execution") + HasTransactionalExecution = true; + else if (Feature == "+vector") + HasVector = true; + } + // If we use the vector ABI, vector types are 64-bit aligned. + if (HasVector) { + 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; + default: + return CCCR_Warning; + } + } + + StringRef getABI() const override { + if (HasVector) + return "vector"; + return ""; + } + + const char *getLongDoubleMangling() const override { return "g"; } +}; +} // 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..967ef5c59ee5 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/TCE.h @@ -0,0 +1,122 @@ +//===--- 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 + // FIXME: generic has to be added to the target + 0, // opencl_generic + 0, // cuda_device + 0, // cuda_constant + 0 // cuda_shared +}; + +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/WebAssembly.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/WebAssembly.cpp new file mode 100644 index 000000000000..b16442b99b62 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/WebAssembly.cpp @@ -0,0 +1,239 @@ +//===--- 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"}}; + +bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature) + .Case("simd128", SIMDLevel >= SIMD128) + .Case("unimplemented-simd128", SIMDLevel >= UnimplementedSIMD128) + .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) + .Default(false); +} + +bool WebAssemblyTargetInfo::isValidCPUName(StringRef Name) const { + return llvm::find(ValidCPUNames, Name) != std::end(ValidCPUNames); +} + +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 >= UnimplementedSIMD128) + Builder.defineMacro("__wasm_unimplemented_simd128__"); + 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__"); +} + +void WebAssemblyTargetInfo::setSIMDLevel(llvm::StringMap<bool> &Features, + SIMDEnum Level) { + switch (Level) { + case UnimplementedSIMD128: + Features["unimplemented-simd128"] = true; + LLVM_FALLTHROUGH; + case SIMD128: + Features["simd128"] = true; + LLVM_FALLTHROUGH; + case NoSIMD: + break; + } +} + +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["atomics"] = true; + Features["mutable-globals"] = true; + setSIMDLevel(Features, SIMD128); + } + // Other targets do not consider user-configured features here, but while we + // are actively developing new features it is useful to let user-configured + // features control availability of builtins + setSIMDLevel(Features, SIMDLevel); + if (HasNontrappingFPToInt) + Features["nontrapping-fptoint"] = true; + if (HasSignExt) + Features["sign-ext"] = true; + if (HasExceptionHandling) + Features["exception-handling"] = true; + if (HasBulkMemory) + Features["bulk-memory"] = true; + if (HasAtomics) + Features["atomics"] = true; + if (HasMutableGlobals) + Features["mutable-globals"] = true; + if (HasMultivalue) + Features["multivalue"] = true; + if (HasTailCall) + Features["tail-call"] = 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 == "+unimplemented-simd128") { + SIMDLevel = std::max(SIMDLevel, SIMDEnum(UnimplementedSIMD128)); + continue; + } + if (Feature == "-unimplemented-simd128") { + SIMDLevel = std::min(SIMDLevel, SIMDEnum(UnimplementedSIMD128 - 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; + } + + 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 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..9665156b143f --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/WebAssembly.h @@ -0,0 +1,152 @@ +//=== 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, + UnimplementedSIMD128, + } 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; + +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; + } + +protected: + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + +private: + static void setSIMDLevel(llvm::StringMap<bool> &Features, SIMDEnum Level); + + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override; + bool hasFeature(StringRef Feature) 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); + } +}; +class LLVM_LIBRARY_VISIBILITY WebAssembly32TargetInfo + : public WebAssemblyTargetInfo { +public: + explicit WebAssembly32TargetInfo(const llvm::Triple &T, + const TargetOptions &Opts) + : WebAssemblyTargetInfo(T, Opts) { + resetDataLayout("e-m:e-p:32:32-i64:64-n32:64-S128"); + } + +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; + resetDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128"); + } + +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..d618c90b05c0 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/X86.cpp @@ -0,0 +1,1895 @@ +//===--- 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/TargetParser.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", +}; + +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) + setFeatureEnabledImpl(Features, "sse2", true); + + const CPUKind Kind = getCPUKind(CPU); + + // Enable X87 for all X86 processors but Lakemont. + if (Kind != CK_Lakemont) + setFeatureEnabledImpl(Features, "x87", true); + + // Enable cmpxchg8 for i586 and greater CPUs. Include generic for backwards + // compatibility. + if (Kind >= CK_i586 || Kind == CK_Generic) + setFeatureEnabledImpl(Features, "cx8", true); + + switch (Kind) { + case CK_Generic: + case CK_i386: + case CK_i486: + case CK_i586: + case CK_Pentium: + case CK_PentiumPro: + case CK_i686: + case CK_Lakemont: + break; + + case CK_PentiumMMX: + case CK_Pentium2: + case CK_K6: + case CK_WinChipC6: + setFeatureEnabledImpl(Features, "mmx", true); + break; + + case CK_Cooperlake: + // CPX inherits all CLX features plus AVX512BF16 + setFeatureEnabledImpl(Features, "avx512bf16", true); + LLVM_FALLTHROUGH; + case CK_Cascadelake: + // CLX inherits all SKX features plus AVX512VNNI + setFeatureEnabledImpl(Features, "avx512vnni", true); + LLVM_FALLTHROUGH; + case CK_SkylakeServer: + setFeatureEnabledImpl(Features, "avx512f", true); + setFeatureEnabledImpl(Features, "avx512cd", true); + setFeatureEnabledImpl(Features, "avx512dq", true); + setFeatureEnabledImpl(Features, "avx512bw", true); + setFeatureEnabledImpl(Features, "avx512vl", true); + setFeatureEnabledImpl(Features, "clwb", true); + setFeatureEnabledImpl(Features, "pku", true); + // SkylakeServer cores inherits all SKL features, except SGX + goto SkylakeCommon; + + case CK_IcelakeServer: + setFeatureEnabledImpl(Features, "pconfig", true); + setFeatureEnabledImpl(Features, "wbnoinvd", true); + LLVM_FALLTHROUGH; + case CK_IcelakeClient: + setFeatureEnabledImpl(Features, "vaes", true); + setFeatureEnabledImpl(Features, "gfni", true); + setFeatureEnabledImpl(Features, "vpclmulqdq", true); + setFeatureEnabledImpl(Features, "avx512bitalg", true); + setFeatureEnabledImpl(Features, "avx512vbmi2", true); + setFeatureEnabledImpl(Features, "avx512vnni", true); + setFeatureEnabledImpl(Features, "avx512vpopcntdq", true); + setFeatureEnabledImpl(Features, "rdpid", true); + setFeatureEnabledImpl(Features, "clwb", true); + LLVM_FALLTHROUGH; + case CK_Cannonlake: + setFeatureEnabledImpl(Features, "avx512f", true); + setFeatureEnabledImpl(Features, "avx512cd", true); + setFeatureEnabledImpl(Features, "avx512dq", true); + setFeatureEnabledImpl(Features, "avx512bw", true); + setFeatureEnabledImpl(Features, "avx512vl", true); + setFeatureEnabledImpl(Features, "avx512ifma", true); + setFeatureEnabledImpl(Features, "avx512vbmi", true); + setFeatureEnabledImpl(Features, "pku", true); + setFeatureEnabledImpl(Features, "sha", true); + LLVM_FALLTHROUGH; + case CK_SkylakeClient: + setFeatureEnabledImpl(Features, "sgx", true); + // SkylakeServer cores inherits all SKL features, except SGX +SkylakeCommon: + setFeatureEnabledImpl(Features, "xsavec", true); + setFeatureEnabledImpl(Features, "xsaves", true); + setFeatureEnabledImpl(Features, "mpx", true); + setFeatureEnabledImpl(Features, "clflushopt", true); + setFeatureEnabledImpl(Features, "aes", true); + LLVM_FALLTHROUGH; + case CK_Broadwell: + setFeatureEnabledImpl(Features, "rdseed", true); + setFeatureEnabledImpl(Features, "adx", true); + setFeatureEnabledImpl(Features, "prfchw", true); + LLVM_FALLTHROUGH; + case CK_Haswell: + setFeatureEnabledImpl(Features, "avx2", true); + setFeatureEnabledImpl(Features, "lzcnt", true); + setFeatureEnabledImpl(Features, "bmi", true); + setFeatureEnabledImpl(Features, "bmi2", true); + setFeatureEnabledImpl(Features, "fma", true); + setFeatureEnabledImpl(Features, "invpcid", true); + setFeatureEnabledImpl(Features, "movbe", true); + LLVM_FALLTHROUGH; + case CK_IvyBridge: + setFeatureEnabledImpl(Features, "rdrnd", true); + setFeatureEnabledImpl(Features, "f16c", true); + setFeatureEnabledImpl(Features, "fsgsbase", true); + LLVM_FALLTHROUGH; + case CK_SandyBridge: + setFeatureEnabledImpl(Features, "avx", true); + setFeatureEnabledImpl(Features, "xsave", true); + setFeatureEnabledImpl(Features, "xsaveopt", true); + LLVM_FALLTHROUGH; + case CK_Westmere: + setFeatureEnabledImpl(Features, "pclmul", true); + LLVM_FALLTHROUGH; + case CK_Nehalem: + setFeatureEnabledImpl(Features, "sse4.2", true); + LLVM_FALLTHROUGH; + case CK_Penryn: + setFeatureEnabledImpl(Features, "sse4.1", true); + LLVM_FALLTHROUGH; + case CK_Core2: + setFeatureEnabledImpl(Features, "ssse3", true); + setFeatureEnabledImpl(Features, "sahf", true); + LLVM_FALLTHROUGH; + case CK_Nocona: + setFeatureEnabledImpl(Features, "cx16", true); + LLVM_FALLTHROUGH; + case CK_Yonah: + case CK_Prescott: + setFeatureEnabledImpl(Features, "sse3", true); + LLVM_FALLTHROUGH; + case CK_PentiumM: + case CK_Pentium4: + case CK_x86_64: + setFeatureEnabledImpl(Features, "sse2", true); + LLVM_FALLTHROUGH; + case CK_Pentium3: + case CK_C3_2: + setFeatureEnabledImpl(Features, "sse", true); + setFeatureEnabledImpl(Features, "fxsr", true); + break; + + case CK_Tremont: + setFeatureEnabledImpl(Features, "cldemote", true); + setFeatureEnabledImpl(Features, "movdiri", true); + setFeatureEnabledImpl(Features, "movdir64b", true); + setFeatureEnabledImpl(Features, "gfni", true); + setFeatureEnabledImpl(Features, "waitpkg", true); + LLVM_FALLTHROUGH; + case CK_GoldmontPlus: + setFeatureEnabledImpl(Features, "ptwrite", true); + setFeatureEnabledImpl(Features, "rdpid", true); + setFeatureEnabledImpl(Features, "sgx", true); + LLVM_FALLTHROUGH; + case CK_Goldmont: + setFeatureEnabledImpl(Features, "sha", true); + setFeatureEnabledImpl(Features, "rdseed", true); + setFeatureEnabledImpl(Features, "xsave", true); + setFeatureEnabledImpl(Features, "xsaveopt", true); + setFeatureEnabledImpl(Features, "xsavec", true); + setFeatureEnabledImpl(Features, "xsaves", true); + setFeatureEnabledImpl(Features, "clflushopt", true); + setFeatureEnabledImpl(Features, "mpx", true); + setFeatureEnabledImpl(Features, "fsgsbase", true); + setFeatureEnabledImpl(Features, "aes", true); + LLVM_FALLTHROUGH; + case CK_Silvermont: + setFeatureEnabledImpl(Features, "rdrnd", true); + setFeatureEnabledImpl(Features, "pclmul", true); + setFeatureEnabledImpl(Features, "sse4.2", true); + setFeatureEnabledImpl(Features, "prfchw", true); + LLVM_FALLTHROUGH; + case CK_Bonnell: + setFeatureEnabledImpl(Features, "movbe", true); + setFeatureEnabledImpl(Features, "ssse3", true); + setFeatureEnabledImpl(Features, "fxsr", true); + setFeatureEnabledImpl(Features, "cx16", true); + setFeatureEnabledImpl(Features, "sahf", true); + break; + + case CK_KNM: + // TODO: Add avx5124fmaps/avx5124vnniw. + setFeatureEnabledImpl(Features, "avx512vpopcntdq", true); + LLVM_FALLTHROUGH; + case CK_KNL: + setFeatureEnabledImpl(Features, "avx512f", true); + setFeatureEnabledImpl(Features, "avx512cd", true); + setFeatureEnabledImpl(Features, "avx512er", true); + setFeatureEnabledImpl(Features, "avx512pf", true); + setFeatureEnabledImpl(Features, "prfchw", true); + setFeatureEnabledImpl(Features, "prefetchwt1", true); + setFeatureEnabledImpl(Features, "fxsr", true); + setFeatureEnabledImpl(Features, "rdseed", true); + setFeatureEnabledImpl(Features, "adx", true); + setFeatureEnabledImpl(Features, "lzcnt", true); + setFeatureEnabledImpl(Features, "bmi", true); + setFeatureEnabledImpl(Features, "bmi2", true); + setFeatureEnabledImpl(Features, "fma", true); + setFeatureEnabledImpl(Features, "rdrnd", true); + setFeatureEnabledImpl(Features, "f16c", true); + setFeatureEnabledImpl(Features, "fsgsbase", true); + setFeatureEnabledImpl(Features, "aes", true); + setFeatureEnabledImpl(Features, "pclmul", true); + setFeatureEnabledImpl(Features, "cx16", true); + setFeatureEnabledImpl(Features, "xsaveopt", true); + setFeatureEnabledImpl(Features, "xsave", true); + setFeatureEnabledImpl(Features, "movbe", true); + setFeatureEnabledImpl(Features, "sahf", true); + break; + + case CK_K6_2: + case CK_K6_3: + case CK_WinChip2: + case CK_C3: + setFeatureEnabledImpl(Features, "3dnow", true); + break; + + case CK_AMDFAM10: + setFeatureEnabledImpl(Features, "sse4a", true); + setFeatureEnabledImpl(Features, "lzcnt", true); + setFeatureEnabledImpl(Features, "popcnt", true); + setFeatureEnabledImpl(Features, "sahf", true); + LLVM_FALLTHROUGH; + case CK_K8SSE3: + setFeatureEnabledImpl(Features, "sse3", true); + LLVM_FALLTHROUGH; + case CK_K8: + setFeatureEnabledImpl(Features, "sse2", true); + LLVM_FALLTHROUGH; + case CK_AthlonXP: + setFeatureEnabledImpl(Features, "sse", true); + setFeatureEnabledImpl(Features, "fxsr", true); + LLVM_FALLTHROUGH; + case CK_Athlon: + case CK_Geode: + setFeatureEnabledImpl(Features, "3dnowa", true); + break; + + case CK_BTVER2: + setFeatureEnabledImpl(Features, "avx", true); + setFeatureEnabledImpl(Features, "aes", true); + setFeatureEnabledImpl(Features, "pclmul", true); + setFeatureEnabledImpl(Features, "bmi", true); + setFeatureEnabledImpl(Features, "f16c", true); + setFeatureEnabledImpl(Features, "xsaveopt", true); + setFeatureEnabledImpl(Features, "movbe", true); + LLVM_FALLTHROUGH; + case CK_BTVER1: + setFeatureEnabledImpl(Features, "ssse3", true); + setFeatureEnabledImpl(Features, "sse4a", true); + setFeatureEnabledImpl(Features, "lzcnt", true); + setFeatureEnabledImpl(Features, "popcnt", true); + setFeatureEnabledImpl(Features, "prfchw", true); + setFeatureEnabledImpl(Features, "cx16", true); + setFeatureEnabledImpl(Features, "fxsr", true); + setFeatureEnabledImpl(Features, "sahf", true); + break; + + case CK_ZNVER2: + setFeatureEnabledImpl(Features, "clwb", true); + setFeatureEnabledImpl(Features, "rdpid", true); + setFeatureEnabledImpl(Features, "wbnoinvd", true); + LLVM_FALLTHROUGH; + case CK_ZNVER1: + setFeatureEnabledImpl(Features, "adx", true); + setFeatureEnabledImpl(Features, "aes", true); + setFeatureEnabledImpl(Features, "avx2", true); + setFeatureEnabledImpl(Features, "bmi", true); + setFeatureEnabledImpl(Features, "bmi2", true); + setFeatureEnabledImpl(Features, "clflushopt", true); + setFeatureEnabledImpl(Features, "clzero", true); + setFeatureEnabledImpl(Features, "cx16", true); + setFeatureEnabledImpl(Features, "f16c", true); + setFeatureEnabledImpl(Features, "fma", true); + setFeatureEnabledImpl(Features, "fsgsbase", true); + setFeatureEnabledImpl(Features, "fxsr", true); + setFeatureEnabledImpl(Features, "lzcnt", true); + setFeatureEnabledImpl(Features, "mwaitx", true); + setFeatureEnabledImpl(Features, "movbe", true); + setFeatureEnabledImpl(Features, "pclmul", true); + setFeatureEnabledImpl(Features, "popcnt", true); + setFeatureEnabledImpl(Features, "prfchw", true); + setFeatureEnabledImpl(Features, "rdrnd", true); + setFeatureEnabledImpl(Features, "rdseed", true); + setFeatureEnabledImpl(Features, "sahf", true); + setFeatureEnabledImpl(Features, "sha", true); + setFeatureEnabledImpl(Features, "sse4a", true); + setFeatureEnabledImpl(Features, "xsave", true); + setFeatureEnabledImpl(Features, "xsavec", true); + setFeatureEnabledImpl(Features, "xsaveopt", true); + setFeatureEnabledImpl(Features, "xsaves", true); + break; + + case CK_BDVER4: + setFeatureEnabledImpl(Features, "avx2", true); + setFeatureEnabledImpl(Features, "bmi2", true); + setFeatureEnabledImpl(Features, "mwaitx", true); + LLVM_FALLTHROUGH; + case CK_BDVER3: + setFeatureEnabledImpl(Features, "fsgsbase", true); + setFeatureEnabledImpl(Features, "xsaveopt", true); + LLVM_FALLTHROUGH; + case CK_BDVER2: + setFeatureEnabledImpl(Features, "bmi", true); + setFeatureEnabledImpl(Features, "fma", true); + setFeatureEnabledImpl(Features, "f16c", true); + setFeatureEnabledImpl(Features, "tbm", true); + LLVM_FALLTHROUGH; + case CK_BDVER1: + // xop implies avx, sse4a and fma4. + setFeatureEnabledImpl(Features, "xop", true); + setFeatureEnabledImpl(Features, "lwp", true); + setFeatureEnabledImpl(Features, "lzcnt", true); + setFeatureEnabledImpl(Features, "aes", true); + setFeatureEnabledImpl(Features, "pclmul", true); + setFeatureEnabledImpl(Features, "prfchw", true); + setFeatureEnabledImpl(Features, "cx16", true); + setFeatureEnabledImpl(Features, "fxsr", true); + setFeatureEnabledImpl(Features, "xsave", true); + setFeatureEnabledImpl(Features, "sahf", true); + break; + } + if (!TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec)) + 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::find(FeaturesVec, "-popcnt") == FeaturesVec.end()) + Features["popcnt"] = true; + + // Enable prfchw if 3DNow! is enabled and prfchw is not explicitly disabled. + I = Features.find("3dnow"); + if (I != Features.end() && I->getValue() && + llvm::find(FeaturesVec, "-prfchw") == FeaturesVec.end()) + Features["prfchw"] = 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::find(FeaturesVec, "-mmx") == FeaturesVec.end()) + Features["mmx"] = true; + + return true; +} + +void X86TargetInfo::setSSELevel(llvm::StringMap<bool> &Features, + X86SSEEnum Level, bool Enabled) { + if (Enabled) { + switch (Level) { + case AVX512F: + Features["avx512f"] = true; + Features["fma"] = true; + Features["f16c"] = true; + LLVM_FALLTHROUGH; + case AVX2: + Features["avx2"] = true; + LLVM_FALLTHROUGH; + case AVX: + Features["avx"] = true; + Features["xsave"] = true; + LLVM_FALLTHROUGH; + case SSE42: + Features["sse4.2"] = true; + LLVM_FALLTHROUGH; + case SSE41: + Features["sse4.1"] = true; + LLVM_FALLTHROUGH; + case SSSE3: + Features["ssse3"] = true; + LLVM_FALLTHROUGH; + case SSE3: + Features["sse3"] = true; + LLVM_FALLTHROUGH; + case SSE2: + Features["sse2"] = true; + LLVM_FALLTHROUGH; + case SSE1: + Features["sse"] = true; + LLVM_FALLTHROUGH; + case NoSSE: + break; + } + return; + } + + switch (Level) { + case NoSSE: + case SSE1: + Features["sse"] = false; + LLVM_FALLTHROUGH; + case SSE2: + Features["sse2"] = Features["pclmul"] = Features["aes"] = false; + Features["sha"] = Features["gfni"] = false; + LLVM_FALLTHROUGH; + case SSE3: + Features["sse3"] = false; + setXOPLevel(Features, NoXOP, false); + LLVM_FALLTHROUGH; + case SSSE3: + Features["ssse3"] = false; + LLVM_FALLTHROUGH; + case SSE41: + Features["sse4.1"] = false; + LLVM_FALLTHROUGH; + case SSE42: + Features["sse4.2"] = false; + LLVM_FALLTHROUGH; + case AVX: + Features["fma"] = Features["avx"] = Features["f16c"] = false; + Features["xsave"] = Features["xsaveopt"] = Features["vaes"] = false; + Features["vpclmulqdq"] = false; + setXOPLevel(Features, FMA4, false); + LLVM_FALLTHROUGH; + case AVX2: + Features["avx2"] = false; + LLVM_FALLTHROUGH; + case AVX512F: + Features["avx512f"] = Features["avx512cd"] = Features["avx512er"] = false; + Features["avx512pf"] = Features["avx512dq"] = Features["avx512bw"] = false; + Features["avx512vl"] = Features["avx512vbmi"] = false; + Features["avx512ifma"] = Features["avx512vpopcntdq"] = false; + Features["avx512bitalg"] = Features["avx512vnni"] = false; + Features["avx512vbmi2"] = Features["avx512bf16"] = false; + Features["avx512vp2intersect"] = false; + break; + } +} + +void X86TargetInfo::setMMXLevel(llvm::StringMap<bool> &Features, + MMX3DNowEnum Level, bool Enabled) { + if (Enabled) { + switch (Level) { + case AMD3DNowAthlon: + Features["3dnowa"] = true; + LLVM_FALLTHROUGH; + case AMD3DNow: + Features["3dnow"] = true; + LLVM_FALLTHROUGH; + case MMX: + Features["mmx"] = true; + LLVM_FALLTHROUGH; + case NoMMX3DNow: + break; + } + return; + } + + switch (Level) { + case NoMMX3DNow: + case MMX: + Features["mmx"] = false; + LLVM_FALLTHROUGH; + case AMD3DNow: + Features["3dnow"] = false; + LLVM_FALLTHROUGH; + case AMD3DNowAthlon: + Features["3dnowa"] = false; + break; + } +} + +void X86TargetInfo::setXOPLevel(llvm::StringMap<bool> &Features, XOPEnum Level, + bool Enabled) { + if (Enabled) { + switch (Level) { + case XOP: + Features["xop"] = true; + LLVM_FALLTHROUGH; + case FMA4: + Features["fma4"] = true; + setSSELevel(Features, AVX, true); + LLVM_FALLTHROUGH; + case SSE4A: + Features["sse4a"] = true; + setSSELevel(Features, SSE3, true); + LLVM_FALLTHROUGH; + case NoXOP: + break; + } + return; + } + + switch (Level) { + case NoXOP: + case SSE4A: + Features["sse4a"] = false; + LLVM_FALLTHROUGH; + case FMA4: + Features["fma4"] = false; + LLVM_FALLTHROUGH; + case XOP: + Features["xop"] = false; + break; + } +} + +void X86TargetInfo::setFeatureEnabledImpl(llvm::StringMap<bool> &Features, + StringRef Name, bool Enabled) { + // This is a bit of a hack to deal with the sse4 target feature when used + // as part of the target attribute. We handle sse4 correctly everywhere + // else. See below for more information on how we handle the sse4 options. + if (Name != "sse4") + Features[Name] = Enabled; + + if (Name == "mmx") { + setMMXLevel(Features, MMX, Enabled); + } else if (Name == "sse") { + setSSELevel(Features, SSE1, Enabled); + } else if (Name == "sse2") { + setSSELevel(Features, SSE2, Enabled); + } else if (Name == "sse3") { + setSSELevel(Features, SSE3, Enabled); + } else if (Name == "ssse3") { + setSSELevel(Features, SSSE3, Enabled); + } else if (Name == "sse4.2") { + setSSELevel(Features, SSE42, Enabled); + } else if (Name == "sse4.1") { + setSSELevel(Features, SSE41, Enabled); + } else if (Name == "3dnow") { + setMMXLevel(Features, AMD3DNow, Enabled); + } else if (Name == "3dnowa") { + setMMXLevel(Features, AMD3DNowAthlon, Enabled); + } else if (Name == "aes") { + if (Enabled) + setSSELevel(Features, SSE2, Enabled); + else + Features["vaes"] = false; + } else if (Name == "vaes") { + if (Enabled) { + setSSELevel(Features, AVX, Enabled); + Features["aes"] = true; + } + } else if (Name == "pclmul") { + if (Enabled) + setSSELevel(Features, SSE2, Enabled); + else + Features["vpclmulqdq"] = false; + } else if (Name == "vpclmulqdq") { + if (Enabled) { + setSSELevel(Features, AVX, Enabled); + Features["pclmul"] = true; + } + } else if (Name == "gfni") { + if (Enabled) + setSSELevel(Features, SSE2, Enabled); + } else if (Name == "avx") { + setSSELevel(Features, AVX, Enabled); + } else if (Name == "avx2") { + setSSELevel(Features, AVX2, Enabled); + } else if (Name == "avx512f") { + setSSELevel(Features, AVX512F, Enabled); + } else if (Name.startswith("avx512")) { + if (Enabled) + setSSELevel(Features, AVX512F, Enabled); + // Enable BWI instruction if certain features are being enabled. + if ((Name == "avx512vbmi" || Name == "avx512vbmi2" || + Name == "avx512bitalg" || Name == "avx512bf16") && Enabled) + Features["avx512bw"] = true; + // Also disable some features if BWI is being disabled. + if (Name == "avx512bw" && !Enabled) { + Features["avx512vbmi"] = false; + Features["avx512vbmi2"] = false; + Features["avx512bitalg"] = false; + Features["avx512bf16"] = false; + } + } else if (Name == "fma") { + if (Enabled) + setSSELevel(Features, AVX, Enabled); + else + setSSELevel(Features, AVX512F, Enabled); + } else if (Name == "fma4") { + setXOPLevel(Features, FMA4, Enabled); + } else if (Name == "xop") { + setXOPLevel(Features, XOP, Enabled); + } else if (Name == "sse4a") { + setXOPLevel(Features, SSE4A, Enabled); + } else if (Name == "f16c") { + if (Enabled) + setSSELevel(Features, AVX, Enabled); + else + setSSELevel(Features, AVX512F, Enabled); + } else if (Name == "sha") { + if (Enabled) + setSSELevel(Features, SSE2, Enabled); + } else 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) + setSSELevel(Features, SSE42, Enabled); + else + setSSELevel(Features, SSE41, Enabled); + } else if (Name == "xsave") { + if (!Enabled) + Features["xsaveopt"] = false; + } else if (Name == "xsaveopt" || Name == "xsavec" || Name == "xsaves") { + if (Enabled) + Features["xsave"] = true; + } +} + +/// 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 == "+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 == "+mpx") { + HasMPX = 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 == "+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; + } + + 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; + 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. + switch (CPU) { + case CK_Generic: + 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_IcelakeServer: + // 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_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_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__"); + + 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 (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 (HasMPX) + Builder.defineMacro("__MPX__"); + if (HasSHSTK) + Builder.defineMacro("__SHSTK__"); + if (HasSGX) + Builder.defineMacro("__SGX__"); + if (HasPREFETCHWT1) + Builder.defineMacro("__PREFETCHWT1__"); + if (HasCLZERO) + Builder.defineMacro("__CLZERO__"); + 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__"); + + // 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_Generic) { + 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("avx", true) + .Case("avx2", true) + .Case("avx512f", true) + .Case("avx512cd", true) + .Case("avx512vpopcntdq", true) + .Case("avx512vnni", true) + .Case("avx512bf16", true) + .Case("avx512er", 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("bmi", true) + .Case("bmi2", true) + .Case("cldemote", true) + .Case("clflushopt", true) + .Case("clwb", true) + .Case("clzero", true) + .Case("cx16", true) + .Case("enqcmd", true) + .Case("f16c", true) + .Case("fma", true) + .Case("fma4", true) + .Case("fsgsbase", true) + .Case("fxsr", true) + .Case("gfni", true) + .Case("invpcid", true) + .Case("lwp", true) + .Case("lzcnt", true) + .Case("mmx", true) + .Case("movbe", true) + .Case("movdiri", true) + .Case("movdir64b", true) + .Case("mpx", 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("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("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("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("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("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("invpcid", HasINVPCID) + .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("mpx", HasMPX) + .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("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("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("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(VAL, ENUM, STR) .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(VAL, ENUM, STR) .Case(STR, llvm::X86::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. +} + +static unsigned getFeaturePriority(llvm::X86::ProcessorFeatures Feat) { + enum class FeatPriority { +#define FEATURE(FEAT) FEAT, +#include "clang/Basic/X86Target.def" + }; + switch (Feat) { +#define FEATURE(FEAT) \ + case llvm::X86::FEAT: \ + return static_cast<unsigned>(FeatPriority::FEAT); +#include "clang/Basic/X86Target.def" + default: + llvm_unreachable("No Feature Priority for non-CPUSupports Features"); + } +} + +unsigned X86TargetInfo::multiVersionSortPriority(StringRef Name) const { + // Valid CPUs have a 'key feature' that compares just better than its key + // feature. + CPUKind Kind = getCPUKind(Name); + if (Kind != CK_Generic) { + switch (Kind) { + default: + llvm_unreachable( + "CPU Type without a key feature used in 'target' attribute"); +#define PROC_WITH_FEAT(ENUM, STR, IS64, KEY_FEAT) \ + case CK_##ENUM: \ + return (getFeaturePriority(llvm::X86::KEY_FEAT) << 1) + 1; +#include "clang/Basic/X86Target.def" + } + } + + // 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 "clang/Basic/X86Target.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 "clang/Basic/X86Target.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 "clang/Basic/X86Target.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 "clang/Basic/X86Target.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_COMPAT_WITH_ALIAS(ARCHNAME, ENUM, STR, ALIAS) \ + .Cases(STR, ALIAS, true) +#define X86_CPU_TYPE_COMPAT(ARCHNAME, ENUM, STR) .Case(STR, true) +#define X86_CPU_SUBTYPE_COMPAT(ARCHNAME, 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': + case '0': // 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; + } +} + +bool X86TargetInfo::validateOutputSize(StringRef Constraint, + unsigned Size) const { + // Strip off constraint modifiers. + while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&') + Constraint = Constraint.substr(1); + + return validateOperandSize(Constraint, Size); +} + +bool X86TargetInfo::validateInputSize(StringRef Constraint, + unsigned Size) const { + return validateOperandSize(Constraint, Size); +} + +bool X86TargetInfo::validateOperandSize(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': + case '0': + // XMM0 + if (SSELevel >= SSE1) + 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; + } + LLVM_FALLTHROUGH; + case 'v': + case 'x': + if (SSELevel >= AVX512F) + // 512-bit zmm registers can be used if target supports AVX512F. + return Size <= 512U; + else if (SSELevel >= 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 '0': + 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); + } +} + +bool X86TargetInfo::checkCPUKind(CPUKind Kind) const { + // Perform any per-CPU checks necessary to determine if this CPU is + // acceptable. + switch (Kind) { + case CK_Generic: + // No processor selected! + return false; +#define PROC(ENUM, STRING, IS64BIT) \ + case CK_##ENUM: \ + return IS64BIT || getTriple().getArch() == llvm::Triple::x86; +#include "clang/Basic/X86Target.def" + } + llvm_unreachable("Unhandled CPU kind"); +} + +void X86TargetInfo::fillValidCPUList(SmallVectorImpl<StringRef> &Values) const { +#define PROC(ENUM, STRING, IS64BIT) \ + if (IS64BIT || getTriple().getArch() == llvm::Triple::x86) \ + Values.emplace_back(STRING); + // For aliases we need to lookup the CPUKind to check get the 64-bit ness. +#define PROC_ALIAS(ENUM, ALIAS) \ + if (checkCPUKind(CK_##ENUM)) \ + Values.emplace_back(ALIAS); +#include "clang/Basic/X86Target.def" +} + +X86TargetInfo::CPUKind X86TargetInfo::getCPUKind(StringRef CPU) const { + return llvm::StringSwitch<CPUKind>(CPU) +#define PROC(ENUM, STRING, IS64BIT) .Case(STRING, CK_##ENUM) +#define PROC_ALIAS(ENUM, ALIAS) .Case(ALIAS, CK_##ENUM) +#include "clang/Basic/X86Target.def" + .Default(CK_Generic); +} + +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..dd1e7db6c81e --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/X86.h @@ -0,0 +1,855 @@ +//===--- 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" + +namespace clang { +namespace targets { + +// 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; + + 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 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 HasMPX = 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; + +protected: + /// Enumeration of all of the X86 CPUs supported by Clang. + /// + /// Each enumeration represents a particular CPU supported by Clang. These + /// loosely correspond to the options passed to '-march' or '-mtune' flags. + enum CPUKind { + CK_Generic, +#define PROC(ENUM, STRING, IS64BIT) CK_##ENUM, +#include "clang/Basic/X86Target.def" + } CPU = CK_Generic; + + bool checkCPUKind(CPUKind Kind) const; + + CPUKind getCPUKind(StringRef CPU) const; + + 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(); + } + + 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 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; + + 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(StringRef Constraint, unsigned Size) const override; + + bool validateInputSize(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(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; + + static void setSSELevel(llvm::StringMap<bool> &Features, X86SSEEnum Level, + bool Enabled); + + static void setMMXLevel(llvm::StringMap<bool> &Features, MMX3DNowEnum Level, + bool Enabled); + + static void setXOPLevel(llvm::StringMap<bool> &Features, XOPEnum Level, + bool Enabled); + + void setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name, + bool Enabled) const override { + setFeatureEnabledImpl(Features, Name, Enabled); + } + + // This exists purely to cut down on the number of virtual calls in + // initFeatureMap which calls this repeatedly. + static void setFeatureEnabledImpl(llvm::StringMap<bool> &Features, + StringRef Name, bool Enabled); + + 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 override; + + 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 isValidCPUName(StringRef Name) const override { + return checkCPUKind(getCPUKind(Name)); + } + + void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; + + bool setCPU(const std::string &Name) override { + return checkCPUKind(CPU = getCPUKind(Name)); + } + + unsigned multiVersionSortPriority(StringRef Name) const override; + + bool setFPMath(StringRef Name) override; + + 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; + default: + return CCCR_Warning; + } + } + + CallingConv getDefaultCallingConv() const override { + return CC_C; + } + + bool hasSjLjLowering() const override { return true; } + + void setSupportedOpenCLOpts() override { + getSupportedOpenCLOpts().supportAll(); + } +}; + +// 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("e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128"); + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + RegParmMax = 3; + + // Use fpret for all types. + RealTypeUsesObjCFPRet = + ((1 << TargetInfo::Float) | (1 << TargetInfo::Double) | + (1 << TargetInfo::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(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(Constraint, Size); + } + + void setMaxAtomicWidth() override { + if (hasFeature("cx8")) + MaxAtomicInlineWidth = 64; + } + + ArrayRef<Builtin::Info> getTargetBuiltins() const override; +}; + +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 { + unsigned Major, Minor, Micro; + getTriple().getOSVersion(Major, Minor, Micro); + // New NetBSD uses the default rounding mode. + if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 26) || Major == 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-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(); + resetDataLayout(IsWinCOFF + ? "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" + : "e-m:e-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"); + } +}; + +// 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-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-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().getEnvironment() == llvm::Triple::GNUX32; + 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-i64:64-f80:128-n8:16:32:64-S128" + : IsWinCOFF ? "e-m:w-i64:64-f80:128-n8:16:32:64-S128" + : "e-m:e-i64:64-f80:128-n8:16:32:64-S128"); + + // Use fpret only for long double. + RealTypeUsesObjCFPRet = (1 << TargetInfo::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_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; +}; + +// 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_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-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..da614f10e338 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/XCore.cpp @@ -0,0 +1,37 @@ +//===--- 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("__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..c94f93a99bca --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Targets/XCore.h @@ -0,0 +1,81 @@ +//===--- 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; } +}; +} // 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..a71cd72517de --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/TokenKinds.cpp @@ -0,0 +1,47 @@ +//===--- 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; +} 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..0c17b39f9e4a --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Version.cpp @@ -0,0 +1,150 @@ +//===- 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> + +#ifdef HAVE_VCS_VERSION_INC +#include "VCSVersion.inc" +#endif + +namespace clang { + +std::string getClangRepositoryPath() { +#if defined(CLANG_REPOSITORY_STRING) + return CLANG_REPOSITORY_STRING; +#else +#ifdef CLANG_REPOSITORY + StringRef URL(CLANG_REPOSITORY); +#else + StringRef URL(""); +#endif + + // If the CLANG_REPOSITORY is empty, try to use the SVN keyword. This helps us + // pick up a tag in an SVN export, for example. + StringRef SVNRepository("$URL: https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_900/final/lib/Basic/Version.cpp $"); + if (URL.empty()) { + URL = SVNRepository.slice(SVNRepository.find(':'), + SVNRepository.find("/lib/Basic")); + } + + // Strip off version from a build from an integration branch. + URL = URL.slice(0, URL.find("/src/tools/clang")); + + // Trim path prefix off, assuming path came from standard cfe path. + size_t Start = URL.find("cfe/"); + if (Start != StringRef::npos) + URL = URL.substr(Start + 4); + + return URL; +#endif +} + +std::string getLLVMRepositoryPath() { +#ifdef LLVM_REPOSITORY + StringRef URL(LLVM_REPOSITORY); +#else + StringRef URL(""); +#endif + + // Trim path prefix off, assuming path came from standard llvm path. + // Leave "llvm/" prefix to distinguish the following llvm revision from the + // clang revision. + size_t Start = URL.find("llvm/"); + if (Start != StringRef::npos) + URL = URL.substr(Start); + + return URL; +} + +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 OS.str(); +} + +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 " " + << getClangFullRepositoryVersion(); + + // If vendor supplied, include the base LLVM version as well. +#ifdef CLANG_VENDOR + OS << " (based on " << BACKEND_PACKAGE_STRING << ")"; +#endif + + return OS.str(); +} + +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 " " << getClangFullRepositoryVersion(); + return OS.str(); +} + +} // 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..88ef2eaa6589 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Warnings.cpp @@ -0,0 +1,229 @@ +//===--- 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() += Opt) + << !Suggestion.empty() << (Prefix.str() += 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 and -Werror-foo. + if (Opt.startswith("error")) { + StringRef Specifier; + if (Opt.size() > 5) { // Specifier must be present. + if ((Opt[5] != '=' && Opt[5] != '-') || Opt.size() == 6) { + 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..ef2470f67200 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/XRayInstr.cpp @@ -0,0 +1,29 @@ +//===--- 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/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::Function) + .Case("typed", XRayInstrKind::Typed) + .Case("none", XRayInstrKind::None) + .Default(XRayInstrKind::None); + return ParsedKind; +} + +} // 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..eb549436710a --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/XRayLists.cpp @@ -0,0 +1,68 @@ +//===-- 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" + +using namespace clang; + +XRayFunctionFilter::XRayFunctionFilter( + ArrayRef<std::string> AlwaysInstrumentPaths, + ArrayRef<std::string> NeverInstrumentPaths, + ArrayRef<std::string> AttrListPaths, SourceManager &SM) + : AlwaysInstrument( + llvm::SpecialCaseList::createOrDie(AlwaysInstrumentPaths)), + NeverInstrument(llvm::SpecialCaseList::createOrDie(NeverInstrumentPaths)), + AttrList(llvm::SpecialCaseList::createOrDie(AttrListPaths)), SM(SM) {} + +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); +} |