diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Basic')
25 files changed, 16719 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/lib/Basic/Attributes.cpp b/contrib/llvm/tools/clang/lib/Basic/Attributes.cpp new file mode 100644 index 0000000..da9ac79 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Attributes.cpp @@ -0,0 +1,17 @@ +#include "clang/Basic/Attributes.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 llvm::Triple &T, + 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); + +#include "clang/Basic/AttrHasAttributeImpl.inc" + + return 0; +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp b/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp new file mode 100644 index 0000000..8efcac6 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp @@ -0,0 +1,131 @@ +//===--- Builtins.cpp - Builtin function implementation -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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/SmallVector.h" +#include "llvm/ADT/StringRef.h" +using namespace clang; + +static const Builtin::Info BuiltinInfo[] = { + { "not a builtin function", nullptr, nullptr, nullptr, ALL_LANGUAGES}, +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, +#define LANGBUILTIN(ID, TYPE, ATTRS, BUILTIN_LANG) { #ID, TYPE, ATTRS, 0, BUILTIN_LANG }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, BUILTIN_LANG) { #ID, TYPE, ATTRS, HEADER,\ + BUILTIN_LANG }, +#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 < NumTSRecords && "Invalid builtin ID!"); + return TSRecords[ID - Builtin::FirstTSBuiltin]; +} + +Builtin::Context::Context() { + // Get the target specific builtins from the target. + TSRecords = nullptr; + NumTSRecords = 0; +} + +void Builtin::Context::InitializeTarget(const TargetInfo &Target) { + assert(NumTSRecords == 0 && "Already initialized target?"); + Target.getTargetBuiltins(TSRecords, NumTSRecords); +} + +bool Builtin::Context::BuiltinIsSupported(const Builtin::Info &BuiltinInfo, + const LangOptions &LangOpts) { + bool BuiltinsUnsupported = LangOpts.NoBuiltin && + strchr(BuiltinInfo.Attributes, 'f'); + bool MathBuiltinsUnsupported = + LangOpts.NoMathBuiltin && BuiltinInfo.HeaderName && + llvm::StringRef(BuiltinInfo.HeaderName).equals("math.h"); + bool GnuModeUnsupported = !LangOpts.GNUMode && + (BuiltinInfo.builtin_lang & GNU_LANG); + bool MSModeUnsupported = !LangOpts.MicrosoftExt && + (BuiltinInfo.builtin_lang & MS_LANG); + bool ObjCUnsupported = !LangOpts.ObjC1 && + BuiltinInfo.builtin_lang == OBJC_LANG; + return !BuiltinsUnsupported && !MathBuiltinsUnsupported && + !GnuModeUnsupported && !MSModeUnsupported && !ObjCUnsupported; +} + +/// 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 = NumTSRecords; i != e; ++i) + if (BuiltinIsSupported(TSRecords[i], LangOpts)) + Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin); +} + +void +Builtin::Context::GetBuiltinNames(SmallVectorImpl<const char *> &Names) { + // Final all target-independent names + for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) + if (!strchr(BuiltinInfo[i].Attributes, 'f')) + Names.push_back(BuiltinInfo[i].Name); + + // Find target-specific names. + for (unsigned i = 0, e = NumTSRecords; i != e; ++i) + if (!strchr(TSRecords[i].Attributes, 'f')) + Names.push_back(TSRecords[i].Name); +} + +void Builtin::Context::ForgetBuiltin(unsigned ID, IdentifierTable &Table) { + Table.get(GetRecord(ID).Name).setBuiltinID(0); +} + +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"); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/CharInfo.cpp b/contrib/llvm/tools/clang/lib/Basic/CharInfo.cpp new file mode 100644 index 0000000..32b3277 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/CharInfo.cpp @@ -0,0 +1,81 @@ +//===--- CharInfo.cpp - Static Data for Classifying ASCII Characters ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/tools/clang/lib/Basic/Diagnostic.cpp b/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp new file mode 100644 index 0000000..f89caf7 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp @@ -0,0 +1,1017 @@ +//===--- Diagnostic.cpp - C Language Family Diagnostic Handling -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Diagnostic-related interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/CrashRecoveryContext.h" +#include "llvm/Support/Locale.h" +#include "llvm/Support/raw_ostream.h" + +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( + const IntrusiveRefCntPtr<DiagnosticIDs> &diags, DiagnosticOptions *DiagOpts, + DiagnosticConsumer *client, bool ShouldOwnClient) + : Diags(diags), DiagOpts(DiagOpts), Client(nullptr), SourceMgr(nullptr) { + setClient(client, ShouldOwnClient); + ArgToStringFn = DummyArgToStringFn; + ArgToStringCookie = nullptr; + + AllExtensionsSilenced = 0; + IgnoreAllWarnings = false; + WarningsAsErrors = false; + EnableAllWarnings = false; + ErrorsAsFatal = false; + SuppressSystemWarnings = false; + SuppressAllDiagnostics = false; + ElideType = true; + PrintTemplateTree = false; + ShowColors = false; + ShowOverloads = Ovl_All; + ExtBehavior = diag::Severity::Ignored; + + ErrorLimit = 0; + TemplateBacktraceLimit = 0; + ConstexprBacktraceLimit = 0; + + 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::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 = ~0U; + LastDiagLevel = DiagnosticIDs::Ignored; + DelayedDiagID = 0; + + // Clear state related to #pragma diagnostic. + DiagStates.clear(); + DiagStatePoints.clear(); + DiagStateOnPushStack.clear(); + + // Create a DiagState and DiagStatePoint representing diagnostic changes + // through command-line. + DiagStates.emplace_back(); + DiagStatePoints.push_back(DiagStatePoint(&DiagStates.back(), FullSourceLoc())); +} + +void DiagnosticsEngine::SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1, + StringRef Arg2) { + if (DelayedDiagID) + return; + + DelayedDiagID = DiagID; + DelayedDiagArg1 = Arg1.str(); + DelayedDiagArg2 = Arg2.str(); +} + +void DiagnosticsEngine::ReportDelayed() { + Report(DelayedDiagID) << DelayedDiagArg1 << DelayedDiagArg2; + DelayedDiagID = 0; + DelayedDiagArg1.clear(); + DelayedDiagArg2.clear(); +} + +DiagnosticsEngine::DiagStatePointsTy::iterator +DiagnosticsEngine::GetDiagStatePointForLoc(SourceLocation L) const { + assert(!DiagStatePoints.empty()); + assert(DiagStatePoints.front().Loc.isInvalid() && + "Should have created a DiagStatePoint for command-line"); + + if (!SourceMgr) + return DiagStatePoints.end() - 1; + + FullSourceLoc Loc(L, *SourceMgr); + if (Loc.isInvalid()) + return DiagStatePoints.end() - 1; + + DiagStatePointsTy::iterator Pos = DiagStatePoints.end(); + FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc; + if (LastStateChangePos.isValid() && + Loc.isBeforeInTranslationUnitThan(LastStateChangePos)) + Pos = std::upper_bound(DiagStatePoints.begin(), DiagStatePoints.end(), + DiagStatePoint(nullptr, Loc)); + --Pos; + return Pos; +} + +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(!DiagStatePoints.empty()); + assert((L.isInvalid() || SourceMgr) && "No SourceMgr for valid location"); + + FullSourceLoc Loc = SourceMgr? FullSourceLoc(L, *SourceMgr) : FullSourceLoc(); + FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc; + // Don't allow a mapping to a warning override an error/fatal mapping. + if (Map == diag::Severity::Warning) { + DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag); + if (Info.getSeverity() == diag::Severity::Error || + Info.getSeverity() == diag::Severity::Fatal) + Map = Info.getSeverity(); + } + DiagnosticMapping Mapping = makeUserMapping(Map, L); + + // Common case; setting all the diagnostics of a group in one place. + if (Loc.isInvalid() || Loc == LastStateChangePos) { + GetCurDiagState()->setMapping(Diag, Mapping); + return; + } + + // Another common case; modifying diagnostic state in a source location + // after the previous one. + if ((Loc.isValid() && LastStateChangePos.isInvalid()) || + LastStateChangePos.isBeforeInTranslationUnitThan(Loc)) { + // 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()); + PushDiagStatePoint(&DiagStates.back(), Loc); + GetCurDiagState()->setMapping(Diag, Mapping); + return; + } + + // We allow setting the diagnostic state in random source order for + // completeness but it should not be actually happening in normal practice. + + DiagStatePointsTy::iterator Pos = GetDiagStatePointForLoc(Loc); + assert(Pos != DiagStatePoints.end()); + + // Update all diagnostic states that are active after the given location. + for (DiagStatePointsTy::iterator + I = Pos+1, E = DiagStatePoints.end(); I != E; ++I) { + GetCurDiagState()->setMapping(Diag, Mapping); + } + + // If the location corresponds to an existing point, just update its state. + if (Pos->Loc == Loc) { + GetCurDiagState()->setMapping(Diag, Mapping); + return; + } + + // Create a new state/point and fit it into the vector of DiagStatePoints + // so that the vector is always ordered according to location. + assert(Pos->Loc.isBeforeInTranslationUnitThan(Loc)); + DiagStates.push_back(*Pos->State); + DiagState *NewState = &DiagStates.back(); + GetCurDiagState()->setMapping(Diag, Mapping); + DiagStatePoints.insert(Pos+1, DiagStatePoint(NewState, + FullSourceLoc(Loc, *SourceMgr))); +} + +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 (unsigned i = 0, e = GroupDiags.size(); i != e; ++i) { + DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(GroupDiags[i]); + + 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 Werror" bit, and + // potentially downgrade anything already mapped to be an 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 (unsigned i = 0, e = GroupDiags.size(); i != e; ++i) { + DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(GroupDiags[i]); + + 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. + SmallVector<diag::kind, 64> AllDiags; + Diags->getAllDiagnostics(Flavor, AllDiags); + + // Set the mapping. + for (unsigned i = 0, e = AllDiags.size(); i != e; ++i) + if (Diags->isBuiltinWarningOrExtension(AllDiags[i])) + setSeverity(AllDiags[i], Map, Loc); +} + +void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) { + assert(CurDiagID == ~0U && "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 = ~0U; +} + +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. + unsigned DiagID = CurDiagID; + Clear(); + + // If there was a delayed diagnostic, emit it now. + if (!Force && DelayedDiagID && DelayedDiagID != DiagID) + ReportDelayed(); + + return Emitted; +} + + +DiagnosticConsumer::~DiagnosticConsumer() {} + +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); +} + +/// 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 (1) { + 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 (1) { + 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; + } +} + +/// \brief 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 *Pipe = ScanFormat(Argument, Argument + ArgumentLen, '|'); + 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_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() { } + +StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, + StringRef Message) + : ID(ID), Level(Level), Loc(), 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()) +{ +} + +StoredDiagnostic::~StoredDiagnostic() { } + +/// 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() {} + +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 lamb"); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp b/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp new file mode 100644 index 0000000..643503b --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp @@ -0,0 +1,721 @@ +//===--- DiagnosticIDs.cpp - Diagnostic IDs Handling ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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 : 5; + + 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; + } +}; + +} // 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/DiagnosticSemaKinds.inc" +#include "clang/Basic/DiagnosticAnalysisKinds.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) { + // If assertions are enabled, verify that the StaticDiagInfo array is sorted. +#ifndef NDEBUG + static bool IsFirst = true; // So the check is only performed on first call. + if (IsFirst) { + for (unsigned i = 1; i != StaticDiagInfoSize; ++i) { + assert(StaticDiagInfo[i-1].DiagID != StaticDiagInfo[i].DiagID && + "Diag ID conflict, the enums at the start of clang::diag (in " + "DiagnosticIDs.h) probably need to be increased"); + + assert(StaticDiagInfo[i-1] < StaticDiagInfo[i] && + "Improperly sorted diag info"); + } + IsFirst = false; + } +#endif + + // 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(SEMA, COMMENT) +CATEGORY(ANALYSIS, SEMA) +#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() { CustomDiagInfo = nullptr; } + +DiagnosticIDs::~DiagnosticIDs() { + delete CustomDiagInfo; +} + +/// 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 = 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; +} + +/// \brief 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)); +} + +/// \brief 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; + + DiagnosticsEngine::DiagStatePointsTy::iterator + Pos = Diag.GetDiagStatePointForLoc(Loc); + DiagnosticsEngine::DiagState *State = Pos->State; + + // Get the mapping information, or compute it lazily. + 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 (Diag.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, Diag.ExtBehavior); + + // At this point, ignored errors can no longer be upgraded. + if (Result == diag::Severity::Ignored) + return Result; + + // Honor -w, which is lower in priority than pedantic-errors, but higher than + // -Werror. + if (Result == diag::Severity::Warning && Diag.IgnoreAllWarnings) + return diag::Severity::Ignored; + + // If -Werror is enabled, map warnings to errors unless explicitly disabled. + if (Result == diag::Severity::Warning) { + if (Diag.WarningsAsErrors && !Mapping.hasNoWarningAsError()) + Result = diag::Severity::Error; + } + + // If -Wfatal-errors is enabled, map errors to fatal unless explicity + // disabled. + if (Result == diag::Severity::Error) { + if (Diag.ErrorsAsFatal && !Mapping.hasNoErrorAsFatal()) + Result = diag::Severity::Fatal; + } + + // 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 (Diag.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 +}; +static const size_t OptionTableSize = llvm::array_lengthof(OptionTable); + +static bool WarningOptionCompare(const WarningOption &LHS, StringRef RHS) { + return LHS.getName() < RHS; +} + +/// 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(); +} + +/// 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 { + const WarningOption *Found = std::lower_bound( + OptionTable, OptionTable + OptionTableSize, Group, WarningOptionCompare); + if (Found == OptionTable + OptionTableSize || + Found->getName() != Group) + return true; // Option not found. + + return ::getDiagnosticsInGroup(Flavor, Found, Diags); +} + +void DiagnosticIDs::getAllDiagnostics(diag::Flavor Flavor, + SmallVectorImpl<diag::kind> &Diags) const { + 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 *i = OptionTable, *e = OptionTable + OptionTableSize; + i != e; ++i) { + // Don't suggest ignored warning flags. + if (!i->Members && !i->SubGroups) + continue; + + unsigned Distance = i->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, i, 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 = i->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; + } + } + + // 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/tools/clang/lib/Basic/DiagnosticOptions.cpp b/contrib/llvm/tools/clang/lib/Basic/DiagnosticOptions.cpp new file mode 100644 index 0000000..f54a0ef --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/DiagnosticOptions.cpp @@ -0,0 +1,24 @@ +//===--- DiagnosticOptions.cpp - C Language Family Diagnostic Handling ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the DiagnosticOptions related interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/DiagnosticOptions.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { + +raw_ostream& operator<<(raw_ostream& Out, DiagnosticLevelMask M) { + using UT = std::underlying_type<DiagnosticLevelMask>::type; + return Out << static_cast<UT>(M); +} + +} // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp b/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp new file mode 100644 index 0000000..d492744 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp @@ -0,0 +1,592 @@ +//===--- FileManager.cpp - File System Probing and Caching ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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 "clang/Frontend/PCHContainerOperations.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" +#include <map> +#include <set> +#include <string> +#include <system_error> + +using namespace clang; + +/// NON_EXISTENT_DIR - A special value distinct from null that is used to +/// represent a dir name that doesn't exist on the disk. +#define NON_EXISTENT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1) + +/// NON_EXISTENT_FILE - A special value distinct from null that is used to +/// represent a filename that doesn't exist on the disk. +#define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1) + +//===----------------------------------------------------------------------===// +// Common logic. +//===----------------------------------------------------------------------===// + +FileManager::FileManager(const FileSystemOptions &FSO, + IntrusiveRefCntPtr<vfs::FileSystem> FS) + : FS(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 (!FS) + this->FS = vfs::getRealFileSystem(); +} + +FileManager::~FileManager() { + for (unsigned i = 0, e = VirtualFileEntries.size(); i != e; ++i) + delete VirtualFileEntries[i]; + for (unsigned i = 0, e = VirtualDirectoryEntries.size(); i != e; ++i) + delete VirtualDirectoryEntries[i]; +} + +void FileManager::addStatCache(std::unique_ptr<FileSystemStatCache> statCache, + bool AtBeginning) { + assert(statCache && "No stat cache provided?"); + if (AtBeginning || !StatCache.get()) { + statCache->setNextStatCache(std::move(StatCache)); + StatCache = std::move(statCache); + return; + } + + FileSystemStatCache *LastCache = StatCache.get(); + while (LastCache->getNextStatCache()) + LastCache = LastCache->getNextStatCache(); + + LastCache->setNextStatCache(std::move(statCache)); +} + +void FileManager::removeStatCache(FileSystemStatCache *statCache) { + if (!statCache) + return; + + if (StatCache.get() == statCache) { + // This is the first stat cache. + StatCache = StatCache->takeNextStatCache(); + return; + } + + // Find the stat cache in the list. + FileSystemStatCache *PrevCache = StatCache.get(); + while (PrevCache && PrevCache->getNextStatCache() != statCache) + PrevCache = PrevCache->getNextStatCache(); + + assert(PrevCache && "Stat cache not found for removal"); + PrevCache->setNextStatCache(statCache->takeNextStatCache()); +} + +void FileManager::clearStatCaches() { + StatCache.reset(); +} + +/// \brief 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()) + return; + + auto &NamedDirEnt = + *SeenDirEntries.insert(std::make_pair(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. + if (NamedDirEnt.second) + return; + + // Add the virtual directory to the cache. + DirectoryEntry *UDE = new DirectoryEntry; + UDE->Name = NamedDirEnt.first().data(); + NamedDirEnt.second = UDE; + VirtualDirectoryEntries.push_back(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 LLVM_ON_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; + auto &NamedDirEnt = + *SeenDirEntries.insert(std::make_pair(DirName, nullptr)).first; + + // See if there was already an entry in the map. Note that the map + // contains both virtual and real directories. + if (NamedDirEnt.second) + return NamedDirEnt.second == NON_EXISTENT_DIR ? nullptr + : NamedDirEnt.second; + + ++NumDirCacheMisses; + + // By default, initialize it to invalid. + NamedDirEnt.second = NON_EXISTENT_DIR; + + // Get the null-terminated directory name as stored as the key of the + // SeenDirEntries map. + const char *InterndDirName = NamedDirEnt.first().data(); + + // Check to see if the directory exists. + FileData Data; + if (getStatValue(InterndDirName, Data, 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[Data.UniqueID]; + + NamedDirEnt.second = &UDE; + if (!UDE.getName()) { + // 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 &NamedFileEnt = + *SeenFileEntries.insert(std::make_pair(Filename, nullptr)).first; + + // See if there is already an entry in the map. + if (NamedFileEnt.second) + return NamedFileEnt.second == NON_EXISTENT_FILE ? nullptr + : NamedFileEnt.second; + + ++NumFileCacheMisses; + + // By default, initialize it to invalid. + NamedFileEnt.second = NON_EXISTENT_FILE; + + // Get the null-terminated file name as stored as the key of the + // SeenFileEntries map. + const char *InterndFileName = NamedFileEnt.first().data(); + + // 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. + + // Nope, there isn't. Check to see if the file exists. + std::unique_ptr<vfs::File> F; + FileData Data; + if (getStatValue(InterndFileName, Data, 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[Data.UniqueID]; + + NamedFileEnt.second = &UFE; + + // If the name returned by getStatValue is different than Filename, re-intern + // the name. + if (Data.Name != Filename) { + auto &NamedFileEnt = + *SeenFileEntries.insert(std::make_pair(Data.Name, nullptr)).first; + if (!NamedFileEnt.second) + NamedFileEnt.second = &UFE; + else + 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 && Data.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 = Data.Size; + UFE.ModTime = Data.ModTime; + UFE.Dir = DirInfo; + UFE.UID = NextFileUID++; + UFE.UniqueID = Data.UniqueID; + UFE.IsNamedPipe = Data.IsNamedPipe; + UFE.InPCH = Data.InPCH; + UFE.File = std::move(F); + UFE.IsValid = true; + 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. + auto &NamedFileEnt = + *SeenFileEntries.insert(std::make_pair(Filename, nullptr)).first; + + // See if there is already an entry in the map. + if (NamedFileEnt.second && NamedFileEnt.second != NON_EXISTENT_FILE) + return NamedFileEnt.second; + + ++NumFileCacheMisses; + + // By default, initialize it to invalid. + NamedFileEnt.second = NON_EXISTENT_FILE; + + 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 + FileData Data; + const char *InterndFileName = NamedFileEnt.first().data(); + if (getStatValue(InterndFileName, Data, true, nullptr) == 0) { + Data.Size = Size; + Data.ModTime = ModificationTime; + UFE = &UniqueRealFiles[Data.UniqueID]; + + 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 = Data.UniqueID; + UFE->IsNamedPipe = Data.IsNamedPipe; + UFE->InPCH = Data.InPCH; + } + + if (!UFE) { + UFE = new FileEntry(); + VirtualFileEntries.push_back(UFE); + NamedFileEnt.second = UFE; + } + + UFE->Name = InterndFileName; + UFE->Size = Size; + UFE->ModTime = ModificationTime; + UFE->Dir = DirInfo; + UFE->UID = NextFileUID++; + UFE->File.reset(); + return UFE; +} + +void FileManager::FixupRelativePath(SmallVectorImpl<char> &path) const { + StringRef pathRef(path.data(), path.size()); + + if (FileSystemOpts.WorkingDir.empty() + || llvm::sys::path::is_absolute(pathRef)) + return; + + SmallString<128> NewPath(FileSystemOpts.WorkingDir); + llvm::sys::path::append(NewPath, pathRef); + path = NewPath; +} + +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; + + const char *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) { + if (FileSystemOpts.WorkingDir.empty()) + return FS->getBufferForFile(Filename); + + SmallString<128> FilePath(Filename); + FixupRelativePath(FilePath); + return FS->getBufferForFile(FilePath.c_str()); +} + +/// 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(const char *Path, FileData &Data, bool isFile, + std::unique_ptr<vfs::File> *F) { + // FIXME: FileSystemOpts shouldn't be passed in here, all paths should be + // absolute! + if (FileSystemOpts.WorkingDir.empty()) + return FileSystemStatCache::get(Path, Data, isFile, F,StatCache.get(), *FS); + + SmallString<128> FilePath(Path); + FixupRelativePath(FilePath); + + return FileSystemStatCache::get(FilePath.c_str(), Data, isFile, F, + StatCache.get(), *FS); +} + +bool FileManager::getNoncachedStatValue(StringRef Path, + vfs::Status &Result) { + SmallString<128> FilePath(Path); + FixupRelativePath(FilePath); + + llvm::ErrorOr<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. + 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() && FE->getValue() != NON_EXISTENT_FILE) + UIDToFiles[FE->getValue()->getUID()] = FE->getValue(); + + // Map virtual file entries + for (SmallVectorImpl<FileEntry *>::const_iterator + VFE = VirtualFileEntries.begin(), VFEEnd = VirtualFileEntries.end(); + VFE != VFEEnd; ++VFE) + if (*VFE && *VFE != NON_EXISTENT_FILE) + UIDToFiles[(*VFE)->getUID()] = *VFE; +} + +void FileManager::modifyFileEntry(FileEntry *File, + off_t Size, time_t ModificationTime) { + File->Size = Size; + File->ModTime = ModificationTime; +} + +/// Remove '.' path components from the given absolute path. +/// \return \c true if any changes were made. +// FIXME: Move this to llvm::sys::path. +bool FileManager::removeDotPaths(SmallVectorImpl<char> &Path) { + using namespace llvm::sys; + + SmallVector<StringRef, 16> ComponentStack; + StringRef P(Path.data(), Path.size()); + + // Skip the root path, then look for traversal in the components. + StringRef Rel = path::relative_path(P); + bool AnyDots = false; + for (StringRef C : llvm::make_range(path::begin(Rel), path::end(Rel))) { + if (C == ".") { + AnyDots = true; + continue; + } + ComponentStack.push_back(C); + } + + if (!AnyDots) + return false; + + SmallString<256> Buffer = path::root_path(P); + for (StringRef C : ComponentStack) + path::append(Buffer, C); + + Path.swap(Buffer); + return true; +} + +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()); + +#ifdef LLVM_ON_UNIX + char CanonicalNameBuf[PATH_MAX]; + if (realpath(Dir->getName(), CanonicalNameBuf)) { + unsigned Len = strlen(CanonicalNameBuf); + char *Mem = static_cast<char *>(CanonicalNameStorage.Allocate(Len, 1)); + memcpy(Mem, CanonicalNameBuf, Len); + CanonicalName = StringRef(Mem, Len); + } +#else + SmallString<256> CanonicalNameBuf(CanonicalName); + llvm::sys::fs::make_absolute(CanonicalNameBuf); + llvm::sys::path::native(CanonicalNameBuf); + removeDotPaths(CanonicalNameBuf); +#endif + + CanonicalDirNames.insert(std::make_pair(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; +} + +// Virtual destructors for abstract base classes that need live in Basic. +PCHContainerWriter::~PCHContainerWriter() {} +PCHContainerReader::~PCHContainerReader() {} diff --git a/contrib/llvm/tools/clang/lib/Basic/FileSystemStatCache.cpp b/contrib/llvm/tools/clang/lib/Basic/FileSystemStatCache.cpp new file mode 100644 index 0000000..187ea37 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/FileSystemStatCache.cpp @@ -0,0 +1,126 @@ +//===--- FileSystemStatCache.cpp - Caching for 'stat' calls ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the FileSystemStatCache interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/FileSystemStatCache.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "llvm/Support/Path.h" + +using namespace clang; + +void FileSystemStatCache::anchor() { } + +static void copyStatusToFileData(const vfs::Status &Status, + FileData &Data) { + Data.Name = Status.getName(); + Data.Size = Status.getSize(); + Data.ModTime = Status.getLastModificationTime().toEpochTime(); + Data.UniqueID = Status.getUniqueID(); + Data.IsDirectory = Status.isDirectory(); + Data.IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file; + Data.InPCH = false; + Data.IsVFSMapped = Status.IsVFSMapped; +} + +/// 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. +bool FileSystemStatCache::get(const char *Path, FileData &Data, bool isFile, + std::unique_ptr<vfs::File> *F, + FileSystemStatCache *Cache, vfs::FileSystem &FS) { + LookupResult R; + bool isForDir = !isFile; + + // If we have a cache, use it to resolve the stat query. + if (Cache) + R = Cache->getStat(Path, Data, 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<vfs::Status> Status = FS.status(Path); + if (!Status) { + R = CacheMissing; + } else { + R = CacheExists; + copyStatusToFileData(*Status, Data); + } + } 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. + R = CacheMissing; + } 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<vfs::Status> Status = (*OwnedFile)->status(); + if (Status) { + R = CacheExists; + copyStatusToFileData(*Status, Data); + *F = std::move(*OwnedFile); + } else { + // fstat rarely fails. If it does, claim the initial open didn't + // succeed. + R = CacheMissing; + *F = nullptr; + } + } + } + + // If the path doesn't exist, return failure. + if (R == CacheMissing) return true; + + // If the path exists, make sure that its "directoryness" matches the clients + // demands. + if (Data.IsDirectory != isForDir) { + // If not, close the file if opened. + if (F) + *F = nullptr; + + return true; + } + + return false; +} + +MemorizeStatCalls::LookupResult +MemorizeStatCalls::getStat(const char *Path, FileData &Data, bool isFile, + std::unique_ptr<vfs::File> *F, vfs::FileSystem &FS) { + LookupResult Result = statChained(Path, Data, isFile, F, FS); + + // 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). + if (Result == CacheMissing) + return Result; + + // Cache file 'stat' results and directories with absolutely paths. + if (!Data.IsDirectory || llvm::sys::path::is_absolute(Path)) + StatCalls[Path] = Data; + + return Result; +} diff --git a/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp b/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp new file mode 100644 index 0000000..7705834 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp @@ -0,0 +1,664 @@ +//===--- IdentifierTable.cpp - Hash table for identifier lookup -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the IdentifierInfo, IdentifierVisitor, and +// IdentifierTable interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/Specifiers.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include <cstdio> + +using namespace clang; + +//===----------------------------------------------------------------------===// +// IdentifierInfo Implementation +//===----------------------------------------------------------------------===// + +IdentifierInfo::IdentifierInfo() { + TokenID = tok::identifier; + ObjCOrBuiltinID = 0; + HasMacro = false; + HadMacro = false; + IsExtension = false; + IsFutureCompatKeyword = false; + IsPoisoned = false; + IsCPPOperatorKeyword = false; + NeedsHandleIdentifier = false; + IsFromAST = false; + ChangedAfterLoad = false; + RevertedTokenID = false; + OutOfDate = false; + IsModulesImport = false; + FETokenInfo = nullptr; + Entry = nullptr; +} + +//===----------------------------------------------------------------------===// +// IdentifierTable Implementation +//===----------------------------------------------------------------------===// + +IdentifierIterator::~IdentifierIterator() { } + +IdentifierInfoLookup::~IdentifierInfoLookup() {} + +namespace { + /// \brief A simple identifier lookup iterator that represents an + /// empty sequence of identifiers. + class EmptyLookupIterator : public IdentifierIterator + { + public: + StringRef Next() override { return StringRef(); } + }; +} + +IdentifierIterator *IdentifierInfoLookup::getIdentifiers() { + return new EmptyLookupIterator(); +} + +IdentifierTable::IdentifierTable(const LangOptions &LangOpts, + IdentifierInfoLookup* externalLookup) + : HashTable(8192), // Start with space for 8K identifiers. + ExternalLookup(externalLookup) { + + // Populate the identifier table with info about keywords for the current + // language. + AddKeywords(LangOpts); + + + // Add the '_experimental_modules_import' contextual keyword. + get("import").setModulesImport(true); +} + +//===----------------------------------------------------------------------===// +// 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, + KEYOPENCL = 0x200, + KEYC11 = 0x400, + KEYARC = 0x800, + KEYNOMS18 = 0x01000, + KEYNOOPENCL = 0x02000, + WCHARSUPPORT = 0x04000, + HALFSUPPORT = 0x08000, + KEYCONCEPTS = 0x10000, + KEYOBJC2 = 0x20000, + KEYZVECTOR = 0x40000, + KEYALL = (0x7ffff & ~KEYNOMS18 & + ~KEYNOOPENCL) // KEYNOMS18 and KEYNOOPENCL are used to exclude. + }; + + /// \brief 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 + }; +} + +/// \brief 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.C99 && (Flags & KEYC99)) return KS_Enabled; + if (LangOpts.GNUKeywords && (Flags & KEYGNU)) return KS_Extension; + if (LangOpts.MicrosoftExt && (Flags & KEYMS)) return KS_Extension; + 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.AltiVec && (Flags & KEYALTIVEC)) return KS_Enabled; + if (LangOpts.OpenCL && (Flags & KEYOPENCL)) 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.ObjC2 && (Flags & KEYARC)) return KS_Enabled; + if (LangOpts.ConceptsTS && (Flags & KEYCONCEPTS)) return KS_Enabled; + if (LangOpts.ObjC2 && (Flags & KEYOBJC2)) return KS_Enabled; + if (LangOpts.CPlusPlus && (Flags & KEYCXX11)) 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 OBJC1_AT_KEYWORD(NAME) \ + if (LangOpts.ObjC1) \ + AddObjCKeyword(StringRef(#NAME), tok::objc_##NAME, *this); +#define OBJC2_AT_KEYWORD(NAME) \ + if (LangOpts.ObjC2) \ + 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); + + // FIXME: __declspec isn't really a CUDA extension, however it is required for + // supporting cuda_builtin_vars.h, which uses __declspec(property). Once that + // has been rewritten in terms of something more generic, remove this code. + if (LangOpts.CUDA) + AddKeyword("__declspec", tok::kw___declspec, KEYALL, LangOpts, *this); +} + +/// \brief 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; + } +} + +/// \brief Returns true if the identifier represents a keyword in the +/// specified language. +bool IdentifierInfo::isKeyword(const LangOptions &LangOpts) { + switch (getTokenKwStatus(LangOpts, getTokenID())) { + case KS_Enabled: + case KS_Extension: + return true; + default: + return false; + } +} + +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 { +/// MultiKeywordSelector - 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 MultiKeywordSelector + : public DeclarationNameExtra, public llvm::FoldingSetNode { + MultiKeywordSelector(unsigned nKeys) { + ExtraKindOrNumArgs = NUM_EXTRA_KINDS + nKeys; + } +public: + // Constructor for keyword selectors. + MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV) { + assert((nKeys > 1) && "not a multi-keyword selector"); + ExtraKindOrNumArgs = NUM_EXTRA_KINDS + nKeys; + + // 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; + + unsigned getNumArgs() const { return ExtraKindOrNumArgs - NUM_EXTRA_KINDS; } + + typedef IdentifierInfo *const *keyword_iterator; + 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()); + } +}; +} // end 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 the number of arguments is 0 then II is guaranteed to not be null. + if (getNumArgs() == 0) + 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(); +} + +/// 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") 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; + case 'i': + if (startsWithWord(name, "init")) return OIT_Init; + 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; + }; +} // end anonymous 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); +} + +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, + llvm::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/tools/clang/lib/Basic/LangOptions.cpp b/contrib/llvm/tools/clang/lib/Basic/LangOptions.cpp new file mode 100644 index 0000000..2c87845 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/LangOptions.cpp @@ -0,0 +1,38 @@ +//===--- LangOptions.cpp - C Language Family Language Options ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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" + + // FIXME: This should not be reset; modules can be different with different + // sanitizer options (this affects __has_feature(address_sanitizer) etc). + Sanitize.clear(); + SanitizerBlacklistFiles.clear(); + + CurrentModule.clear(); + ImplementationOfModule.clear(); +} + diff --git a/contrib/llvm/tools/clang/lib/Basic/Module.cpp b/contrib/llvm/tools/clang/lib/Basic/Module.cpp new file mode 100644 index 0000000..4314b41 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Module.cpp @@ -0,0 +1,526 @@ +//===--- Module.cpp - Describe a module -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Module class, which describes a module in the source +// code. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Module.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent, + bool IsFramework, bool IsExplicit, unsigned VisibilityID) + : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent), Directory(), + Umbrella(), Signature(0), ASTFile(nullptr), VisibilityID(VisibilityID), + IsMissingRequirement(false), IsAvailable(true), IsFromModuleFile(false), + IsFramework(IsFramework), IsExplicit(IsExplicit), IsSystem(false), + IsExternC(false), IsInferred(false), InferSubmodules(false), + InferExplicitSubmodules(false), InferExportWildcard(false), + ConfigMacrosExhaustive(false), NameVisibility(Hidden) { + if (Parent) { + if (!Parent->isAvailable()) + IsAvailable = false; + if (Parent->IsSystem) + IsSystem = true; + if (Parent->IsExternC) + IsExternC = 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; + } +} + +/// \brief 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("cplusplus", LangOpts.CPlusPlus) + .Case("cplusplus11", LangOpts.CPlusPlus11) + .Case("objc", LangOpts.ObjC1) + .Case("objc_arc", LangOpts.ObjCAutoRefCount) + .Case("opencl", LangOpts.OpenCL) + .Case("tls", Target.isTLSSupported()) + .Case("zvector", LangOpts.ZVector) + .Default(Target.hasFeature(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) const { + if (IsAvailable) + return true; + + for (const Module *Current = this; Current; Current = Current->Parent) { + 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; +} + +std::string Module::getFullModuleName() 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; + for (SmallVectorImpl<StringRef>::reverse_iterator I = Names.rbegin(), + IEnd = Names.rend(); + I != IEnd; ++I) { + if (!Result.empty()) + Result += '.'; + + Result += *I; + } + + return Result; +} + +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; + 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()]; +} + +static void printModuleId(raw_ostream &OS, const ModuleId &Id) { + for (unsigned I = 0, N = Id.size(); I != N; ++I) { + if (I) + OS << "."; + OS << Id[I].first; + } +} + +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 " << Name; + + 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) { + for (auto &H : Headers[K.Kind]) { + OS.indent(Indent + 2); + OS << K.Prefix << "header \""; + OS.write_escaped(H.NameAsWritten); + OS << "\"\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(); + 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) { + if (UnresolvedExports[I].Id.empty()) + OS << "*"; + else + OS << ".*"; + } + OS << "\n"; + } + + for (unsigned I = 0, N = DirectUses.size(); I != N; ++I) { + OS.indent(Indent + 2); + OS << "use "; + OS << DirectUses[I]->getFullModuleName(); + 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(); + 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"; +} + +void Module::dump() const { + print(llvm::errs()); +} + +void VisibleModuleSet::setVisible(Module *M, SourceLocation Loc, + VisibleCallback Vis, ConflictCallback Cb) { + if (isVisible(M)) + return; + + ++Generation; + + struct Visiting { + Module *M; + Visiting *ExportedBy; + }; + + std::function<void(Visiting)> VisitModule = [&](Visiting V) { + // Modules that aren't available cannot be made visible. + if (!V.M->isAvailable()) + return; + + // 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) + 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/tools/clang/lib/Basic/ObjCRuntime.cpp b/contrib/llvm/tools/clang/lib/Basic/ObjCRuntime.cpp new file mode 100644 index 0000000..be50fc4 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/ObjCRuntime.cpp @@ -0,0 +1,90 @@ +//===- ObjCRuntime.cpp - Objective-C Runtime Handling -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the ObjCRuntime class, which represents the +// target Objective-C runtime. +// +//===----------------------------------------------------------------------===// +#include "clang/Basic/ObjCRuntime.h" +#include "llvm/Support/raw_ostream.h" + +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::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 == "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/tools/clang/lib/Basic/OpenMPKinds.cpp b/contrib/llvm/tools/clang/lib/Basic/OpenMPKinds.cpp new file mode 100644 index 0000000..b7407f6 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/OpenMPKinds.cpp @@ -0,0 +1,396 @@ +//===--- OpenMPKinds.cpp - Token Kinds Support ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// \brief 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" + .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_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<OpenMPScheduleClauseKind>(Str) +#define OPENMP_SCHEDULE_KIND(Name) .Case(#Name, OMPC_SCHEDULE_##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_unknown: + case OMPC_threadprivate: + case OMPC_if: + case OMPC_final: + case OMPC_num_threads: + case OMPC_safelen: + case OMPC_collapse: + case OMPC_private: + case OMPC_firstprivate: + case OMPC_lastprivate: + case OMPC_shared: + case OMPC_reduction: + case OMPC_linear: + 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: + 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: + return "unknown"; +#define OPENMP_SCHEDULE_KIND(Name) \ + case OMPC_SCHEDULE_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + 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 'schedule' clause type"); + case OMPC_unknown: + case OMPC_threadprivate: + case OMPC_if: + case OMPC_final: + case OMPC_num_threads: + case OMPC_safelen: + case OMPC_collapse: + case OMPC_private: + case OMPC_firstprivate: + case OMPC_lastprivate: + case OMPC_shared: + case OMPC_reduction: + case OMPC_linear: + 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: + 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_teams: + switch (CKind) { +#define OPENMP_TEAMS_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_unknown: + case OMPD_threadprivate: + case OMPD_section: + case OMPD_master: + case OMPD_critical: + case OMPD_taskyield: + case OMPD_barrier: + case OMPD_taskwait: + case OMPD_taskgroup: + case OMPD_cancellation_point: + case OMPD_cancel: + case OMPD_ordered: + 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; // TODO add next directives. +} + +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; // TODO add next directives. +} + +bool clang::isOpenMPParallelDirective(OpenMPDirectiveKind DKind) { + return DKind == OMPD_parallel || DKind == OMPD_parallel_for || + DKind == OMPD_parallel_for_simd || + DKind == OMPD_parallel_sections; // TODO add next directives. +} + +bool clang::isOpenMPTeamsDirective(OpenMPDirectiveKind DKind) { + return DKind == OMPD_teams; // TODO add next directives. +} + +bool clang::isOpenMPSimdDirective(OpenMPDirectiveKind DKind) { + return DKind == OMPD_simd || DKind == OMPD_for_simd || + DKind == OMPD_parallel_for_simd; // TODO add next directives. +} + +bool clang::isOpenMPPrivate(OpenMPClauseKind Kind) { + return Kind == OMPC_private || Kind == OMPC_firstprivate || + Kind == OMPC_lastprivate || Kind == OMPC_linear || + Kind == OMPC_reduction; // TODO add next clauses like 'reduction'. +} + +bool clang::isOpenMPThreadPrivate(OpenMPClauseKind Kind) { + return Kind == OMPC_threadprivate || Kind == OMPC_copyin; +} + diff --git a/contrib/llvm/tools/clang/lib/Basic/OperatorPrecedence.cpp b/contrib/llvm/tools/clang/lib/Basic/OperatorPrecedence.cpp new file mode 100644 index 0000000..ade8d6d --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/OperatorPrecedence.cpp @@ -0,0 +1,76 @@ +//===--- OperatorPrecedence.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief 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::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::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/tools/clang/lib/Basic/SanitizerBlacklist.cpp b/contrib/llvm/tools/clang/lib/Basic/SanitizerBlacklist.cpp new file mode 100644 index 0000000..095fcd6 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/SanitizerBlacklist.cpp @@ -0,0 +1,46 @@ +//===--- SanitizerBlacklist.cpp - Blacklist for sanitizers ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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) + : SCL(llvm::SpecialCaseList::createOrDie(BlacklistPaths)), SM(SM) {} + +bool SanitizerBlacklist::isBlacklistedGlobal(StringRef GlobalName, + StringRef Category) const { + return SCL->inSection("global", GlobalName, Category); +} + +bool SanitizerBlacklist::isBlacklistedType(StringRef MangledTypeName, + StringRef Category) const { + return SCL->inSection("type", MangledTypeName, Category); +} + +bool SanitizerBlacklist::isBlacklistedFunction(StringRef FunctionName) const { + return SCL->inSection("fun", FunctionName); +} + +bool SanitizerBlacklist::isBlacklistedFile(StringRef FileName, + StringRef Category) const { + return SCL->inSection("src", FileName, Category); +} + +bool SanitizerBlacklist::isBlacklistedLocation(SourceLocation Loc, + StringRef Category) const { + return !Loc.isInvalid() && + isBlacklistedFile(SM.getFilename(SM.getFileLoc(Loc)), Category); +} + diff --git a/contrib/llvm/tools/clang/lib/Basic/Sanitizers.cpp b/contrib/llvm/tools/clang/lib/Basic/Sanitizers.cpp new file mode 100644 index 0000000..91b6b2d --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Sanitizers.cpp @@ -0,0 +1,37 @@ +//===--- Sanitizers.cpp - C Language Family Language Options ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the classes from Sanitizers.h +// +//===----------------------------------------------------------------------===// +#include "clang/Basic/Sanitizers.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; + +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 : 0) +#include "clang/Basic/Sanitizers.def" + .Default(0); + 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; +} diff --git a/contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp b/contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp new file mode 100644 index 0000000..d254e86 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/SourceLocation.cpp @@ -0,0 +1,142 @@ +//==--- SourceLocation.cpp - Compact identifier for Source Files -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines accessor methods for the FullSourceLoc class. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/PrettyStackTrace.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include <cstdio> +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); +} + +//===----------------------------------------------------------------------===// +// 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); +} + +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/tools/clang/lib/Basic/SourceManager.cpp b/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp new file mode 100644 index 0000000..c0b0453 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp @@ -0,0 +1,2169 @@ +//===--- SourceManager.cpp - Track and cache source files -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the SourceManager interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManagerInternals.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Capacity.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cstring> +#include <string> + +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; + + 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(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(DoNotFree? DoNotFreeFlag : 0); +} + +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(); + } + + 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"); + Buffer.setPointer(MemoryBuffer::getNewUninitMemBuffer( + ContentsEntry->getSize(), "<invalid>").release()); + char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart()); + for (unsigned i = 0, e = ContentsEntry->getSize(); i != e; ++i) + Ptr[i] = FillStr[i % FillStr.size()]; + + 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("\xFE\xFF", "UTF-16 (BE)") + .StartsWith("\xFF\xFE", "UTF-16 (LE)") + .StartsWith("\x00\x00\xFE\xFF", "UTF-32 (BE)") + .StartsWith("\xFF\xFE\x00\x00", "UTF-32 (LE)") + .StartsWith("\x2B\x2F\x76", "UTF-7") + .StartsWith("\xF7\x64\x4C", "UTF-1") + .StartsWith("\xDD\x73\x66\x73", "UTF-EBCDIC") + .StartsWith("\x0E\xFE\xFF", "SDSU") + .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.insert(std::make_pair(Name, FilenamesByID.size())); + if (IterBool.second) + FilenamesByID.push_back(&*IterBool.first); + return IterBool.first->second; +} + +/// AddLineNote - Add a line note to the line table that indicates that there +/// is a \#line at the specified FID/Offset location which changes the presumed +/// location to LineNo/FilenameID. +void LineTableInfo::AddLineNote(FileID FID, unsigned Offset, + unsigned LineNo, int FilenameID) { + std::vector<LineEntry> &Entries = LineEntries[FID]; + + assert((Entries.empty() || Entries.back().FileOffset < Offset) && + "Adding line entries out of order!"); + + SrcMgr::CharacteristicKind Kind = SrcMgr::C_User; + unsigned IncludeOffset = 0; + + if (!Entries.empty()) { + // If this is a '#line 4' after '#line 42 "foo.h"', make sure to remember + // that we are still in "foo.h". + if (FilenameID == -1) + FilenameID = Entries.back().FilenameID; + + // If we are after a line marker that switched us to system header mode, or + // that set #include information, preserve it. + Kind = Entries.back().FileKind; + IncludeOffset = Entries.back().IncludeOffset; + } + + Entries.push_back(LineEntry::get(Offset, LineNo, FilenameID, Kind, + IncludeOffset)); +} + +/// AddLineNote This is the same as the previous version of AddLineNote, but is +/// used for GNU line markers. 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) { + assert(FilenameID != -1 && "Unspecified filename should use other accessor"); + + std::vector<LineEntry> &Entries = LineEntries[FID]; + + 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 = + std::upper_bound(Entries.begin(), Entries.end(), Offset); + if (I == Entries.begin()) return nullptr; + return &*--I; +} + +/// \brief 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) { + if (!LineTable) + LineTable = new LineTableInfo(); + return LineTable->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) { + 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(); + + if (!LineTable) + LineTable = new LineTableInfo(); + LineTable->AddLineNote(LocInfo.first, LocInfo.second, LineNo, FilenameID); +} + +/// AddLineNote - Add a GNU line marker to the line table. +void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo, + int FilenameID, bool IsFileEntry, + bool IsFileExit, bool IsSystemHeader, + bool IsExternCHeader) { + // If there is no filename and no flags, this is treated just like a #line, + // which does not change the flags of the previous line marker. + if (FilenameID == -1) { + assert(!IsFileEntry && !IsFileExit && !IsSystemHeader && !IsExternCHeader && + "Can't set flags without setting the filename!"); + return AddLineNote(Loc, LineNo, FilenameID); + } + + 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(); + + if (!LineTable) + LineTable = new LineTableInfo(); + + SrcMgr::CharacteristicKind FileKind; + if (IsExternCHeader) + FileKind = SrcMgr::C_ExternCSystem; + else if (IsSystemHeader) + FileKind = SrcMgr::C_System; + else + FileKind = SrcMgr::C_User; + + 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 = new LineTableInfo(); + return *LineTable; +} + +//===----------------------------------------------------------------------===// +// Private 'Create' methods. +//===----------------------------------------------------------------------===// + +SourceManager::SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr, + bool UserFilesAreVolatile) + : Diag(Diag), FileMgr(FileMgr), OverridenFilesKeepOriginalName(true), + UserFilesAreVolatile(UserFilesAreVolatile), + ExternalSLocEntries(nullptr), LineTable(nullptr), NumLinearScans(0), + NumBinaryProbes(0) { + clearIDTables(); + Diag.setSourceManager(this); +} + +SourceManager::~SourceManager() { + delete LineTable; + + // 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); + } + } + + llvm::DeleteContainerSeconds(MacroArgsCacheMap); +} + +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); +} + +/// 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; + + return Entry; +} + + +/// createMemBufferContentCache - Create a new ContentCache for the specified +/// memory buffer. This does no caching. +const ContentCache *SourceManager::createMemBufferContentCache( + std::unique_ptr<llvm::MemoryBuffer> Buffer) { + // Add a new ContentCache to the MemBufferInfos list and return it. + ContentCache *Entry = ContentCacheAlloc.Allocate<ContentCache>(); + new (Entry) ContentCache(); + MemBufferInfos.push_back(Entry); + Entry->setBuffer(std::move(Buffer)); + return Entry; +} + +const SrcMgr::SLocEntry &SourceManager::loadSLocEntry(unsigned Index, + bool *Invalid) const { + assert(!SLocEntryLoaded[Index]); + if (ExternalSLocEntries->ReadSLocEntry(-(static_cast<int>(Index) + 2))) { + if (Invalid) + *Invalid = true; + // If the file of the SLocEntry changed we could still have loaded it. + if (!SLocEntryLoaded[Index]) { + // Try to recover; create a SLocEntry so the rest of clang can handle it. + 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"); + LoadedSLocEntryTable.resize(LoadedSLocEntryTable.size() + NumSLocEntries); + SLocEntryLoaded.resize(LoadedSLocEntryTable.size()); + CurrentLoadedOffset -= TotalSize; + assert(CurrentLoadedOffset >= NextLocalOffset && "Out of source locations"); + int ID = LoadedSLocEntryTable.size(); + return std::make_pair(-ID - 1, CurrentLoadedOffset); +} + +/// \brief 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(); +} + +/// \brief 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(); +} + +/// \brief 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); +} + +/// \brief 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, + int LoadedID, + unsigned LoadedOffset) { + ExpansionInfo Info = ExpansionInfo::create(SpellingLoc, ExpansionLocStart, + ExpansionLocEnd); + return createExpansionLocImpl(Info, TokLength, LoadedID, LoadedOffset); +} + +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)); +} + +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); +} + +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>>>>>"; + } + + 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. +//===----------------------------------------------------------------------===// + +/// \brief 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); +} + +/// \brief 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 (1) { + --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 (1) { + 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; + } +} + +/// \brief 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 (1) { + ++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).first; + } 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. +std::pair<SourceLocation,SourceLocation> +SourceManager::getImmediateExpansionRange(SourceLocation Loc) const { + assert(Loc.isMacroID() && "Not a macro expansion loc!"); + const ExpansionInfo &Expansion = getSLocEntry(getFileID(Loc)).getExpansion(); + return Expansion.getExpansionLocRange(); +} + +/// getExpansionRange - Given a SourceLocation object, return the range of +/// tokens covered by the expansion in the ultimate file. +std::pair<SourceLocation,SourceLocation> +SourceManager::getExpansionRange(SourceLocation Loc) const { + if (Loc.isFileID()) return std::make_pair(Loc, Loc); + + std::pair<SourceLocation,SourceLocation> Res = + getImmediateExpansionRange(Loc); + + // Fully resolve the start and end locations to their ultimate expansion + // points. + while (!Res.first.isFileID()) + Res.first = getImmediateExpansionRange(Res.first).first; + while (!Res.second.isFileID()) + Res.second = getImmediateExpansionRange(Res.second).second; + return Res; +} + +bool SourceManager::isMacroArgExpansion(SourceLocation Loc) const { + if (!Loc.isMacroID()) return false; + + FileID FID = getFileID(Loc); + const SrcMgr::ExpansionInfo &Expansion = getSLocEntry(FID).getExpansion(); + return Expansion.isMacroArgExpansion(); +} + +bool SourceManager::isMacroBodyExpansion(SourceLocation Loc) const { + if (!Loc.isMacroID()) return false; + + FileID FID = getFileID(Loc); + const SrcMgr::ExpansionInfo &Expansion = getSLocEntry(FID).getExpansion(); + return Expansion.isMacroBodyExpansion(); +} + +bool SourceManager::isAtStartOfImmediateMacroExpansion(SourceLocation Loc, + SourceLocation *MacroBegin) const { + assert(Loc.isValid() && Loc.isMacroID() && "Expected a valid macro loc"); + + std::pair<FileID, unsigned> DecompLoc = getDecomposedLoc(Loc); + if (DecompLoc.second > 0) + return false; // Does not point at the start of expansion range. + + bool Invalid = false; + const SrcMgr::ExpansionInfo &ExpInfo = + getSLocEntry(DecompLoc.first, &Invalid).getExpansion(); + if (Invalid) + return false; + SourceLocation ExpLoc = ExpInfo.getExpansionLocStart(); + + if (ExpInfo.isMacroArgExpansion()) { + // For macro argument expansions, check if the previous FileID is part of + // the same argument expansion, in which case this Loc is not at the + // beginning of the expansion. + FileID PrevFID = getPreviousFileID(DecompLoc.first); + if (!PrevFID.isInvalid()) { + const SrcMgr::SLocEntry &PrevEntry = getSLocEntry(PrevFID, &Invalid); + if (Invalid) + return false; + if (PrevEntry.isExpansion() && + PrevEntry.getExpansion().getExpansionLocStart() == ExpLoc) + return false; + } + } + + if (MacroBegin) + *MacroBegin = ExpLoc; + return true; +} + +bool SourceManager::isAtEndOfImmediateMacroExpansion(SourceLocation Loc, + SourceLocation *MacroEnd) const { + assert(Loc.isValid() && Loc.isMacroID() && "Expected a valid macro loc"); + + FileID FID = getFileID(Loc); + SourceLocation NextLoc = Loc.getLocWithOffset(1); + if (isInFileID(NextLoc, FID)) + return false; // Does not point at the end of expansion range. + + bool Invalid = false; + const SrcMgr::ExpansionInfo &ExpInfo = + getSLocEntry(FID, &Invalid).getExpansion(); + if (Invalid) + return false; + + if (ExpInfo.isMacroArgExpansion()) { + // For macro argument expansions, check if the next FileID is part of the + // same argument expansion, in which case this Loc is not at the end of the + // expansion. + FileID NextFID = getNextFileID(FID); + if (!NextFID.isInvalid()) { + const SrcMgr::SLocEntry &NextEntry = getSLocEntry(NextFID, &Invalid); + if (Invalid) + return false; + if (NextEntry.isExpansion() && + NextEntry.getExpansion().getExpansionLocStart() == + ExpInfo.getExpansionLocStart()) + return false; + } + } + + if (MacroEnd) + *MacroEnd = ExpInfo.getExpansionLocEnd(); + return true; +} + + +//===----------------------------------------------------------------------===// +// Queries about the code at a SourceLocation. +//===----------------------------------------------------------------------===// + +/// getCharacterData - Return a pointer to the start of the specified location +/// in the appropriate MemoryBuffer. +const char *SourceManager::getCharacterData(SourceLocation SL, + bool *Invalid) const { + // Note that this is a hot function in the getSpelling() path, which is + // heavily used by -E mode. + std::pair<FileID, unsigned> LocInfo = getDecomposedSpellingLoc(SL); + + // Note that calling 'getBuffer()' may lazily page in a source file. + bool CharDataInvalid = false; + const SLocEntry &Entry = getSLocEntry(LocInfo.first, &CharDataInvalid); + if (CharDataInvalid || !Entry.isFile()) { + if (Invalid) + *Invalid = true; + + return "<<<<INVALID BUFFER>>>>"; + } + llvm::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; + 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; + } + + // 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) + return FilePos - LineStart + 1; + } + + const char *Buf = MemBuf->getBufferStart(); + 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. +static bool isInvalid(SourceLocation 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 { + if (isInvalid(Loc, Invalid)) return 0; + return getPresumedLoc(Loc).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. + 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 Offs = 0; + while (1) { + // Skip over the contents of the line. + const unsigned char *NextBuf = (const unsigned char *)Buf; + +#ifdef __SSE2__ + // Try to skip to the next newline using SSE instructions. This is very + // performance sensitive for programs with lots of diagnostics and in -E + // mode. + __m128i CRs = _mm_set1_epi8('\r'); + __m128i LFs = _mm_set1_epi8('\n'); + + // First fix up the alignment to 16 bytes. + while (((uintptr_t)NextBuf & 0xF) != 0) { + if (*NextBuf == '\n' || *NextBuf == '\r' || *NextBuf == '\0') + goto FoundSpecialChar; + ++NextBuf; + } + + // Scan 16 byte chunks for '\r' and '\n'. Ignore '\0'. + while (NextBuf+16 <= End) { + const __m128i Chunk = *(const __m128i*)NextBuf; + __m128i Cmp = _mm_or_si128(_mm_cmpeq_epi8(Chunk, CRs), + _mm_cmpeq_epi8(Chunk, LFs)); + unsigned Mask = _mm_movemask_epi8(Cmp); + + // If we found a newline, adjust the pointer and jump to the handling code. + if (Mask != 0) { + NextBuf += llvm::countTrailingZeros(Mask); + goto FoundSpecialChar; + } + NextBuf += 16; + } +#endif + + while (*NextBuf != '\n' && *NextBuf != '\r' && *NextBuf != '\0') + ++NextBuf; + +#ifdef __SSE2__ +FoundSpecialChar: +#endif + Offs += NextBuf-Buf; + Buf = NextBuf; + + if (Buf[0] == '\n' || Buf[0] == '\r') { + // If this is \n\r or \r\n, skip both characters. + if ((Buf[1] == '\n' || Buf[1] == '\r') && Buf[0] != Buf[1]) + ++Offs, ++Buf; + ++Offs, ++Buf; + LineOffsets.push_back(Offs); + } else { + // Otherwise, this is a null. If end of file, exit. + if (Buf == End) break; + // Otherwise, skip the null. + ++Offs, ++Buf; + } + } + + // 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 { + if (isInvalid(Loc, Invalid)) return 0; + return getPresumedLoc(Loc).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.isInvalid() && "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. +const char *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. + const char *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); + + // 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, LineNo, ColNo, IncludeLoc); +} + +/// \brief 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(); +} + +/// \brief 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. +//===----------------------------------------------------------------------===// + +/// \brief 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; +} + +/// \brief 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); +} + +/// \brief 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.isInvalid()) { + bool Invalid = false; + const SLocEntry &MainSLoc = getSLocEntry(MainFileID, &Invalid); + if (Invalid) + return FileID(); + + if (MainSLoc.isFile()) { + const ContentCache *MainContentCache + = MainSLoc.getFile().getContentCache(); + if (!MainContentCache) { + // 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; +} + +/// \brief 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 != 0 && "Passed a zero-based line"); + + 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); + } + + 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); +} + +/// \brief 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 *&CachePtr, + FileID FID) const { + assert(!FID.isInvalid()); + assert(!CachePtr); + + CachePtr = new MacroArgsMap(); + MacroArgsMap &MacroArgsCache = *CachePtr; + // Initially no macro argument chunk is present. + MacroArgsCache.insert(std::make_pair(0, SourceLocation())); + + int ID = FID.ID; + while (1) { + ++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 (1) { + 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 offet 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; +} + +/// \brief 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; + + MacroArgsMap *&MacroArgsCache = MacroArgsCacheMap[FID]; + if (!MacroArgsCache) + 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. + + typedef std::pair<FileID, unsigned> DecompTy; + typedef llvm::DenseMap<FileID, DecompTy> MapTy; + std::pair<MapTy::iterator, bool> + InsertOp = IncludedLocMap.insert(std::make_pair(FID, DecompTy())); + 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; +} + +/// \brief 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(); + + // If the source locations are in the same file, just compare offsets. + if (LOffs.first == ROffs.first) + return 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 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. + typedef llvm::SmallDenseMap<FileID, unsigned, 16> LocSet; + 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 IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.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. + + // Clear the lookup cache, it depends on a common location. + IsBeforeInTUCache.clear(); + llvm::MemoryBuffer *LBuf = getBuffer(LOffs.first); + llvm::MemoryBuffer *RBuf = getBuffer(ROffs.first); + bool LIsBuiltins = strcmp("<built-in>", LBuf->getBufferIdentifier()) == 0; + bool RIsBuiltins = strcmp("<built-in>", RBuf->getBufferIdentifier()) == 0; + // 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 = strcmp("<inline asm>", LBuf->getBufferIdentifier()) == 0; + bool RIsAsm = strcmp("<inline asm>", RBuf->getBufferIdentifier()) == 0; + // Sort assembler after built-ins, but before the rest. + if (LIsAsm || RIsAsm) { + if (LIsAsm != RIsAsm) + return RIsAsm; + assert(LOffs.first == ROffs.first); + return false; + } + llvm_unreachable("Unsortable locations found"); +} + +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"; +} + +ExternalSLocEntrySource::~ExternalSLocEntrySource() { } + +/// 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; +} diff --git a/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp b/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp new file mode 100644 index 0000000..dbd2f9a --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp @@ -0,0 +1,667 @@ +//===--- TargetInfo.cpp - Information about Target machine ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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/LangOptions.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/ErrorHandling.h" +#include <cstdlib> +using namespace clang; + +static const LangAS::Map 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 = true; + TLSSupported = true; + NoAsmVariants = false; + PointerWidth = PointerAlign = 32; + BoolWidth = BoolAlign = 8; + IntWidth = IntAlign = 32; + LongWidth = LongAlign = 32; + LongLongWidth = LongLongAlign = 64; + SuitableAlign = 64; + DefaultAlignForAttributeAligned = 128; + MinGlobalAlign = 0; + HalfWidth = 16; + HalfAlign = 16; + FloatWidth = 32; + FloatAlign = 32; + DoubleWidth = 64; + DoubleAlign = 64; + LongDoubleWidth = 64; + LongDoubleAlign = 64; + 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; + ZeroLengthBitfieldBoundary = 0; + HalfFormat = &llvm::APFloat::IEEEhalf; + FloatFormat = &llvm::APFloat::IEEEsingle; + DoubleFormat = &llvm::APFloat::IEEEdouble; + LongDoubleFormat = &llvm::APFloat::IEEEdouble; + DescriptionString = nullptr; + UserLabelPrefix = "_"; + MCountName = "mcount"; + RegParmMax = 0; + SSERegParmMax = 0; + HasAlignMac68kSupport = 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() {} + +/// 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 ""; + case UnsignedShort: + if (getShortWidth() < getIntWidth()) + return ""; + 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; + 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. +void TargetInfo::adjust(const LangOptions &Opts) { + if (Opts.NoBitFieldTypeAlign) + UseBitFieldTypeAlignment = false; + if (Opts.ShortWChar) + WCharType = UnsignedShort; + + 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; + + assert(PointerWidth == 32 || PointerWidth == 64); + bool Is32BitArch = PointerWidth == 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; + } +} + +//===----------------------------------------------------------------------===// + + +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; + + const char * const *Names; + unsigned NumNames; + + // Get rid of any register prefix. + Name = removeGCCRegisterPrefix(Name); + if (Name.empty()) + return false; + + getGCCRegNames(Names, NumNames); + + // If we have a number it maps to an entry in the register name array. + if (isDigit(Name[0])) { + int n; + if (!Name.getAsInteger(0, n)) + return n >= 0 && (unsigned)n < NumNames; + } + + // Check register names. + for (unsigned i = 0; i < NumNames; i++) { + if (Name == Names[i]) + return true; + } + + // Check any additional names that we have. + const AddlRegName *AddlNames; + unsigned NumAddlNames; + getGCCAddlRegNames(AddlNames, NumAddlNames); + for (unsigned i = 0; i < NumAddlNames; i++) + for (unsigned j = 0; j < llvm::array_lengthof(AddlNames[i].Names); j++) { + if (!AddlNames[i].Names[j]) + break; + // Make sure the register that the additional name is for is within + // the bounds of the register names from above. + if (AddlNames[i].Names[j] == Name && AddlNames[i].RegNum < NumNames) + return true; + } + + // Now check aliases. + const GCCRegAlias *Aliases; + unsigned NumAliases; + + getGCCRegAliases(Aliases, NumAliases); + for (unsigned i = 0; i < NumAliases; i++) { + for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) { + if (!Aliases[i].Aliases[j]) + break; + if (Aliases[i].Aliases[j] == Name) + return true; + } + } + + return false; +} + +StringRef +TargetInfo::getNormalizedGCCRegisterName(StringRef Name) const { + assert(isValidGCCRegisterName(Name) && "Invalid register passed in"); + + // Get rid of any register prefix. + Name = removeGCCRegisterPrefix(Name); + + const char * const *Names; + unsigned NumNames; + + getGCCRegNames(Names, NumNames); + + // First, check if we have a number. + if (isDigit(Name[0])) { + int n; + if (!Name.getAsInteger(0, n)) { + assert(n >= 0 && (unsigned)n < NumNames && + "Out of bounds register number!"); + return Names[n]; + } + } + + // Check any additional names that we have. + const AddlRegName *AddlNames; + unsigned NumAddlNames; + getGCCAddlRegNames(AddlNames, NumAddlNames); + for (unsigned i = 0; i < NumAddlNames; i++) + for (unsigned j = 0; j < llvm::array_lengthof(AddlNames[i].Names); j++) { + if (!AddlNames[i].Names[j]) + break; + // Make sure the register that the additional name is for is within + // the bounds of the register names from above. + if (AddlNames[i].Names[j] == Name && AddlNames[i].RegNum < NumNames) + return Name; + } + + // Now check aliases. + const GCCRegAlias *Aliases; + unsigned NumAliases; + + getGCCRegAliases(Aliases, NumAliases); + for (unsigned i = 0; i < NumAliases; i++) { + for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) { + if (!Aliases[i].Aliases[j]) + break; + if (Aliases[i].Aliases[j] == Name) + return Aliases[i].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. + 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, + ConstraintInfo *OutputConstraints, + unsigned NumOutputs, + 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 != NumOutputs; ++Index) + if (SymbolicName == OutputConstraints[Index].getName()) + return true; + + return false; +} + +bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints, + unsigned NumOutputs, + 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 >= NumOutputs) 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, NumOutputs, 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. + case 'n': // immediate integer with a known value. + 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; +} + +bool TargetCXXABI::tryParse(llvm::StringRef name) { + const Kind unknown = static_cast<Kind>(-1); + Kind kind = llvm::StringSwitch<Kind>(name) + .Case("arm", GenericARM) + .Case("ios", iOS) + .Case("itanium", GenericItanium) + .Case("microsoft", Microsoft) + .Case("mips", GenericMIPS) + .Default(unknown); + if (kind == unknown) return false; + + set(kind); + return true; +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp new file mode 100644 index 0000000..9e44f7d --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp @@ -0,0 +1,7449 @@ +//===--- Targets.cpp - Implement -arch option and targets -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements construction of a TargetInfo object from a +// target triple. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetParser.h" +#include <algorithm> +#include <memory> +using namespace clang; + +//===----------------------------------------------------------------------===// +// 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. +static 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 + "__"); +} + +static void defineCPUMacros(MacroBuilder &Builder, StringRef CPUName, + bool Tuning = true) { + Builder.defineMacro("__" + CPUName); + Builder.defineMacro("__" + CPUName + "__"); + if (Tuning) + Builder.defineMacro("__tune_" + CPUName + "__"); +} + +//===----------------------------------------------------------------------===// +// Defines specific to certain operating systems. +//===----------------------------------------------------------------------===// + +namespace { +template<typename TgtInfo> +class OSTargetInfo : public TgtInfo { +protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const=0; +public: + OSTargetInfo(const llvm::Triple &Triple) : TgtInfo(Triple) {} + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + TgtInfo::getTargetDefines(Opts, Builder); + getOSDefines(Opts, TgtInfo::getTriple(), Builder); + } + +}; +} // end anonymous namespace + + +static 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("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"); + + if (!Opts.ObjCAutoRefCount) { + // __weak is always defined, for use in blocks and with objc pointers. + Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))"); + + // Darwin defines __strong even in C mode (just to nothing). + if (Opts.getGC() != LangOptions::NonGC) + Builder.defineMacro("__strong", "__attribute__((objc_gc(strong)))"); + else + Builder.defineMacro("__strong", ""); + + // __unsafe_unretained is defined to nothing in non-ARC mode. We even + // allow this in C, since one might have block pointers in structs that + // are used in pure C code and in Objective-C ARC. + 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 = "macosx"; + } 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 < 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_IPHONE_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); +} + +namespace { +// CloudABI Target +template <typename Target> +class 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) + : OSTargetInfo<Target>(Triple) { + this->UserLabelPrefix = ""; + } +}; + +template<typename Target> +class 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) : OSTargetInfo<Target>(Triple) { + this->TLSSupported = Triple.isMacOSX() && !Triple.isMacOSXVersionLT(10, 7); + 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; + } +}; + + +// DragonFlyBSD Target +template<typename Target> +class 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) + : OSTargetInfo<Target>(Triple) { + this->UserLabelPrefix = ""; + + switch (Triple.getArch()) { + default: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + this->MCountName = ".mcount"; + break; + } + } +}; + +// FreeBSD Target +template<typename Target> +class 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 = 8; + + Builder.defineMacro("__FreeBSD__", Twine(Release)); + Builder.defineMacro("__FreeBSD_cc_version", Twine(Release * 100000U + 1U)); + 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) : OSTargetInfo<Target>(Triple) { + this->UserLabelPrefix = ""; + + 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 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) + : OSTargetInfo<Target>(Triple) { + this->UserLabelPrefix = ""; + } +}; + +// Minix Target +template<typename Target> +class 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) : OSTargetInfo<Target>(Triple) { + this->UserLabelPrefix = ""; + } +}; + +// Linux target +template<typename Target> +class 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("__gnu_linux__"); + Builder.defineMacro("__ELF__"); + if (Triple.getEnvironment() == llvm::Triple::Android) { + Builder.defineMacro("__ANDROID__", "1"); + unsigned Maj, Min, Rev; + Triple.getEnvironmentVersion(Maj, Min, Rev); + this->PlatformName = "android"; + this->PlatformMinVersion = VersionTuple(Maj, Min, Rev); + } + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + } +public: + LinuxTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) { + this->UserLabelPrefix = ""; + this->WIntType = TargetInfo::UnsignedInt; + + switch (Triple.getArch()) { + default: + break; + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + this->MCountName = "_mcount"; + break; + } + } + + const char *getStaticInitSectionSpecifier() const override { + return ".text.startup"; + } +}; + +// NetBSD Target +template<typename Target> +class 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("_POSIX_THREADS"); + + switch (Triple.getArch()) { + default: + break; + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + Builder.defineMacro("__ARM_DWARF_EH__"); + break; + } + } +public: + NetBSDTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) { + this->UserLabelPrefix = ""; + this->MCountName = "_mcount"; + } +}; + +// OpenBSD Target +template<typename Target> +class 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"); + } +public: + OpenBSDTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) { + this->UserLabelPrefix = ""; + this->TLSSupported = false; + + switch (Triple.getArch()) { + default: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + case llvm::Triple::arm: + case llvm::Triple::sparc: + this->MCountName = "__mcount"; + break; + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + case llvm::Triple::ppc: + case llvm::Triple::sparcv9: + this->MCountName = "_mcount"; + break; + } + } +}; + +// Bitrig Target +template<typename Target> +class BitrigTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // Bitrig defines; list based off of gcc output + + Builder.defineMacro("__Bitrig__"); + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + + switch (Triple.getArch()) { + default: + break; + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + Builder.defineMacro("__ARM_DWARF_EH__"); + break; + } + } +public: + BitrigTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) { + this->UserLabelPrefix = ""; + this->MCountName = "__mcount"; + } +}; + +// PSP Target +template<typename Target> +class 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) { + this->UserLabelPrefix = ""; + } +}; + +// PS3 PPU Target +template<typename Target> +class 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) : OSTargetInfo<Target>(Triple) { + this->UserLabelPrefix = ""; + this->LongWidth = this->LongAlign = 32; + this->PointerWidth = this->PointerAlign = 32; + this->IntMaxType = TargetInfo::SignedLongLong; + this->Int64Type = TargetInfo::SignedLongLong; + this->SizeType = TargetInfo::UnsignedInt; + this->DescriptionString = "E-m:e-p:32:32-i64:64-n32:64"; + } +}; + +template <typename Target> +class 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("__PS4__"); + } +public: + PS4OSTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) { + this->WCharType = this->UnsignedShort; + + // On PS4, TLS variable cannot be aligned to more than 32 bytes (256 bits). + this->MaxTLSAlign = 256; + this->UserLabelPrefix = ""; + + switch (Triple.getArch()) { + default: + case llvm::Triple::x86_64: + this->MCountName = ".mcount"; + break; + } + } +}; + +// Solaris target +template<typename Target> +class 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("_LARGEFILE_SOURCE"); + Builder.defineMacro("_LARGEFILE64_SOURCE"); + Builder.defineMacro("__EXTENSIONS__"); + Builder.defineMacro("_REENTRANT"); + } +public: + SolarisTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) { + this->UserLabelPrefix = ""; + this->WCharType = this->SignedInt; + // FIXME: WIntType should be SignedLong + } +}; + +// Windows target +template<typename Target> +class WindowsTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + Builder.defineMacro("_WIN32"); + } + void getVisualStudioDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + if (Opts.CPlusPlus) { + if (Opts.RTTIData) + Builder.defineMacro("_CPPRTTI"); + + if (Opts.CXXExceptions) + Builder.defineMacro("_CPPUNWIND"); + } + + 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.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"); + } + +public: + WindowsTargetInfo(const llvm::Triple &Triple) + : OSTargetInfo<Target>(Triple) {} +}; + +template <typename Target> +class 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) : OSTargetInfo<Target>(Triple) { + this->UserLabelPrefix = ""; + 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->DescriptionString = "e-m:e-p:32:32-i64:64-n8:16:32-S128"; + } else if (Triple.getArch() == llvm::Triple::x86_64) { + this->DescriptionString = "e-m:e-p:32:32-i64:64-n8:16:32:64-S128"; + } else if (Triple.getArch() == llvm::Triple::mipsel) { + // Handled on mips' setDescriptionString. + } else { + assert(Triple.getArch() == llvm::Triple::le32); + this->DescriptionString = "e-p:32:32-i64:64"; + } + } +}; + +//===----------------------------------------------------------------------===// +// Specific target implementations. +//===----------------------------------------------------------------------===// + +// PPC abstract base class +class PPCTargetInfo : public TargetInfo { + static const Builtin::Info BuiltinInfo[]; + static const char * const GCCRegNames[]; + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + std::string CPU; + + // Target cpu features. + bool HasVSX; + bool HasP8Vector; + bool HasP8Crypto; + bool HasDirectMove; + bool HasQPX; + bool HasHTM; + bool HasBPERMD; + bool HasExtDiv; + +protected: + std::string ABI; + +public: + PPCTargetInfo(const llvm::Triple &Triple) + : TargetInfo(Triple), HasVSX(false), HasP8Vector(false), + HasP8Crypto(false), HasDirectMove(false), HasQPX(false), HasHTM(false), + HasBPERMD(false), HasExtDiv(false) { + BigEndian = (Triple.getArch() != llvm::Triple::ppc64le); + SimdDefaultAlign = 128; + LongDoubleWidth = LongDoubleAlign = 128; + LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble; + } + + /// \brief 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, + ArchDefineA2 = 1 << 13, + ArchDefineA2q = 1 << 14 + } ArchDefineTypes; + + // 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 setCPU(const std::string &Name) override { + bool CPUKnown = llvm::StringSwitch<bool>(Name) + .Case("generic", true) + .Case("440", true) + .Case("450", true) + .Case("601", true) + .Case("602", true) + .Case("603", true) + .Case("603e", true) + .Case("603ev", true) + .Case("604", true) + .Case("604e", true) + .Case("620", true) + .Case("630", true) + .Case("g3", true) + .Case("7400", true) + .Case("g4", true) + .Case("7450", true) + .Case("g4+", true) + .Case("750", true) + .Case("970", true) + .Case("g5", true) + .Case("a2", true) + .Case("a2q", true) + .Case("e500mc", true) + .Case("e5500", true) + .Case("power3", true) + .Case("pwr3", true) + .Case("power4", true) + .Case("pwr4", true) + .Case("power5", true) + .Case("pwr5", true) + .Case("power5x", true) + .Case("pwr5x", true) + .Case("power6", true) + .Case("pwr6", true) + .Case("power6x", true) + .Case("pwr6x", true) + .Case("power7", true) + .Case("pwr7", true) + .Case("power8", true) + .Case("pwr8", true) + .Case("powerpc", true) + .Case("ppc", true) + .Case("powerpc64", true) + .Case("ppc64", true) + .Case("powerpc64le", true) + .Case("ppc64le", true) + .Default(false); + + if (CPUKnown) + CPU = Name; + + return CPUKnown; + } + + + StringRef getABI() const override { return ABI; } + + void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const override { + Records = BuiltinInfo; + NumRecords = clang::PPC::LastTSBuiltin-Builtin::FirstTSBuiltin; + } + + bool isCLZForZeroUndef() const override { return false; } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + void getDefaultFeatures(llvm::StringMap<bool> &Features) 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; + + void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const override; + void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const override; + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + switch (*Name) { + default: return false; + case 'O': // Zero + break; + case 'b': // Base register + case 'f': // Floating point 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 + 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 float data + case 'a':// Any VSX register + case 'c':// An individual CR bit + 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; + } + + bool useFloat128ManglingForLongDouble() const override { + return LongDoubleWidth == 128 && + LongDoubleFormat == &llvm::APFloat::PPCDoubleDouble && + getTriple().isOSBinFormatELF(); + } +}; + +const Builtin::Info PPCTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\ + ALL_LANGUAGES }, +#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) { + for (unsigned i = 0, e = Features.size(); i !=e; ++i) { + // Ignore disabled features. + if (Features[i][0] == '-') + continue; + + StringRef Feature = StringRef(Features[i]).substr(1); + + if (Feature == "vsx") { + HasVSX = true; + continue; + } + + if (Feature == "bpermd") { + HasBPERMD = true; + continue; + } + + if (Feature == "extdiv") { + HasExtDiv = true; + continue; + } + + if (Feature == "power8-vector") { + HasP8Vector = true; + continue; + } + + if (Feature == "crypto") { + HasP8Crypto = true; + continue; + } + + if (Feature == "direct-move") { + HasDirectMove = true; + continue; + } + + if (Feature == "qpx") { + HasQPX = true; + continue; + } + + if (Feature == "htm") { + HasHTM = true; + continue; + } + + // TODO: Finish this list and add an assert that we've handled them + // all. + } + if (!HasVSX && (HasP8Vector || HasDirectMove)) { + if (HasP8Vector) + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mpower8-vector" << + "-mno-vsx"; + else if (HasDirectMove) + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mdirect-move" << + "-mno-vsx"; + return false; + } + + 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().getOS() != llvm::Triple::NetBSD && + getTriple().getOS() != llvm::Triple::OpenBSD) + 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"); + + // Subtarget options. + Builder.defineMacro("__NATURAL_ALIGNMENT__"); + Builder.defineMacro("__REGISTER_PREFIX__", ""); + + // FIXME: Should be controlled by command line option. + if (LongDoubleWidth == 128) + Builder.defineMacro("__LONG_DOUBLE_128__"); + + if (Opts.AltiVec) { + Builder.defineMacro("__VEC__", "10206"); + Builder.defineMacro("__ALTIVEC__"); + } + + // CPU identification. + ArchDefineTypes defs = (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) + .Case("pwr3", ArchDefinePpcgr) + .Case("pwr4", ArchDefineName | ArchDefinePpcgr | ArchDefinePpcsq) + .Case("pwr5", ArchDefineName | ArchDefinePwr4 | ArchDefinePpcgr + | ArchDefinePpcsq) + .Case("pwr5x", ArchDefineName | ArchDefinePwr5 | ArchDefinePwr4 + | ArchDefinePpcgr | ArchDefinePpcsq) + .Case("pwr6", ArchDefineName | ArchDefinePwr5x | ArchDefinePwr5 + | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) + .Case("pwr6x", ArchDefineName | ArchDefinePwr6 | ArchDefinePwr5x + | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr + | ArchDefinePpcsq) + .Case("pwr7", ArchDefineName | ArchDefinePwr6x | ArchDefinePwr6 + | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 + | ArchDefinePpcgr | ArchDefinePpcsq) + .Case("pwr8", ArchDefineName | ArchDefinePwr7 | ArchDefinePwr6x + | ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 + | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) + .Case("power3", ArchDefinePpcgr) + .Case("power4", ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) + .Case("power5", ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr + | ArchDefinePpcsq) + .Case("power5x", ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 + | ArchDefinePpcgr | ArchDefinePpcsq) + .Case("power6", ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 + | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) + .Case("power6x", ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x + | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr + | ArchDefinePpcsq) + .Case("power7", ArchDefinePwr7 | ArchDefinePwr6x | ArchDefinePwr6 + | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 + | ArchDefinePpcgr | ArchDefinePpcsq) + .Case("power8", ArchDefinePwr8 | ArchDefinePwr7 | ArchDefinePwr6x + | ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 + | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) + .Default(ArchDefineNone); + + if (defs & ArchDefineName) + Builder.defineMacro(Twine("_ARCH_", StringRef(CPU).upper())); + if (defs & ArchDefinePpcgr) + Builder.defineMacro("_ARCH_PPCGR"); + if (defs & ArchDefinePpcsq) + Builder.defineMacro("_ARCH_PPCSQ"); + if (defs & ArchDefine440) + Builder.defineMacro("_ARCH_440"); + if (defs & ArchDefine603) + Builder.defineMacro("_ARCH_603"); + if (defs & ArchDefine604) + Builder.defineMacro("_ARCH_604"); + if (defs & ArchDefinePwr4) + Builder.defineMacro("_ARCH_PWR4"); + if (defs & ArchDefinePwr5) + Builder.defineMacro("_ARCH_PWR5"); + if (defs & ArchDefinePwr5x) + Builder.defineMacro("_ARCH_PWR5X"); + if (defs & ArchDefinePwr6) + Builder.defineMacro("_ARCH_PWR6"); + if (defs & ArchDefinePwr6x) + Builder.defineMacro("_ARCH_PWR6X"); + if (defs & ArchDefinePwr7) + Builder.defineMacro("_ARCH_PWR7"); + if (defs & ArchDefinePwr8) + Builder.defineMacro("_ARCH_PWR8"); + if (defs & ArchDefineA2) + Builder.defineMacro("_ARCH_A2"); + if (defs & 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 (HasVSX) + Builder.defineMacro("__VSX__"); + if (HasP8Vector) + Builder.defineMacro("__POWER8_VECTOR__"); + if (HasP8Crypto) + Builder.defineMacro("__CRYPTO__"); + if (HasHTM) + Builder.defineMacro("__HTM__"); + if (getTriple().getArch() == llvm::Triple::ppc64le || + (defs & ArchDefinePwr8) || (CPU == "pwr8")) { + 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"); + } + + // 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__ + // __HAVE_BSWAP__ + // __LONGDOUBLE128 + // __CMODEL_MEDIUM__ + // __CMODEL_LARGE__ + // _CALL_SYSV + // _CALL_DARWIN + // __NO_FPRS__ +} + +void PPCTargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) 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("ppc64", true) + .Case("ppc64le", true) + .Default(false); + + Features["qpx"] = (CPU == "a2q"); + Features["crypto"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr8", true) + .Default(false); + Features["power8-vector"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr8", true) + .Default(false); + Features["bpermd"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr8", true) + .Case("pwr7", true) + .Default(false); + Features["extdiv"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr8", true) + .Case("pwr7", true) + .Default(false); + Features["direct-move"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr8", true) + .Default(false); + Features["vsx"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr8", true) + .Case("pwr7", true) + .Default(false); +} + +bool PPCTargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature) + .Case("powerpc", true) + .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) + .Default(false); +} + +/* There is no clear way for the target to know which of the features in the + final feature vector came from defaults and which are actually specified by + the user. To that end, we use the fact that this function is not called on + default features - only user specified ones. By the first time this + function is called, the default features are populated. + We then keep track of the features that the user specified so that we + can ensure we do not override a user's request (only defaults). + For example: + -mcpu=pwr8 -mno-vsx (should disable vsx and everything that depends on it) + -mcpu=pwr8 -mdirect-move -mno-vsx (should actually be diagnosed) + +NOTE: Do not call this from PPCTargetInfo::getDefaultFeatures +*/ +void PPCTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, + StringRef Name, bool Enabled) const { + static llvm::StringMap<bool> ExplicitFeatures; + ExplicitFeatures[Name] = Enabled; + + // At this point, -mno-vsx turns off the dependent features but we respect + // the user's requests. + if (!Enabled && Name == "vsx") { + Features["direct-move"] = ExplicitFeatures["direct-move"]; + Features["power8-vector"] = ExplicitFeatures["power8-vector"]; + } + if ((Enabled && Name == "power8-vector") || + (Enabled && Name == "direct-move")) { + if (ExplicitFeatures.find("vsx") == ExplicitFeatures.end()) { + Features["vsx"] = true; + } + } + Features[Name] = Enabled; +} + +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" +}; + +void PPCTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(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" }, +}; + +void PPCTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + Aliases = GCCRegAliases; + NumAliases = llvm::array_lengthof(GCCRegAliases); +} + +class PPC32TargetInfo : public PPCTargetInfo { +public: + PPC32TargetInfo(const llvm::Triple &Triple) : PPCTargetInfo(Triple) { + DescriptionString = "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; + default: + break; + } + + if (getTriple().getOS() == llvm::Triple::FreeBSD) { + 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 PPC64TargetInfo : public PPCTargetInfo { +public: + PPC64TargetInfo(const llvm::Triple &Triple) : PPCTargetInfo(Triple) { + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + IntMaxType = SignedLong; + Int64Type = SignedLong; + + if ((Triple.getArch() == llvm::Triple::ppc64le)) { + DescriptionString = "e-m:e-i64:64-n32:64"; + ABI = "elfv2"; + } else { + DescriptionString = "E-m:e-i64:64-n32:64"; + ABI = "elfv1"; + } + + switch (getTriple().getOS()) { + case llvm::Triple::FreeBSD: + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble; + break; + case llvm::Triple::NetBSD: + IntMaxType = SignedLongLong; + Int64Type = SignedLongLong; + break; + default: + break; + } + + // 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; + } +}; + +class DarwinPPC32TargetInfo : + public DarwinTargetInfo<PPC32TargetInfo> { +public: + DarwinPPC32TargetInfo(const llvm::Triple &Triple) + : DarwinTargetInfo<PPC32TargetInfo>(Triple) { + HasAlignMac68kSupport = true; + BoolWidth = BoolAlign = 32; //XXX support -mone-byte-bool? + PtrDiffType = SignedInt; // for http://llvm.org/bugs/show_bug.cgi?id=15726 + LongLongAlign = 32; + SuitableAlign = 128; + DescriptionString = "E-m:o-p:32:32-f64:32:64-n32"; + } + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::CharPtrBuiltinVaList; + } +}; + +class DarwinPPC64TargetInfo : + public DarwinTargetInfo<PPC64TargetInfo> { +public: + DarwinPPC64TargetInfo(const llvm::Triple &Triple) + : DarwinTargetInfo<PPC64TargetInfo>(Triple) { + HasAlignMac68kSupport = true; + SuitableAlign = 128; + DescriptionString = "E-m:o-i64:64-n32:64"; + } +}; + + static const unsigned NVPTXAddrSpaceMap[] = { + 1, // opencl_global + 3, // opencl_local + 4, // opencl_constant + // FIXME: generic has to be added to the target + 0, // opencl_generic + 1, // cuda_device + 4, // cuda_constant + 3, // cuda_shared + }; + class NVPTXTargetInfo : public TargetInfo { + static const char * const GCCRegNames[]; + static const Builtin::Info BuiltinInfo[]; + + // The GPU profiles supported by the NVPTX backend + enum GPUKind { + GK_NONE, + GK_SM20, + GK_SM21, + GK_SM30, + GK_SM35, + GK_SM37, + } GPU; + + public: + NVPTXTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { + BigEndian = false; + TLSSupported = false; + LongWidth = LongAlign = 64; + AddrSpaceMap = &NVPTXAddrSpaceMap; + UseAddrSpaceMapMangling = true; + // Define available target features + // These must be defined in sorted order! + NoAsmVariants = true; + // Set the default GPU to sm20 + GPU = GK_SM20; + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + Builder.defineMacro("__PTX__"); + Builder.defineMacro("__NVPTX__"); + if (Opts.CUDAIsDevice) { + // Set __CUDA_ARCH__ for the GPU specified. + std::string CUDAArchCode; + switch (GPU) { + case GK_SM20: + CUDAArchCode = "200"; + break; + case GK_SM21: + CUDAArchCode = "210"; + break; + case GK_SM30: + CUDAArchCode = "300"; + break; + case GK_SM35: + CUDAArchCode = "350"; + break; + case GK_SM37: + CUDAArchCode = "370"; + break; + default: + llvm_unreachable("Unhandled target CPU"); + } + Builder.defineMacro("__CUDA_ARCH__", CUDAArchCode); + } + } + void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const override { + Records = BuiltinInfo; + NumRecords = clang::NVPTX::LastTSBuiltin-Builtin::FirstTSBuiltin; + } + bool hasFeature(StringRef Feature) const override { + return Feature == "ptx" || Feature == "nvptx"; + } + + void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const override; + void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const override { + // No aliases. + Aliases = nullptr; + NumAliases = 0; + } + 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 setCPU(const std::string &Name) override { + GPU = llvm::StringSwitch<GPUKind>(Name) + .Case("sm_20", GK_SM20) + .Case("sm_21", GK_SM21) + .Case("sm_30", GK_SM30) + .Case("sm_35", GK_SM35) + .Case("sm_37", GK_SM37) + .Default(GK_NONE); + + return GPU != GK_NONE; + } + }; + + const Builtin::Info NVPTXTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\ + ALL_LANGUAGES }, +#include "clang/Basic/BuiltinsNVPTX.def" + }; + + const char * const NVPTXTargetInfo::GCCRegNames[] = { + "r0" + }; + + void NVPTXTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); + } + + class NVPTX32TargetInfo : public NVPTXTargetInfo { + public: + NVPTX32TargetInfo(const llvm::Triple &Triple) : NVPTXTargetInfo(Triple) { + PointerWidth = PointerAlign = 32; + SizeType = TargetInfo::UnsignedInt; + PtrDiffType = TargetInfo::SignedInt; + IntPtrType = TargetInfo::SignedInt; + DescriptionString = "e-p:32:32-i64:64-v16:16-v32:32-n16:32:64"; + } + }; + + class NVPTX64TargetInfo : public NVPTXTargetInfo { + public: + NVPTX64TargetInfo(const llvm::Triple &Triple) : NVPTXTargetInfo(Triple) { + PointerWidth = PointerAlign = 64; + SizeType = TargetInfo::UnsignedLong; + PtrDiffType = TargetInfo::SignedLong; + IntPtrType = TargetInfo::SignedLong; + DescriptionString = "e-i64:64-v16:16-v32:32-n16:32:64"; + } + }; + +static const unsigned AMDGPUAddrSpaceMap[] = { + 1, // opencl_global + 3, // opencl_local + 2, // opencl_constant + 4, // opencl_generic + 1, // cuda_device + 2, // cuda_constant + 3 // cuda_shared +}; + +// If you edit the description strings, make sure you update +// getPointerWidthV(). + +static const char *DescriptionStringR600 = + "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"; + +static const char *DescriptionStringR600DoubleOps = + "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"; + +static const char *DescriptionStringSI = + "e-p:32:32-p1:64:64-p2:64:64-p3:32:32-p4:64:64-p5:32:32-p24:64:64" + "-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128" + "-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64"; + +class AMDGPUTargetInfo : public TargetInfo { + static const Builtin::Info BuiltinInfo[]; + static const char * const GCCRegNames[]; + + /// \brief The GPU profiles supported by the AMDGPU target. + enum GPUKind { + GK_NONE, + GK_R600, + GK_R600_DOUBLE_OPS, + GK_R700, + GK_R700_DOUBLE_OPS, + GK_EVERGREEN, + GK_EVERGREEN_DOUBLE_OPS, + GK_NORTHERN_ISLANDS, + GK_CAYMAN, + GK_SOUTHERN_ISLANDS, + GK_SEA_ISLANDS, + GK_VOLCANIC_ISLANDS + } GPU; + + bool hasFP64:1; + bool hasFMAF:1; + bool hasLDEXPF:1; + +public: + AMDGPUTargetInfo(const llvm::Triple &Triple) + : TargetInfo(Triple) { + + if (Triple.getArch() == llvm::Triple::amdgcn) { + DescriptionString = DescriptionStringSI; + GPU = GK_SOUTHERN_ISLANDS; + hasFP64 = true; + hasFMAF = true; + hasLDEXPF = true; + } else { + DescriptionString = DescriptionStringR600; + GPU = GK_R600; + hasFP64 = false; + hasFMAF = false; + hasLDEXPF = false; + } + AddrSpaceMap = &AMDGPUAddrSpaceMap; + UseAddrSpaceMapMangling = true; + } + + uint64_t getPointerWidthV(unsigned AddrSpace) const override { + if (GPU <= GK_CAYMAN) + return 32; + + switch(AddrSpace) { + default: + return 64; + case 0: + case 3: + case 5: + return 32; + } + } + + const char * getClobbers() const override { + return ""; + } + + void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const override; + + void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const override { + Aliases = nullptr; + NumAliases = 0; + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override { + return true; + } + + void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const override { + Records = BuiltinInfo; + NumRecords = clang::AMDGPU::LastTSBuiltin - Builtin::FirstTSBuiltin; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + Builder.defineMacro("__R600__"); + if (hasFMAF) + Builder.defineMacro("__HAS_FMAF__"); + if (hasLDEXPF) + Builder.defineMacro("__HAS_LDEXPF__"); + if (hasFP64 && Opts.OpenCL) { + Builder.defineMacro("cl_khr_fp64"); + } + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::CharPtrBuiltinVaList; + } + + bool setCPU(const std::string &Name) override { + GPU = llvm::StringSwitch<GPUKind>(Name) + .Case("r600" , GK_R600) + .Case("rv610", GK_R600) + .Case("rv620", GK_R600) + .Case("rv630", GK_R600) + .Case("rv635", GK_R600) + .Case("rs780", GK_R600) + .Case("rs880", GK_R600) + .Case("rv670", GK_R600_DOUBLE_OPS) + .Case("rv710", GK_R700) + .Case("rv730", GK_R700) + .Case("rv740", GK_R700_DOUBLE_OPS) + .Case("rv770", GK_R700_DOUBLE_OPS) + .Case("palm", GK_EVERGREEN) + .Case("cedar", GK_EVERGREEN) + .Case("sumo", GK_EVERGREEN) + .Case("sumo2", GK_EVERGREEN) + .Case("redwood", GK_EVERGREEN) + .Case("juniper", GK_EVERGREEN) + .Case("hemlock", GK_EVERGREEN_DOUBLE_OPS) + .Case("cypress", GK_EVERGREEN_DOUBLE_OPS) + .Case("barts", GK_NORTHERN_ISLANDS) + .Case("turks", GK_NORTHERN_ISLANDS) + .Case("caicos", GK_NORTHERN_ISLANDS) + .Case("cayman", GK_CAYMAN) + .Case("aruba", GK_CAYMAN) + .Case("tahiti", GK_SOUTHERN_ISLANDS) + .Case("pitcairn", GK_SOUTHERN_ISLANDS) + .Case("verde", GK_SOUTHERN_ISLANDS) + .Case("oland", GK_SOUTHERN_ISLANDS) + .Case("hainan", GK_SOUTHERN_ISLANDS) + .Case("bonaire", GK_SEA_ISLANDS) + .Case("kabini", GK_SEA_ISLANDS) + .Case("kaveri", GK_SEA_ISLANDS) + .Case("hawaii", GK_SEA_ISLANDS) + .Case("mullins", GK_SEA_ISLANDS) + .Case("tonga", GK_VOLCANIC_ISLANDS) + .Case("iceland", GK_VOLCANIC_ISLANDS) + .Case("carrizo", GK_VOLCANIC_ISLANDS) + .Default(GK_NONE); + + if (GPU == GK_NONE) { + return false; + } + + // Set the correct data layout + switch (GPU) { + case GK_NONE: + case GK_R600: + case GK_R700: + case GK_EVERGREEN: + case GK_NORTHERN_ISLANDS: + DescriptionString = DescriptionStringR600; + hasFP64 = false; + hasFMAF = false; + hasLDEXPF = false; + break; + case GK_R600_DOUBLE_OPS: + case GK_R700_DOUBLE_OPS: + case GK_EVERGREEN_DOUBLE_OPS: + case GK_CAYMAN: + DescriptionString = DescriptionStringR600DoubleOps; + hasFP64 = true; + hasFMAF = true; + hasLDEXPF = false; + break; + case GK_SOUTHERN_ISLANDS: + case GK_SEA_ISLANDS: + case GK_VOLCANIC_ISLANDS: + DescriptionString = DescriptionStringSI; + hasFP64 = true; + hasFMAF = true; + hasLDEXPF = true; + break; + } + + return true; + } +}; + +const Builtin::Info AMDGPUTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, +#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_scr", "exec_lo", "exec_hi", + "vcc_lo", "vcc_hi", "flat_scr_lo", "flat_scr_hi" +}; + +void AMDGPUTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); +} + +// Namespace for x86 abstract base class +const Builtin::Info BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\ + ALL_LANGUAGES }, +#include "clang/Basic/BuiltinsX86.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", +}; + +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 }, +}; + +// X86 target abstract base class; x86-32 and x86-64 are very close, so +// most of the implementation can be shared. +class X86TargetInfo : public TargetInfo { + enum X86SSEEnum { + NoSSE, SSE1, SSE2, SSE3, SSSE3, SSE41, SSE42, AVX, AVX2, AVX512F + } SSELevel; + enum MMX3DNowEnum { + NoMMX3DNow, MMX, AMD3DNow, AMD3DNowAthlon + } MMX3DNowLevel; + enum XOPEnum { + NoXOP, + SSE4A, + FMA4, + XOP + } XOPLevel; + + bool HasAES; + bool HasPCLMUL; + bool HasLZCNT; + bool HasRDRND; + bool HasFSGSBASE; + bool HasBMI; + bool HasBMI2; + bool HasPOPCNT; + bool HasRTM; + bool HasPRFCHW; + bool HasRDSEED; + bool HasADX; + bool HasTBM; + bool HasFMA; + bool HasF16C; + bool HasAVX512CD, HasAVX512ER, HasAVX512PF, HasAVX512DQ, HasAVX512BW, + HasAVX512VL; + bool HasSHA; + bool HasCX16; + + /// \brief 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, + + /// \name i386 + /// i386-generation processors. + //@{ + CK_i386, + //@} + + /// \name i486 + /// i486-generation processors. + //@{ + CK_i486, + CK_WinChipC6, + CK_WinChip2, + CK_C3, + //@} + + /// \name i586 + /// i586-generation processors, P5 microarchitecture based. + //@{ + CK_i586, + CK_Pentium, + CK_PentiumMMX, + //@} + + /// \name i686 + /// i686-generation processors, P6 / Pentium M microarchitecture based. + //@{ + CK_i686, + CK_PentiumPro, + CK_Pentium2, + CK_Pentium3, + CK_Pentium3M, + CK_PentiumM, + CK_C3_2, + + /// This enumerator is a bit odd, as GCC no longer accepts -march=yonah. + /// Clang however has some logic to suport this. + // FIXME: Warn, deprecate, and potentially remove this. + CK_Yonah, + //@} + + /// \name Netburst + /// Netburst microarchitecture based processors. + //@{ + CK_Pentium4, + CK_Pentium4M, + CK_Prescott, + CK_Nocona, + //@} + + /// \name Core + /// Core microarchitecture based processors. + //@{ + CK_Core2, + + /// This enumerator, like \see CK_Yonah, is a bit odd. It is another + /// codename which GCC no longer accepts as an option to -march, but Clang + /// has some logic for recognizing it. + // FIXME: Warn, deprecate, and potentially remove this. + CK_Penryn, + //@} + + /// \name Atom + /// Atom processors + //@{ + CK_Bonnell, + CK_Silvermont, + //@} + + /// \name Nehalem + /// Nehalem microarchitecture based processors. + CK_Nehalem, + + /// \name Westmere + /// Westmere microarchitecture based processors. + CK_Westmere, + + /// \name Sandy Bridge + /// Sandy Bridge microarchitecture based processors. + CK_SandyBridge, + + /// \name Ivy Bridge + /// Ivy Bridge microarchitecture based processors. + CK_IvyBridge, + + /// \name Haswell + /// Haswell microarchitecture based processors. + CK_Haswell, + + /// \name Broadwell + /// Broadwell microarchitecture based processors. + CK_Broadwell, + + /// \name Skylake + /// Skylake microarchitecture based processors. + CK_Skylake, + + /// \name Knights Landing + /// Knights Landing processor. + CK_KNL, + + /// \name K6 + /// K6 architecture processors. + //@{ + CK_K6, + CK_K6_2, + CK_K6_3, + //@} + + /// \name K7 + /// K7 architecture processors. + //@{ + CK_Athlon, + CK_AthlonThunderbird, + CK_Athlon4, + CK_AthlonXP, + CK_AthlonMP, + //@} + + /// \name K8 + /// K8 architecture processors. + //@{ + CK_Athlon64, + CK_Athlon64SSE3, + CK_AthlonFX, + CK_K8, + CK_K8SSE3, + CK_Opteron, + CK_OpteronSSE3, + CK_AMDFAM10, + //@} + + /// \name Bobcat + /// Bobcat architecture processors. + //@{ + CK_BTVER1, + CK_BTVER2, + //@} + + /// \name Bulldozer + /// Bulldozer architecture processors. + //@{ + CK_BDVER1, + CK_BDVER2, + CK_BDVER3, + CK_BDVER4, + //@} + + /// This specification is deprecated and will be removed in the future. + /// Users should prefer \see CK_K8. + // FIXME: Warn on this when the CPU is set to it. + //@{ + CK_x86_64, + //@} + + /// \name Geode + /// Geode processors. + //@{ + CK_Geode + //@} + } CPU; + + enum FPMathKind { + FP_Default, + FP_SSE, + FP_387 + } FPMath; + +public: + X86TargetInfo(const llvm::Triple &Triple) + : TargetInfo(Triple), SSELevel(NoSSE), MMX3DNowLevel(NoMMX3DNow), + XOPLevel(NoXOP), HasAES(false), HasPCLMUL(false), HasLZCNT(false), + HasRDRND(false), HasFSGSBASE(false), HasBMI(false), HasBMI2(false), + HasPOPCNT(false), HasRTM(false), HasPRFCHW(false), HasRDSEED(false), + HasADX(false), HasTBM(false), HasFMA(false), HasF16C(false), + HasAVX512CD(false), HasAVX512ER(false), HasAVX512PF(false), + HasAVX512DQ(false), HasAVX512BW(false), HasAVX512VL(false), + HasSHA(false), HasCX16(false), CPU(CK_Generic), FPMath(FP_Default) { + BigEndian = false; + LongDoubleFormat = &llvm::APFloat::x87DoubleExtended; + } + unsigned getFloatEvalMethod() const override { + // X87 evaluates with 80 bits "long double" precision. + return SSELevel == NoSSE ? 2 : 0; + } + void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const override { + Records = BuiltinInfo; + NumRecords = clang::X86::LastTSBuiltin-Builtin::FirstTSBuiltin; + } + void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const override { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); + } + void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const override { + Aliases = nullptr; + NumAliases = 0; + } + void getGCCAddlRegNames(const AddlRegName *&Names, + unsigned &NumNames) const override { + Names = AddlRegNames; + NumNames = llvm::array_lengthof(AddlRegNames); + } + bool validateCpuSupports(StringRef Name) const override; + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override; + + bool validateOutputSize(StringRef Constraint, unsigned Size) const override; + + bool validateInputSize(StringRef Constraint, unsigned Size) const override; + + 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}"; + } + 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 + // getDefaultFeatures which calls this repeatedly. + static void setFeatureEnabledImpl(llvm::StringMap<bool> &Features, + StringRef Name, bool Enabled); + void getDefaultFeatures(llvm::StringMap<bool> &Features) 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"; + else if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX) + return "avx"; + else if (getTriple().getArch() == llvm::Triple::x86 && + MMX3DNowLevel == NoMMX3DNow) + return "no-mmx"; + return ""; + } + bool setCPU(const std::string &Name) override { + CPU = llvm::StringSwitch<CPUKind>(Name) + .Case("i386", CK_i386) + .Case("i486", CK_i486) + .Case("winchip-c6", CK_WinChipC6) + .Case("winchip2", CK_WinChip2) + .Case("c3", CK_C3) + .Case("i586", CK_i586) + .Case("pentium", CK_Pentium) + .Case("pentium-mmx", CK_PentiumMMX) + .Case("i686", CK_i686) + .Case("pentiumpro", CK_PentiumPro) + .Case("pentium2", CK_Pentium2) + .Case("pentium3", CK_Pentium3) + .Case("pentium3m", CK_Pentium3M) + .Case("pentium-m", CK_PentiumM) + .Case("c3-2", CK_C3_2) + .Case("yonah", CK_Yonah) + .Case("pentium4", CK_Pentium4) + .Case("pentium4m", CK_Pentium4M) + .Case("prescott", CK_Prescott) + .Case("nocona", CK_Nocona) + .Case("core2", CK_Core2) + .Case("penryn", CK_Penryn) + .Case("bonnell", CK_Bonnell) + .Case("atom", CK_Bonnell) // Legacy name. + .Case("silvermont", CK_Silvermont) + .Case("slm", CK_Silvermont) // Legacy name. + .Case("nehalem", CK_Nehalem) + .Case("corei7", CK_Nehalem) // Legacy name. + .Case("westmere", CK_Westmere) + .Case("sandybridge", CK_SandyBridge) + .Case("corei7-avx", CK_SandyBridge) // Legacy name. + .Case("ivybridge", CK_IvyBridge) + .Case("core-avx-i", CK_IvyBridge) // Legacy name. + .Case("haswell", CK_Haswell) + .Case("core-avx2", CK_Haswell) // Legacy name. + .Case("broadwell", CK_Broadwell) + .Case("skylake", CK_Skylake) + .Case("skx", CK_Skylake) // Legacy name. + .Case("knl", CK_KNL) + .Case("k6", CK_K6) + .Case("k6-2", CK_K6_2) + .Case("k6-3", CK_K6_3) + .Case("athlon", CK_Athlon) + .Case("athlon-tbird", CK_AthlonThunderbird) + .Case("athlon-4", CK_Athlon4) + .Case("athlon-xp", CK_AthlonXP) + .Case("athlon-mp", CK_AthlonMP) + .Case("athlon64", CK_Athlon64) + .Case("athlon64-sse3", CK_Athlon64SSE3) + .Case("athlon-fx", CK_AthlonFX) + .Case("k8", CK_K8) + .Case("k8-sse3", CK_K8SSE3) + .Case("opteron", CK_Opteron) + .Case("opteron-sse3", CK_OpteronSSE3) + .Case("barcelona", CK_AMDFAM10) + .Case("amdfam10", CK_AMDFAM10) + .Case("btver1", CK_BTVER1) + .Case("btver2", CK_BTVER2) + .Case("bdver1", CK_BDVER1) + .Case("bdver2", CK_BDVER2) + .Case("bdver3", CK_BDVER3) + .Case("bdver4", CK_BDVER4) + .Case("x86-64", CK_x86_64) + .Case("geode", CK_Geode) + .Default(CK_Generic); + + // Perform any per-CPU checks necessary to determine if this CPU is + // acceptable. + // FIXME: This results in terrible diagnostics. Clang just says the CPU is + // invalid without explaining *why*. + switch (CPU) { + case CK_Generic: + // No processor selected! + return false; + + case CK_i386: + case CK_i486: + case CK_WinChipC6: + case CK_WinChip2: + case CK_C3: + case CK_i586: + case CK_Pentium: + case CK_PentiumMMX: + case CK_i686: + case CK_PentiumPro: + case CK_Pentium2: + case CK_Pentium3: + case CK_Pentium3M: + case CK_PentiumM: + case CK_Yonah: + case CK_C3_2: + case CK_Pentium4: + case CK_Pentium4M: + case CK_Prescott: + case CK_K6: + case CK_K6_2: + case CK_K6_3: + case CK_Athlon: + case CK_AthlonThunderbird: + case CK_Athlon4: + case CK_AthlonXP: + case CK_AthlonMP: + case CK_Geode: + // Only accept certain architectures when compiling in 32-bit mode. + if (getTriple().getArch() != llvm::Triple::x86) + return false; + + // Fallthrough + case CK_Nocona: + case CK_Core2: + case CK_Penryn: + case CK_Bonnell: + case CK_Silvermont: + case CK_Nehalem: + case CK_Westmere: + case CK_SandyBridge: + case CK_IvyBridge: + case CK_Haswell: + case CK_Broadwell: + case CK_Skylake: + case CK_KNL: + case CK_Athlon64: + case CK_Athlon64SSE3: + case CK_AthlonFX: + case CK_K8: + case CK_K8SSE3: + case CK_Opteron: + case CK_OpteronSSE3: + case CK_AMDFAM10: + case CK_BTVER1: + case CK_BTVER2: + case CK_BDVER1: + case CK_BDVER2: + case CK_BDVER3: + case CK_BDVER4: + case CK_x86_64: + return true; + } + llvm_unreachable("Unhandled CPU kind"); + } + + bool setFPMath(StringRef Name) override; + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + // We accept all non-ARM calling conventions + return (CC == CC_X86ThisCall || + CC == CC_X86FastCall || + CC == CC_X86StdCall || + CC == CC_X86VectorCall || + CC == CC_C || + CC == CC_X86Pascal || + CC == CC_IntelOclBicc) ? CCCR_OK : CCCR_Warning; + } + + CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override { + return MT == CCMT_Member ? CC_X86ThisCall : CC_C; + } + + bool hasSjLjLowering() const override { + return true; + } +}; + +bool X86TargetInfo::setFPMath(StringRef Name) { + if (Name == "387") { + FPMath = FP_387; + return true; + } + if (Name == "sse") { + FPMath = FP_SSE; + return true; + } + return false; +} + +void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { + // FIXME: This *really* should not be here. + + // X86_64 always has SSE2. + if (getTriple().getArch() == llvm::Triple::x86_64) + setFeatureEnabledImpl(Features, "sse2", true); + + switch (CPU) { + case CK_Generic: + case CK_i386: + case CK_i486: + case CK_i586: + case CK_Pentium: + case CK_i686: + case CK_PentiumPro: + break; + case CK_PentiumMMX: + case CK_Pentium2: + case CK_K6: + case CK_WinChipC6: + setFeatureEnabledImpl(Features, "mmx", true); + break; + case CK_Pentium3: + case CK_Pentium3M: + case CK_C3_2: + setFeatureEnabledImpl(Features, "sse", true); + break; + case CK_PentiumM: + case CK_Pentium4: + case CK_Pentium4M: + case CK_x86_64: + setFeatureEnabledImpl(Features, "sse2", true); + break; + case CK_Yonah: + case CK_Prescott: + case CK_Nocona: + setFeatureEnabledImpl(Features, "sse3", true); + setFeatureEnabledImpl(Features, "cx16", true); + break; + case CK_Core2: + case CK_Bonnell: + setFeatureEnabledImpl(Features, "ssse3", true); + setFeatureEnabledImpl(Features, "cx16", true); + break; + case CK_Penryn: + setFeatureEnabledImpl(Features, "sse4.1", true); + setFeatureEnabledImpl(Features, "cx16", true); + break; + case CK_Skylake: + setFeatureEnabledImpl(Features, "avx512f", true); + setFeatureEnabledImpl(Features, "avx512cd", true); + setFeatureEnabledImpl(Features, "avx512dq", true); + setFeatureEnabledImpl(Features, "avx512bw", true); + setFeatureEnabledImpl(Features, "avx512vl", true); + // FALLTHROUGH + case CK_Broadwell: + setFeatureEnabledImpl(Features, "rdseed", true); + setFeatureEnabledImpl(Features, "adx", true); + // FALLTHROUGH + case CK_Haswell: + setFeatureEnabledImpl(Features, "avx2", true); + setFeatureEnabledImpl(Features, "lzcnt", true); + setFeatureEnabledImpl(Features, "bmi", true); + setFeatureEnabledImpl(Features, "bmi2", true); + setFeatureEnabledImpl(Features, "rtm", true); + setFeatureEnabledImpl(Features, "fma", true); + // FALLTHROUGH + case CK_IvyBridge: + setFeatureEnabledImpl(Features, "rdrnd", true); + setFeatureEnabledImpl(Features, "f16c", true); + setFeatureEnabledImpl(Features, "fsgsbase", true); + // FALLTHROUGH + case CK_SandyBridge: + setFeatureEnabledImpl(Features, "avx", true); + // FALLTHROUGH + case CK_Westmere: + case CK_Silvermont: + setFeatureEnabledImpl(Features, "aes", true); + setFeatureEnabledImpl(Features, "pclmul", true); + // FALLTHROUGH + case CK_Nehalem: + setFeatureEnabledImpl(Features, "sse4.2", true); + setFeatureEnabledImpl(Features, "cx16", true); + break; + case CK_KNL: + setFeatureEnabledImpl(Features, "avx512f", true); + setFeatureEnabledImpl(Features, "avx512cd", true); + setFeatureEnabledImpl(Features, "avx512er", true); + setFeatureEnabledImpl(Features, "avx512pf", true); + setFeatureEnabledImpl(Features, "rdseed", true); + setFeatureEnabledImpl(Features, "adx", true); + setFeatureEnabledImpl(Features, "lzcnt", true); + setFeatureEnabledImpl(Features, "bmi", true); + setFeatureEnabledImpl(Features, "bmi2", true); + setFeatureEnabledImpl(Features, "rtm", 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); + break; + case CK_K6_2: + case CK_K6_3: + case CK_WinChip2: + case CK_C3: + setFeatureEnabledImpl(Features, "3dnow", true); + break; + case CK_Athlon: + case CK_AthlonThunderbird: + case CK_Geode: + setFeatureEnabledImpl(Features, "3dnowa", true); + break; + case CK_Athlon4: + case CK_AthlonXP: + case CK_AthlonMP: + setFeatureEnabledImpl(Features, "sse", true); + setFeatureEnabledImpl(Features, "3dnowa", true); + break; + case CK_K8: + case CK_Opteron: + case CK_Athlon64: + case CK_AthlonFX: + setFeatureEnabledImpl(Features, "sse2", true); + setFeatureEnabledImpl(Features, "3dnowa", true); + break; + case CK_AMDFAM10: + setFeatureEnabledImpl(Features, "sse4a", true); + setFeatureEnabledImpl(Features, "lzcnt", true); + setFeatureEnabledImpl(Features, "popcnt", true); + // FALLTHROUGH + case CK_K8SSE3: + case CK_OpteronSSE3: + case CK_Athlon64SSE3: + setFeatureEnabledImpl(Features, "sse3", true); + 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); + // 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); + break; + case CK_BDVER4: + setFeatureEnabledImpl(Features, "avx2", true); + setFeatureEnabledImpl(Features, "bmi2", true); + // FALLTHROUGH + case CK_BDVER3: + setFeatureEnabledImpl(Features, "fsgsbase", true); + // FALLTHROUGH + case CK_BDVER2: + setFeatureEnabledImpl(Features, "bmi", true); + setFeatureEnabledImpl(Features, "fma", true); + setFeatureEnabledImpl(Features, "f16c", true); + setFeatureEnabledImpl(Features, "tbm", true); + // FALLTHROUGH + case CK_BDVER1: + // xop implies avx, sse4a and fma4. + setFeatureEnabledImpl(Features, "xop", true); + setFeatureEnabledImpl(Features, "lzcnt", true); + setFeatureEnabledImpl(Features, "aes", true); + setFeatureEnabledImpl(Features, "pclmul", true); + setFeatureEnabledImpl(Features, "prfchw", true); + setFeatureEnabledImpl(Features, "cx16", true); + break; + } +} + +void X86TargetInfo::setSSELevel(llvm::StringMap<bool> &Features, + X86SSEEnum Level, bool Enabled) { + if (Enabled) { + switch (Level) { + case AVX512F: + Features["avx512f"] = true; + case AVX2: + Features["avx2"] = true; + case AVX: + Features["avx"] = true; + case SSE42: + Features["sse4.2"] = true; + case SSE41: + Features["sse4.1"] = true; + case SSSE3: + Features["ssse3"] = true; + case SSE3: + Features["sse3"] = true; + case SSE2: + Features["sse2"] = true; + case SSE1: + Features["sse"] = true; + case NoSSE: + break; + } + return; + } + + switch (Level) { + case NoSSE: + case SSE1: + Features["sse"] = false; + case SSE2: + Features["sse2"] = Features["pclmul"] = Features["aes"] = + Features["sha"] = false; + case SSE3: + Features["sse3"] = false; + setXOPLevel(Features, NoXOP, false); + case SSSE3: + Features["ssse3"] = false; + case SSE41: + Features["sse4.1"] = false; + case SSE42: + Features["sse4.2"] = false; + case AVX: + Features["fma"] = Features["avx"] = Features["f16c"] = false; + setXOPLevel(Features, FMA4, false); + case AVX2: + Features["avx2"] = false; + case AVX512F: + Features["avx512f"] = Features["avx512cd"] = Features["avx512er"] = + Features["avx512pf"] = Features["avx512dq"] = Features["avx512bw"] = + Features["avx512vl"] = false; + } +} + +void X86TargetInfo::setMMXLevel(llvm::StringMap<bool> &Features, + MMX3DNowEnum Level, bool Enabled) { + if (Enabled) { + switch (Level) { + case AMD3DNowAthlon: + Features["3dnowa"] = true; + case AMD3DNow: + Features["3dnow"] = true; + case MMX: + Features["mmx"] = true; + case NoMMX3DNow: + break; + } + return; + } + + switch (Level) { + case NoMMX3DNow: + case MMX: + Features["mmx"] = false; + case AMD3DNow: + Features["3dnow"] = false; + case AMD3DNowAthlon: + Features["3dnowa"] = false; + } +} + +void X86TargetInfo::setXOPLevel(llvm::StringMap<bool> &Features, XOPEnum Level, + bool Enabled) { + if (Enabled) { + switch (Level) { + case XOP: + Features["xop"] = true; + case FMA4: + Features["fma4"] = true; + setSSELevel(Features, AVX, true); + case SSE4A: + Features["sse4a"] = true; + setSSELevel(Features, SSE3, true); + case NoXOP: + break; + } + return; + } + + switch (Level) { + case NoXOP: + case SSE4A: + Features["sse4a"] = false; + case FMA4: + Features["fma4"] = false; + case XOP: + Features["xop"] = false; + } +} + +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 if (Name == "pclmul") { + 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 == "avx512cd" || Name == "avx512er" || Name == "avx512pf" + || Name == "avx512dq" || Name == "avx512bw" || Name == "avx512vl") { + if (Enabled) + setSSELevel(Features, AVX512F, Enabled); + } else if (Name == "fma") { + if (Enabled) + setSSELevel(Features, AVX, 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 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); + } +} + +/// handleTargetFeatures - Perform initialization based on the user +/// configured set of features. +bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) { + // Remember the maximum enabled sselevel. + for (unsigned i = 0, e = Features.size(); i !=e; ++i) { + // Ignore disabled features. + if (Features[i][0] == '-') + continue; + + StringRef Feature = StringRef(Features[i]).substr(1); + + if (Feature == "aes") { + HasAES = true; + continue; + } + + if (Feature == "pclmul") { + HasPCLMUL = true; + continue; + } + + if (Feature == "lzcnt") { + HasLZCNT = true; + continue; + } + + if (Feature == "rdrnd") { + HasRDRND = true; + continue; + } + + if (Feature == "fsgsbase") { + HasFSGSBASE = true; + continue; + } + + if (Feature == "bmi") { + HasBMI = true; + continue; + } + + if (Feature == "bmi2") { + HasBMI2 = true; + continue; + } + + if (Feature == "popcnt") { + HasPOPCNT = true; + continue; + } + + if (Feature == "rtm") { + HasRTM = true; + continue; + } + + if (Feature == "prfchw") { + HasPRFCHW = true; + continue; + } + + if (Feature == "rdseed") { + HasRDSEED = true; + continue; + } + + if (Feature == "adx") { + HasADX = true; + continue; + } + + if (Feature == "tbm") { + HasTBM = true; + continue; + } + + if (Feature == "fma") { + HasFMA = true; + continue; + } + + if (Feature == "f16c") { + HasF16C = true; + continue; + } + + if (Feature == "avx512cd") { + HasAVX512CD = true; + continue; + } + + if (Feature == "avx512er") { + HasAVX512ER = true; + continue; + } + + if (Feature == "avx512pf") { + HasAVX512PF = true; + continue; + } + + if (Feature == "avx512dq") { + HasAVX512DQ = true; + continue; + } + + if (Feature == "avx512bw") { + HasAVX512BW = true; + continue; + } + + if (Feature == "avx512vl") { + HasAVX512VL = true; + continue; + } + + if (Feature == "sha") { + HasSHA = true; + continue; + } + + if (Feature == "cx16") { + HasCX16 = true; + continue; + } + + assert(Features[i][0] == '+' && "Invalid target feature!"); + 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); + } + + // Enable popcnt if sse4.2 is enabled and popcnt is not explicitly disabled. + // Can't do this earlier because we need to be able to explicitly enable + // popcnt and still disable sse4.2. + if (!HasPOPCNT && SSELevel >= SSE42 && + std::find(Features.begin(), Features.end(), "-popcnt") == Features.end()){ + HasPOPCNT = true; + Features.push_back("+popcnt"); + } + + // Enable prfchw if 3DNow! is enabled and prfchw is not explicitly disabled. + if (!HasPRFCHW && MMX3DNowLevel >= AMD3DNow && + std::find(Features.begin(), Features.end(), "-prfchw") == Features.end()){ + HasPRFCHW = true; + Features.push_back("+prfchw"); + } + + // 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) { + Diags.Report(diag::err_target_unsupported_fpmath) << "sse"; + return false; + } else if (FPMath == FP_387 && SSELevel >= SSE1) { + Diags.Report(diag::err_target_unsupported_fpmath) << "387"; + return false; + } + + // Don't tell the backend if we're turning off mmx; it will end up disabling + // SSE, which we don't want. + // Additionally, if SSE is enabled and mmx is not explicitly disabled, + // then enable MMX. + std::vector<std::string>::iterator it; + it = std::find(Features.begin(), Features.end(), "-mmx"); + if (it != Features.end()) + Features.erase(it); + else if (SSELevel > NoSSE) + MMX3DNowLevel = std::max(MMX3DNowLevel, MMX); + + SimdDefaultAlign = + (getABI() == "avx512") ? 512 : (getABI() == "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 { + // 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); + } + + // 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__"); + // Fallthrough + case CK_i586: + case CK_Pentium: + defineCPUMacros(Builder, "i586"); + defineCPUMacros(Builder, "pentium"); + break; + case CK_Pentium3: + case CK_Pentium3M: + case CK_PentiumM: + Builder.defineMacro("__tune_pentium3__"); + // Fallthrough + case CK_Pentium2: + case CK_C3_2: + Builder.defineMacro("__tune_pentium2__"); + // Fallthrough + case CK_PentiumPro: + Builder.defineMacro("__tune_i686__"); + Builder.defineMacro("__tune_pentiumpro__"); + // Fallthrough + case CK_i686: + Builder.defineMacro("__i686"); + Builder.defineMacro("__i686__"); + // Strangely, __tune_i686__ isn't defined by GCC when CPU == i686. + Builder.defineMacro("__pentiumpro"); + Builder.defineMacro("__pentiumpro__"); + break; + case CK_Pentium4: + case CK_Pentium4M: + 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_Nehalem: + case CK_Westmere: + case CK_SandyBridge: + case CK_IvyBridge: + case CK_Haswell: + case CK_Broadwell: + // 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_Skylake: + // FIXME: Historically, we defined this legacy name, it would be nice to + // remove it at some point. This is the only fine-grained CPU macro in the + // main intel CPU line, and it would be better to not have these and force + // people to use ISA macros. + defineCPUMacros(Builder, "skx"); + break; + case CK_KNL: + defineCPUMacros(Builder, "knl"); + break; + case CK_K6_2: + Builder.defineMacro("__k6_2__"); + Builder.defineMacro("__tune_k6_2__"); + // 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__"); + } + // Fallthrough + case CK_K6: + defineCPUMacros(Builder, "k6"); + break; + case CK_Athlon: + case CK_AthlonThunderbird: + case CK_Athlon4: + case CK_AthlonXP: + case CK_AthlonMP: + 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: + case CK_Opteron: + case CK_OpteronSSE3: + case CK_Athlon64: + case CK_Athlon64SSE3: + case CK_AthlonFX: + 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_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 (HasPCLMUL) + Builder.defineMacro("__PCLMUL__"); + + 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__"); + + switch (XOPLevel) { + case XOP: + Builder.defineMacro("__XOP__"); + case FMA4: + Builder.defineMacro("__FMA4__"); + case SSE4A: + Builder.defineMacro("__SSE4A__"); + case NoXOP: + break; + } + + if (HasFMA) + Builder.defineMacro("__FMA__"); + + if (HasF16C) + Builder.defineMacro("__F16C__"); + + if (HasAVX512CD) + Builder.defineMacro("__AVX512CD__"); + if (HasAVX512ER) + Builder.defineMacro("__AVX512ER__"); + if (HasAVX512PF) + Builder.defineMacro("__AVX512PF__"); + if (HasAVX512DQ) + Builder.defineMacro("__AVX512DQ__"); + if (HasAVX512BW) + Builder.defineMacro("__AVX512BW__"); + if (HasAVX512VL) + Builder.defineMacro("__AVX512VL__"); + + if (HasSHA) + Builder.defineMacro("__SHA__"); + + if (HasCX16) + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16"); + + // Each case falls through to the previous one here. + switch (SSELevel) { + case AVX512F: + Builder.defineMacro("__AVX512F__"); + case AVX2: + Builder.defineMacro("__AVX2__"); + case AVX: + Builder.defineMacro("__AVX__"); + case SSE42: + Builder.defineMacro("__SSE4_2__"); + case SSE41: + Builder.defineMacro("__SSE4_1__"); + case SSSE3: + Builder.defineMacro("__SSSE3__"); + case SSE3: + Builder.defineMacro("__SSE3__"); + case SSE2: + Builder.defineMacro("__SSE2__"); + Builder.defineMacro("__SSE2_MATH__"); // -mfp-math=sse always implied. + case SSE1: + Builder.defineMacro("__SSE__"); + Builder.defineMacro("__SSE_MATH__"); // -mfp-math=sse always implied. + 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)); + } + } + + // Each case falls through to the previous one here. + switch (MMX3DNowLevel) { + case AMD3DNowAthlon: + Builder.defineMacro("__3dNOW_A__"); + case AMD3DNow: + Builder.defineMacro("__3dNOW__"); + case MMX: + Builder.defineMacro("__MMX__"); + case NoMMX3DNow: + break; + } + + if (CPU >= CK_i486) { + 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 (CPU >= CK_i586) + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); +} + +bool X86TargetInfo::hasFeature(StringRef Feature) const { + return llvm::StringSwitch<bool>(Feature) + .Case("aes", HasAES) + .Case("avx", SSELevel >= AVX) + .Case("avx2", SSELevel >= AVX2) + .Case("avx512f", SSELevel >= AVX512F) + .Case("avx512cd", HasAVX512CD) + .Case("avx512er", HasAVX512ER) + .Case("avx512pf", HasAVX512PF) + .Case("avx512dq", HasAVX512DQ) + .Case("avx512bw", HasAVX512BW) + .Case("avx512vl", HasAVX512VL) + .Case("bmi", HasBMI) + .Case("bmi2", HasBMI2) + .Case("cx16", HasCX16) + .Case("f16c", HasF16C) + .Case("fma", HasFMA) + .Case("fma4", XOPLevel >= FMA4) + .Case("fsgsbase", HasFSGSBASE) + .Case("lzcnt", HasLZCNT) + .Case("mm3dnow", MMX3DNowLevel >= AMD3DNow) + .Case("mm3dnowa", MMX3DNowLevel >= AMD3DNowAthlon) + .Case("mmx", MMX3DNowLevel >= MMX) + .Case("pclmul", HasPCLMUL) + .Case("popcnt", HasPOPCNT) + .Case("prfchw", HasPRFCHW) + .Case("rdrnd", HasRDRND) + .Case("rdseed", HasRDSEED) + .Case("rtm", HasRTM) + .Case("sha", HasSHA) + .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("x86", true) + .Case("x86_32", getTriple().getArch() == llvm::Triple::x86) + .Case("x86_64", getTriple().getArch() == llvm::Triple::x86_64) + .Case("xop", XOPLevel >= XOP) + .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) + .Case("cmov", true) + .Case("mmx", true) + .Case("popcnt", true) + .Case("sse", true) + .Case("sse2", true) + .Case("sse3", true) + .Case("sse4.1", true) + .Case("sse4.2", true) + .Case("avx", true) + .Case("avx2", true) + .Case("sse4a", true) + .Case("fma4", true) + .Case("xop", true) + .Case("fma", true) + .Case("avx512f", true) + .Case("bmi", true) + .Case("bmi2", true) + .Default(false); +} + +bool +X86TargetInfo::validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const { + switch (*Name) { + default: return false; + 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': + // FIXME: properly analyze this constraint: + // must be one of 0xff, 0xffff, or 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; + case 'Y': // first letter of a pair: + switch (*(Name+1)) { + default: return false; + case '0': // First SSE register. + 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. + break; // falls through to setAllowsRegister. + } + 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 'x': // Any SSE register. + 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; + case 'C': // SSE floating point constant. + case 'G': // x87 floating point constant. + case 'e': // 32-bit signed integer constant for use with zero-extending + // x86_64 instructions. + case 'Z': // 32-bit unsigned integer constant for use with zero-extending + // x86_64 instructions. + return true; + } +} + +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 'y': + return Size <= 64; + case 'f': + case 't': + case 'u': + return Size <= 128; + case 'x': + // 256-bit ymm registers can be used if target supports AVX. + return Size <= (SSELevel >= AVX ? 256U : 128U); + } + + return true; +} + +std::string +X86TargetInfo::convertConstraint(const char *&Constraint) const { + switch (*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. + default: + return std::string(1, *Constraint); + } +} + +// X86-32 generic target +class X86_32TargetInfo : public X86TargetInfo { +public: + X86_32TargetInfo(const llvm::Triple &Triple) : X86TargetInfo(Triple) { + DoubleAlign = LongLongAlign = 32; + LongDoubleWidth = 96; + LongDoubleAlign = 32; + SuitableAlign = 128; + DescriptionString = "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 + // FIXME: Check that we actually have cmpxchg8b before setting + // MaxAtomicInlineWidth. (cmpxchg8b is an i586 instruction.) + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + } + 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); + } +}; + +class NetBSDI386TargetInfo : public NetBSDTargetInfo<X86_32TargetInfo> { +public: + NetBSDI386TargetInfo(const llvm::Triple &Triple) + : NetBSDTargetInfo<X86_32TargetInfo>(Triple) {} + + 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 OpenBSDI386TargetInfo : public OpenBSDTargetInfo<X86_32TargetInfo> { +public: + OpenBSDI386TargetInfo(const llvm::Triple &Triple) + : OpenBSDTargetInfo<X86_32TargetInfo>(Triple) { + SizeType = UnsignedLong; + IntPtrType = SignedLong; + PtrDiffType = SignedLong; + } +}; + +class BitrigI386TargetInfo : public BitrigTargetInfo<X86_32TargetInfo> { +public: + BitrigI386TargetInfo(const llvm::Triple &Triple) + : BitrigTargetInfo<X86_32TargetInfo>(Triple) { + SizeType = UnsignedLong; + IntPtrType = SignedLong; + PtrDiffType = SignedLong; + } +}; + +class DarwinI386TargetInfo : public DarwinTargetInfo<X86_32TargetInfo> { +public: + DarwinI386TargetInfo(const llvm::Triple &Triple) + : DarwinTargetInfo<X86_32TargetInfo>(Triple) { + LongDoubleWidth = 128; + LongDoubleAlign = 128; + SuitableAlign = 128; + MaxVectorAlign = 256; + SizeType = UnsignedLong; + IntPtrType = SignedLong; + DescriptionString = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128"; + HasAlignMac68kSupport = true; + } + +}; + +// x86-32 Windows target +class WindowsX86_32TargetInfo : public WindowsTargetInfo<X86_32TargetInfo> { +public: + WindowsX86_32TargetInfo(const llvm::Triple &Triple) + : WindowsTargetInfo<X86_32TargetInfo>(Triple) { + WCharType = UnsignedShort; + DoubleAlign = LongLongAlign = 64; + bool IsWinCOFF = + getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF(); + DescriptionString = 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"; + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + WindowsTargetInfo<X86_32TargetInfo>::getTargetDefines(Opts, Builder); + } +}; + +// x86-32 Windows Visual Studio target +class MicrosoftX86_32TargetInfo : public WindowsX86_32TargetInfo { +public: + MicrosoftX86_32TargetInfo(const llvm::Triple &Triple) + : WindowsX86_32TargetInfo(Triple) { + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble; + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder); + WindowsX86_32TargetInfo::getVisualStudioDefines(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"); + } +}; +} // end anonymous namespace + +static 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); + } + } +} + +static void addMinGWDefines(const LangOptions &Opts, MacroBuilder &Builder) { + Builder.defineMacro("__MSVCRT__"); + Builder.defineMacro("__MINGW32__"); + addCygMingDefines(Opts, Builder); +} + +namespace { +// x86-32 MinGW target +class MinGWX86_32TargetInfo : public WindowsX86_32TargetInfo { +public: + MinGWX86_32TargetInfo(const llvm::Triple &Triple) + : WindowsX86_32TargetInfo(Triple) {} + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder); + DefineStd(Builder, "WIN32", Opts); + DefineStd(Builder, "WINNT", Opts); + Builder.defineMacro("_X86_"); + addMinGWDefines(Opts, Builder); + } +}; + +// x86-32 Cygwin target +class CygwinX86_32TargetInfo : public X86_32TargetInfo { +public: + CygwinX86_32TargetInfo(const llvm::Triple &Triple) + : X86_32TargetInfo(Triple) { + TLSSupported = false; + WCharType = UnsignedShort; + DoubleAlign = LongLongAlign = 64; + DescriptionString = "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 HaikuX86_32TargetInfo : public X86_32TargetInfo { +public: + HaikuX86_32TargetInfo(const llvm::Triple &Triple) : X86_32TargetInfo(Triple) { + SizeType = UnsignedLong; + IntPtrType = SignedLong; + PtrDiffType = SignedLong; + ProcessIDType = SignedLong; + this->UserLabelPrefix = ""; + this->TLSSupported = false; + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + X86_32TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__INTEL__"); + Builder.defineMacro("__HAIKU__"); + } +}; + +// RTEMS Target +template<typename Target> +class 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__"); + } + +public: + RTEMSTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) { + this->UserLabelPrefix = ""; + + 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; + } + } +}; + +// x86-32 RTEMS target +class RTEMSX86_32TargetInfo : public X86_32TargetInfo { +public: + RTEMSX86_32TargetInfo(const llvm::Triple &Triple) : X86_32TargetInfo(Triple) { + SizeType = UnsignedLong; + IntPtrType = SignedLong; + PtrDiffType = SignedLong; + this->UserLabelPrefix = ""; + } + 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 X86_64TargetInfo : public X86TargetInfo { +public: + X86_64TargetInfo(const llvm::Triple &Triple) : X86TargetInfo(Triple) { + 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. + DescriptionString = 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; + + // x86-64 has atomics up to 16 bytes. + MaxAtomicPromoteWidth = 128; + MaxAtomicInlineWidth = 128; + } + 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 { + return (CC == CC_C || + CC == CC_X86VectorCall || + CC == CC_IntelOclBicc || + CC == CC_X86_64Win64) ? CCCR_OK : CCCR_Warning; + } + + CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override { + return CC_C; + } + + // for x32 we need it here explicitly + bool hasInt128Type() const override { return true; } +}; + +// x86-64 Windows target +class WindowsX86_64TargetInfo : public WindowsTargetInfo<X86_64TargetInfo> { +public: + WindowsX86_64TargetInfo(const llvm::Triple &Triple) + : WindowsTargetInfo<X86_64TargetInfo>(Triple) { + WCharType = UnsignedShort; + LongWidth = LongAlign = 32; + DoubleAlign = LongLongAlign = 64; + IntMaxType = SignedLongLong; + Int64Type = SignedLongLong; + SizeType = UnsignedLongLong; + PtrDiffType = SignedLongLong; + IntPtrType = SignedLongLong; + this->UserLabelPrefix = ""; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + WindowsTargetInfo<X86_64TargetInfo>::getTargetDefines(Opts, Builder); + Builder.defineMacro("_WIN64"); + } + + 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_X86_64SysV: + return CCCR_OK; + default: + return CCCR_Warning; + } + } +}; + +// x86-64 Windows Visual Studio target +class MicrosoftX86_64TargetInfo : public WindowsX86_64TargetInfo { +public: + MicrosoftX86_64TargetInfo(const llvm::Triple &Triple) + : WindowsX86_64TargetInfo(Triple) { + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble; + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder); + WindowsX86_64TargetInfo::getVisualStudioDefines(Opts, Builder); + Builder.defineMacro("_M_X64"); + Builder.defineMacro("_M_AMD64"); + } +}; + +// x86-64 MinGW target +class MinGWX86_64TargetInfo : public WindowsX86_64TargetInfo { +public: + MinGWX86_64TargetInfo(const llvm::Triple &Triple) + : WindowsX86_64TargetInfo(Triple) { + // 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; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder); + DefineStd(Builder, "WIN64", Opts); + Builder.defineMacro("__MINGW64__"); + addMinGWDefines(Opts, Builder); + + // GCC defines this macro when it is using __gxx_personality_seh0. + if (!Opts.SjLjExceptions) + Builder.defineMacro("__SEH__"); + } +}; + +class DarwinX86_64TargetInfo : public DarwinTargetInfo<X86_64TargetInfo> { +public: + DarwinX86_64TargetInfo(const llvm::Triple &Triple) + : DarwinTargetInfo<X86_64TargetInfo>(Triple) { + Int64Type = SignedLongLong; + MaxVectorAlign = 256; + // The 64-bit iOS simulator uses the builtin bool type for Objective-C. + llvm::Triple T = llvm::Triple(Triple); + if (T.isiOS()) + UseSignedCharForObjCBool = false; + DescriptionString = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"; + } +}; + +class OpenBSDX86_64TargetInfo : public OpenBSDTargetInfo<X86_64TargetInfo> { +public: + OpenBSDX86_64TargetInfo(const llvm::Triple &Triple) + : OpenBSDTargetInfo<X86_64TargetInfo>(Triple) { + IntMaxType = SignedLongLong; + Int64Type = SignedLongLong; + } +}; + +class BitrigX86_64TargetInfo : public BitrigTargetInfo<X86_64TargetInfo> { +public: + BitrigX86_64TargetInfo(const llvm::Triple &Triple) + : BitrigTargetInfo<X86_64TargetInfo>(Triple) { + IntMaxType = SignedLongLong; + Int64Type = SignedLongLong; + } +}; + +class ARMTargetInfo : public TargetInfo { + // Possible FPU choices. + enum FPUMode { + VFP2FPU = (1 << 0), + VFP3FPU = (1 << 1), + VFP4FPU = (1 << 2), + NeonFPU = (1 << 3), + FPARMV8 = (1 << 4) + }; + + // 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; + + enum { + FP_Default, + FP_VFP, + FP_Neon + } FPMath; + + unsigned FPU : 5; + + unsigned IsAAPCS : 1; + unsigned IsThumb : 1; + unsigned HWDiv : 2; + + // Initialized via features. + unsigned SoftFloat : 1; + unsigned SoftFloatABI : 1; + + unsigned CRC : 1; + unsigned Crypto : 1; + + // 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[]; + + static bool shouldUseInlineAtomic(const llvm::Triple &T) { + StringRef ArchName = T.getArchName(); + if (T.getArch() == llvm::Triple::arm || + T.getArch() == llvm::Triple::armeb) { + StringRef VersionStr; + if (ArchName.startswith("armv")) + VersionStr = ArchName.substr(4, 1); + else if (ArchName.startswith("armebv")) + VersionStr = ArchName.substr(6, 1); + else + return false; + unsigned Version; + if (VersionStr.getAsInteger(10, Version)) + return false; + return Version >= 6; + } + assert(T.getArch() == llvm::Triple::thumb || + T.getArch() == llvm::Triple::thumbeb); + StringRef VersionStr; + if (ArchName.startswith("thumbv")) + VersionStr = ArchName.substr(6, 1); + else if (ArchName.startswith("thumbebv")) + VersionStr = ArchName.substr(8, 1); + else + return false; + unsigned Version; + if (VersionStr.getAsInteger(10, Version)) + return false; + return Version >= 7; + } + + void setABIAAPCS() { + IsAAPCS = true; + + DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64; + const llvm::Triple &T = getTriple(); + + // size_t is unsigned long on MachO-derived environments, NetBSD and Bitrig. + if (T.isOSBinFormatMachO() || T.getOS() == llvm::Triple::NetBSD || + T.getOS() == llvm::Triple::Bitrig) + SizeType = UnsignedLong; + else + SizeType = UnsignedInt; + + switch (T.getOS()) { + case llvm::Triple::NetBSD: + WCharType = SignedInt; + break; + case llvm::Triple::Win32: + WCharType = UnsignedShort; + break; + case llvm::Triple::Linux: + default: + // AAPCS 7.1.1, ARM-Linux ABI 2.4: type of wchar_t is unsigned int. + WCharType = UnsignedInt; + break; + } + + 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()) { + DescriptionString = + BigEndian ? "E-m:o-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" + : "e-m:o-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"; + } else if (T.isOSWindows()) { + assert(!BigEndian && "Windows on ARM does not support big endian"); + DescriptionString = "e" + "-m:w" + "-p:32:32" + "-i64:64" + "-v128:64:128" + "-a:0:32" + "-n32" + "-S64"; + } else if (T.isOSNaCl()) { + assert(!BigEndian && "NaCl on ARM does not support big endian"); + DescriptionString = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S128"; + } else { + DescriptionString = + BigEndian ? "E-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" + : "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"; + } + + // FIXME: Enumerated types are variable width in straight AAPCS. + } + + void setABIAPCS() { + const llvm::Triple &T = getTriple(); + + IsAAPCS = false; + + DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 32; + + // size_t is unsigned int on FreeBSD. + if (T.getOS() == llvm::Triple::FreeBSD) + SizeType = UnsignedInt; + else + SizeType = UnsignedLong; + + // Revert to using SignedInt on apcs-gnu to comply with existing behaviour. + 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()) + DescriptionString = + BigEndian + ? "E-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" + : "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"; + else + DescriptionString = + BigEndian + ? "E-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" + : "e-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"; + + // FIXME: Override "preferred align" for double and long long. + } + +public: + ARMTargetInfo(const llvm::Triple &Triple, bool IsBigEndian) + : TargetInfo(Triple), CPU("arm1136j-s"), FPMath(FP_Default), + IsAAPCS(true), HW_FP(0) { + BigEndian = IsBigEndian; + + switch (getTriple().getOS()) { + case llvm::Triple::NetBSD: + PtrDiffType = SignedLong; + break; + default: + PtrDiffType = SignedInt; + break; + } + + // {} in inline assembly are neon specifiers, not assembly variant + // specifiers. + NoAsmVariants = true; + + // FIXME: Should we just treat this as a feature? + IsThumb = getTriple().getArchName().startswith("thumb"); + + // 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 || + StringRef(CPU).startswith("cortex-m")) { + setABI("aapcs"); + } 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: + 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 (Triple.getOS() == llvm::Triple::NetBSD) + setABI("apcs-gnu"); + else + setABI("aapcs"); + break; + } + } + + // ARM targets default to using the ARM C++ ABI. + TheCXXABI.set(TargetCXXABI::GenericARM); + + // ARM has atomics up to 8 bytes + MaxAtomicPromoteWidth = 64; + if (shouldUseInlineAtomic(getTriple())) + MaxAtomicInlineWidth = 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; + } + + StringRef getABI() const override { return ABI; } + + bool setABI(const std::string &Name) override { + 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") { + setABIAPCS(); + 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. + void getDefaultFeatures(llvm::StringMap<bool> &Features) const override { + StringRef ArchName = getTriple().getArchName(); + unsigned ArchKind = llvm::ARMTargetParser::parseArch(ArchName); + bool IsV8 = (ArchKind == llvm::ARM::AK_ARMV8A || + ArchKind == llvm::ARM::AK_ARMV8_1A); + + if (CPU == "arm1136jf-s" || CPU == "arm1176jzf-s" || CPU == "mpcore") + Features["vfp2"] = true; + else if (CPU == "cortex-a8" || CPU == "cortex-a9") { + Features["vfp3"] = true; + Features["neon"] = true; + } + else if (CPU == "cortex-a5") { + Features["vfp4"] = true; + Features["neon"] = true; + } else if (CPU == "swift" || CPU == "cortex-a7" || + CPU == "cortex-a12" || CPU == "cortex-a15" || + CPU == "cortex-a17" || CPU == "krait") { + Features["vfp4"] = true; + Features["neon"] = true; + Features["hwdiv"] = true; + Features["hwdiv-arm"] = true; + } else if (CPU == "cyclone" || CPU == "cortex-a53" || CPU == "cortex-a57" || + CPU == "cortex-a72") { + Features["fp-armv8"] = true; + Features["neon"] = true; + Features["hwdiv"] = true; + Features["hwdiv-arm"] = true; + Features["crc"] = true; + Features["crypto"] = true; + } else if (CPU == "cortex-r5" || CPU == "cortex-r7" || IsV8) { + Features["hwdiv"] = true; + Features["hwdiv-arm"] = true; + } else if (CPU == "cortex-m3" || CPU == "cortex-m4" || CPU == "cortex-m7" || + CPU == "sc300" || CPU == "cortex-r4" || CPU == "cortex-r4f") { + Features["hwdiv"] = true; + } + } + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override { + FPU = 0; + CRC = 0; + Crypto = 0; + SoftFloat = SoftFloatABI = false; + HWDiv = 0; + + // This does not diagnose illegal cases like having both + // "+vfpv2" and "+vfpv3" or having "+neon" and "+fp-only-sp". + uint32_t HW_FP_remove = 0; + for (const auto &Feature : Features) { + if (Feature == "+soft-float") { + SoftFloat = true; + } else if (Feature == "+soft-float-abi") { + SoftFloatABI = true; + } else if (Feature == "+vfp2") { + FPU |= VFP2FPU; + HW_FP |= HW_FP_SP | HW_FP_DP; + } else if (Feature == "+vfp3") { + FPU |= VFP3FPU; + HW_FP |= HW_FP_SP | HW_FP_DP; + } else if (Feature == "+vfp4") { + FPU |= VFP4FPU; + HW_FP |= HW_FP_SP | HW_FP_DP | HW_FP_HP; + } else if (Feature == "+fp-armv8") { + FPU |= FPARMV8; + HW_FP |= HW_FP_SP | HW_FP_DP | HW_FP_HP; + } else if (Feature == "+neon") { + FPU |= NeonFPU; + HW_FP |= HW_FP_SP | HW_FP_DP; + } 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 == "+fp-only-sp") { + HW_FP_remove |= HW_FP_DP | HW_FP_HP; + } + } + HW_FP &= ~HW_FP_remove; + + 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"); + + // Remove front-end specific options which the backend handles differently. + auto Feature = + std::find(Features.begin(), Features.end(), "+soft-float-abi"); + if (Feature != Features.end()) + Features.erase(Feature); + + return true; + } + + bool hasFeature(StringRef Feature) const override { + return llvm::StringSwitch<bool>(Feature) + .Case("arm", true) + .Case("softfloat", SoftFloat) + .Case("thumb", IsThumb) + .Case("neon", (FPU & NeonFPU) && !SoftFloat) + .Case("hwdiv", HWDiv & HWDivThumb) + .Case("hwdiv-arm", HWDiv & HWDivARM) + .Default(false); + } + const char *getCPUDefineSuffix(StringRef Name) const { + if(Name == "generic") { + auto subarch = getTriple().getSubArch(); + switch (subarch) { + case llvm::Triple::SubArchType::ARMSubArch_v8_1a: + return "8_1A"; + default: + break; + } + } + + unsigned ArchKind = llvm::ARMTargetParser::parseCPUArch(Name); + if (ArchKind == llvm::ARM::AK_INVALID) + return ""; + + // For most sub-arches, the build attribute CPU name is enough. + // For Cortex variants, it's slightly different. + switch(ArchKind) { + default: + return llvm::ARMTargetParser::getCPUAttr(ArchKind); + case llvm::ARM::AK_ARMV6M: + case llvm::ARM::AK_ARMV6SM: + return "6M"; + case llvm::ARM::AK_ARMV7: + case llvm::ARM::AK_ARMV7A: + case llvm::ARM::AK_ARMV7S: + return "7A"; + case llvm::ARM::AK_ARMV7R: + return "7R"; + case llvm::ARM::AK_ARMV7M: + return "7M"; + case llvm::ARM::AK_ARMV7EM: + return "7EM"; + case llvm::ARM::AK_ARMV8A: + return "8A"; + case llvm::ARM::AK_ARMV8_1A: + return "8_1A"; + } + } + const char *getCPUProfile(StringRef Name) const { + if(Name == "generic") { + auto subarch = getTriple().getSubArch(); + switch (subarch) { + case llvm::Triple::SubArchType::ARMSubArch_v8_1a: + return "A"; + default: + break; + } + } + + unsigned CPUArch = llvm::ARMTargetParser::parseCPUArch(Name); + if (CPUArch == llvm::ARM::AK_INVALID) + return ""; + + StringRef ArchName = llvm::ARMTargetParser::getArchName(CPUArch); + switch(llvm::ARMTargetParser::parseArchProfile(ArchName)) { + case llvm::ARM::PK_A: + return "A"; + case llvm::ARM::PK_R: + return "R"; + case llvm::ARM::PK_M: + return "M"; + default: + return ""; + } + } + bool setCPU(const std::string &Name) override { + if (!getCPUDefineSuffix(Name)) + return false; + + // Cortex M does not support 8 byte atomics, while general Thumb2 does. + StringRef Profile = getCPUProfile(Name); + if (Profile == "M" && MaxAtomicInlineWidth) { + MaxAtomicPromoteWidth = 32; + MaxAtomicInlineWidth = 32; + } + + CPU = Name; + return true; + } + bool setFPMath(StringRef Name) override; + bool supportsThumb(StringRef ArchName, StringRef CPUArch, + unsigned CPUArchVer) const { + return CPUArchVer >= 7 || (CPUArch.find('T') != StringRef::npos) || + (CPUArch.find('M') != StringRef::npos); + } + bool supportsThumb2(StringRef ArchName, StringRef CPUArch, + unsigned CPUArchVer) const { + // We check both CPUArchVer and ArchName because when only triple is + // specified, the default CPU is arm1136j-s. + return ArchName.endswith("v6t2") || ArchName.endswith("v7") || + ArchName.endswith("v8.1a") || + ArchName.endswith("v8") || CPUArch == "6T2" || CPUArchVer >= 7; + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + // Target identification. + Builder.defineMacro("__arm"); + Builder.defineMacro("__arm__"); + + // Target properties. + Builder.defineMacro("__REGISTER_PREFIX__", ""); + + StringRef CPUArch = getCPUDefineSuffix(CPU); + unsigned int CPUArchVer; + if (CPUArch.substr(0, 1).getAsInteger<unsigned int>(10, CPUArchVer)) + llvm_unreachable("Invalid char for architecture version number"); + Builder.defineMacro("__ARM_ARCH_" + CPUArch + "__"); + + // ACLE 6.4.1 ARM/Thumb instruction set architecture + StringRef CPUProfile = getCPUProfile(CPU); + StringRef ArchName = getTriple().getArchName(); + + // __ARM_ARCH is defined as an integer value indicating the current ARM ISA + Builder.defineMacro("__ARM_ARCH", CPUArch.substr(0, 1)); + if (CPUArch[0] >= '8') { + Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN"); + Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING"); + } + + // __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 deffault profile is assumed to be 'A' + if (CPUProfile.empty() || CPUProfile != "M") + Builder.defineMacro("__ARM_ARCH_ISA_ARM", "1"); + + // __ARM_ARCH_ISA_THUMB is defined to 1 if the core supporst the original + // Thumb ISA (including v6-M). It is set to 2 if the core supports the + // Thumb-2 ISA as found in the v6T2 architecture and all v7 architecture. + if (supportsThumb2(ArchName, CPUArch, CPUArchVer)) + Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "2"); + else if (supportsThumb(ArchName, CPUArch, CPUArchVer)) + 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.5.1 Hardware Floating Point + if (HW_FP) + Builder.defineMacro("__ARM_FP", "0x" + llvm::utohexstr(HW_FP)); + + // ACLE predefines. + Builder.defineMacro("__ARM_ACLE", "200"); + + // 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 <= CPUArchVer && CPUArchVer <= 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().isOSDarwin() && !getTriple().isOSWindows()) + Builder.defineMacro("__ARM_EABI__"); + Builder.defineMacro("__ARM_PCS", "1"); + + if ((!SoftFloat && !SoftFloatABI) || ABI == "aapcs-vfp") + Builder.defineMacro("__ARM_PCS_VFP", "1"); + } + + if (SoftFloat) + Builder.defineMacro("__SOFTFP__"); + + if (CPU == "xscale") + Builder.defineMacro("__XSCALE__"); + + if (IsThumb) { + Builder.defineMacro("__THUMBEL__"); + Builder.defineMacro("__thumb__"); + if (supportsThumb2(ArchName, CPUArch, CPUArchVer)) + Builder.defineMacro("__thumb2__"); + } + if (((HWDiv & HWDivThumb) && IsThumb) || ((HWDiv & HWDivARM) && !IsThumb)) + 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__"); + } + + // 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 && CPUArchVer >= 7) { + Builder.defineMacro("__ARM_NEON"); + Builder.defineMacro("__ARM_NEON__"); + } + + Builder.defineMacro("__ARM_SIZEOF_WCHAR_T", + Opts.ShortWChar ? "2" : "4"); + + Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM", + Opts.ShortEnums ? "1" : "4"); + + if (CRC) + Builder.defineMacro("__ARM_FEATURE_CRC32"); + + if (Crypto) + Builder.defineMacro("__ARM_FEATURE_CRYPTO"); + + if (CPUArchVer >= 6 && CPUArch != "6M") { + 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"); + } + + bool is5EOrAbove = (CPUArchVer >= 6 || + (CPUArchVer == 5 && + CPUArch.find('E') != StringRef::npos)); + bool is32Bit = (!IsThumb || supportsThumb2(ArchName, CPUArch, CPUArchVer)); + if (is5EOrAbove && is32Bit && (CPUProfile != "M" || CPUArch == "7EM")) + Builder.defineMacro("__ARM_FEATURE_DSP"); + } + void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const override { + Records = BuiltinInfo; + NumRecords = clang::ARM::LastTSBuiltin-Builtin::FirstTSBuiltin; + } + bool isCLZForZeroUndef() const override { return false; } + BuiltinVaListKind getBuiltinVaListKind() const override { + return IsAAPCS ? AAPCSABIBuiltinVaList : TargetInfo::VoidPtrBuiltinVaList; + } + void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const override; + void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const override; + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + switch (*Name) { + default: break; + case 'l': // r0-r7 + case 'h': // r8-r15 + case 'w': // VFP Floating point register single precision + case 'P': // 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 '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; + } + } + return false; + } + std::string convertConstraint(const char *&Constraint) const override { + std::string R; + switch (*Constraint) { + case 'U': // Two-character constraint; add "^" hint for later parsing. + 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 + validateConstraintModifier(StringRef Constraint, char Modifier, unsigned Size, + std::string &SuggestedModifier) const override { + 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 *getClobbers() const override { + // FIXME: Is this really right? + return ""; + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + return (CC == CC_AAPCS || CC == CC_AAPCS_VFP) ? CCCR_OK : CCCR_Warning; + } + + int getEHDataRegisterNumber(unsigned RegNo) const override { + if (RegNo == 0) return 0; + if (RegNo == 1) return 1; + return -1; + } +}; + +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; +} + +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" +}; + +void ARMTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(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. +}; + +void ARMTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + Aliases = GCCRegAliases; + NumAliases = llvm::array_lengthof(GCCRegAliases); +} + +const Builtin::Info ARMTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\ + ALL_LANGUAGES }, +#include "clang/Basic/BuiltinsNEON.def" + +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, +#define LANGBUILTIN(ID, TYPE, ATTRS, LANG) { #ID, TYPE, ATTRS, 0, LANG }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\ + ALL_LANGUAGES }, +#include "clang/Basic/BuiltinsARM.def" +}; + +class ARMleTargetInfo : public ARMTargetInfo { +public: + ARMleTargetInfo(const llvm::Triple &Triple) + : ARMTargetInfo(Triple, false) { } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + Builder.defineMacro("__ARMEL__"); + ARMTargetInfo::getTargetDefines(Opts, Builder); + } +}; + +class ARMbeTargetInfo : public ARMTargetInfo { +public: + ARMbeTargetInfo(const llvm::Triple &Triple) + : ARMTargetInfo(Triple, true) { } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + Builder.defineMacro("__ARMEB__"); + Builder.defineMacro("__ARM_BIG_ENDIAN"); + ARMTargetInfo::getTargetDefines(Opts, Builder); + } +}; + +class WindowsARMTargetInfo : public WindowsTargetInfo<ARMleTargetInfo> { + const llvm::Triple Triple; +public: + WindowsARMTargetInfo(const llvm::Triple &Triple) + : WindowsTargetInfo<ARMleTargetInfo>(Triple), Triple(Triple) { + TLSSupported = false; + WCharType = UnsignedShort; + SizeType = UnsignedInt; + UserLabelPrefix = ""; + } + void getVisualStudioDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + WindowsTargetInfo<ARMleTargetInfo>::getVisualStudioDefines(Opts, Builder); + + // 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"); + } + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::CharPtrBuiltinVaList; + } +}; + +// Windows ARM + Itanium C++ ABI Target +class ItaniumWindowsARMleTargetInfo : public WindowsARMTargetInfo { +public: + ItaniumWindowsARMleTargetInfo(const llvm::Triple &Triple) + : WindowsARMTargetInfo(Triple) { + TheCXXABI.set(TargetCXXABI::GenericARM); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + WindowsARMTargetInfo::getTargetDefines(Opts, Builder); + + if (Opts.MSVCCompat) + WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder); + } +}; + +// Windows ARM, MS (C++) ABI +class MicrosoftARMleTargetInfo : public WindowsARMTargetInfo { +public: + MicrosoftARMleTargetInfo(const llvm::Triple &Triple) + : WindowsARMTargetInfo(Triple) { + TheCXXABI.set(TargetCXXABI::Microsoft); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + WindowsARMTargetInfo::getTargetDefines(Opts, Builder); + WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder); + } +}; + +class DarwinARMTargetInfo : + public DarwinTargetInfo<ARMleTargetInfo> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion); + } + +public: + DarwinARMTargetInfo(const llvm::Triple &Triple) + : DarwinTargetInfo<ARMleTargetInfo>(Triple) { + HasAlignMac68kSupport = true; + // iOS always has 64-bit atomic instructions. + // FIXME: This should be based off of the target features in + // ARMleTargetInfo. + MaxAtomicInlineWidth = 64; + + // Darwin on iOS uses a variant of the ARM C++ ABI. + TheCXXABI.set(TargetCXXABI::iOS); + } +}; + +class AArch64TargetInfo : public TargetInfo { + virtual void setDescriptionString() = 0; + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + static const char *const GCCRegNames[]; + + enum FPUModeEnum { + FPUMode, + NeonMode + }; + + unsigned FPU; + unsigned CRC; + unsigned Crypto; + + static const Builtin::Info BuiltinInfo[]; + + std::string ABI; + +public: + AArch64TargetInfo(const llvm::Triple &Triple) + : TargetInfo(Triple), ABI("aapcs") { + + if (getTriple().getOS() == llvm::Triple::NetBSD) { + WCharType = SignedInt; + + // NetBSD apparently prefers consistency across ARM targets to consistency + // across 64-bit targets. + Int64Type = SignedLongLong; + IntMaxType = SignedLongLong; + } else { + WCharType = UnsignedInt; + Int64Type = SignedLong; + IntMaxType = SignedLong; + } + + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + MaxVectorAlign = 128; + MaxAtomicInlineWidth = 128; + MaxAtomicPromoteWidth = 128; + + LongDoubleWidth = LongDoubleAlign = SuitableAlign = 128; + LongDoubleFormat = &llvm::APFloat::IEEEquad; + + // {} 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." + UseBitFieldTypeAlignment = true; + UseZeroLengthBitfieldAlignment = true; + + // AArch64 targets default to using the ARM C++ ABI. + TheCXXABI.set(TargetCXXABI::GenericAArch64); + } + + StringRef getABI() const override { return ABI; } + bool setABI(const std::string &Name) override { + if (Name != "aapcs" && Name != "darwinpcs") + return false; + + ABI = Name; + return true; + } + + bool setCPU(const std::string &Name) override { + bool CPUKnown = llvm::StringSwitch<bool>(Name) + .Case("generic", true) + .Cases("cortex-a53", "cortex-a57", "cortex-a72", true) + .Case("cyclone", true) + .Default(false); + return CPUKnown; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + // Target identification. + Builder.defineMacro("__aarch64__"); + + // Target properties. + 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"); + Builder.defineMacro("__ARM_PCS_AAPCS64"); + Builder.defineMacro("__ARM_ARCH_ISA_A64"); + + Builder.defineMacro("__ARM_FEATURE_UNALIGNED"); + Builder.defineMacro("__ARM_FEATURE_CLZ"); + Builder.defineMacro("__ARM_FEATURE_FMA"); + Builder.defineMacro("__ARM_FEATURE_DIV"); + Builder.defineMacro("__ARM_FEATURE_IDIV"); // As specified in ACLE + Builder.defineMacro("__ARM_FEATURE_DIV"); // For backwards compatibility + Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN"); + Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING"); + + 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"); + + if (Opts.FastMath || Opts.FiniteMathOnly) + Builder.defineMacro("__ARM_FP_FAST"); + + if (Opts.C99 && !Opts.Freestanding) + Builder.defineMacro("__ARM_FP_FENV_ROUNDING"); + + Builder.defineMacro("__ARM_SIZEOF_WCHAR_T", Opts.ShortWChar ? "2" : "4"); + + Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM", + Opts.ShortEnums ? "1" : "4"); + + if (FPU == NeonMode) { + Builder.defineMacro("__ARM_NEON"); + // 64-bit NEON supports half, single and double precision operations. + Builder.defineMacro("__ARM_NEON_FP", "0xe"); + } + + if (CRC) + Builder.defineMacro("__ARM_FEATURE_CRC32"); + + if (Crypto) + Builder.defineMacro("__ARM_FEATURE_CRYPTO"); + + // 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"); + } + + void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const override { + Records = BuiltinInfo; + NumRecords = clang::AArch64::LastTSBuiltin - Builtin::FirstTSBuiltin; + } + + bool hasFeature(StringRef Feature) const override { + return Feature == "aarch64" || + Feature == "arm64" || + (Feature == "neon" && FPU == NeonMode); + } + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override { + FPU = FPUMode; + CRC = 0; + Crypto = 0; + for (unsigned i = 0, e = Features.size(); i != e; ++i) { + if (Features[i] == "+neon") + FPU = NeonMode; + if (Features[i] == "+crc") + CRC = 1; + if (Features[i] == "+crypto") + Crypto = 1; + } + + setDescriptionString(); + + return true; + } + + bool isCLZForZeroUndef() const override { return false; } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::AArch64ABIBuiltinVaList; + } + + void getGCCRegNames(const char *const *&Names, + unsigned &NumNames) const override; + void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const override; + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + 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 + validateConstraintModifier(StringRef Constraint, char Modifier, unsigned Size, + std::string &SuggestedModifier) const override { + // 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 *getClobbers() const override { return ""; } + + int getEHDataRegisterNumber(unsigned RegNo) const override { + if (RegNo == 0) + return 0; + if (RegNo == 1) + return 1; + return -1; + } +}; + +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", + + // 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" +}; + +void AArch64TargetInfo::getGCCRegNames(const char *const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); +} + +const TargetInfo::GCCRegAlias AArch64TargetInfo::GCCRegAliases[] = { + { { "w31" }, "wsp" }, + { { "x29" }, "fp" }, + { { "x30" }, "lr" }, + { { "x31" }, "sp" }, + // 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. +}; + +void AArch64TargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + Aliases = GCCRegAliases; + NumAliases = llvm::array_lengthof(GCCRegAliases); +} + +const Builtin::Info AArch64TargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, +#include "clang/Basic/BuiltinsNEON.def" + +#define BUILTIN(ID, TYPE, ATTRS) \ + { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, +#include "clang/Basic/BuiltinsAArch64.def" +}; + +class AArch64leTargetInfo : public AArch64TargetInfo { + void setDescriptionString() override { + if (getTriple().isOSBinFormatMachO()) + DescriptionString = "e-m:o-i64:64-i128:128-n32:64-S128"; + else + DescriptionString = "e-m:e-i64:64-i128:128-n32:64-S128"; + } + +public: + AArch64leTargetInfo(const llvm::Triple &Triple) + : AArch64TargetInfo(Triple) { + BigEndian = false; + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + Builder.defineMacro("__AARCH64EL__"); + AArch64TargetInfo::getTargetDefines(Opts, Builder); + } +}; + +class AArch64beTargetInfo : public AArch64TargetInfo { + void setDescriptionString() override { + assert(!getTriple().isOSBinFormatMachO()); + DescriptionString = "E-m:e-i64:64-i128:128-n32:64-S128"; + } + +public: + AArch64beTargetInfo(const llvm::Triple &Triple) + : AArch64TargetInfo(Triple) { } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + Builder.defineMacro("__AARCH64EB__"); + Builder.defineMacro("__AARCH_BIG_ENDIAN"); + Builder.defineMacro("__ARM_BIG_ENDIAN"); + AArch64TargetInfo::getTargetDefines(Opts, Builder); + } +}; + +class DarwinAArch64TargetInfo : public DarwinTargetInfo<AArch64leTargetInfo> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + 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); + } + +public: + DarwinAArch64TargetInfo(const llvm::Triple &Triple) + : DarwinTargetInfo<AArch64leTargetInfo>(Triple) { + Int64Type = SignedLongLong; + WCharType = SignedInt; + UseSignedCharForObjCBool = false; + + LongDoubleWidth = LongDoubleAlign = SuitableAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble; + + TheCXXABI.set(TargetCXXABI::iOS64); + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::CharPtrBuiltinVaList; + } +}; + +// Hexagon abstract base class +class HexagonTargetInfo : public TargetInfo { + static const Builtin::Info BuiltinInfo[]; + static const char * const GCCRegNames[]; + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + std::string CPU; +public: + HexagonTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { + BigEndian = false; + DescriptionString = "e-m:e-p:32:32-i1:32-i64:64-a:0-n32"; + + // {} in inline assembly are packet specifiers, not assembly variant + // specifiers. + NoAsmVariants = true; + } + + void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const override { + Records = BuiltinInfo; + NumRecords = clang::Hexagon::LastTSBuiltin-Builtin::FirstTSBuiltin; + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + return true; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool hasFeature(StringRef Feature) const override { + return Feature == "hexagon"; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::CharPtrBuiltinVaList; + } + void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const override; + void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const override; + const char *getClobbers() const override { + return ""; + } + + static const char *getHexagonCPUSuffix(StringRef Name) { + return llvm::StringSwitch<const char*>(Name) + .Case("hexagonv4", "4") + .Case("hexagonv5", "5") + .Default(nullptr); + } + + bool setCPU(const std::string &Name) override { + if (!getHexagonCPUSuffix(Name)) + return false; + + CPU = Name; + return true; + } +}; + +void HexagonTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("qdsp6"); + Builder.defineMacro("__qdsp6", "1"); + Builder.defineMacro("__qdsp6__", "1"); + + Builder.defineMacro("hexagon"); + Builder.defineMacro("__hexagon", "1"); + Builder.defineMacro("__hexagon__", "1"); + + if(CPU == "hexagonv1") { + Builder.defineMacro("__HEXAGON_V1__"); + Builder.defineMacro("__HEXAGON_ARCH__", "1"); + if(Opts.HexagonQdsp6Compat) { + Builder.defineMacro("__QDSP6_V1__"); + Builder.defineMacro("__QDSP6_ARCH__", "1"); + } + } + else if(CPU == "hexagonv2") { + Builder.defineMacro("__HEXAGON_V2__"); + Builder.defineMacro("__HEXAGON_ARCH__", "2"); + if(Opts.HexagonQdsp6Compat) { + Builder.defineMacro("__QDSP6_V2__"); + Builder.defineMacro("__QDSP6_ARCH__", "2"); + } + } + else if(CPU == "hexagonv3") { + Builder.defineMacro("__HEXAGON_V3__"); + Builder.defineMacro("__HEXAGON_ARCH__", "3"); + if(Opts.HexagonQdsp6Compat) { + Builder.defineMacro("__QDSP6_V3__"); + Builder.defineMacro("__QDSP6_ARCH__", "3"); + } + } + else if(CPU == "hexagonv4") { + Builder.defineMacro("__HEXAGON_V4__"); + Builder.defineMacro("__HEXAGON_ARCH__", "4"); + if(Opts.HexagonQdsp6Compat) { + Builder.defineMacro("__QDSP6_V4__"); + Builder.defineMacro("__QDSP6_ARCH__", "4"); + } + } + else if(CPU == "hexagonv5") { + Builder.defineMacro("__HEXAGON_V5__"); + Builder.defineMacro("__HEXAGON_ARCH__", "5"); + if(Opts.HexagonQdsp6Compat) { + Builder.defineMacro("__QDSP6_V5__"); + Builder.defineMacro("__QDSP6_ARCH__", "5"); + } + } +} + +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" +}; + +void HexagonTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); +} + + +const TargetInfo::GCCRegAlias HexagonTargetInfo::GCCRegAliases[] = { + { { "sp" }, "r29" }, + { { "fp" }, "r30" }, + { { "lr" }, "r31" }, + }; + +void HexagonTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + Aliases = GCCRegAliases; + NumAliases = llvm::array_lengthof(GCCRegAliases); +} + + +const Builtin::Info HexagonTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\ + ALL_LANGUAGES }, +#include "clang/Basic/BuiltinsHexagon.def" +}; + +// Shared base class for SPARC v8 (32-bit) and SPARC v9 (64-bit). +class SparcTargetInfo : public TargetInfo { + static const TargetInfo::GCCRegAlias GCCRegAliases[]; + static const char * const GCCRegNames[]; + bool SoftFloat; +public: + SparcTargetInfo(const llvm::Triple &Triple) + : TargetInfo(Triple), SoftFloat(false) {} + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override { + // The backend doesn't actually handle soft float yet, but in case someone + // is using the support for the front end continue to support it. + auto Feature = std::find(Features.begin(), Features.end(), "+soft-float"); + if (Feature != Features.end()) { + SoftFloat = true; + Features.erase(Feature); + } + return true; + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + DefineStd(Builder, "sparc", Opts); + Builder.defineMacro("__REGISTER_PREFIX__", ""); + + if (SoftFloat) + Builder.defineMacro("SOFT_FLOAT", "1"); + } + + bool hasFeature(StringRef Feature) const override { + return llvm::StringSwitch<bool>(Feature) + .Case("softfloat", SoftFloat) + .Case("sparc", true) + .Default(false); + } + + void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const override { + // FIXME: Implement! + } + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const override; + void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) 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; + } + return false; + } + const char *getClobbers() const override { + // FIXME: Implement! + return ""; + } +}; + +const char * const SparcTargetInfo::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" +}; + +void SparcTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(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" }, +}; + +void SparcTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + Aliases = GCCRegAliases; + NumAliases = llvm::array_lengthof(GCCRegAliases); +} + +// SPARC v8 is the 32-bit mode selected by Triple::sparc. +class SparcV8TargetInfo : public SparcTargetInfo { +public: + SparcV8TargetInfo(const llvm::Triple &Triple) : SparcTargetInfo(Triple) { + DescriptionString = "E-m:e-p:32:32-i64:64-f128:64-n32-S64"; + // NetBSD uses long (same as llvm default); everyone else uses int. + if (getTriple().getOS() == llvm::Triple::NetBSD) { + SizeType = UnsignedLong; + IntPtrType = SignedLong; + PtrDiffType = SignedLong; + } else { + SizeType = UnsignedInt; + IntPtrType = SignedInt; + PtrDiffType = SignedInt; + } + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + SparcTargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__sparcv8"); + } +}; + +// SPARCV8el is the 32-bit little-endian mode selected by Triple::sparcel. +class SparcV8elTargetInfo : public SparcV8TargetInfo { + public: + SparcV8elTargetInfo(const llvm::Triple &Triple) : SparcV8TargetInfo(Triple) { + DescriptionString = "e-m:e-p:32:32-i64:64-f128:64-n32-S64"; + BigEndian = false; + } +}; + +// SPARC v9 is the 64-bit mode selected by Triple::sparcv9. +class SparcV9TargetInfo : public SparcTargetInfo { +public: + SparcV9TargetInfo(const llvm::Triple &Triple) : SparcTargetInfo(Triple) { + // FIXME: Support Sparc quad-precision long double? + DescriptionString = "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().getOS() == llvm::Triple::OpenBSD) + 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 { + 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__"); + } + } + + bool setCPU(const std::string &Name) override { + bool CPUKnown = llvm::StringSwitch<bool>(Name) + .Case("v9", true) + .Case("ultrasparc", true) + .Case("ultrasparc3", true) + .Case("niagara", true) + .Case("niagara2", true) + .Case("niagara3", true) + .Case("niagara4", true) + .Default(false); + + // No need to store the CPU yet. There aren't any CPU-specific + // macros to define. + return CPUKnown; + } +}; + +class SystemZTargetInfo : public TargetInfo { + static const Builtin::Info BuiltinInfo[]; + static const char *const GCCRegNames[]; + std::string CPU; + bool HasTransactionalExecution; + bool HasVector; + +public: + SystemZTargetInfo(const llvm::Triple &Triple) + : TargetInfo(Triple), CPU("z10"), 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; + DescriptionString = "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 { + Builder.defineMacro("__s390__"); + Builder.defineMacro("__s390x__"); + Builder.defineMacro("__zarch__"); + Builder.defineMacro("__LONG_DOUBLE_128__"); + if (HasTransactionalExecution) + Builder.defineMacro("__HTM__"); + if (Opts.ZVector) + Builder.defineMacro("__VEC__", "10301"); + } + void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const override { + Records = BuiltinInfo; + NumRecords = clang::SystemZ::LastTSBuiltin-Builtin::FirstTSBuiltin; + } + + void getGCCRegNames(const char *const *&Names, + unsigned &NumNames) const override; + void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const override { + // No aliases. + Aliases = nullptr; + NumAliases = 0; + } + 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; + } + bool setCPU(const std::string &Name) override { + CPU = Name; + bool CPUKnown = llvm::StringSwitch<bool>(Name) + .Case("z10", true) + .Case("z196", true) + .Case("zEC12", true) + .Case("z13", true) + .Default(false); + + return CPUKnown; + } + void getDefaultFeatures(llvm::StringMap<bool> &Features) const override { + if (CPU == "zEC12") + Features["transactional-execution"] = true; + if (CPU == "z13") { + Features["transactional-execution"] = true; + Features["vector"] = true; + } + } + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override { + HasTransactionalExecution = false; + for (unsigned i = 0, e = Features.size(); i != e; ++i) { + if (Features[i] == "+transactional-execution") + HasTransactionalExecution = true; + if (Features[i] == "+vector") + HasVector = true; + } + // If we use the vector ABI, vector types are 64-bit aligned. + if (HasVector) { + MaxVectorAlign = 64; + DescriptionString = "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 { + return llvm::StringSwitch<bool>(Feature) + .Case("systemz", true) + .Case("htm", HasTransactionalExecution) + .Case("vx", HasVector) + .Default(false); + } + + StringRef getABI() const override { + if (HasVector) + return "vector"; + return ""; + } + + bool useFloat128ManglingForLongDouble() const override { + return true; + } +}; + +const Builtin::Info SystemZTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, +#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" +}; + +void SystemZTargetInfo::getGCCRegNames(const char *const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); +} + +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 + 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; + } +} + + class MSP430TargetInfo : public TargetInfo { + static const char * const GCCRegNames[]; + public: + MSP430TargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { + BigEndian = false; + TLSSupported = false; + IntWidth = 16; IntAlign = 16; + LongWidth = 32; LongLongWidth = 64; + LongAlign = LongLongAlign = 16; + PointerWidth = 16; PointerAlign = 16; + SuitableAlign = 16; + SizeType = UnsignedInt; + IntMaxType = SignedLongLong; + IntPtrType = SignedInt; + PtrDiffType = SignedInt; + SigAtomicType = SignedLong; + DescriptionString = "e-m:e-p:16:16-i32:16:32-a:16-n8:16"; + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + Builder.defineMacro("MSP430"); + Builder.defineMacro("__MSP430__"); + // FIXME: defines for different 'flavours' of MCU + } + void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const override { + // FIXME: Implement. + Records = nullptr; + NumRecords = 0; + } + bool hasFeature(StringRef Feature) const override { + return Feature == "msp430"; + } + void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const override; + void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const override { + // No aliases. + Aliases = nullptr; + NumAliases = 0; + } + 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; + } + }; + + const char * const MSP430TargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" + }; + + void MSP430TargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); + } + + // 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[] = { + 3, // opencl_global + 4, // opencl_local + 5, // opencl_constant + // FIXME: generic has to be added to the target + 0, // opencl_generic + 0, // cuda_device + 0, // cuda_constant + 0 // cuda_shared + }; + + class TCETargetInfo : public TargetInfo{ + public: + TCETargetInfo(const llvm::Triple &Triple) : 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; + DescriptionString = "E-p:32:32-i8:8:32-i16:16:32-i64:32" + "-f64:32-v64:32-v128:32-a:0:32-n32"; + AddrSpaceMap = &TCEOpenCLAddrSpaceMap; + UseAddrSpaceMapMangling = true; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + DefineStd(Builder, "tce", Opts); + Builder.defineMacro("__TCE__"); + Builder.defineMacro("__TCE_V1__"); + } + bool hasFeature(StringRef Feature) const override { + return Feature == "tce"; + } + + void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const override {} + const char *getClobbers() const override { + return ""; + } + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const override {} + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override{ + return true; + } + void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const override {} + }; + +class BPFTargetInfo : public TargetInfo { +public: + BPFTargetInfo(const llvm::Triple &Triple) : 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) { + BigEndian = true; + DescriptionString = "E-m:e-p:64:64-i64:64-n32:64-S128"; + } else { + BigEndian = false; + DescriptionString = "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 { + DefineStd(Builder, "bpf", Opts); + Builder.defineMacro("__BPF__"); + } + bool hasFeature(StringRef Feature) const override { + return Feature == "bpf"; + } + + void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const override {} + const char *getClobbers() const override { + return ""; + } + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const override { + Names = nullptr; + NumNames = 0; + } + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override { + return true; + } + void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const override { + Aliases = nullptr; + NumAliases = 0; + } +}; + +class MipsTargetInfoBase : public TargetInfo { + virtual void setDescriptionString() = 0; + + static const Builtin::Info BuiltinInfo[]; + std::string CPU; + bool IsMips16; + bool IsMicromips; + bool IsNan2008; + bool IsSingleFloat; + enum MipsFloatABI { + HardFloat, SoftFloat + } FloatABI; + enum DspRevEnum { + NoDSP, DSP1, DSP2 + } DspRev; + bool HasMSA; + +protected: + bool HasFP64; + std::string ABI; + +public: + MipsTargetInfoBase(const llvm::Triple &Triple, const std::string &ABIStr, + const std::string &CPUStr) + : TargetInfo(Triple), CPU(CPUStr), IsMips16(false), IsMicromips(false), + IsNan2008(false), IsSingleFloat(false), FloatABI(HardFloat), + DspRev(NoDSP), HasMSA(false), HasFP64(false), ABI(ABIStr) { + TheCXXABI.set(TargetCXXABI::GenericMIPS); + } + + bool isNaN2008Default() const { + return CPU == "mips32r6" || CPU == "mips64r6"; + } + + bool isFP64Default() const { + return CPU == "mips32r6" || ABI == "n32" || ABI == "n64" || ABI == "64"; + } + + bool isNan2008() const override { + return IsNan2008; + } + + StringRef getABI() const override { return ABI; } + bool setCPU(const std::string &Name) override { + bool IsMips32 = getTriple().getArch() == llvm::Triple::mips || + getTriple().getArch() == llvm::Triple::mipsel; + CPU = Name; + return llvm::StringSwitch<bool>(Name) + .Case("mips1", IsMips32) + .Case("mips2", IsMips32) + .Case("mips3", true) + .Case("mips4", true) + .Case("mips5", true) + .Case("mips32", IsMips32) + .Case("mips32r2", IsMips32) + .Case("mips32r3", IsMips32) + .Case("mips32r5", IsMips32) + .Case("mips32r6", IsMips32) + .Case("mips64", true) + .Case("mips64r2", true) + .Case("mips64r3", true) + .Case("mips64r5", true) + .Case("mips64r6", true) + .Case("octeon", true) + .Default(false); + } + const std::string& getCPU() const { return CPU; } + void getDefaultFeatures(llvm::StringMap<bool> &Features) const override { + if (CPU == "octeon") + Features["mips64r2"] = Features["cnmips"] = true; + else + Features[CPU] = true; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + Builder.defineMacro("__mips__"); + Builder.defineMacro("_mips"); + if (Opts.GNUMode) + Builder.defineMacro("mips"); + + 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)); + + Builder.defineMacro("__mips_fpr", HasFP64 ? Twine(64) : Twine(32)); + Builder.defineMacro("_MIPS_FPSET", + Twine(32 / (HasFP64 || IsSingleFloat ? 1 : 2))); + + if (IsMips16) + Builder.defineMacro("__mips16", Twine(1)); + + if (IsMicromips) + Builder.defineMacro("__mips_micromips", Twine(1)); + + if (IsNan2008) + Builder.defineMacro("__mips_nan2008", 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)); + + Builder.defineMacro("_MIPS_SZPTR", Twine(getPointerWidth(0))); + Builder.defineMacro("_MIPS_SZINT", Twine(getIntWidth())); + Builder.defineMacro("_MIPS_SZLONG", Twine(getLongWidth())); + + Builder.defineMacro("_MIPS_ARCH", "\"" + CPU + "\""); + Builder.defineMacro("_MIPS_ARCH_" + StringRef(CPU).upper()); + } + + void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const override { + Records = BuiltinInfo; + NumRecords = clang::Mips::LastTSBuiltin - Builtin::FirstTSBuiltin; + } + bool hasFeature(StringRef Feature) const override { + return llvm::StringSwitch<bool>(Feature) + .Case("mips", true) + .Case("fp64", HasFP64) + .Default(false); + } + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) 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", + // 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" + }; + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); + } + void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const override = 0; + 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 = isNaN2008Default(); + IsSingleFloat = false; + FloatABI = HardFloat; + DspRev = NoDSP; + HasFP64 = isFP64Default(); + + for (std::vector<std::string>::iterator it = Features.begin(), + ie = Features.end(); it != ie; ++it) { + if (*it == "+single-float") + IsSingleFloat = true; + else if (*it == "+soft-float") + FloatABI = SoftFloat; + else if (*it == "+mips16") + IsMips16 = true; + else if (*it == "+micromips") + IsMicromips = true; + else if (*it == "+dsp") + DspRev = std::max(DspRev, DSP1); + else if (*it == "+dspr2") + DspRev = std::max(DspRev, DSP2); + else if (*it == "+msa") + HasMSA = true; + else if (*it == "+fp64") + HasFP64 = true; + else if (*it == "-fp64") + HasFP64 = false; + else if (*it == "+nan2008") + IsNan2008 = true; + else if (*it == "-nan2008") + IsNan2008 = false; + } + + setDescriptionString(); + + 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; } +}; + +const Builtin::Info MipsTargetInfoBase::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\ + ALL_LANGUAGES }, +#include "clang/Basic/BuiltinsMips.def" +}; + +class Mips32TargetInfoBase : public MipsTargetInfoBase { +public: + Mips32TargetInfoBase(const llvm::Triple &Triple) + : MipsTargetInfoBase(Triple, "o32", "mips32r2") { + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + Int64Type = SignedLongLong; + IntMaxType = Int64Type; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; + } + bool setABI(const std::string &Name) override { + if (Name == "o32" || Name == "eabi") { + ABI = Name; + return true; + } + return false; + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + MipsTargetInfoBase::getTargetDefines(Opts, Builder); + + Builder.defineMacro("__mips", "32"); + Builder.defineMacro("_MIPS_ISA", "_MIPS_ISA_MIPS32"); + + const std::string& CPUStr = getCPU(); + if (CPUStr == "mips32") + Builder.defineMacro("__mips_isa_rev", "1"); + else if (CPUStr == "mips32r2") + Builder.defineMacro("__mips_isa_rev", "2"); + else if (CPUStr == "mips32r3") + Builder.defineMacro("__mips_isa_rev", "3"); + else if (CPUStr == "mips32r5") + Builder.defineMacro("__mips_isa_rev", "5"); + else if (CPUStr == "mips32r6") + Builder.defineMacro("__mips_isa_rev", "6"); + + if (ABI == "o32") { + Builder.defineMacro("__mips_o32"); + Builder.defineMacro("_ABIO32", "1"); + Builder.defineMacro("_MIPS_SIM", "_ABIO32"); + } + else if (ABI == "eabi") + Builder.defineMacro("__mips_eabi"); + else + llvm_unreachable("Invalid ABI for Mips32."); + } + void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const override { + static const TargetInfo::GCCRegAlias GCCRegAliases[] = { + { { "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" } + }; + Aliases = GCCRegAliases; + NumAliases = llvm::array_lengthof(GCCRegAliases); + } +}; + +class Mips32EBTargetInfo : public Mips32TargetInfoBase { + void setDescriptionString() override { + DescriptionString = "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64"; + } + +public: + Mips32EBTargetInfo(const llvm::Triple &Triple) + : Mips32TargetInfoBase(Triple) { + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + DefineStd(Builder, "MIPSEB", Opts); + Builder.defineMacro("_MIPSEB"); + Mips32TargetInfoBase::getTargetDefines(Opts, Builder); + } +}; + +class Mips32ELTargetInfo : public Mips32TargetInfoBase { + void setDescriptionString() override { + DescriptionString = "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64"; + } + +public: + Mips32ELTargetInfo(const llvm::Triple &Triple) + : Mips32TargetInfoBase(Triple) { + BigEndian = false; + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + DefineStd(Builder, "MIPSEL", Opts); + Builder.defineMacro("_MIPSEL"); + Mips32TargetInfoBase::getTargetDefines(Opts, Builder); + } +}; + +class Mips64TargetInfoBase : public MipsTargetInfoBase { +public: + Mips64TargetInfoBase(const llvm::Triple &Triple) + : MipsTargetInfoBase(Triple, "n64", "mips64r2") { + LongDoubleWidth = LongDoubleAlign = 128; + LongDoubleFormat = &llvm::APFloat::IEEEquad; + if (getTriple().getOS() == llvm::Triple::FreeBSD) { + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble; + } + setN64ABITypes(); + SuitableAlign = 128; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + } + + void setN64ABITypes() { + LongWidth = LongAlign = 64; + PointerWidth = PointerAlign = 64; + SizeType = UnsignedLong; + PtrDiffType = SignedLong; + Int64Type = SignedLong; + IntMaxType = Int64Type; + } + + void setN32ABITypes() { + LongWidth = LongAlign = 32; + PointerWidth = PointerAlign = 32; + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + Int64Type = SignedLongLong; + IntMaxType = Int64Type; + } + + bool setABI(const std::string &Name) override { + if (Name == "n32") { + setN32ABITypes(); + ABI = Name; + return true; + } + if (Name == "n64") { + setN64ABITypes(); + ABI = Name; + return true; + } + return false; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + MipsTargetInfoBase::getTargetDefines(Opts, Builder); + + Builder.defineMacro("__mips", "64"); + Builder.defineMacro("__mips64"); + Builder.defineMacro("__mips64__"); + Builder.defineMacro("_MIPS_ISA", "_MIPS_ISA_MIPS64"); + + const std::string& CPUStr = getCPU(); + if (CPUStr == "mips64") + Builder.defineMacro("__mips_isa_rev", "1"); + else if (CPUStr == "mips64r2") + Builder.defineMacro("__mips_isa_rev", "2"); + else if (CPUStr == "mips64r3") + Builder.defineMacro("__mips_isa_rev", "3"); + else if (CPUStr == "mips64r5") + Builder.defineMacro("__mips_isa_rev", "5"); + else if (CPUStr == "mips64r6") + Builder.defineMacro("__mips_isa_rev", "6"); + + 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 for Mips64."); + } + void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const override { + static const TargetInfo::GCCRegAlias GCCRegAliases[] = { + { { "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" } + }; + Aliases = GCCRegAliases; + NumAliases = llvm::array_lengthof(GCCRegAliases); + } + + bool hasInt128Type() const override { return true; } +}; + +class Mips64EBTargetInfo : public Mips64TargetInfoBase { + void setDescriptionString() override { + if (ABI == "n32") + DescriptionString = "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32:64-S128"; + else + DescriptionString = "E-m:m-i8:8:32-i16:16:32-i64:64-n32:64-S128"; + + } + +public: + Mips64EBTargetInfo(const llvm::Triple &Triple) + : Mips64TargetInfoBase(Triple) {} + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + DefineStd(Builder, "MIPSEB", Opts); + Builder.defineMacro("_MIPSEB"); + Mips64TargetInfoBase::getTargetDefines(Opts, Builder); + } +}; + +class Mips64ELTargetInfo : public Mips64TargetInfoBase { + void setDescriptionString() override { + if (ABI == "n32") + DescriptionString = "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32:64-S128"; + else + DescriptionString = "e-m:m-i8:8:32-i16:16:32-i64:64-n32:64-S128"; + } +public: + Mips64ELTargetInfo(const llvm::Triple &Triple) + : Mips64TargetInfoBase(Triple) { + // Default ABI is n64. + BigEndian = false; + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + DefineStd(Builder, "MIPSEL", Opts); + Builder.defineMacro("_MIPSEL"); + Mips64TargetInfoBase::getTargetDefines(Opts, Builder); + } +}; + +class PNaClTargetInfo : public TargetInfo { +public: + PNaClTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { + BigEndian = false; + this->UserLabelPrefix = ""; + 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 getDefaultFeatures(llvm::StringMap<bool> &Features) const override { + } + void getArchDefines(const LangOptions &Opts, MacroBuilder &Builder) const { + Builder.defineMacro("__le32__"); + Builder.defineMacro("__pnacl__"); + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + getArchDefines(Opts, Builder); + } + bool hasFeature(StringRef Feature) const override { + return Feature == "pnacl"; + } + void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const override { + } + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::PNaClABIBuiltinVaList; + } + void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const override; + void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const override; + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + return false; + } + + const char *getClobbers() const override { + return ""; + } +}; + +void PNaClTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = nullptr; + NumNames = 0; +} + +void PNaClTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + Aliases = nullptr; + NumAliases = 0; +} + +// We attempt to use PNaCl (le32) frontend and Mips32EL backend. +class NaClMips32ELTargetInfo : public Mips32ELTargetInfo { +public: + NaClMips32ELTargetInfo(const llvm::Triple &Triple) : + Mips32ELTargetInfo(Triple) { + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 0; + } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::PNaClABIBuiltinVaList; + } +}; + +class Le64TargetInfo : public TargetInfo { + static const Builtin::Info BuiltinInfo[]; + +public: + Le64TargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { + BigEndian = false; + NoAsmVariants = true; + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + DescriptionString = + "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 { + DefineStd(Builder, "unix", Opts); + defineCPUMacros(Builder, "le64", /*Tuning=*/false); + Builder.defineMacro("__ELF__"); + } + void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const override { + Records = BuiltinInfo; + NumRecords = clang::Le64::LastTSBuiltin - Builtin::FirstTSBuiltin; + } + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::PNaClABIBuiltinVaList; + } + const char *getClobbers() const override { return ""; } + void getGCCRegNames(const char *const *&Names, + unsigned &NumNames) const override { + Names = nullptr; + NumNames = 0; + } + void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const override { + Aliases = nullptr; + NumAliases = 0; + } + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + return false; + } + + bool hasProtectedVisibility() const override { return false; } +}; +} // end anonymous namespace. + +const Builtin::Info Le64TargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, +#include "clang/Basic/BuiltinsLe64.def" +}; + +namespace { + static const unsigned SPIRAddrSpaceMap[] = { + 1, // opencl_global + 3, // opencl_local + 2, // opencl_constant + 4, // opencl_generic + 0, // cuda_device + 0, // cuda_constant + 0 // cuda_shared + }; + class SPIRTargetInfo : public TargetInfo { + public: + SPIRTargetInfo(const llvm::Triple &Triple) : 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"); + BigEndian = false; + TLSSupported = false; + LongWidth = LongAlign = 64; + AddrSpaceMap = &SPIRAddrSpaceMap; + UseAddrSpaceMapMangling = true; + // Define available target features + // These must be defined in sorted order! + NoAsmVariants = true; + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + DefineStd(Builder, "SPIR", Opts); + } + bool hasFeature(StringRef Feature) const override { + return Feature == "spir"; + } + + void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const override {} + const char *getClobbers() const override { + return ""; + } + void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const override {} + bool + validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override { + return true; + } + void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const override {} + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + return (CC == CC_SpirFunction || + CC == CC_SpirKernel) ? CCCR_OK : CCCR_Warning; + } + + CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override { + return CC_SpirFunction; + } + }; + + + class SPIR32TargetInfo : public SPIRTargetInfo { + public: + SPIR32TargetInfo(const llvm::Triple &Triple) : SPIRTargetInfo(Triple) { + PointerWidth = PointerAlign = 32; + SizeType = TargetInfo::UnsignedInt; + PtrDiffType = IntPtrType = TargetInfo::SignedInt; + DescriptionString + = "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 { + DefineStd(Builder, "SPIR32", Opts); + } + }; + + class SPIR64TargetInfo : public SPIRTargetInfo { + public: + SPIR64TargetInfo(const llvm::Triple &Triple) : SPIRTargetInfo(Triple) { + PointerWidth = PointerAlign = 64; + SizeType = TargetInfo::UnsignedLong; + PtrDiffType = IntPtrType = TargetInfo::SignedLong; + DescriptionString = "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 { + DefineStd(Builder, "SPIR64", Opts); + } + }; + +class XCoreTargetInfo : public TargetInfo { + static const Builtin::Info BuiltinInfo[]; +public: + XCoreTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { + BigEndian = false; + NoAsmVariants = true; + LongLongAlign = 32; + SuitableAlign = 32; + DoubleAlign = LongDoubleAlign = 32; + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + WCharType = UnsignedChar; + WIntType = UnsignedInt; + UseZeroLengthBitfieldAlignment = true; + DescriptionString = "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 { + Builder.defineMacro("__XS1B__"); + } + void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const override { + Records = BuiltinInfo; + NumRecords = clang::XCore::LastTSBuiltin-Builtin::FirstTSBuiltin; + } + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + const char *getClobbers() const override { + return ""; + } + void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const override { + static const char * const GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "cp", "dp", "sp", "lr" + }; + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); + } + void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const override { + Aliases = nullptr; + NumAliases = 0; + } + 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; + } +}; + +const Builtin::Info XCoreTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\ + ALL_LANGUAGES }, +#include "clang/Basic/BuiltinsXCore.def" +}; +} // end anonymous namespace. + +namespace { +// x86_32 Android target +class AndroidX86_32TargetInfo : public LinuxTargetInfo<X86_32TargetInfo> { +public: + AndroidX86_32TargetInfo(const llvm::Triple &Triple) + : LinuxTargetInfo<X86_32TargetInfo>(Triple) { + SuitableAlign = 32; + LongDoubleWidth = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble; + } +}; +} // end anonymous namespace + +namespace { +// x86_64 Android target +class AndroidX86_64TargetInfo : public LinuxTargetInfo<X86_64TargetInfo> { +public: + AndroidX86_64TargetInfo(const llvm::Triple &Triple) + : LinuxTargetInfo<X86_64TargetInfo>(Triple) { + LongDoubleFormat = &llvm::APFloat::IEEEquad; + } + + bool useFloat128ManglingForLongDouble() const override { + return true; + } +}; +} // end anonymous namespace + + +//===----------------------------------------------------------------------===// +// Driver code +//===----------------------------------------------------------------------===// + +static TargetInfo *AllocateTarget(const llvm::Triple &Triple) { + llvm::Triple::OSType os = Triple.getOS(); + + switch (Triple.getArch()) { + default: + return nullptr; + + case llvm::Triple::xcore: + return new XCoreTargetInfo(Triple); + + case llvm::Triple::hexagon: + return new HexagonTargetInfo(Triple); + + case llvm::Triple::aarch64: + if (Triple.isOSDarwin()) + return new DarwinAArch64TargetInfo(Triple); + + switch (os) { + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<AArch64leTargetInfo>(Triple); + case llvm::Triple::Linux: + return new LinuxTargetInfo<AArch64leTargetInfo>(Triple); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<AArch64leTargetInfo>(Triple); + default: + return new AArch64leTargetInfo(Triple); + } + + case llvm::Triple::aarch64_be: + switch (os) { + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<AArch64beTargetInfo>(Triple); + case llvm::Triple::Linux: + return new LinuxTargetInfo<AArch64beTargetInfo>(Triple); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<AArch64beTargetInfo>(Triple); + default: + return new AArch64beTargetInfo(Triple); + } + + case llvm::Triple::arm: + case llvm::Triple::thumb: + if (Triple.isOSBinFormatMachO()) + return new DarwinARMTargetInfo(Triple); + + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<ARMleTargetInfo>(Triple); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<ARMleTargetInfo>(Triple); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<ARMleTargetInfo>(Triple); + case llvm::Triple::OpenBSD: + return new OpenBSDTargetInfo<ARMleTargetInfo>(Triple); + case llvm::Triple::Bitrig: + return new BitrigTargetInfo<ARMleTargetInfo>(Triple); + case llvm::Triple::RTEMS: + return new RTEMSTargetInfo<ARMleTargetInfo>(Triple); + case llvm::Triple::NaCl: + return new NaClTargetInfo<ARMleTargetInfo>(Triple); + case llvm::Triple::Win32: + switch (Triple.getEnvironment()) { + case llvm::Triple::Itanium: + return new ItaniumWindowsARMleTargetInfo(Triple); + case llvm::Triple::MSVC: + default: // Assume MSVC for unknown environments + return new MicrosoftARMleTargetInfo(Triple); + } + default: + return new ARMleTargetInfo(Triple); + } + + case llvm::Triple::armeb: + case llvm::Triple::thumbeb: + if (Triple.isOSDarwin()) + return new DarwinARMTargetInfo(Triple); + + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<ARMbeTargetInfo>(Triple); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<ARMbeTargetInfo>(Triple); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<ARMbeTargetInfo>(Triple); + case llvm::Triple::OpenBSD: + return new OpenBSDTargetInfo<ARMbeTargetInfo>(Triple); + case llvm::Triple::Bitrig: + return new BitrigTargetInfo<ARMbeTargetInfo>(Triple); + case llvm::Triple::RTEMS: + return new RTEMSTargetInfo<ARMbeTargetInfo>(Triple); + case llvm::Triple::NaCl: + return new NaClTargetInfo<ARMbeTargetInfo>(Triple); + default: + return new ARMbeTargetInfo(Triple); + } + + case llvm::Triple::bpfeb: + case llvm::Triple::bpfel: + return new BPFTargetInfo(Triple); + + case llvm::Triple::msp430: + return new MSP430TargetInfo(Triple); + + case llvm::Triple::mips: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<Mips32EBTargetInfo>(Triple); + case llvm::Triple::RTEMS: + return new RTEMSTargetInfo<Mips32EBTargetInfo>(Triple); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<Mips32EBTargetInfo>(Triple); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<Mips32EBTargetInfo>(Triple); + default: + return new Mips32EBTargetInfo(Triple); + } + + case llvm::Triple::mipsel: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<Mips32ELTargetInfo>(Triple); + case llvm::Triple::RTEMS: + return new RTEMSTargetInfo<Mips32ELTargetInfo>(Triple); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<Mips32ELTargetInfo>(Triple); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<Mips32ELTargetInfo>(Triple); + case llvm::Triple::NaCl: + return new NaClTargetInfo<NaClMips32ELTargetInfo>(Triple); + default: + return new Mips32ELTargetInfo(Triple); + } + + case llvm::Triple::mips64: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<Mips64EBTargetInfo>(Triple); + case llvm::Triple::RTEMS: + return new RTEMSTargetInfo<Mips64EBTargetInfo>(Triple); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<Mips64EBTargetInfo>(Triple); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<Mips64EBTargetInfo>(Triple); + case llvm::Triple::OpenBSD: + return new OpenBSDTargetInfo<Mips64EBTargetInfo>(Triple); + default: + return new Mips64EBTargetInfo(Triple); + } + + case llvm::Triple::mips64el: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<Mips64ELTargetInfo>(Triple); + case llvm::Triple::RTEMS: + return new RTEMSTargetInfo<Mips64ELTargetInfo>(Triple); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<Mips64ELTargetInfo>(Triple); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<Mips64ELTargetInfo>(Triple); + case llvm::Triple::OpenBSD: + return new OpenBSDTargetInfo<Mips64ELTargetInfo>(Triple); + default: + return new Mips64ELTargetInfo(Triple); + } + + case llvm::Triple::le32: + switch (os) { + case llvm::Triple::NaCl: + return new NaClTargetInfo<PNaClTargetInfo>(Triple); + default: + return nullptr; + } + + case llvm::Triple::le64: + return new Le64TargetInfo(Triple); + + case llvm::Triple::ppc: + if (Triple.isOSDarwin()) + return new DarwinPPC32TargetInfo(Triple); + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<PPC32TargetInfo>(Triple); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<PPC32TargetInfo>(Triple); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<PPC32TargetInfo>(Triple); + case llvm::Triple::OpenBSD: + return new OpenBSDTargetInfo<PPC32TargetInfo>(Triple); + case llvm::Triple::RTEMS: + return new RTEMSTargetInfo<PPC32TargetInfo>(Triple); + default: + return new PPC32TargetInfo(Triple); + } + + case llvm::Triple::ppc64: + if (Triple.isOSDarwin()) + return new DarwinPPC64TargetInfo(Triple); + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<PPC64TargetInfo>(Triple); + case llvm::Triple::Lv2: + return new PS3PPUTargetInfo<PPC64TargetInfo>(Triple); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<PPC64TargetInfo>(Triple); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<PPC64TargetInfo>(Triple); + default: + return new PPC64TargetInfo(Triple); + } + + case llvm::Triple::ppc64le: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<PPC64TargetInfo>(Triple); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<PPC64TargetInfo>(Triple); + default: + return new PPC64TargetInfo(Triple); + } + + case llvm::Triple::nvptx: + return new NVPTX32TargetInfo(Triple); + case llvm::Triple::nvptx64: + return new NVPTX64TargetInfo(Triple); + + case llvm::Triple::amdgcn: + case llvm::Triple::r600: + return new AMDGPUTargetInfo(Triple); + + case llvm::Triple::sparc: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<SparcV8TargetInfo>(Triple); + case llvm::Triple::Solaris: + return new SolarisTargetInfo<SparcV8TargetInfo>(Triple); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<SparcV8TargetInfo>(Triple); + case llvm::Triple::OpenBSD: + return new OpenBSDTargetInfo<SparcV8TargetInfo>(Triple); + case llvm::Triple::RTEMS: + return new RTEMSTargetInfo<SparcV8TargetInfo>(Triple); + default: + return new SparcV8TargetInfo(Triple); + } + + // 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); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<SparcV8elTargetInfo>(Triple); + case llvm::Triple::OpenBSD: + return new OpenBSDTargetInfo<SparcV8elTargetInfo>(Triple); + case llvm::Triple::RTEMS: + return new RTEMSTargetInfo<SparcV8elTargetInfo>(Triple); + default: + return new SparcV8elTargetInfo(Triple); + } + + case llvm::Triple::sparcv9: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<SparcV9TargetInfo>(Triple); + case llvm::Triple::Solaris: + return new SolarisTargetInfo<SparcV9TargetInfo>(Triple); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<SparcV9TargetInfo>(Triple); + case llvm::Triple::OpenBSD: + return new OpenBSDTargetInfo<SparcV9TargetInfo>(Triple); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<SparcV9TargetInfo>(Triple); + default: + return new SparcV9TargetInfo(Triple); + } + + case llvm::Triple::systemz: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<SystemZTargetInfo>(Triple); + default: + return new SystemZTargetInfo(Triple); + } + + case llvm::Triple::tce: + return new TCETargetInfo(Triple); + + case llvm::Triple::x86: + if (Triple.isOSDarwin()) + return new DarwinI386TargetInfo(Triple); + + switch (os) { + case llvm::Triple::CloudABI: + return new CloudABITargetInfo<X86_32TargetInfo>(Triple); + case llvm::Triple::Linux: { + switch (Triple.getEnvironment()) { + default: + return new LinuxTargetInfo<X86_32TargetInfo>(Triple); + case llvm::Triple::Android: + return new AndroidX86_32TargetInfo(Triple); + } + } + case llvm::Triple::DragonFly: + return new DragonFlyBSDTargetInfo<X86_32TargetInfo>(Triple); + case llvm::Triple::NetBSD: + return new NetBSDI386TargetInfo(Triple); + case llvm::Triple::OpenBSD: + return new OpenBSDI386TargetInfo(Triple); + case llvm::Triple::Bitrig: + return new BitrigI386TargetInfo(Triple); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<X86_32TargetInfo>(Triple); + case llvm::Triple::KFreeBSD: + return new KFreeBSDTargetInfo<X86_32TargetInfo>(Triple); + case llvm::Triple::Minix: + return new MinixTargetInfo<X86_32TargetInfo>(Triple); + case llvm::Triple::Solaris: + return new SolarisTargetInfo<X86_32TargetInfo>(Triple); + case llvm::Triple::Win32: { + switch (Triple.getEnvironment()) { + case llvm::Triple::Cygnus: + return new CygwinX86_32TargetInfo(Triple); + case llvm::Triple::GNU: + return new MinGWX86_32TargetInfo(Triple); + case llvm::Triple::Itanium: + case llvm::Triple::MSVC: + default: // Assume MSVC for unknown environments + return new MicrosoftX86_32TargetInfo(Triple); + } + } + case llvm::Triple::Haiku: + return new HaikuX86_32TargetInfo(Triple); + case llvm::Triple::RTEMS: + return new RTEMSX86_32TargetInfo(Triple); + case llvm::Triple::NaCl: + return new NaClTargetInfo<X86_32TargetInfo>(Triple); + default: + return new X86_32TargetInfo(Triple); + } + + case llvm::Triple::x86_64: + if (Triple.isOSDarwin() || Triple.isOSBinFormatMachO()) + return new DarwinX86_64TargetInfo(Triple); + + switch (os) { + case llvm::Triple::CloudABI: + return new CloudABITargetInfo<X86_64TargetInfo>(Triple); + case llvm::Triple::Linux: { + switch (Triple.getEnvironment()) { + default: + return new LinuxTargetInfo<X86_64TargetInfo>(Triple); + case llvm::Triple::Android: + return new AndroidX86_64TargetInfo(Triple); + } + } + case llvm::Triple::DragonFly: + return new DragonFlyBSDTargetInfo<X86_64TargetInfo>(Triple); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<X86_64TargetInfo>(Triple); + case llvm::Triple::OpenBSD: + return new OpenBSDX86_64TargetInfo(Triple); + case llvm::Triple::Bitrig: + return new BitrigX86_64TargetInfo(Triple); + case llvm::Triple::FreeBSD: + return new FreeBSDTargetInfo<X86_64TargetInfo>(Triple); + case llvm::Triple::KFreeBSD: + return new KFreeBSDTargetInfo<X86_64TargetInfo>(Triple); + case llvm::Triple::Solaris: + return new SolarisTargetInfo<X86_64TargetInfo>(Triple); + case llvm::Triple::Win32: { + switch (Triple.getEnvironment()) { + case llvm::Triple::GNU: + return new MinGWX86_64TargetInfo(Triple); + case llvm::Triple::MSVC: + default: // Assume MSVC for unknown environments + return new MicrosoftX86_64TargetInfo(Triple); + } + } + case llvm::Triple::NaCl: + return new NaClTargetInfo<X86_64TargetInfo>(Triple); + case llvm::Triple::PS4: + return new PS4OSTargetInfo<X86_64TargetInfo>(Triple); + default: + return new X86_64TargetInfo(Triple); + } + + case llvm::Triple::spir: { + if (Triple.getOS() != llvm::Triple::UnknownOS || + Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) + return nullptr; + return new SPIR32TargetInfo(Triple); + } + case llvm::Triple::spir64: { + if (Triple.getOS() != llvm::Triple::UnknownOS || + Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) + return nullptr; + return new SPIR64TargetInfo(Triple); + } + } +} + +/// CreateTargetInfo - Return the target info object for the specified target +/// triple. +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)); + 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; + 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; + Target->getDefaultFeatures(Features); + + // Apply the user specified deltas. + for (unsigned I = 0, N = Opts->FeaturesAsWritten.size(); + I < N; ++I) { + const char *Name = Opts->FeaturesAsWritten[I].c_str(); + // Apply the feature via the target. + bool Enabled = Name[0] == '+'; + Target->setFeatureEnabled(Features, Name + 1, Enabled); + } + + // Add the features to the compile options. + // + // FIXME: If we are completely confident that we have the right set, we only + // need to pass the minuses. + Opts->Features.clear(); + for (llvm::StringMap<bool>::const_iterator it = Features.begin(), + ie = Features.end(); it != ie; ++it) + Opts->Features.push_back((it->second ? "+" : "-") + it->first().str()); + if (!Target->handleTargetFeatures(Opts->Features, Diags)) + return nullptr; + + return Target.release(); +} diff --git a/contrib/llvm/tools/clang/lib/Basic/TokenKinds.cpp b/contrib/llvm/tools/clang/lib/Basic/TokenKinds.cpp new file mode 100644 index 0000000..3b1f8fe --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/TokenKinds.cpp @@ -0,0 +1,48 @@ +//===--- TokenKinds.cpp - Token Kinds Support -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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/tools/clang/lib/Basic/Version.cpp b/contrib/llvm/tools/clang/lib/Basic/Version.cpp new file mode 100644 index 0000000..4b10dcd --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Version.cpp @@ -0,0 +1,153 @@ +//===- Version.cpp - Clang Version Number -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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_SVN_VERSION_INC +# include "SVNVersion.inc" +#endif + +namespace clang { + +std::string getClangRepositoryPath() { +#if defined(CLANG_REPOSITORY_STRING) + return CLANG_REPOSITORY_STRING; +#else +#ifdef SVN_REPOSITORY + StringRef URL(SVN_REPOSITORY); +#else + StringRef URL(""); +#endif + + // If the SVN_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_371/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 SVN_REVISION + return SVN_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(); + +#ifdef CLANG_VENDOR_SUFFIX + OS << CLANG_VENDOR_SUFFIX; +#elif defined(CLANG_VENDOR) + // If vendor supplied, include the base LLVM version as well. + 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/tools/clang/lib/Basic/VersionTuple.cpp b/contrib/llvm/tools/clang/lib/Basic/VersionTuple.cpp new file mode 100644 index 0000000..9c73fd9 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/VersionTuple.cpp @@ -0,0 +1,100 @@ +//===- VersionTuple.cpp - Version Number Handling ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the VersionTuple class, which represents a version in +// the form major[.minor[.subminor]]. +// +//===----------------------------------------------------------------------===// +#include "clang/Basic/VersionTuple.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +std::string VersionTuple::getAsString() const { + std::string Result; + { + llvm::raw_string_ostream Out(Result); + Out << *this; + } + return Result; +} + +raw_ostream& clang::operator<<(raw_ostream &Out, + const VersionTuple &V) { + Out << V.getMajor(); + if (Optional<unsigned> Minor = V.getMinor()) + Out << (V.usesUnderscores() ? '_' : '.') << *Minor; + if (Optional<unsigned> Subminor = V.getSubminor()) + Out << (V.usesUnderscores() ? '_' : '.') << *Subminor; + if (Optional<unsigned> Build = V.getBuild()) + Out << (V.usesUnderscores() ? '_' : '.') << *Build; + return Out; +} + +static bool parseInt(StringRef &input, unsigned &value) { + assert(value == 0); + if (input.empty()) return true; + + char next = input[0]; + input = input.substr(1); + if (next < '0' || next > '9') return true; + value = (unsigned) (next - '0'); + + while (!input.empty()) { + next = input[0]; + if (next < '0' || next > '9') return false; + input = input.substr(1); + value = value * 10 + (unsigned) (next - '0'); + } + + return false; +} + +bool VersionTuple::tryParse(StringRef input) { + unsigned major = 0, minor = 0, micro = 0, build = 0; + + // Parse the major version, [0-9]+ + if (parseInt(input, major)) return true; + + if (input.empty()) { + *this = VersionTuple(major); + return false; + } + + // If we're not done, parse the minor version, \.[0-9]+ + if (input[0] != '.') return true; + input = input.substr(1); + if (parseInt(input, minor)) return true; + + if (input.empty()) { + *this = VersionTuple(major, minor); + return false; + } + + // If we're not done, parse the micro version, \.[0-9]+ + if (input[0] != '.') return true; + input = input.substr(1); + if (parseInt(input, micro)) return true; + + if (input.empty()) { + *this = VersionTuple(major, minor, micro); + return false; + } + + // If we're not done, parse the micro version, \.[0-9]+ + if (input[0] != '.') return true; + input = input.substr(1); + if (parseInt(input, build)) return true; + + // If we have characters left over, it's an error. + if (!input.empty()) return true; + + *this = VersionTuple(major, minor, micro, build); + return false; +} diff --git a/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp b/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp new file mode 100644 index 0000000..a36102c --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp @@ -0,0 +1,1179 @@ +//===- VirtualFileSystem.cpp - Virtual File System Layer --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This file implements the VirtualFileSystem interface. +//===----------------------------------------------------------------------===// + +#include "clang/Basic/VirtualFileSystem.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/YAMLParser.h" +#include <atomic> +#include <memory> + +using namespace clang; +using namespace clang::vfs; +using namespace llvm; +using llvm::sys::fs::file_status; +using llvm::sys::fs::file_type; +using llvm::sys::fs::perms; +using llvm::sys::fs::UniqueID; + +Status::Status(const file_status &Status) + : UID(Status.getUniqueID()), MTime(Status.getLastModificationTime()), + User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()), + Type(Status.type()), Perms(Status.permissions()), IsVFSMapped(false) {} + +Status::Status(StringRef Name, StringRef ExternalName, UniqueID UID, + sys::TimeValue MTime, uint32_t User, uint32_t Group, + uint64_t Size, file_type Type, perms Perms) + : Name(Name), UID(UID), MTime(MTime), User(User), Group(Group), Size(Size), + Type(Type), Perms(Perms), IsVFSMapped(false) {} + +bool Status::equivalent(const Status &Other) const { + return getUniqueID() == Other.getUniqueID(); +} +bool Status::isDirectory() const { + return Type == file_type::directory_file; +} +bool Status::isRegularFile() const { + return Type == file_type::regular_file; +} +bool Status::isOther() const { + return exists() && !isRegularFile() && !isDirectory() && !isSymlink(); +} +bool Status::isSymlink() const { + return Type == file_type::symlink_file; +} +bool Status::isStatusKnown() const { + return Type != file_type::status_error; +} +bool Status::exists() const { + return isStatusKnown() && Type != file_type::file_not_found; +} + +File::~File() {} + +FileSystem::~FileSystem() {} + +ErrorOr<std::unique_ptr<MemoryBuffer>> +FileSystem::getBufferForFile(const llvm::Twine &Name, int64_t FileSize, + bool RequiresNullTerminator, bool IsVolatile) { + auto F = openFileForRead(Name); + if (!F) + return F.getError(); + + return (*F)->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile); +} + +//===-----------------------------------------------------------------------===/ +// RealFileSystem implementation +//===-----------------------------------------------------------------------===/ + +namespace { +/// \brief Wrapper around a raw file descriptor. +class RealFile : public File { + int FD; + Status S; + friend class RealFileSystem; + RealFile(int FD) : FD(FD) { + assert(FD >= 0 && "Invalid or inactive file descriptor"); + } + +public: + ~RealFile() override; + ErrorOr<Status> status() override; + ErrorOr<std::unique_ptr<MemoryBuffer>> + getBuffer(const Twine &Name, int64_t FileSize = -1, + bool RequiresNullTerminator = true, + bool IsVolatile = false) override; + std::error_code close() override; + void setName(StringRef Name) override; +}; +} // end anonymous namespace +RealFile::~RealFile() { close(); } + +ErrorOr<Status> RealFile::status() { + assert(FD != -1 && "cannot stat closed file"); + if (!S.isStatusKnown()) { + file_status RealStatus; + if (std::error_code EC = sys::fs::status(FD, RealStatus)) + return EC; + Status NewS(RealStatus); + NewS.setName(S.getName()); + S = std::move(NewS); + } + return S; +} + +ErrorOr<std::unique_ptr<MemoryBuffer>> +RealFile::getBuffer(const Twine &Name, int64_t FileSize, + bool RequiresNullTerminator, bool IsVolatile) { + assert(FD != -1 && "cannot get buffer for closed file"); + return MemoryBuffer::getOpenFile(FD, Name, FileSize, RequiresNullTerminator, + IsVolatile); +} + +// FIXME: This is terrible, we need this for ::close. +#if !defined(_MSC_VER) && !defined(__MINGW32__) +#include <unistd.h> +#include <sys/uio.h> +#else +#include <io.h> +#ifndef S_ISFIFO +#define S_ISFIFO(x) (0) +#endif +#endif +std::error_code RealFile::close() { + if (::close(FD)) + return std::error_code(errno, std::generic_category()); + FD = -1; + return std::error_code(); +} + +void RealFile::setName(StringRef Name) { + S.setName(Name); +} + +namespace { +/// \brief The file system according to your operating system. +class RealFileSystem : public FileSystem { +public: + ErrorOr<Status> status(const Twine &Path) override; + ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override; + directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override; +}; +} // end anonymous namespace + +ErrorOr<Status> RealFileSystem::status(const Twine &Path) { + sys::fs::file_status RealStatus; + if (std::error_code EC = sys::fs::status(Path, RealStatus)) + return EC; + Status Result(RealStatus); + Result.setName(Path.str()); + return Result; +} + +ErrorOr<std::unique_ptr<File>> +RealFileSystem::openFileForRead(const Twine &Name) { + int FD; + if (std::error_code EC = sys::fs::openFileForRead(Name, FD)) + return EC; + std::unique_ptr<File> Result(new RealFile(FD)); + Result->setName(Name.str()); + return std::move(Result); +} + +IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() { + static IntrusiveRefCntPtr<FileSystem> FS = new RealFileSystem(); + return FS; +} + +namespace { +class RealFSDirIter : public clang::vfs::detail::DirIterImpl { + std::string Path; + llvm::sys::fs::directory_iterator Iter; +public: + RealFSDirIter(const Twine &_Path, std::error_code &EC) + : Path(_Path.str()), Iter(Path, EC) { + if (!EC && Iter != llvm::sys::fs::directory_iterator()) { + llvm::sys::fs::file_status S; + EC = Iter->status(S); + if (!EC) { + CurrentEntry = Status(S); + CurrentEntry.setName(Iter->path()); + } + } + } + + std::error_code increment() override { + std::error_code EC; + Iter.increment(EC); + if (EC) { + return EC; + } else if (Iter == llvm::sys::fs::directory_iterator()) { + CurrentEntry = Status(); + } else { + llvm::sys::fs::file_status S; + EC = Iter->status(S); + CurrentEntry = Status(S); + CurrentEntry.setName(Iter->path()); + } + return EC; + } +}; +} + +directory_iterator RealFileSystem::dir_begin(const Twine &Dir, + std::error_code &EC) { + return directory_iterator(std::make_shared<RealFSDirIter>(Dir, EC)); +} + +//===-----------------------------------------------------------------------===/ +// OverlayFileSystem implementation +//===-----------------------------------------------------------------------===/ +OverlayFileSystem::OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> BaseFS) { + pushOverlay(BaseFS); +} + +void OverlayFileSystem::pushOverlay(IntrusiveRefCntPtr<FileSystem> FS) { + FSList.push_back(FS); +} + +ErrorOr<Status> OverlayFileSystem::status(const Twine &Path) { + // FIXME: handle symlinks that cross file systems + for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) { + ErrorOr<Status> Status = (*I)->status(Path); + if (Status || Status.getError() != llvm::errc::no_such_file_or_directory) + return Status; + } + return make_error_code(llvm::errc::no_such_file_or_directory); +} + +ErrorOr<std::unique_ptr<File>> +OverlayFileSystem::openFileForRead(const llvm::Twine &Path) { + // FIXME: handle symlinks that cross file systems + for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) { + auto Result = (*I)->openFileForRead(Path); + if (Result || Result.getError() != llvm::errc::no_such_file_or_directory) + return Result; + } + return make_error_code(llvm::errc::no_such_file_or_directory); +} + +clang::vfs::detail::DirIterImpl::~DirIterImpl() { } + +namespace { +class OverlayFSDirIterImpl : public clang::vfs::detail::DirIterImpl { + OverlayFileSystem &Overlays; + std::string Path; + OverlayFileSystem::iterator CurrentFS; + directory_iterator CurrentDirIter; + llvm::StringSet<> SeenNames; + + std::error_code incrementFS() { + assert(CurrentFS != Overlays.overlays_end() && "incrementing past end"); + ++CurrentFS; + for (auto E = Overlays.overlays_end(); CurrentFS != E; ++CurrentFS) { + std::error_code EC; + CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC); + if (EC && EC != errc::no_such_file_or_directory) + return EC; + if (CurrentDirIter != directory_iterator()) + break; // found + } + return std::error_code(); + } + + std::error_code incrementDirIter(bool IsFirstTime) { + assert((IsFirstTime || CurrentDirIter != directory_iterator()) && + "incrementing past end"); + std::error_code EC; + if (!IsFirstTime) + CurrentDirIter.increment(EC); + if (!EC && CurrentDirIter == directory_iterator()) + EC = incrementFS(); + return EC; + } + + std::error_code incrementImpl(bool IsFirstTime) { + while (true) { + std::error_code EC = incrementDirIter(IsFirstTime); + if (EC || CurrentDirIter == directory_iterator()) { + CurrentEntry = Status(); + return EC; + } + CurrentEntry = *CurrentDirIter; + StringRef Name = llvm::sys::path::filename(CurrentEntry.getName()); + if (SeenNames.insert(Name).second) + return EC; // name not seen before + } + llvm_unreachable("returned above"); + } + +public: + OverlayFSDirIterImpl(const Twine &Path, OverlayFileSystem &FS, + std::error_code &EC) + : Overlays(FS), Path(Path.str()), CurrentFS(Overlays.overlays_begin()) { + CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC); + EC = incrementImpl(true); + } + + std::error_code increment() override { return incrementImpl(false); } +}; +} // end anonymous namespace + +directory_iterator OverlayFileSystem::dir_begin(const Twine &Dir, + std::error_code &EC) { + return directory_iterator( + std::make_shared<OverlayFSDirIterImpl>(Dir, *this, EC)); +} + +//===-----------------------------------------------------------------------===/ +// VFSFromYAML implementation +//===-----------------------------------------------------------------------===/ + +namespace { + +enum EntryKind { + EK_Directory, + EK_File +}; + +/// \brief A single file or directory in the VFS. +class Entry { + EntryKind Kind; + std::string Name; + +public: + virtual ~Entry(); + Entry(EntryKind K, StringRef Name) : Kind(K), Name(Name) {} + StringRef getName() const { return Name; } + EntryKind getKind() const { return Kind; } +}; + +class DirectoryEntry : public Entry { + std::vector<Entry *> Contents; + Status S; + +public: + ~DirectoryEntry() override; + DirectoryEntry(StringRef Name, std::vector<Entry *> Contents, Status S) + : Entry(EK_Directory, Name), Contents(std::move(Contents)), + S(std::move(S)) {} + Status getStatus() { return S; } + typedef std::vector<Entry *>::iterator iterator; + iterator contents_begin() { return Contents.begin(); } + iterator contents_end() { return Contents.end(); } + static bool classof(const Entry *E) { return E->getKind() == EK_Directory; } +}; + +class FileEntry : public Entry { +public: + enum NameKind { + NK_NotSet, + NK_External, + NK_Virtual + }; +private: + std::string ExternalContentsPath; + NameKind UseName; +public: + FileEntry(StringRef Name, StringRef ExternalContentsPath, NameKind UseName) + : Entry(EK_File, Name), ExternalContentsPath(ExternalContentsPath), + UseName(UseName) {} + StringRef getExternalContentsPath() const { return ExternalContentsPath; } + /// \brief whether to use the external path as the name for this file. + bool useExternalName(bool GlobalUseExternalName) const { + return UseName == NK_NotSet ? GlobalUseExternalName + : (UseName == NK_External); + } + static bool classof(const Entry *E) { return E->getKind() == EK_File; } +}; + +class VFSFromYAML; + +class VFSFromYamlDirIterImpl : public clang::vfs::detail::DirIterImpl { + std::string Dir; + VFSFromYAML &FS; + DirectoryEntry::iterator Current, End; +public: + VFSFromYamlDirIterImpl(const Twine &Path, VFSFromYAML &FS, + DirectoryEntry::iterator Begin, + DirectoryEntry::iterator End, std::error_code &EC); + std::error_code increment() override; +}; + +/// \brief A virtual file system parsed from a YAML file. +/// +/// Currently, this class allows creating virtual directories and mapping +/// virtual file paths to existing external files, available in \c ExternalFS. +/// +/// The basic structure of the parsed file is: +/// \verbatim +/// { +/// 'version': <version number>, +/// <optional configuration> +/// 'roots': [ +/// <directory entries> +/// ] +/// } +/// \endverbatim +/// +/// All configuration options are optional. +/// 'case-sensitive': <boolean, default=true> +/// 'use-external-names': <boolean, default=true> +/// +/// Virtual directories are represented as +/// \verbatim +/// { +/// 'type': 'directory', +/// 'name': <string>, +/// 'contents': [ <file or directory entries> ] +/// } +/// \endverbatim +/// +/// The default attributes for virtual directories are: +/// \verbatim +/// MTime = now() when created +/// Perms = 0777 +/// User = Group = 0 +/// Size = 0 +/// UniqueID = unspecified unique value +/// \endverbatim +/// +/// Re-mapped files are represented as +/// \verbatim +/// { +/// 'type': 'file', +/// 'name': <string>, +/// 'use-external-name': <boolean> # Optional +/// 'external-contents': <path to external file>) +/// } +/// \endverbatim +/// +/// and inherit their attributes from the external contents. +/// +/// In both cases, the 'name' field may contain multiple path components (e.g. +/// /path/to/file). However, any directory that contains more than one child +/// must be uniquely represented by a directory entry. +class VFSFromYAML : public vfs::FileSystem { + std::vector<Entry *> Roots; ///< The root(s) of the virtual file system. + /// \brief The file system to use for external references. + IntrusiveRefCntPtr<FileSystem> ExternalFS; + + /// @name Configuration + /// @{ + + /// \brief Whether to perform case-sensitive comparisons. + /// + /// Currently, case-insensitive matching only works correctly with ASCII. + bool CaseSensitive; + + /// \brief Whether to use to use the value of 'external-contents' for the + /// names of files. This global value is overridable on a per-file basis. + bool UseExternalNames; + /// @} + + friend class VFSFromYAMLParser; + +private: + VFSFromYAML(IntrusiveRefCntPtr<FileSystem> ExternalFS) + : ExternalFS(ExternalFS), CaseSensitive(true), UseExternalNames(true) {} + + /// \brief Looks up \p Path in \c Roots. + ErrorOr<Entry *> lookupPath(const Twine &Path); + + /// \brief Looks up the path <tt>[Start, End)</tt> in \p From, possibly + /// recursing into the contents of \p From if it is a directory. + ErrorOr<Entry *> lookupPath(sys::path::const_iterator Start, + sys::path::const_iterator End, Entry *From); + + /// \brief Get the status of a given an \c Entry. + ErrorOr<Status> status(const Twine &Path, Entry *E); + +public: + ~VFSFromYAML() override; + + /// \brief Parses \p Buffer, which is expected to be in YAML format and + /// returns a virtual file system representing its contents. + static VFSFromYAML *create(std::unique_ptr<MemoryBuffer> Buffer, + SourceMgr::DiagHandlerTy DiagHandler, + void *DiagContext, + IntrusiveRefCntPtr<FileSystem> ExternalFS); + + ErrorOr<Status> status(const Twine &Path) override; + ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override; + + directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override{ + ErrorOr<Entry *> E = lookupPath(Dir); + if (!E) { + EC = E.getError(); + return directory_iterator(); + } + ErrorOr<Status> S = status(Dir, *E); + if (!S) { + EC = S.getError(); + return directory_iterator(); + } + if (!S->isDirectory()) { + EC = std::error_code(static_cast<int>(errc::not_a_directory), + std::system_category()); + return directory_iterator(); + } + + DirectoryEntry *D = cast<DirectoryEntry>(*E); + return directory_iterator(std::make_shared<VFSFromYamlDirIterImpl>(Dir, + *this, D->contents_begin(), D->contents_end(), EC)); + } +}; + +/// \brief A helper class to hold the common YAML parsing state. +class VFSFromYAMLParser { + yaml::Stream &Stream; + + void error(yaml::Node *N, const Twine &Msg) { + Stream.printError(N, Msg); + } + + // false on error + bool parseScalarString(yaml::Node *N, StringRef &Result, + SmallVectorImpl<char> &Storage) { + yaml::ScalarNode *S = dyn_cast<yaml::ScalarNode>(N); + if (!S) { + error(N, "expected string"); + return false; + } + Result = S->getValue(Storage); + return true; + } + + // false on error + bool parseScalarBool(yaml::Node *N, bool &Result) { + SmallString<5> Storage; + StringRef Value; + if (!parseScalarString(N, Value, Storage)) + return false; + + if (Value.equals_lower("true") || Value.equals_lower("on") || + Value.equals_lower("yes") || Value == "1") { + Result = true; + return true; + } else if (Value.equals_lower("false") || Value.equals_lower("off") || + Value.equals_lower("no") || Value == "0") { + Result = false; + return true; + } + + error(N, "expected boolean value"); + return false; + } + + struct KeyStatus { + KeyStatus(bool Required=false) : Required(Required), Seen(false) {} + bool Required; + bool Seen; + }; + typedef std::pair<StringRef, KeyStatus> KeyStatusPair; + + // false on error + bool checkDuplicateOrUnknownKey(yaml::Node *KeyNode, StringRef Key, + DenseMap<StringRef, KeyStatus> &Keys) { + if (!Keys.count(Key)) { + error(KeyNode, "unknown key"); + return false; + } + KeyStatus &S = Keys[Key]; + if (S.Seen) { + error(KeyNode, Twine("duplicate key '") + Key + "'"); + return false; + } + S.Seen = true; + return true; + } + + // false on error + bool checkMissingKeys(yaml::Node *Obj, DenseMap<StringRef, KeyStatus> &Keys) { + for (DenseMap<StringRef, KeyStatus>::iterator I = Keys.begin(), + E = Keys.end(); + I != E; ++I) { + if (I->second.Required && !I->second.Seen) { + error(Obj, Twine("missing key '") + I->first + "'"); + return false; + } + } + return true; + } + + Entry *parseEntry(yaml::Node *N) { + yaml::MappingNode *M = dyn_cast<yaml::MappingNode>(N); + if (!M) { + error(N, "expected mapping node for file or directory entry"); + return nullptr; + } + + KeyStatusPair Fields[] = { + KeyStatusPair("name", true), + KeyStatusPair("type", true), + KeyStatusPair("contents", false), + KeyStatusPair("external-contents", false), + KeyStatusPair("use-external-name", false), + }; + + DenseMap<StringRef, KeyStatus> Keys( + &Fields[0], Fields + sizeof(Fields)/sizeof(Fields[0])); + + bool HasContents = false; // external or otherwise + std::vector<Entry *> EntryArrayContents; + std::string ExternalContentsPath; + std::string Name; + FileEntry::NameKind UseExternalName = FileEntry::NK_NotSet; + EntryKind Kind; + + for (yaml::MappingNode::iterator I = M->begin(), E = M->end(); I != E; + ++I) { + StringRef Key; + // Reuse the buffer for key and value, since we don't look at key after + // parsing value. + SmallString<256> Buffer; + if (!parseScalarString(I->getKey(), Key, Buffer)) + return nullptr; + + if (!checkDuplicateOrUnknownKey(I->getKey(), Key, Keys)) + return nullptr; + + StringRef Value; + if (Key == "name") { + if (!parseScalarString(I->getValue(), Value, Buffer)) + return nullptr; + Name = Value; + } else if (Key == "type") { + if (!parseScalarString(I->getValue(), Value, Buffer)) + return nullptr; + if (Value == "file") + Kind = EK_File; + else if (Value == "directory") + Kind = EK_Directory; + else { + error(I->getValue(), "unknown value for 'type'"); + return nullptr; + } + } else if (Key == "contents") { + if (HasContents) { + error(I->getKey(), + "entry already has 'contents' or 'external-contents'"); + return nullptr; + } + HasContents = true; + yaml::SequenceNode *Contents = + dyn_cast<yaml::SequenceNode>(I->getValue()); + if (!Contents) { + // FIXME: this is only for directories, what about files? + error(I->getValue(), "expected array"); + return nullptr; + } + + for (yaml::SequenceNode::iterator I = Contents->begin(), + E = Contents->end(); + I != E; ++I) { + if (Entry *E = parseEntry(&*I)) + EntryArrayContents.push_back(E); + else + return nullptr; + } + } else if (Key == "external-contents") { + if (HasContents) { + error(I->getKey(), + "entry already has 'contents' or 'external-contents'"); + return nullptr; + } + HasContents = true; + if (!parseScalarString(I->getValue(), Value, Buffer)) + return nullptr; + ExternalContentsPath = Value; + } else if (Key == "use-external-name") { + bool Val; + if (!parseScalarBool(I->getValue(), Val)) + return nullptr; + UseExternalName = Val ? FileEntry::NK_External : FileEntry::NK_Virtual; + } else { + llvm_unreachable("key missing from Keys"); + } + } + + if (Stream.failed()) + return nullptr; + + // check for missing keys + if (!HasContents) { + error(N, "missing key 'contents' or 'external-contents'"); + return nullptr; + } + if (!checkMissingKeys(N, Keys)) + return nullptr; + + // check invalid configuration + if (Kind == EK_Directory && UseExternalName != FileEntry::NK_NotSet) { + error(N, "'use-external-name' is not supported for directories"); + return nullptr; + } + + // Remove trailing slash(es), being careful not to remove the root path + StringRef Trimmed(Name); + size_t RootPathLen = sys::path::root_path(Trimmed).size(); + while (Trimmed.size() > RootPathLen && + sys::path::is_separator(Trimmed.back())) + Trimmed = Trimmed.slice(0, Trimmed.size()-1); + // Get the last component + StringRef LastComponent = sys::path::filename(Trimmed); + + Entry *Result = nullptr; + switch (Kind) { + case EK_File: + Result = new FileEntry(LastComponent, std::move(ExternalContentsPath), + UseExternalName); + break; + case EK_Directory: + Result = new DirectoryEntry(LastComponent, std::move(EntryArrayContents), + Status("", "", getNextVirtualUniqueID(), sys::TimeValue::now(), 0, 0, + 0, file_type::directory_file, sys::fs::all_all)); + break; + } + + StringRef Parent = sys::path::parent_path(Trimmed); + if (Parent.empty()) + return Result; + + // if 'name' contains multiple components, create implicit directory entries + for (sys::path::reverse_iterator I = sys::path::rbegin(Parent), + E = sys::path::rend(Parent); + I != E; ++I) { + Result = new DirectoryEntry(*I, llvm::makeArrayRef(Result), + Status("", "", getNextVirtualUniqueID(), sys::TimeValue::now(), 0, 0, + 0, file_type::directory_file, sys::fs::all_all)); + } + return Result; + } + +public: + VFSFromYAMLParser(yaml::Stream &S) : Stream(S) {} + + // false on error + bool parse(yaml::Node *Root, VFSFromYAML *FS) { + yaml::MappingNode *Top = dyn_cast<yaml::MappingNode>(Root); + if (!Top) { + error(Root, "expected mapping node"); + return false; + } + + KeyStatusPair Fields[] = { + KeyStatusPair("version", true), + KeyStatusPair("case-sensitive", false), + KeyStatusPair("use-external-names", false), + KeyStatusPair("roots", true), + }; + + DenseMap<StringRef, KeyStatus> Keys( + &Fields[0], Fields + sizeof(Fields)/sizeof(Fields[0])); + + // Parse configuration and 'roots' + for (yaml::MappingNode::iterator I = Top->begin(), E = Top->end(); I != E; + ++I) { + SmallString<10> KeyBuffer; + StringRef Key; + if (!parseScalarString(I->getKey(), Key, KeyBuffer)) + return false; + + if (!checkDuplicateOrUnknownKey(I->getKey(), Key, Keys)) + return false; + + if (Key == "roots") { + yaml::SequenceNode *Roots = dyn_cast<yaml::SequenceNode>(I->getValue()); + if (!Roots) { + error(I->getValue(), "expected array"); + return false; + } + + for (yaml::SequenceNode::iterator I = Roots->begin(), E = Roots->end(); + I != E; ++I) { + if (Entry *E = parseEntry(&*I)) + FS->Roots.push_back(E); + else + return false; + } + } else if (Key == "version") { + StringRef VersionString; + SmallString<4> Storage; + if (!parseScalarString(I->getValue(), VersionString, Storage)) + return false; + int Version; + if (VersionString.getAsInteger<int>(10, Version)) { + error(I->getValue(), "expected integer"); + return false; + } + if (Version < 0) { + error(I->getValue(), "invalid version number"); + return false; + } + if (Version != 0) { + error(I->getValue(), "version mismatch, expected 0"); + return false; + } + } else if (Key == "case-sensitive") { + if (!parseScalarBool(I->getValue(), FS->CaseSensitive)) + return false; + } else if (Key == "use-external-names") { + if (!parseScalarBool(I->getValue(), FS->UseExternalNames)) + return false; + } else { + llvm_unreachable("key missing from Keys"); + } + } + + if (Stream.failed()) + return false; + + if (!checkMissingKeys(Top, Keys)) + return false; + return true; + } +}; +} // end of anonymous namespace + +Entry::~Entry() {} +DirectoryEntry::~DirectoryEntry() { llvm::DeleteContainerPointers(Contents); } + +VFSFromYAML::~VFSFromYAML() { llvm::DeleteContainerPointers(Roots); } + +VFSFromYAML *VFSFromYAML::create(std::unique_ptr<MemoryBuffer> Buffer, + SourceMgr::DiagHandlerTy DiagHandler, + void *DiagContext, + IntrusiveRefCntPtr<FileSystem> ExternalFS) { + + SourceMgr SM; + yaml::Stream Stream(Buffer->getMemBufferRef(), SM); + + SM.setDiagHandler(DiagHandler, DiagContext); + yaml::document_iterator DI = Stream.begin(); + yaml::Node *Root = DI->getRoot(); + if (DI == Stream.end() || !Root) { + SM.PrintMessage(SMLoc(), SourceMgr::DK_Error, "expected root node"); + return nullptr; + } + + VFSFromYAMLParser P(Stream); + + std::unique_ptr<VFSFromYAML> FS(new VFSFromYAML(ExternalFS)); + if (!P.parse(Root, FS.get())) + return nullptr; + + return FS.release(); +} + +ErrorOr<Entry *> VFSFromYAML::lookupPath(const Twine &Path_) { + SmallString<256> Path; + Path_.toVector(Path); + + // Handle relative paths + if (std::error_code EC = sys::fs::make_absolute(Path)) + return EC; + + if (Path.empty()) + return make_error_code(llvm::errc::invalid_argument); + + sys::path::const_iterator Start = sys::path::begin(Path); + sys::path::const_iterator End = sys::path::end(Path); + for (std::vector<Entry *>::iterator I = Roots.begin(), E = Roots.end(); + I != E; ++I) { + ErrorOr<Entry *> Result = lookupPath(Start, End, *I); + if (Result || Result.getError() != llvm::errc::no_such_file_or_directory) + return Result; + } + return make_error_code(llvm::errc::no_such_file_or_directory); +} + +ErrorOr<Entry *> VFSFromYAML::lookupPath(sys::path::const_iterator Start, + sys::path::const_iterator End, + Entry *From) { + if (Start->equals(".")) + ++Start; + + // FIXME: handle .. + if (CaseSensitive ? !Start->equals(From->getName()) + : !Start->equals_lower(From->getName())) + // failure to match + return make_error_code(llvm::errc::no_such_file_or_directory); + + ++Start; + + if (Start == End) { + // Match! + return From; + } + + DirectoryEntry *DE = dyn_cast<DirectoryEntry>(From); + if (!DE) + return make_error_code(llvm::errc::not_a_directory); + + for (DirectoryEntry::iterator I = DE->contents_begin(), + E = DE->contents_end(); + I != E; ++I) { + ErrorOr<Entry *> Result = lookupPath(Start, End, *I); + if (Result || Result.getError() != llvm::errc::no_such_file_or_directory) + return Result; + } + return make_error_code(llvm::errc::no_such_file_or_directory); +} + +ErrorOr<Status> VFSFromYAML::status(const Twine &Path, Entry *E) { + assert(E != nullptr); + std::string PathStr(Path.str()); + if (FileEntry *F = dyn_cast<FileEntry>(E)) { + ErrorOr<Status> S = ExternalFS->status(F->getExternalContentsPath()); + assert(!S || S->getName() == F->getExternalContentsPath()); + if (S && !F->useExternalName(UseExternalNames)) + S->setName(PathStr); + if (S) + S->IsVFSMapped = true; + return S; + } else { // directory + DirectoryEntry *DE = cast<DirectoryEntry>(E); + Status S = DE->getStatus(); + S.setName(PathStr); + return S; + } +} + +ErrorOr<Status> VFSFromYAML::status(const Twine &Path) { + ErrorOr<Entry *> Result = lookupPath(Path); + if (!Result) + return Result.getError(); + return status(Path, *Result); +} + +ErrorOr<std::unique_ptr<File>> VFSFromYAML::openFileForRead(const Twine &Path) { + ErrorOr<Entry *> E = lookupPath(Path); + if (!E) + return E.getError(); + + FileEntry *F = dyn_cast<FileEntry>(*E); + if (!F) // FIXME: errc::not_a_file? + return make_error_code(llvm::errc::invalid_argument); + + auto Result = ExternalFS->openFileForRead(F->getExternalContentsPath()); + if (!Result) + return Result; + + if (!F->useExternalName(UseExternalNames)) + (*Result)->setName(Path.str()); + + return Result; +} + +IntrusiveRefCntPtr<FileSystem> +vfs::getVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer, + SourceMgr::DiagHandlerTy DiagHandler, void *DiagContext, + IntrusiveRefCntPtr<FileSystem> ExternalFS) { + return VFSFromYAML::create(std::move(Buffer), DiagHandler, DiagContext, + ExternalFS); +} + +UniqueID vfs::getNextVirtualUniqueID() { + static std::atomic<unsigned> UID; + unsigned ID = ++UID; + // The following assumes that uint64_t max will never collide with a real + // dev_t value from the OS. + return UniqueID(std::numeric_limits<uint64_t>::max(), ID); +} + +#ifndef NDEBUG +static bool pathHasTraversal(StringRef Path) { + using namespace llvm::sys; + for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path))) + if (Comp == "." || Comp == "..") + return true; + return false; +} +#endif + +void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) { + assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute"); + assert(sys::path::is_absolute(RealPath) && "real path not absolute"); + assert(!pathHasTraversal(VirtualPath) && "path traversal is not supported"); + Mappings.emplace_back(VirtualPath, RealPath); +} + +namespace { +class JSONWriter { + llvm::raw_ostream &OS; + SmallVector<StringRef, 16> DirStack; + inline unsigned getDirIndent() { return 4 * DirStack.size(); } + inline unsigned getFileIndent() { return 4 * (DirStack.size() + 1); } + bool containedIn(StringRef Parent, StringRef Path); + StringRef containedPart(StringRef Parent, StringRef Path); + void startDirectory(StringRef Path); + void endDirectory(); + void writeEntry(StringRef VPath, StringRef RPath); + +public: + JSONWriter(llvm::raw_ostream &OS) : OS(OS) {} + void write(ArrayRef<YAMLVFSEntry> Entries, Optional<bool> IsCaseSensitive); +}; +} + +bool JSONWriter::containedIn(StringRef Parent, StringRef Path) { + using namespace llvm::sys; + // Compare each path component. + auto IParent = path::begin(Parent), EParent = path::end(Parent); + for (auto IChild = path::begin(Path), EChild = path::end(Path); + IParent != EParent && IChild != EChild; ++IParent, ++IChild) { + if (*IParent != *IChild) + return false; + } + // Have we exhausted the parent path? + return IParent == EParent; +} + +StringRef JSONWriter::containedPart(StringRef Parent, StringRef Path) { + assert(!Parent.empty()); + assert(containedIn(Parent, Path)); + return Path.slice(Parent.size() + 1, StringRef::npos); +} + +void JSONWriter::startDirectory(StringRef Path) { + StringRef Name = + DirStack.empty() ? Path : containedPart(DirStack.back(), Path); + DirStack.push_back(Path); + unsigned Indent = getDirIndent(); + OS.indent(Indent) << "{\n"; + OS.indent(Indent + 2) << "'type': 'directory',\n"; + OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(Name) << "\",\n"; + OS.indent(Indent + 2) << "'contents': [\n"; +} + +void JSONWriter::endDirectory() { + unsigned Indent = getDirIndent(); + OS.indent(Indent + 2) << "]\n"; + OS.indent(Indent) << "}"; + + DirStack.pop_back(); +} + +void JSONWriter::writeEntry(StringRef VPath, StringRef RPath) { + unsigned Indent = getFileIndent(); + OS.indent(Indent) << "{\n"; + OS.indent(Indent + 2) << "'type': 'file',\n"; + OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(VPath) << "\",\n"; + OS.indent(Indent + 2) << "'external-contents': \"" + << llvm::yaml::escape(RPath) << "\"\n"; + OS.indent(Indent) << "}"; +} + +void JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries, + Optional<bool> IsCaseSensitive) { + using namespace llvm::sys; + + OS << "{\n" + " 'version': 0,\n"; + if (IsCaseSensitive.hasValue()) + OS << " 'case-sensitive': '" + << (IsCaseSensitive.getValue() ? "true" : "false") << "',\n"; + OS << " 'roots': [\n"; + + if (!Entries.empty()) { + const YAMLVFSEntry &Entry = Entries.front(); + startDirectory(path::parent_path(Entry.VPath)); + writeEntry(path::filename(Entry.VPath), Entry.RPath); + + for (const auto &Entry : Entries.slice(1)) { + StringRef Dir = path::parent_path(Entry.VPath); + if (Dir == DirStack.back()) + OS << ",\n"; + else { + while (!DirStack.empty() && !containedIn(DirStack.back(), Dir)) { + OS << "\n"; + endDirectory(); + } + OS << ",\n"; + startDirectory(Dir); + } + writeEntry(path::filename(Entry.VPath), Entry.RPath); + } + + while (!DirStack.empty()) { + OS << "\n"; + endDirectory(); + } + OS << "\n"; + } + + OS << " ]\n" + << "}\n"; +} + +void YAMLVFSWriter::write(llvm::raw_ostream &OS) { + std::sort(Mappings.begin(), Mappings.end(), + [](const YAMLVFSEntry &LHS, const YAMLVFSEntry &RHS) { + return LHS.VPath < RHS.VPath; + }); + + JSONWriter(OS).write(Mappings, IsCaseSensitive); +} + +VFSFromYamlDirIterImpl::VFSFromYamlDirIterImpl(const Twine &_Path, + VFSFromYAML &FS, + DirectoryEntry::iterator Begin, + DirectoryEntry::iterator End, + std::error_code &EC) + : Dir(_Path.str()), FS(FS), Current(Begin), End(End) { + if (Current != End) { + SmallString<128> PathStr(Dir); + llvm::sys::path::append(PathStr, (*Current)->getName()); + llvm::ErrorOr<vfs::Status> S = FS.status(PathStr); + if (S) + CurrentEntry = *S; + else + EC = S.getError(); + } +} + +std::error_code VFSFromYamlDirIterImpl::increment() { + assert(Current != End && "cannot iterate past end"); + if (++Current != End) { + SmallString<128> PathStr(Dir); + llvm::sys::path::append(PathStr, (*Current)->getName()); + llvm::ErrorOr<vfs::Status> S = FS.status(PathStr); + if (!S) + return S.getError(); + CurrentEntry = *S; + } else { + CurrentEntry = Status(); + } + return std::error_code(); +} + +vfs::recursive_directory_iterator::recursive_directory_iterator(FileSystem &FS_, + const Twine &Path, + std::error_code &EC) + : FS(&FS_) { + directory_iterator I = FS->dir_begin(Path, EC); + if (!EC && I != directory_iterator()) { + State = std::make_shared<IterState>(); + State->push(I); + } +} + +vfs::recursive_directory_iterator & +recursive_directory_iterator::increment(std::error_code &EC) { + assert(FS && State && !State->empty() && "incrementing past end"); + assert(State->top()->isStatusKnown() && "non-canonical end iterator"); + vfs::directory_iterator End; + if (State->top()->isDirectory()) { + vfs::directory_iterator I = FS->dir_begin(State->top()->getName(), EC); + if (EC) + return *this; + if (I != End) { + State->push(I); + return *this; + } + } + + while (!State->empty() && State->top().increment(EC) == End) + State->pop(); + + if (State->empty()) + State.reset(); // end iterator + + return *this; +} diff --git a/contrib/llvm/tools/clang/lib/Basic/Warnings.cpp b/contrib/llvm/tools/clang/lib/Basic/Warnings.cpp new file mode 100644 index 0000000..6306cea --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Basic/Warnings.cpp @@ -0,0 +1,230 @@ +//===--- Warnings.cpp - C-Language Front-end ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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); + } + } + } +} |