diff options
author | dim <dim@FreeBSD.org> | 2015-12-30 13:34:49 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2015-12-30 13:34:49 +0000 |
commit | 63b24cc778504ffd19e4c30a730e574c346312ee (patch) | |
tree | 28726ef2038e86121e353aabf52297b35a48efa2 /contrib/llvm/tools/clang/lib/Basic | |
parent | 9b5bf5c4f53d65d6a48722d7410ed7cb15f5ba3a (diff) | |
parent | 3176e97f130184ece0e1a21352c8124cc83ff24a (diff) | |
download | FreeBSD-src-63b24cc778504ffd19e4c30a730e574c346312ee.zip FreeBSD-src-63b24cc778504ffd19e4c30a730e574c346312ee.tar.gz |
Update clang to trunk r256633.
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Basic')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/Attributes.cpp | 4 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/Builtins.cpp | 86 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp | 24 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp | 38 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/FileManager.cpp | 92 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp | 9 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/Module.cpp | 20 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/ObjCRuntime.cpp | 3 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/OpenMPKinds.cpp | 168 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/SanitizerBlacklist.cpp | 2 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp | 97 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp | 144 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/Targets.cpp | 3323 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/Version.cpp | 2 | ||||
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp | 631 |
15 files changed, 2840 insertions, 1803 deletions
diff --git a/contrib/llvm/tools/clang/lib/Basic/Attributes.cpp b/contrib/llvm/tools/clang/lib/Basic/Attributes.cpp index da9ac79..c215366 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Attributes.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Attributes.cpp @@ -4,8 +4,8 @@ using namespace clang; int clang::hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope, - const IdentifierInfo *Attr, const llvm::Triple &T, - const LangOptions &LangOpts) { + const IdentifierInfo *Attr, const TargetInfo &Target, + const LangOptions &LangOpts) { StringRef Name = Attr->getName(); // Normalize the attribute name, __foo__ becomes foo. if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__")) diff --git a/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp b/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp index 8efcac6..69b10c1 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Builtins.cpp @@ -15,86 +15,78 @@ #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 }, + { "not a builtin function", nullptr, nullptr, nullptr, ALL_LANGUAGES,nullptr}, +#define BUILTIN(ID, TYPE, ATTRS) \ + { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, +#define LANGBUILTIN(ID, TYPE, ATTRS, LANGS) \ + { #ID, TYPE, ATTRS, nullptr, LANGS, nullptr }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, LANGS) \ + { #ID, TYPE, ATTRS, HEADER, LANGS, nullptr }, #include "clang/Basic/Builtins.def" }; -const Builtin::Info &Builtin::Context::GetRecord(unsigned ID) const { +const Builtin::Info &Builtin::Context::getRecord(unsigned ID) const { if (ID < Builtin::FirstTSBuiltin) return BuiltinInfo[ID]; - assert(ID - Builtin::FirstTSBuiltin < NumTSRecords && "Invalid builtin ID!"); + assert(((ID - Builtin::FirstTSBuiltin) < + (TSRecords.size() + AuxTSRecords.size())) && + "Invalid builtin ID!"); + if (isAuxBuiltinID(ID)) + return AuxTSRecords[getAuxBuiltinID(ID) - Builtin::FirstTSBuiltin]; return TSRecords[ID - Builtin::FirstTSBuiltin]; } -Builtin::Context::Context() { - // Get the target specific builtins from the target. - TSRecords = nullptr; - NumTSRecords = 0; +void Builtin::Context::InitializeTarget(const TargetInfo &Target, + const TargetInfo *AuxTarget) { + assert(TSRecords.empty() && "Already initialized target?"); + TSRecords = Target.getTargetBuiltins(); + if (AuxTarget) + AuxTSRecords = AuxTarget->getTargetBuiltins(); } -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, +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 && + 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; + bool GnuModeUnsupported = !LangOpts.GNUMode && (BuiltinInfo.Langs & GNU_LANG); + bool MSModeUnsupported = + !LangOpts.MicrosoftExt && (BuiltinInfo.Langs & MS_LANG); + bool ObjCUnsupported = !LangOpts.ObjC1 && BuiltinInfo.Langs == OBJC_LANG; return !BuiltinsUnsupported && !MathBuiltinsUnsupported && !GnuModeUnsupported && !MSModeUnsupported && !ObjCUnsupported; } -/// InitializeBuiltins - Mark the identifiers for all the builtins with their +/// 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, +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)) { + 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); + for (unsigned i = 0, e = TSRecords.size(); i != e; ++i) + if (builtinIsSupported(TSRecords[i], LangOpts)) + Table.get(TSRecords[i].Name).setBuiltinID(i + Builtin::FirstTSBuiltin); + + // Step #3: Register target-specific builtins for AuxTarget. + for (unsigned i = 0, e = AuxTSRecords.size(); i != e; ++i) + Table.get(AuxTSRecords[i].Name) + .setBuiltinID(i + Builtin::FirstTSBuiltin + TSRecords.size()); } -void Builtin::Context::ForgetBuiltin(unsigned ID, IdentifierTable &Table) { - Table.get(GetRecord(ID).Name).setBuiltinID(0); +void Builtin::Context::forgetBuiltin(unsigned ID, IdentifierTable &Table) { + Table.get(getRecord(ID).Name).setBuiltinID(0); } bool Builtin::Context::isLike(unsigned ID, unsigned &FormatIdx, @@ -105,7 +97,7 @@ bool Builtin::Context::isLike(unsigned ID, unsigned &FormatIdx, assert(::toupper(Fmt[0]) == Fmt[1] && "Format string is not in the form \"xX\""); - const char *Like = ::strpbrk(GetRecord(ID).Attributes, Fmt); + const char *Like = ::strpbrk(getRecord(ID).Attributes, Fmt); if (!Like) return false; diff --git a/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp b/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp index f89caf7..7cf7305 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp @@ -226,12 +226,12 @@ void DiagnosticsEngine::setSeverity(diag::kind Diag, diag::Severity Map, // 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); + I->State->setMapping(Diag, Mapping); } // If the location corresponds to an existing point, just update its state. if (Pos->Loc == Loc) { - GetCurDiagState()->setMapping(Diag, Mapping); + Pos->State->setMapping(Diag, Mapping); return; } @@ -240,7 +240,7 @@ void DiagnosticsEngine::setSeverity(diag::kind Diag, diag::Severity Map, assert(Pos->Loc.isBeforeInTranslationUnitThan(Loc)); DiagStates.push_back(*Pos->State); DiagState *NewState = &DiagStates.back(); - GetCurDiagState()->setMapping(Diag, Mapping); + NewState->setMapping(Diag, Mapping); DiagStatePoints.insert(Pos+1, DiagStatePoint(NewState, FullSourceLoc(Loc, *SourceMgr))); } @@ -278,8 +278,8 @@ bool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group, return true; // Perform the mapping change. - for (unsigned i = 0, e = GroupDiags.size(); i != e; ++i) { - DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(GroupDiags[i]); + for (diag::kind Diag : GroupDiags) { + DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag); if (Info.getSeverity() == diag::Severity::Error || Info.getSeverity() == diag::Severity::Fatal) @@ -309,8 +309,8 @@ bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group, return true; // Perform the mapping change. - for (unsigned i = 0, e = GroupDiags.size(); i != e; ++i) { - DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(GroupDiags[i]); + for (diag::kind Diag : GroupDiags) { + DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag); if (Info.getSeverity() == diag::Severity::Fatal) Info.setSeverity(diag::Severity::Error); @@ -329,9 +329,9 @@ void DiagnosticsEngine::setSeverityForAll(diag::Flavor Flavor, 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); + for (diag::kind Diag : AllDiags) + if (Diags->isBuiltinWarningOrExtension(Diag)) + setSeverity(Diag, Map, Loc); } void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) { @@ -945,8 +945,6 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd, OutStr.append(Tree.begin(), Tree.end()); } -StoredDiagnostic::StoredDiagnostic() { } - StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, StringRef Message) : ID(ID), Level(Level), Loc(), Message(Message) { } @@ -975,8 +973,6 @@ StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, { } -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 diff --git a/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp b/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp index 643503b..a34c7fec 100644 --- a/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp @@ -100,14 +100,10 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) { #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"); - } + assert(std::is_sorted(std::begin(StaticDiagInfo), + std::end(StaticDiagInfo)) && + "Diag ID conflict, the enums at the start of clang::diag (in " + "DiagnosticIDs.h) probably need to be increased"); IsFirst = false; } #endif @@ -505,11 +501,6 @@ static const WarningOption OptionTable[] = { #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 @@ -553,10 +544,12 @@ static bool getDiagnosticsInGroup(diag::Flavor Flavor, 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) + auto Found = std::lower_bound(std::begin(OptionTable), std::end(OptionTable), + Group, + [](const WarningOption &LHS, StringRef RHS) { + return LHS.getName() < RHS; + }); + if (Found == std::end(OptionTable) || Found->getName() != Group) return true; // Option not found. return ::getDiagnosticsInGroup(Flavor, Found, Diags); @@ -573,19 +566,18 @@ 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) { + for (const WarningOption &O : OptionTable) { // Don't suggest ignored warning flags. - if (!i->Members && !i->SubGroups) + if (!O.Members && !O.SubGroups) continue; - unsigned Distance = i->getName().edit_distance(Group, true, BestDistance); + unsigned Distance = O.getName().edit_distance(Group, true, BestDistance); if (Distance > BestDistance) continue; // Don't suggest groups that are not of this kind. llvm::SmallVector<diag::kind, 8> Diags; - if (::getDiagnosticsInGroup(Flavor, i, Diags) || Diags.empty()) + if (::getDiagnosticsInGroup(Flavor, &O, Diags) || Diags.empty()) continue; if (Distance == BestDistance) { @@ -593,7 +585,7 @@ StringRef DiagnosticIDs::getNearestOption(diag::Flavor Flavor, Best = ""; } else if (Distance < BestDistance) { // This is a better match. - Best = i->getName(); + Best = O.getName(); BestDistance = Distance; } } diff --git a/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp b/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp index d492744..cb3f75c 100644 --- a/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp @@ -22,6 +22,7 @@ #include "clang/Frontend/PCHContainerOperations.h" #include "llvm/ADT/SmallString.h" #include "llvm/Config/llvm-config.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" @@ -58,12 +59,7 @@ FileManager::FileManager(const FileSystemOptions &FSO, 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]; -} +FileManager::~FileManager() = default; void FileManager::addStatCache(std::unique_ptr<FileSystemStatCache> statCache, bool AtBeginning) { @@ -137,14 +133,14 @@ void FileManager::addAncestorsAsVirtualDirs(StringRef Path) { // 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) + if (NamedDirEnt.second && NamedDirEnt.second != NON_EXISTENT_DIR) return; // Add the virtual directory to the cache. - DirectoryEntry *UDE = new DirectoryEntry; + auto UDE = llvm::make_unique<DirectoryEntry>(); UDE->Name = NamedDirEnt.first().data(); - NamedDirEnt.second = UDE; - VirtualDirectoryEntries.push_back(UDE); + NamedDirEnt.second = UDE.get(); + VirtualDirectoryEntries.push_back(std::move(UDE)); // Recursively add the other ancestors. addAncestorsAsVirtualDirs(DirName); @@ -375,8 +371,8 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size, } if (!UFE) { - UFE = new FileEntry(); - VirtualFileEntries.push_back(UFE); + VirtualFileEntries.push_back(llvm::make_unique<FileEntry>()); + UFE = VirtualFileEntries.back().get(); NamedFileEnt.second = UFE; } @@ -389,16 +385,28 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size, return UFE; } -void FileManager::FixupRelativePath(SmallVectorImpl<char> &path) const { +bool FileManager::FixupRelativePath(SmallVectorImpl<char> &path) const { StringRef pathRef(path.data(), path.size()); if (FileSystemOpts.WorkingDir.empty() || llvm::sys::path::is_absolute(pathRef)) - return; + return false; SmallString<128> NewPath(FileSystemOpts.WorkingDir); llvm::sys::path::append(NewPath, pathRef); path = NewPath; + return true; +} + +bool FileManager::makeAbsolutePath(SmallVectorImpl<char> &Path) const { + bool Changed = FixupRelativePath(Path); + + if (!llvm::sys::path::is_absolute(StringRef(Path.data(), Path.size()))) { + llvm::sys::fs::make_absolute(Path); + Changed = true; + } + + return Changed; } llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> @@ -501,11 +509,9 @@ void FileManager::GetUniqueIDMapping( 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; + for (const auto &VFE : VirtualFileEntries) + if (VFE && VFE.get() != NON_EXISTENT_FILE) + UIDToFiles[VFE->getUID()] = VFE.get(); } void FileManager::modifyFileEntry(FileEntry *File, @@ -514,37 +520,6 @@ void FileManager::modifyFileEntry(FileEntry *File, 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 @@ -556,17 +531,20 @@ StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) { #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); - } + if (realpath(Dir->getName(), CanonicalNameBuf)) + CanonicalName = StringRef(CanonicalNameBuf).copy(CanonicalNameStorage); #else SmallString<256> CanonicalNameBuf(CanonicalName); llvm::sys::fs::make_absolute(CanonicalNameBuf); llvm::sys::path::native(CanonicalNameBuf); - removeDotPaths(CanonicalNameBuf); + // We've run into needing to remove '..' here in the wild though, so + // remove it. + // On Windows, symlinks are significantly less prevalent, so removing + // '..' is pretty safe. + // Ideally we'd have an equivalent of `realpath` and could implement + // sys::fs::canonical across all the platforms. + llvm::sys::path::remove_dots(CanonicalNameBuf, /* remove_dot_dot */ true); + CanonicalName = StringRef(CanonicalNameBuf).copy(CanonicalNameStorage); #endif CanonicalDirNames.insert(std::make_pair(Dir, CanonicalName)); diff --git a/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp b/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp index 7705834..67de1cb 100644 --- a/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp @@ -111,7 +111,8 @@ namespace { KEYCONCEPTS = 0x10000, KEYOBJC2 = 0x20000, KEYZVECTOR = 0x40000, - KEYALL = (0x7ffff & ~KEYNOMS18 & + KEYCOROUTINES = 0x80000, + KEYALL = (0xfffff & ~KEYNOMS18 & ~KEYNOOPENCL) // KEYNOMS18 and KEYNOOPENCL are used to exclude. }; @@ -147,6 +148,7 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts, 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.Coroutines && (Flags & KEYCOROUTINES)) return KS_Enabled; if (LangOpts.CPlusPlus && (Flags & KEYCXX11)) return KS_Future; return KS_Disabled; } @@ -220,10 +222,7 @@ void IdentifierTable::AddKeywords(const LangOptions &LangOpts) { 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) + if (LangOpts.DeclSpecKeyword) AddKeyword("__declspec", tok::kw___declspec, KEYALL, LangOpts, *this); } diff --git a/contrib/llvm/tools/clang/lib/Basic/Module.cpp b/contrib/llvm/tools/clang/lib/Basic/Module.cpp index 4314b41..0b78326 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Module.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Module.cpp @@ -28,11 +28,12 @@ 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) { + IsMissingRequirement(false), HasIncompatibleModuleFile(false), + IsAvailable(true), IsFromModuleFile(false), IsFramework(IsFramework), + IsExplicit(IsExplicit), IsSystem(false), IsExternC(false), + IsInferred(false), InferSubmodules(false), InferExplicitSubmodules(false), + InferExportWildcard(false), ConfigMacrosExhaustive(false), + NameVisibility(Hidden) { if (Parent) { if (!Parent->isAvailable()) IsAvailable = false; @@ -139,6 +140,15 @@ std::string Module::getFullModuleName() const { return Result; } +bool Module::fullModuleNameIs(ArrayRef<StringRef> nameParts) const { + for (const Module *M = this; M; M = M->Parent) { + if (nameParts.empty() || M->Name != nameParts.back()) + return false; + nameParts = nameParts.drop_back(); + } + return nameParts.empty(); +} + Module::DirectoryName Module::getUmbrellaDir() const { if (Header U = getUmbrellaHeader()) return {"", U.Entry->getDir()}; diff --git a/contrib/llvm/tools/clang/lib/Basic/ObjCRuntime.cpp b/contrib/llvm/tools/clang/lib/Basic/ObjCRuntime.cpp index be50fc4..133c669 100644 --- a/contrib/llvm/tools/clang/lib/Basic/ObjCRuntime.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/ObjCRuntime.cpp @@ -30,6 +30,7 @@ raw_ostream &clang::operator<<(raw_ostream &out, const ObjCRuntime &value) { case ObjCRuntime::MacOSX: out << "macosx"; break; case ObjCRuntime::FragileMacOSX: out << "macosx-fragile"; break; case ObjCRuntime::iOS: out << "ios"; break; + case ObjCRuntime::WatchOS: out << "watchos"; break; case ObjCRuntime::GNUstep: out << "gnustep"; break; case ObjCRuntime::GCC: out << "gcc"; break; case ObjCRuntime::ObjFW: out << "objfw"; break; @@ -62,6 +63,8 @@ bool ObjCRuntime::tryParse(StringRef input) { kind = ObjCRuntime::FragileMacOSX; } else if (runtimeName == "ios") { kind = ObjCRuntime::iOS; + } else if (runtimeName == "watchos") { + kind = ObjCRuntime::WatchOS; } else if (runtimeName == "gnustep") { // If no version is specified then default to the most recent one that we // know about. diff --git a/contrib/llvm/tools/clang/lib/Basic/OpenMPKinds.cpp b/contrib/llvm/tools/clang/lib/Basic/OpenMPKinds.cpp index b7407f6..577132d 100644 --- a/contrib/llvm/tools/clang/lib/Basic/OpenMPKinds.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/OpenMPKinds.cpp @@ -87,8 +87,11 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, #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) + return llvm::StringSwitch<unsigned>(Str) +#define OPENMP_SCHEDULE_KIND(Name) \ + .Case(#Name, static_cast<unsigned>(OMPC_SCHEDULE_##Name)) +#define OPENMP_SCHEDULE_MODIFIER(Name) \ + .Case(#Name, static_cast<unsigned>(OMPC_SCHEDULE_MODIFIER_##Name)) #include "clang/Basic/OpenMPKinds.def" .Default(OMPC_SCHEDULE_unknown); case OMPC_depend: @@ -96,19 +99,29 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, #define OPENMP_DEPEND_KIND(Name) .Case(#Name, OMPC_DEPEND_##Name) #include "clang/Basic/OpenMPKinds.def" .Default(OMPC_DEPEND_unknown); + case OMPC_linear: + return llvm::StringSwitch<OpenMPLinearClauseKind>(Str) +#define OPENMP_LINEAR_KIND(Name) .Case(#Name, OMPC_LINEAR_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_LINEAR_unknown); + case OMPC_map: + return llvm::StringSwitch<OpenMPMapClauseKind>(Str) +#define OPENMP_MAP_KIND(Name) .Case(#Name, OMPC_MAP_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_MAP_unknown); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: case OMPC_final: case OMPC_num_threads: case OMPC_safelen: + case OMPC_simdlen: case OMPC_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: @@ -122,6 +135,16 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, case OMPC_update: case OMPC_capture: case OMPC_seq_cst: + case OMPC_device: + case OMPC_threads: + case OMPC_simd: + case OMPC_num_teams: + case OMPC_thread_limit: + case OMPC_priority: + case OMPC_grainsize: + case OMPC_nogroup: + case OMPC_num_tasks: + case OMPC_hint: break; } llvm_unreachable("Invalid OpenMP simple clause kind"); @@ -153,12 +176,17 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, case OMPC_schedule: switch (Type) { case OMPC_SCHEDULE_unknown: + case OMPC_SCHEDULE_MODIFIER_last: return "unknown"; #define OPENMP_SCHEDULE_KIND(Name) \ - case OMPC_SCHEDULE_##Name: \ - return #Name; + case OMPC_SCHEDULE_##Name: \ + return #Name; +#define OPENMP_SCHEDULE_MODIFIER(Name) \ + case OMPC_SCHEDULE_MODIFIER_##Name: \ + return #Name; #include "clang/Basic/OpenMPKinds.def" } + llvm_unreachable("Invalid OpenMP 'schedule' clause type"); case OMPC_depend: switch (Type) { case OMPC_DEPEND_unknown: @@ -168,20 +196,42 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, return #Name; #include "clang/Basic/OpenMPKinds.def" } - llvm_unreachable("Invalid OpenMP 'schedule' clause type"); + llvm_unreachable("Invalid OpenMP 'depend' clause type"); + case OMPC_linear: + switch (Type) { + case OMPC_LINEAR_unknown: + return "unknown"; +#define OPENMP_LINEAR_KIND(Name) \ + case OMPC_LINEAR_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'linear' clause type"); + case OMPC_map: + switch (Type) { + case OMPC_MAP_unknown: + return "unknown"; +#define OPENMP_MAP_KIND(Name) \ + case OMPC_MAP_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + llvm_unreachable("Invalid OpenMP 'map' clause type"); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: case OMPC_final: case OMPC_num_threads: case OMPC_safelen: + case OMPC_simdlen: case OMPC_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: @@ -195,6 +245,16 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, case OMPC_update: case OMPC_capture: case OMPC_seq_cst: + case OMPC_device: + case OMPC_threads: + case OMPC_simd: + case OMPC_num_teams: + case OMPC_thread_limit: + case OMPC_priority: + case OMPC_grainsize: + case OMPC_nogroup: + case OMPC_num_tasks: + case OMPC_hint: break; } llvm_unreachable("Invalid OpenMP simple clause kind"); @@ -328,6 +388,16 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, break; } break; + case OMPD_target_data: + switch (CKind) { +#define OPENMP_TARGET_DATA_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; case OMPD_teams: switch (CKind) { #define OPENMP_TEAMS_CLAUSE(Name) \ @@ -338,18 +408,75 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, break; } break; + case OMPD_cancel: + switch (CKind) { +#define OPENMP_CANCEL_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_ordered: + switch (CKind) { +#define OPENMP_ORDERED_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_taskloop: + switch (CKind) { +#define OPENMP_TASKLOOP_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_taskloop_simd: + switch (CKind) { +#define OPENMP_TASKLOOP_SIMD_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_critical: + switch (CKind) { +#define OPENMP_CRITICAL_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_distribute: + switch (CKind) { +#define OPENMP_DISTRIBUTE_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; case OMPD_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; @@ -357,8 +484,10 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, 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. + DKind == OMPD_parallel_for || DKind == OMPD_parallel_for_simd || + DKind == OMPD_taskloop || + DKind == OMPD_taskloop_simd || + DKind == OMPD_distribute; // TODO add next directives. } bool clang::isOpenMPWorksharingDirective(OpenMPDirectiveKind DKind) { @@ -369,19 +498,32 @@ bool clang::isOpenMPWorksharingDirective(OpenMPDirectiveKind DKind) { DKind == OMPD_parallel_sections; // TODO add next directives. } +bool clang::isOpenMPTaskLoopDirective(OpenMPDirectiveKind DKind) { + return DKind == OMPD_taskloop || DKind == OMPD_taskloop_simd; +} + bool clang::isOpenMPParallelDirective(OpenMPDirectiveKind DKind) { return DKind == OMPD_parallel || DKind == OMPD_parallel_for || DKind == OMPD_parallel_for_simd || DKind == OMPD_parallel_sections; // TODO add next directives. } +bool clang::isOpenMPTargetDirective(OpenMPDirectiveKind DKind) { + return DKind == OMPD_target; // 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. + DKind == OMPD_parallel_for_simd || + DKind == OMPD_taskloop_simd; // TODO add next directives. +} + +bool clang::isOpenMPDistributeDirective(OpenMPDirectiveKind Kind) { + return Kind == OMPD_distribute; // TODO add next directives. } bool clang::isOpenMPPrivate(OpenMPClauseKind Kind) { diff --git a/contrib/llvm/tools/clang/lib/Basic/SanitizerBlacklist.cpp b/contrib/llvm/tools/clang/lib/Basic/SanitizerBlacklist.cpp index 095fcd6..de78c94 100644 --- a/contrib/llvm/tools/clang/lib/Basic/SanitizerBlacklist.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/SanitizerBlacklist.cpp @@ -40,7 +40,7 @@ bool SanitizerBlacklist::isBlacklistedFile(StringRef FileName, bool SanitizerBlacklist::isBlacklistedLocation(SourceLocation Loc, StringRef Category) const { - return !Loc.isInvalid() && + return Loc.isValid() && isBlacklistedFile(SM.getFilename(SM.getFileLoc(Loc)), Category); } diff --git a/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp b/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp index c0b0453..4c50161 100644 --- a/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp @@ -279,9 +279,7 @@ void LineTableInfo::AddEntry(FileID FID, /// getLineTableFilenameID - Return the uniqued ID for the specified filename. /// unsigned SourceManager::getLineTableFilenameID(StringRef Name) { - if (!LineTable) - LineTable = new LineTableInfo(); - return LineTable->getLineTableFilenameID(Name); + return getLineTable().getLineTableFilenameID(Name); } @@ -302,9 +300,7 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo, // 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); + getLineTable().AddLineNote(LocInfo.first, LocInfo.second, LineNo, FilenameID); } /// AddLineNote - Add a GNU line marker to the line table. @@ -332,8 +328,7 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo, // Remember that this file has #line directives now if it doesn't already. const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives(); - if (!LineTable) - LineTable = new LineTableInfo(); + (void) getLineTable(); SrcMgr::CharacteristicKind FileKind; if (IsExternCHeader) @@ -366,7 +361,7 @@ LineTableInfo &SourceManager::getLineTable() { SourceManager::SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr, bool UserFilesAreVolatile) : Diag(Diag), FileMgr(FileMgr), OverridenFilesKeepOriginalName(true), - UserFilesAreVolatile(UserFilesAreVolatile), + UserFilesAreVolatile(UserFilesAreVolatile), FilesAreTransient(false), ExternalSLocEntries(nullptr), LineTable(nullptr), NumLinearScans(0), NumBinaryProbes(0) { clearIDTables(); @@ -444,6 +439,7 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt, } Entry->IsSystemFile = isSystemFile; + Entry->IsTransient = FilesAreTransient; return Entry; } @@ -484,10 +480,12 @@ std::pair<int, unsigned> SourceManager::AllocateLoadedSLocEntries(unsigned NumSLocEntries, unsigned TotalSize) { assert(ExternalSLocEntries && "Don't have an external sloc source"); + // Make sure we're not about to run out of source locations. + if (CurrentLoadedOffset - TotalSize < NextLocalOffset) + return std::make_pair(0, 0); LoadedSLocEntryTable.resize(LoadedSLocEntryTable.size() + NumSLocEntries); SLocEntryLoaded.resize(LoadedSLocEntryTable.size()); CurrentLoadedOffset -= TotalSize; - assert(CurrentLoadedOffset >= NextLocalOffset && "Out of source locations"); int ID = LoadedSLocEntryTable.size(); return std::make_pair(-ID - 1, CurrentLoadedOffset); } @@ -676,6 +674,11 @@ void SourceManager::disableFileContentsOverride(const FileEntry *File) { OverriddenFilesInfo->OverriddenFilesWithBuffer.erase(File); } +void SourceManager::setFileIsTransient(const FileEntry *File) { + const SrcMgr::ContentCache *CC = getOrCreateContentCache(File); + const_cast<SrcMgr::ContentCache *>(CC)->IsTransient = true; +} + StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const { bool MyInvalid = false; const SLocEntry &SLoc = getSLocEntry(FID, &MyInvalid); @@ -995,12 +998,17 @@ SourceManager::getExpansionRange(SourceLocation Loc) const { return Res; } -bool SourceManager::isMacroArgExpansion(SourceLocation Loc) const { +bool SourceManager::isMacroArgExpansion(SourceLocation Loc, + SourceLocation *StartLoc) const { if (!Loc.isMacroID()) return false; FileID FID = getFileID(Loc); const SrcMgr::ExpansionInfo &Expansion = getSLocEntry(FID).getExpansion(); - return Expansion.isMacroArgExpansion(); + if (!Expansion.isMacroArgExpansion()) return false; + + if (StartLoc) + *StartLoc = Expansion.getExpansionLocStart(); + return true; } bool SourceManager::isMacroBodyExpansion(SourceLocation Loc) const { @@ -1394,7 +1402,7 @@ unsigned SourceManager::getPresumedLineNumber(SourceLocation Loc, /// 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!"); + assert(Loc.isValid() && "Can't get file characteristic of invalid loc!"); std::pair<FileID, unsigned> LocInfo = getDecomposedExpansionLoc(Loc); bool Invalid = false; const SLocEntry &SEntry = getSLocEntry(LocInfo.first, &Invalid); @@ -1599,7 +1607,7 @@ FileID SourceManager::translateFile(const FileEntry *SourceFile) const { // location in the main file. Optional<llvm::sys::fs::UniqueID> SourceFileUID; Optional<StringRef> SourceFileName; - if (!MainFileID.isInvalid()) { + if (MainFileID.isValid()) { bool Invalid = false; const SLocEntry &MainSLoc = getSLocEntry(MainFileID, &Invalid); if (Invalid) @@ -1709,7 +1717,7 @@ SourceLocation SourceManager::translateLineCol(FileID FID, 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"); + assert(Line && Col && "Line and column should start from 1!"); if (FID.isInvalid()) return SourceLocation(); @@ -1772,7 +1780,7 @@ SourceLocation SourceManager::translateLineCol(FileID FID, /// 110 -> SourceLocation() void SourceManager::computeMacroArgsCache(MacroArgsMap *&CachePtr, FileID FID) const { - assert(!FID.isInvalid()); + assert(FID.isValid()); assert(!CachePtr); CachePtr = new MacroArgsMap(); @@ -2133,6 +2141,63 @@ void SourceManager::PrintStats() const { << NumBinaryProbes << " binary.\n"; } +LLVM_DUMP_METHOD void SourceManager::dump() const { + llvm::raw_ostream &out = llvm::errs(); + + auto DumpSLocEntry = [&](int ID, const SrcMgr::SLocEntry &Entry, + llvm::Optional<unsigned> NextStart) { + out << "SLocEntry <FileID " << ID << "> " << (Entry.isFile() ? "file" : "expansion") + << " <SourceLocation " << Entry.getOffset() << ":"; + if (NextStart) + out << *NextStart << ">\n"; + else + out << "???\?>\n"; + if (Entry.isFile()) { + auto &FI = Entry.getFile(); + if (FI.NumCreatedFIDs) + out << " covers <FileID " << ID << ":" << int(ID + FI.NumCreatedFIDs) + << ">\n"; + if (FI.getIncludeLoc().isValid()) + out << " included from " << FI.getIncludeLoc().getOffset() << "\n"; + if (auto *CC = FI.getContentCache()) { + out << " for " << (CC->OrigEntry ? CC->OrigEntry->getName() : "<none>") + << "\n"; + if (CC->BufferOverridden) + out << " contents overridden\n"; + if (CC->ContentsEntry != CC->OrigEntry) { + out << " contents from " + << (CC->ContentsEntry ? CC->ContentsEntry->getName() : "<none>") + << "\n"; + } + } + } else { + auto &EI = Entry.getExpansion(); + out << " spelling from " << EI.getSpellingLoc().getOffset() << "\n"; + out << " macro " << (EI.isMacroArgExpansion() ? "arg" : "body") + << " range <" << EI.getExpansionLocStart().getOffset() << ":" + << EI.getExpansionLocEnd().getOffset() << ">\n"; + } + }; + + // Dump local SLocEntries. + for (unsigned ID = 0, NumIDs = LocalSLocEntryTable.size(); ID != NumIDs; ++ID) { + DumpSLocEntry(ID, LocalSLocEntryTable[ID], + ID == NumIDs - 1 ? NextLocalOffset + : LocalSLocEntryTable[ID + 1].getOffset()); + } + // Dump loaded SLocEntries. + llvm::Optional<unsigned> NextStart; + for (unsigned Index = 0; Index != LoadedSLocEntryTable.size(); ++Index) { + int ID = -(int)Index - 2; + if (SLocEntryLoaded[Index]) { + DumpSLocEntry(ID, LoadedSLocEntryTable[Index], NextStart); + NextStart = LoadedSLocEntryTable[Index].getOffset(); + } else { + NextStart = None; + } + } +} + ExternalSLocEntrySource::~ExternalSLocEntrySource() { } /// Return the amount of memory used by memory buffers, breaking down diff --git a/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp b/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp index dbd2f9a..1648a27 100644 --- a/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp @@ -71,12 +71,13 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) { FloatFormat = &llvm::APFloat::IEEEsingle; DoubleFormat = &llvm::APFloat::IEEEdouble; LongDoubleFormat = &llvm::APFloat::IEEEdouble; - DescriptionString = nullptr; + DataLayoutString = nullptr; UserLabelPrefix = "_"; MCountName = "mcount"; RegParmMax = 0; SSERegParmMax = 0; HasAlignMac68kSupport = false; + HasBuiltinMSVaList = false; // Default to no types using fpret. RealTypeUsesObjCFPRet = 0; @@ -286,9 +287,9 @@ void TargetInfo::adjust(const LangOptions &Opts) { 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 + + // 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; @@ -311,6 +312,18 @@ void TargetInfo::adjust(const LangOptions &Opts) { } } +bool TargetInfo::initFeatureMap( + llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, + const std::vector<std::string> &FeatureVec) const { + for (const auto &F : FeatureVec) { + StringRef Name = F; + // Apply the feature via the target. + bool Enabled = Name[0] == '+'; + setFeatureEnabled(Features, Name.substr(1), Enabled); + } + return true; +} + //===----------------------------------------------------------------------===// @@ -326,7 +339,7 @@ static StringRef removeGCCRegisterPrefix(StringRef Name) { /// Sema. bool TargetInfo::isValidClobber(StringRef Name) const { return (isValidGCCRegisterName(Name) || - Name == "memory" || Name == "cc"); + Name == "memory" || Name == "cc"); } /// isValidGCCRegisterName - Returns whether the passed in string @@ -336,56 +349,43 @@ 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; + return false; - getGCCRegNames(Names, NumNames); + ArrayRef<const char *> Names = getGCCRegNames(); // If we have a number it maps to an entry in the register name array. if (isDigit(Name[0])) { - int n; + unsigned n; if (!Name.getAsInteger(0, n)) - return n >= 0 && (unsigned)n < NumNames; + return n < Names.size(); } // Check register names. - for (unsigned i = 0; i < NumNames; i++) { - if (Name == Names[i]) - return true; - } + if (std::find(Names.begin(), Names.end(), Name) != Names.end()) + 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; + for (const AddlRegName &ARN : getGCCAddlRegNames()) + for (const char *AN : ARN.Names) { + if (!AN) + break; // Make sure the register that the additional name is for is within // the bounds of the register names from above. - if (AddlNames[i].Names[j] == Name && AddlNames[i].RegNum < NumNames) - return true; - } + if (AN == Name && ARN.RegNum < Names.size()) + 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]) + for (const GCCRegAlias &GRA : getGCCRegAliases()) + for (const char *A : GRA.Aliases) { + if (!A) break; - if (Aliases[i].Aliases[j] == Name) + if (A == Name) return true; } - } return false; } @@ -397,48 +397,36 @@ TargetInfo::getNormalizedGCCRegisterName(StringRef Name) const { // Get rid of any register prefix. Name = removeGCCRegisterPrefix(Name); - const char * const *Names; - unsigned NumNames; - - getGCCRegNames(Names, NumNames); + ArrayRef<const char *> Names = getGCCRegNames(); // First, check if we have a number. if (isDigit(Name[0])) { - int n; + unsigned n; if (!Name.getAsInteger(0, n)) { - assert(n >= 0 && (unsigned)n < NumNames && - "Out of bounds register number!"); + assert(n < Names.size() && "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; + for (const AddlRegName &ARN : getGCCAddlRegNames()) + for (const char *AN : ARN.Names) { + if (!AN) + break; // Make sure the register that the additional name is for is within // the bounds of the register names from above. - if (AddlNames[i].Names[j] == Name && AddlNames[i].RegNum < NumNames) - return Name; + if (AN == Name && ARN.RegNum < Names.size()) + 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]) + for (const GCCRegAlias &RA : getGCCRegAliases()) + for (const char *A : RA.Aliases) { + if (!A) break; - if (Aliases[i].Aliases[j] == Name) - return Aliases[i].Register; + if (A == Name) + return RA.Register; } - } return Name; } @@ -513,8 +501,7 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const { } bool TargetInfo::resolveSymbolicName(const char *&Name, - ConstraintInfo *OutputConstraints, - unsigned NumOutputs, + ArrayRef<ConstraintInfo> OutputConstraints, unsigned &Index) const { assert(*Name == '[' && "Symbolic name did not start with '['"); Name++; @@ -529,16 +516,16 @@ bool TargetInfo::resolveSymbolicName(const char *&Name, std::string SymbolicName(Start, Name - Start); - for (Index = 0; Index != NumOutputs; ++Index) + for (Index = 0; Index != OutputConstraints.size(); ++Index) if (SymbolicName == OutputConstraints[Index].getName()) return true; return false; } -bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints, - unsigned NumOutputs, - ConstraintInfo &Info) const { +bool TargetInfo::validateInputConstraint( + MutableArrayRef<ConstraintInfo> OutputConstraints, + ConstraintInfo &Info) const { const char *Name = Info.ConstraintStr.c_str(); if (!*Name) @@ -559,13 +546,13 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints, return false; // Check if matching constraint is out of bounds. - if (i >= NumOutputs) return false; + if (i >= OutputConstraints.size()) return false; // A number must refer to an output only operand. if (OutputConstraints[i].isReadWrite()) return false; - // If the constraint is already tied, it must be tied to the + // 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; @@ -582,10 +569,10 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints, break; case '[': { unsigned Index = 0; - if (!resolveSymbolicName(Name, OutputConstraints, NumOutputs, Index)) + if (!resolveSymbolicName(Name, OutputConstraints, Index)) return false; - // If the constraint is already tied, it must be tied to the + // 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; @@ -650,18 +637,3 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints, 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 index 9e44f7d..893bd7c 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Targets.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp @@ -1,4 +1,4 @@ -//===--- Targets.cpp - Implement -arch option and targets -----------------===// +//===--- Targets.cpp - Implement target feature support -------------------===// // // The LLVM Compiler Infrastructure // @@ -19,6 +19,7 @@ #include "clang/Basic/MacroBuilder.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetOptions.h" +#include "clang/Basic/Version.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" @@ -30,6 +31,7 @@ #include "llvm/Support/TargetParser.h" #include <algorithm> #include <memory> + using namespace clang; //===----------------------------------------------------------------------===// @@ -82,8 +84,28 @@ public: } }; -} // end anonymous 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 = ""; + } +}; static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, const llvm::Triple &Triple, @@ -97,19 +119,11 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, if (Opts.Sanitize.has(SanitizerKind::Address)) Builder.defineMacro("_FORTIFY_SOURCE", "0"); - if (!Opts.ObjCAutoRefCount) { + // Darwin defines __weak, __strong, and __unsafe_unretained even in C mode. + if (!Opts.ObjC1) { // __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("__strong", ""); Builder.defineMacro("__unsafe_unretained", ""); } @@ -149,8 +163,22 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, Str[3] = '0' + (Rev / 10); Str[4] = '0' + (Rev % 10); Str[5] = '\0'; - Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", - Str); + if (Triple.isTvOS()) + Builder.defineMacro("__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__", Str); + else + Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", + Str); + + } else if (Triple.isWatchOS()) { + assert(Maj < 10 && Min < 100 && Rev < 100 && "Invalid version!"); + char Str[6]; + Str[0] = '0' + Maj; + Str[1] = '0' + (Min / 10); + Str[2] = '0' + (Min % 10); + Str[3] = '0' + (Rev / 10); + Str[4] = '0' + (Rev % 10); + Str[5] = '\0'; + Builder.defineMacro("__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__", Str); } else if (Triple.isMacOSX()) { // Note that the Driver allows versions which aren't representable in the // define (because we only get a single digit for the minor and micro @@ -184,29 +212,6 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, 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: @@ -386,7 +391,7 @@ protected: DefineStd(Builder, "linux", Opts); Builder.defineMacro("__gnu_linux__"); Builder.defineMacro("__ELF__"); - if (Triple.getEnvironment() == llvm::Triple::Android) { + if (Triple.isAndroid()) { Builder.defineMacro("__ANDROID__", "1"); unsigned Maj, Min, Rev; Triple.getEnvironmentVersion(Maj, Min, Rev); @@ -560,7 +565,7 @@ public: this->IntMaxType = TargetInfo::SignedLongLong; this->Int64Type = TargetInfo::SignedLongLong; this->SizeType = TargetInfo::UnsignedInt; - this->DescriptionString = "E-m:e-p:32:32-i64:64-n32:64"; + this->DataLayoutString = "E-m:e-p:32:32-i64:64-n32:64"; } }; @@ -645,6 +650,9 @@ protected: Builder.defineMacro("_CPPUNWIND"); } + if (Opts.Bool) + Builder.defineMacro("__BOOL_DEFINED"); + if (!Opts.CharIsSigned) Builder.defineMacro("_CHAR_UNSIGNED"); @@ -719,18 +727,45 @@ public: 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"; + this->DataLayoutString = "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"; + this->DataLayoutString = "e-m:e-p:32:32-i64:64-n8:16:32:64-S128"; } else if (Triple.getArch() == llvm::Triple::mipsel) { - // Handled on mips' setDescriptionString. + // Handled on mips' setDataLayoutString. } else { assert(Triple.getArch() == llvm::Triple::le32); - this->DescriptionString = "e-p:32:32-i64:64"; + this->DataLayoutString = "e-p:32:32-i64:64"; } } }; +// WebAssembly target +template <typename Target> +class WebAssemblyOSTargetInfo : public OSTargetInfo<Target> { + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const final { + // A common platform macro. + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + // Follow g++ convention and predefine _GNU_SOURCE for C++. + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + } + + // As an optimization, group static init code together in a section. + const char *getStaticInitSectionSpecifier() const final { + return ".text.__startup"; + } + +public: + explicit WebAssemblyOSTargetInfo(const llvm::Triple &Triple) + : OSTargetInfo<Target>(Triple) { + this->MCountName = "__mcount"; + this->UserLabelPrefix = ""; + this->TheCXXABI.set(TargetCXXABI::WebAssembly); + } +}; + //===----------------------------------------------------------------------===// // Specific target implementations. //===----------------------------------------------------------------------===// @@ -849,10 +884,9 @@ public: StringRef getABI() const override { return ABI; } - void getTargetBuiltins(const Builtin::Info *&Records, - unsigned &NumRecords) const override { - Records = BuiltinInfo; - NumRecords = clang::PPC::LastTSBuiltin-Builtin::FirstTSBuiltin; + ArrayRef<Builtin::Info> getTargetBuiltins() const override { + return llvm::makeArrayRef(BuiltinInfo, + clang::PPC::LastTSBuiltin-Builtin::FirstTSBuiltin); } bool isCLZForZeroUndef() const override { return false; } @@ -860,7 +894,10 @@ public: void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; - void getDefaultFeatures(llvm::StringMap<bool> &Features) const override; + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override; bool handleTargetFeatures(std::vector<std::string> &Features, DiagnosticsEngine &Diags) override; @@ -868,10 +905,8 @@ public: 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; + ArrayRef<const char *> getGCCRegNames() const override; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { switch (*Name) { @@ -1006,9 +1041,10 @@ public: }; 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 }, +#define BUILTIN(ID, TYPE, ATTRS) \ + { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsPPC.def" }; @@ -1016,65 +1052,27 @@ const Builtin::Info PPCTargetInfo::BuiltinInfo[] = { /// 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") { + for (const auto &Feature : Features) { + if (Feature == "+vsx") { HasVSX = true; - continue; - } - - if (Feature == "bpermd") { + } else if (Feature == "+bpermd") { HasBPERMD = true; - continue; - } - - if (Feature == "extdiv") { + } else if (Feature == "+extdiv") { HasExtDiv = true; - continue; - } - - if (Feature == "power8-vector") { + } else if (Feature == "+power8-vector") { HasP8Vector = true; - continue; - } - - if (Feature == "crypto") { + } else if (Feature == "+crypto") { HasP8Crypto = true; - continue; - } - - if (Feature == "direct-move") { + } else if (Feature == "+direct-move") { HasDirectMove = true; - continue; - } - - if (Feature == "qpx") { + } else if (Feature == "+qpx") { HasQPX = true; - continue; - } - - if (Feature == "htm") { + } else 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; } @@ -1228,14 +1226,12 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts, 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"); - } + + 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: @@ -1258,7 +1254,36 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts, // __NO_FPRS__ } -void PPCTargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { +// Handle explicit options being passed to the compiler here: if we've +// explicitly turned off vsx and turned on power8-vector or direct-move then +// go ahead and error since the customer has expressed a somewhat incompatible +// set of options. +static bool ppcUserFeaturesCheck(DiagnosticsEngine &Diags, + const std::vector<std::string> &FeaturesVec) { + + if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "-vsx") != + FeaturesVec.end()) { + if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+power8-vector") != + FeaturesVec.end()) { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mpower8-vector" + << "-mno-vsx"; + return false; + } + + if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+direct-move") != + FeaturesVec.end()) { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mdirect-move" + << "-mno-vsx"; + return false; + } + } + + return true; +} + +bool PPCTargetInfo::initFeatureMap( + llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, + const std::vector<std::string> &FeaturesVec) const { Features["altivec"] = llvm::StringSwitch<bool>(CPU) .Case("7400", true) .Case("g4", true) @@ -1301,6 +1326,11 @@ void PPCTargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { .Case("pwr8", true) .Case("pwr7", true) .Default(false); + + if (!ppcUserFeaturesCheck(Diags, FeaturesVec)) + return false; + + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } bool PPCTargetInfo::hasFeature(StringRef Feature) const { @@ -1317,37 +1347,29 @@ bool PPCTargetInfo::hasFeature(StringRef Feature) const { .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; + // If we're enabling direct-move or power8-vector go ahead and enable vsx + // as well. Do the inverse if we're disabling vsx. We'll diagnose any user + // incompatible options. + if (Enabled) { + if (Name == "vsx") { + Features[Name] = true; + } else if (Name == "direct-move") { + Features[Name] = Features["vsx"] = true; + } else if (Name == "power8-vector") { + Features[Name] = Features["vsx"] = true; + } else { + Features[Name] = true; + } + } else { + if (Name == "vsx") { + Features[Name] = Features["direct-move"] = Features["power8-vector"] = + false; + } else { + Features[Name] = false; } } - Features[Name] = Enabled; } const char * const PPCTargetInfo::GCCRegNames[] = { @@ -1371,10 +1393,8 @@ const char * const PPCTargetInfo::GCCRegNames[] = { "sfp" }; -void PPCTargetInfo::getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const { - Names = GCCRegNames; - NumNames = llvm::array_lengthof(GCCRegNames); +ArrayRef<const char*> PPCTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); } const TargetInfo::GCCRegAlias PPCTargetInfo::GCCRegAliases[] = { @@ -1447,16 +1467,14 @@ const TargetInfo::GCCRegAlias PPCTargetInfo::GCCRegAliases[] = { { { "cc" }, "cr0" }, }; -void PPCTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const { - Aliases = GCCRegAliases; - NumAliases = llvm::array_lengthof(GCCRegAliases); +ArrayRef<TargetInfo::GCCRegAlias> PPCTargetInfo::getGCCRegAliases() const { + return llvm::makeArrayRef(GCCRegAliases); } class PPC32TargetInfo : public PPCTargetInfo { public: PPC32TargetInfo(const llvm::Triple &Triple) : PPCTargetInfo(Triple) { - DescriptionString = "E-m:e-p:32:32-i64:64-n32"; + DataLayoutString = "E-m:e-p:32:32-i64:64-n32"; switch (getTriple().getOS()) { case llvm::Triple::Linux: @@ -1495,10 +1513,10 @@ public: Int64Type = SignedLong; if ((Triple.getArch() == llvm::Triple::ppc64le)) { - DescriptionString = "e-m:e-i64:64-n32:64"; + DataLayoutString = "e-m:e-i64:64-n32:64"; ABI = "elfv2"; } else { - DescriptionString = "E-m:e-i64:64-n32:64"; + DataLayoutString = "E-m:e-i64:64-n32:64"; ABI = "elfv1"; } @@ -1541,7 +1559,7 @@ public: 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"; + DataLayoutString = "E-m:o-p:32:32-f64:32:64-n32"; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; @@ -1555,23 +1573,24 @@ public: : DarwinTargetInfo<PPC64TargetInfo>(Triple) { HasAlignMac68kSupport = true; SuitableAlign = 128; - DescriptionString = "E-m:o-i64:64-n32:64"; + DataLayoutString = "E-m:o-i64:64-n32:64"; } }; - static const unsigned NVPTXAddrSpaceMap[] = { - 1, // opencl_global - 3, // opencl_local - 4, // opencl_constant +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[]; + 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 { @@ -1583,139 +1602,133 @@ public: 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; +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); } - 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); + } + ArrayRef<Builtin::Info> getTargetBuiltins() const override { + return llvm::makeArrayRef(BuiltinInfo, + clang::NVPTX::LastTSBuiltin - Builtin::FirstTSBuiltin); + } + bool hasFeature(StringRef Feature) const override { + return Feature == "ptx" || Feature == "nvptx"; + } - return GPU != GK_NONE; + ArrayRef<const char *> getGCCRegNames() const override; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + // No aliases. + return None; + } + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + switch (*Name) { + default: + return false; + case 'c': + case 'h': + case 'r': + case 'l': + case 'f': + case 'd': + Info.setAllowsRegister(); + return true; } - }; + } + const char *getClobbers() const override { + // FIXME: Is this really right? + return ""; + } + BuiltinVaListKind getBuiltinVaListKind() const override { + // FIXME: implement + return TargetInfo::CharPtrBuiltinVaList; + } + bool 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); - 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 }, + return GPU != GK_NONE; + } +}; + +const Builtin::Info NVPTXTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsNVPTX.def" - }; +}; - const char * const NVPTXTargetInfo::GCCRegNames[] = { - "r0" - }; +const char *const NVPTXTargetInfo::GCCRegNames[] = {"r0"}; - void NVPTXTargetInfo::getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const { - Names = GCCRegNames; - NumNames = llvm::array_lengthof(GCCRegNames); - } +ArrayRef<const char *> NVPTXTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(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 NVPTX32TargetInfo : public NVPTXTargetInfo { +public: + NVPTX32TargetInfo(const llvm::Triple &Triple) : NVPTXTargetInfo(Triple) { + LongWidth = LongAlign = 32; + PointerWidth = PointerAlign = 32; + SizeType = TargetInfo::UnsignedInt; + PtrDiffType = TargetInfo::SignedInt; + IntPtrType = TargetInfo::SignedInt; + DataLayoutString = "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"; - } - }; +class NVPTX64TargetInfo : public NVPTXTargetInfo { +public: + NVPTX64TargetInfo(const llvm::Triple &Triple) : NVPTXTargetInfo(Triple) { + PointerWidth = PointerAlign = 64; + SizeType = TargetInfo::UnsignedLong; + PtrDiffType = TargetInfo::SignedLong; + IntPtrType = TargetInfo::SignedLong; + DataLayoutString = "e-i64:64-v16:16-v32:32-n16:32:64"; + } +}; static const unsigned AMDGPUAddrSpaceMap[] = { 1, // opencl_global @@ -1730,15 +1743,15 @@ static const unsigned AMDGPUAddrSpaceMap[] = { // If you edit the description strings, make sure you update // getPointerWidthV(). -static const char *DescriptionStringR600 = +static const char *const DataLayoutStringR600 = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128" "-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64"; -static const char *DescriptionStringR600DoubleOps = +static const char *const DataLayoutStringR600DoubleOps = "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 = +static const char *const DataLayoutStringSI = "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"; @@ -1772,13 +1785,13 @@ public: : TargetInfo(Triple) { if (Triple.getArch() == llvm::Triple::amdgcn) { - DescriptionString = DescriptionStringSI; + DataLayoutString = DataLayoutStringSI; GPU = GK_SOUTHERN_ISLANDS; hasFP64 = true; hasFMAF = true; hasLDEXPF = true; } else { - DescriptionString = DescriptionStringR600; + DataLayoutString = DataLayoutStringR600; GPU = GK_R600; hasFP64 = false; hasFMAF = false; @@ -1806,24 +1819,27 @@ public: return ""; } - void getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const override; + ArrayRef<const char *> getGCCRegNames() const override; - void getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const override { - Aliases = nullptr; - NumAliases = 0; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; } bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const override { - return true; + TargetInfo::ConstraintInfo &Info) const override { + switch (*Name) { + default: break; + case 'v': // vgpr + case 's': // sgpr + Info.setAllowsRegister(); + return true; + } + return false; } - void getTargetBuiltins(const Builtin::Info *&Records, - unsigned &NumRecords) const override { - Records = BuiltinInfo; - NumRecords = clang::AMDGPU::LastTSBuiltin - Builtin::FirstTSBuiltin; + ArrayRef<Builtin::Info> getTargetBuiltins() const override { + return llvm::makeArrayRef(BuiltinInfo, + clang::AMDGPU::LastTSBuiltin - Builtin::FirstTSBuiltin); } void getTargetDefines(const LangOptions &Opts, @@ -1833,8 +1849,16 @@ public: Builder.defineMacro("__HAS_FMAF__"); if (hasLDEXPF) Builder.defineMacro("__HAS_LDEXPF__"); - if (hasFP64 && Opts.OpenCL) { + if (hasFP64 && Opts.OpenCL) Builder.defineMacro("cl_khr_fp64"); + if (Opts.OpenCL) { + if (GPU >= GK_NORTHERN_ISLANDS) { + Builder.defineMacro("cl_khr_byte_addressable_store"); + Builder.defineMacro("cl_khr_global_int32_base_atomics"); + Builder.defineMacro("cl_khr_global_int32_extended_atomics"); + Builder.defineMacro("cl_khr_local_int32_base_atomics"); + Builder.defineMacro("cl_khr_local_int32_extended_atomics"); + } } } @@ -1895,7 +1919,7 @@ public: case GK_R700: case GK_EVERGREEN: case GK_NORTHERN_ISLANDS: - DescriptionString = DescriptionStringR600; + DataLayoutString = DataLayoutStringR600; hasFP64 = false; hasFMAF = false; hasLDEXPF = false; @@ -1904,7 +1928,7 @@ public: case GK_R700_DOUBLE_OPS: case GK_EVERGREEN_DOUBLE_OPS: case GK_CAYMAN: - DescriptionString = DescriptionStringR600DoubleOps; + DataLayoutString = DataLayoutStringR600DoubleOps; hasFP64 = true; hasFMAF = true; hasLDEXPF = false; @@ -1912,7 +1936,7 @@ public: case GK_SOUTHERN_ISLANDS: case GK_SEA_ISLANDS: case GK_VOLCANIC_ISLANDS: - DescriptionString = DescriptionStringSI; + DataLayoutString = DataLayoutStringSI; hasFP64 = true; hasFMAF = true; hasLDEXPF = true; @@ -1925,7 +1949,7 @@ public: const Builtin::Info AMDGPUTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ - { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, + { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsAMDGPU.def" }; const char * const AMDGPUTargetInfo::GCCRegNames[] = { @@ -1981,17 +2005,18 @@ const char * const AMDGPUTargetInfo::GCCRegNames[] = { "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); +ArrayRef<const char *> AMDGPUTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(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 }, +#define BUILTIN(ID, TYPE, ATTRS) \ + { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE }, #include "clang/Basic/BuiltinsX86.def" }; @@ -2016,6 +2041,14 @@ const TargetInfo::AddlRegName AddlRegNames[] = { { { "edi", "rdi" }, 5 }, { { "esp", "rsp" }, 7 }, { { "ebp", "rbp" }, 6 }, + { { "r8d", "r8w", "r8b" }, 38 }, + { { "r9d", "r9w", "r9b" }, 39 }, + { { "r10d", "r10w", "r10b" }, 40 }, + { { "r11d", "r11w", "r11b" }, 41 }, + { { "r12d", "r12w", "r12b" }, 42 }, + { { "r13d", "r13w", "r13b" }, 43 }, + { { "r14d", "r14w", "r14b" }, 44 }, + { { "r15d", "r15w", "r15b" }, 45 }, }; // X86 target abstract base class; x86-32 and x86-64 are very close, so @@ -2023,36 +2056,45 @@ const TargetInfo::AddlRegName AddlRegNames[] = { class X86TargetInfo : public TargetInfo { enum X86SSEEnum { NoSSE, SSE1, SSE2, SSE3, SSSE3, SSE41, SSE42, AVX, AVX2, AVX512F - } SSELevel; + } SSELevel = NoSSE; enum MMX3DNowEnum { NoMMX3DNow, MMX, AMD3DNow, AMD3DNowAthlon - } MMX3DNowLevel; + } MMX3DNowLevel = NoMMX3DNow; 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; + } XOPLevel = NoXOP; + + bool HasAES = false; + bool HasPCLMUL = false; + bool HasLZCNT = false; + bool HasRDRND = false; + bool HasFSGSBASE = false; + bool HasBMI = false; + bool HasBMI2 = false; + bool HasPOPCNT = false; + bool HasRTM = false; + bool HasPRFCHW = false; + bool HasRDSEED = false; + bool HasADX = false; + bool HasTBM = false; + bool HasFMA = false; + bool HasF16C = false; + bool HasAVX512CD = false; + bool HasAVX512ER = false; + bool HasAVX512PF = false; + bool HasAVX512DQ = false; + bool HasAVX512BW = false; + bool HasAVX512VL = false; + bool HasSHA = false; + bool HasCX16 = false; + bool HasFXSR = false; + bool HasXSAVE = false; + bool HasXSAVEOPT = false; + bool HasXSAVEC = false; + bool HasXSAVES = false; /// \brief Enumeration of all of the X86 CPUs supported by Clang. /// @@ -2220,24 +2262,85 @@ class X86TargetInfo : public TargetInfo { //@{ CK_Geode //@} - } CPU; + } CPU = CK_Generic; + + CPUKind getCPUKind(StringRef CPU) const { + return llvm::StringSwitch<CPUKind>(CPU) + .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); + } enum FPMathKind { FP_Default, FP_SSE, FP_387 - } FPMath; + } FPMath = FP_Default; 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) { + X86TargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { BigEndian = false; LongDoubleFormat = &llvm::APFloat::x87DoubleExtended; } @@ -2245,30 +2348,37 @@ public: // 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; + ArrayRef<Builtin::Info> getTargetBuiltins() const override { + return llvm::makeArrayRef(BuiltinInfo, + clang::X86::LastTSBuiltin-Builtin::FirstTSBuiltin); } - void getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const override { - Names = GCCRegNames; - NumNames = llvm::array_lengthof(GCCRegNames); + ArrayRef<const char *> getGCCRegNames() const override { + return llvm::makeArrayRef(GCCRegNames); } - void getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const override { - Aliases = nullptr; - NumAliases = 0; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; } - void getGCCAddlRegNames(const AddlRegName *&Names, - unsigned &NumNames) const override { - Names = AddlRegNames; - NumNames = llvm::array_lengthof(AddlRegNames); + ArrayRef<TargetInfo::AddlRegName> getGCCAddlRegNames() const override { + return llvm::makeArrayRef(AddlRegNames); } bool validateCpuSupports(StringRef Name) const override; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override; + bool validateGlobalRegisterVariable(StringRef RegName, + unsigned RegSize, + bool &HasSizeMismatch) const override { + // esp and ebp are the only 32-bit registers the x86 backend can currently + // handle. + if (RegName.equals("esp") || RegName.equals("ebp")) { + // Check that the register size is 32-bit. + HasSizeMismatch = RegSize != 32; + return true; + } + + return false; + } + bool validateOutputSize(StringRef Constraint, unsigned Size) const override; bool validateInputSize(StringRef Constraint, unsigned Size) const override; @@ -2292,90 +2402,28 @@ public: setFeatureEnabledImpl(Features, Name, Enabled); } // This exists purely to cut down on the number of virtual calls in - // getDefaultFeatures which calls this repeatedly. + // initFeatureMap which calls this repeatedly. static void setFeatureEnabledImpl(llvm::StringMap<bool> &Features, StringRef Name, bool Enabled); - void getDefaultFeatures(llvm::StringMap<bool> &Features) const override; + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override; bool hasFeature(StringRef Feature) const override; bool handleTargetFeatures(std::vector<std::string> &Features, DiagnosticsEngine &Diags) override; 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) + if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX) return "avx"; - else if (getTriple().getArch() == llvm::Triple::x86 && + 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); + CPU = getCPUKind(Name); // Perform any per-CPU checks necessary to determine if this CPU is // acceptable. @@ -2486,14 +2534,15 @@ bool X86TargetInfo::setFPMath(StringRef Name) { return false; } -void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { +bool X86TargetInfo::initFeatureMap( + llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, + const std::vector<std::string> &FeaturesVec) const { // FIXME: This *really* should not be here. - // X86_64 always has SSE2. if (getTriple().getArch() == llvm::Triple::x86_64) setFeatureEnabledImpl(Features, "sse2", true); - switch (CPU) { + switch (getCPUKind(CPU)) { case CK_Generic: case CK_i386: case CK_i486: @@ -2512,26 +2561,31 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { case CK_Pentium3M: case CK_C3_2: setFeatureEnabledImpl(Features, "sse", true); + setFeatureEnabledImpl(Features, "fxsr", true); break; case CK_PentiumM: case CK_Pentium4: case CK_Pentium4M: case CK_x86_64: setFeatureEnabledImpl(Features, "sse2", true); + setFeatureEnabledImpl(Features, "fxsr", true); break; case CK_Yonah: case CK_Prescott: case CK_Nocona: setFeatureEnabledImpl(Features, "sse3", true); + setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "cx16", true); break; case CK_Core2: case CK_Bonnell: setFeatureEnabledImpl(Features, "ssse3", true); + setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "cx16", true); break; case CK_Penryn: setFeatureEnabledImpl(Features, "sse4.1", true); + setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "cx16", true); break; case CK_Skylake: @@ -2540,6 +2594,8 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { setFeatureEnabledImpl(Features, "avx512dq", true); setFeatureEnabledImpl(Features, "avx512bw", true); setFeatureEnabledImpl(Features, "avx512vl", true); + setFeatureEnabledImpl(Features, "xsavec", true); + setFeatureEnabledImpl(Features, "xsaves", true); // FALLTHROUGH case CK_Broadwell: setFeatureEnabledImpl(Features, "rdseed", true); @@ -2560,6 +2616,8 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { // FALLTHROUGH case CK_SandyBridge: setFeatureEnabledImpl(Features, "avx", true); + setFeatureEnabledImpl(Features, "xsave", true); + setFeatureEnabledImpl(Features, "xsaveopt", true); // FALLTHROUGH case CK_Westmere: case CK_Silvermont: @@ -2568,6 +2626,7 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { // FALLTHROUGH case CK_Nehalem: setFeatureEnabledImpl(Features, "sse4.2", true); + setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "cx16", true); break; case CK_KNL: @@ -2575,6 +2634,7 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { setFeatureEnabledImpl(Features, "avx512cd", true); setFeatureEnabledImpl(Features, "avx512er", true); setFeatureEnabledImpl(Features, "avx512pf", true); + setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "rdseed", true); setFeatureEnabledImpl(Features, "adx", true); setFeatureEnabledImpl(Features, "lzcnt", true); @@ -2588,6 +2648,8 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { setFeatureEnabledImpl(Features, "aes", true); setFeatureEnabledImpl(Features, "pclmul", true); setFeatureEnabledImpl(Features, "cx16", true); + setFeatureEnabledImpl(Features, "xsaveopt", true); + setFeatureEnabledImpl(Features, "xsave", true); break; case CK_K6_2: case CK_K6_3: @@ -2605,6 +2667,7 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { case CK_AthlonMP: setFeatureEnabledImpl(Features, "sse", true); setFeatureEnabledImpl(Features, "3dnowa", true); + setFeatureEnabledImpl(Features, "fxsr", true); break; case CK_K8: case CK_Opteron: @@ -2612,6 +2675,7 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { case CK_AthlonFX: setFeatureEnabledImpl(Features, "sse2", true); setFeatureEnabledImpl(Features, "3dnowa", true); + setFeatureEnabledImpl(Features, "fxsr", true); break; case CK_AMDFAM10: setFeatureEnabledImpl(Features, "sse4a", true); @@ -2623,6 +2687,7 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { case CK_Athlon64SSE3: setFeatureEnabledImpl(Features, "sse3", true); setFeatureEnabledImpl(Features, "3dnowa", true); + setFeatureEnabledImpl(Features, "fxsr", true); break; case CK_BTVER2: setFeatureEnabledImpl(Features, "avx", true); @@ -2630,6 +2695,7 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { setFeatureEnabledImpl(Features, "pclmul", true); setFeatureEnabledImpl(Features, "bmi", true); setFeatureEnabledImpl(Features, "f16c", true); + setFeatureEnabledImpl(Features, "xsaveopt", true); // FALLTHROUGH case CK_BTVER1: setFeatureEnabledImpl(Features, "ssse3", true); @@ -2638,6 +2704,8 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { setFeatureEnabledImpl(Features, "popcnt", true); setFeatureEnabledImpl(Features, "prfchw", true); setFeatureEnabledImpl(Features, "cx16", true); + setFeatureEnabledImpl(Features, "fxsr", true); + setFeatureEnabledImpl(Features, "xsave", true); break; case CK_BDVER4: setFeatureEnabledImpl(Features, "avx2", true); @@ -2645,6 +2713,7 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { // FALLTHROUGH case CK_BDVER3: setFeatureEnabledImpl(Features, "fsgsbase", true); + setFeatureEnabledImpl(Features, "xsaveopt", true); // FALLTHROUGH case CK_BDVER2: setFeatureEnabledImpl(Features, "bmi", true); @@ -2660,8 +2729,39 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { setFeatureEnabledImpl(Features, "pclmul", true); setFeatureEnabledImpl(Features, "prfchw", true); setFeatureEnabledImpl(Features, "cx16", true); + setFeatureEnabledImpl(Features, "fxsr", true); + setFeatureEnabledImpl(Features, "xsave", true); break; } + if (!TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec)) + return false; + + // Can't do this earlier because we need to be able to explicitly enable + // or disable these features and the things that they depend upon. + + // Enable popcnt if sse4.2 is enabled and popcnt is not explicitly disabled. + auto I = Features.find("sse4.2"); + if (I != Features.end() && I->getValue() && + std::find(FeaturesVec.begin(), FeaturesVec.end(), "-popcnt") == + FeaturesVec.end()) + Features["popcnt"] = true; + + // Enable prfchw if 3DNow! is enabled and prfchw is not explicitly disabled. + I = Features.find("3dnow"); + if (I != Features.end() && I->getValue() && + std::find(FeaturesVec.begin(), FeaturesVec.end(), "-prfchw") == + FeaturesVec.end()) + Features["prfchw"] = true; + + // Additionally, if SSE is enabled and mmx is not explicitly disabled, + // then enable MMX. + I = Features.find("sse"); + if (I != Features.end() && I->getValue() && + std::find(FeaturesVec.begin(), FeaturesVec.end(), "-mmx") == + FeaturesVec.end()) + Features["mmx"] = true; + + return true; } void X86TargetInfo::setSSELevel(llvm::StringMap<bool> &Features, @@ -2674,6 +2774,7 @@ void X86TargetInfo::setSSELevel(llvm::StringMap<bool> &Features, Features["avx2"] = true; case AVX: Features["avx"] = true; + Features["xsave"] = true; case SSE42: Features["sse4.2"] = true; case SSE41: @@ -2709,7 +2810,8 @@ void X86TargetInfo::setSSELevel(llvm::StringMap<bool> &Features, case SSE42: Features["sse4.2"] = false; case AVX: - Features["fma"] = Features["avx"] = Features["f16c"] = false; + Features["fma"] = Features["avx"] = Features["f16c"] = Features["xsave"] = + Features["xsaveopt"] = false; setXOPLevel(Features, FMA4, false); case AVX2: Features["avx2"] = false; @@ -2842,6 +2944,16 @@ void X86TargetInfo::setFeatureEnabledImpl(llvm::StringMap<bool> &Features, setSSELevel(Features, SSE42, Enabled); else setSSELevel(Features, SSE41, Enabled); + } else if (Name == "xsave") { + if (Enabled) + setSSELevel(Features, AVX, Enabled); + else + Features["xsaveopt"] = false; + } else if (Name == "xsaveopt" || Name == "xsavec" || Name == "xsaves") { + if (Enabled) { + Features["xsave"] = true; + setSSELevel(Features, AVX, Enabled); + } } } @@ -2849,198 +2961,108 @@ void X86TargetInfo::setFeatureEnabledImpl(llvm::StringMap<bool> &Features, /// 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] == '-') + for (const auto &Feature : Features) { + if (Feature[0] != '+') continue; - StringRef Feature = StringRef(Features[i]).substr(1); - - if (Feature == "aes") { + if (Feature == "+aes") { HasAES = true; - continue; - } - - if (Feature == "pclmul") { + } else if (Feature == "+pclmul") { HasPCLMUL = true; - continue; - } - - if (Feature == "lzcnt") { + } else if (Feature == "+lzcnt") { HasLZCNT = true; - continue; - } - - if (Feature == "rdrnd") { + } else if (Feature == "+rdrnd") { HasRDRND = true; - continue; - } - - if (Feature == "fsgsbase") { + } else if (Feature == "+fsgsbase") { HasFSGSBASE = true; - continue; - } - - if (Feature == "bmi") { + } else if (Feature == "+bmi") { HasBMI = true; - continue; - } - - if (Feature == "bmi2") { + } else if (Feature == "+bmi2") { HasBMI2 = true; - continue; - } - - if (Feature == "popcnt") { + } else if (Feature == "+popcnt") { HasPOPCNT = true; - continue; - } - - if (Feature == "rtm") { + } else if (Feature == "+rtm") { HasRTM = true; - continue; - } - - if (Feature == "prfchw") { + } else if (Feature == "+prfchw") { HasPRFCHW = true; - continue; - } - - if (Feature == "rdseed") { + } else if (Feature == "+rdseed") { HasRDSEED = true; - continue; - } - - if (Feature == "adx") { + } else if (Feature == "+adx") { HasADX = true; - continue; - } - - if (Feature == "tbm") { + } else if (Feature == "+tbm") { HasTBM = true; - continue; - } - - if (Feature == "fma") { + } else if (Feature == "+fma") { HasFMA = true; - continue; - } - - if (Feature == "f16c") { + } else if (Feature == "+f16c") { HasF16C = true; - continue; - } - - if (Feature == "avx512cd") { + } else if (Feature == "+avx512cd") { HasAVX512CD = true; - continue; - } - - if (Feature == "avx512er") { + } else if (Feature == "+avx512er") { HasAVX512ER = true; - continue; - } - - if (Feature == "avx512pf") { + } else if (Feature == "+avx512pf") { HasAVX512PF = true; - continue; - } - - if (Feature == "avx512dq") { + } else if (Feature == "+avx512dq") { HasAVX512DQ = true; - continue; - } - - if (Feature == "avx512bw") { + } else if (Feature == "+avx512bw") { HasAVX512BW = true; - continue; - } - - if (Feature == "avx512vl") { + } else if (Feature == "+avx512vl") { HasAVX512VL = true; - continue; - } - - if (Feature == "sha") { + } else if (Feature == "+sha") { HasSHA = true; - continue; - } - - if (Feature == "cx16") { + } else if (Feature == "+cx16") { HasCX16 = true; - continue; + } else if (Feature == "+fxsr") { + HasFXSR = true; + } else if (Feature == "+xsave") { + HasXSAVE = true; + } else if (Feature == "+xsaveopt") { + HasXSAVEOPT = true; + } else if (Feature == "+xsavec") { + HasXSAVEC = true; + } else if (Feature == "+xsaves") { + HasXSAVES = true; } - 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) + .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) + .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) + .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"; + if ((FPMath == FP_SSE && SSELevel < SSE1) || + (FPMath == FP_387 && SSELevel >= SSE1)) { + Diags.Report(diag::err_target_unsupported_fpmath) << + (FPMath == FP_SSE ? "sse" : "387"); return false; } - // 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; + hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128; return true; } @@ -3290,6 +3312,17 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, if (HasSHA) Builder.defineMacro("__SHA__"); + if (HasFXSR) + Builder.defineMacro("__FXSR__"); + if (HasXSAVE) + Builder.defineMacro("__XSAVE__"); + if (HasXSAVEOPT) + Builder.defineMacro("__XSAVEOPT__"); + if (HasXSAVEC) + Builder.defineMacro("__XSAVEC__"); + if (HasXSAVES) + Builder.defineMacro("__XSAVES__"); + if (HasCX16) Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16"); @@ -3379,6 +3412,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const { .Case("fma", HasFMA) .Case("fma4", XOPLevel >= FMA4) .Case("fsgsbase", HasFSGSBASE) + .Case("fxsr", HasFXSR) .Case("lzcnt", HasLZCNT) .Case("mm3dnow", MMX3DNowLevel >= AMD3DNow) .Case("mm3dnowa", MMX3DNowLevel >= AMD3DNowAthlon) @@ -3402,6 +3436,10 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const { .Case("x86_32", getTriple().getArch() == llvm::Triple::x86) .Case("x86_64", getTriple().getArch() == llvm::Triple::x86_64) .Case("xop", XOPLevel >= XOP) + .Case("xsave", HasXSAVE) + .Case("xsavec", HasXSAVEC) + .Case("xsaves", HasXSAVES) + .Case("xsaveopt", HasXSAVEOPT) .Default(false); } @@ -3437,6 +3475,14 @@ X86TargetInfo::validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const { switch (*Name) { default: return false; + // Constant constraints. + case 'e': // 32-bit signed integer constant for use with sign-extending x86_64 + // instructions. + case 'Z': // 32-bit unsigned integer constant for use with zero-extending + // x86_64 instructions. + case 's': + Info.setRequiresImmediate(); + return true; case 'I': Info.setRequiresImmediate(0, 31); return true; @@ -3447,8 +3493,7 @@ X86TargetInfo::validateAsmConstraint(const char *&Name, Info.setRequiresImmediate(-128, 127); return true; case 'L': - // FIXME: properly analyze this constraint: - // must be one of 0xff, 0xffff, or 0xffffffff + Info.setRequiresImmediate({ int(0xff), int(0xffff), int(0xffffffff) }); return true; case 'M': Info.setRequiresImmediate(0, 3); @@ -3459,20 +3504,24 @@ X86TargetInfo::validateAsmConstraint(const char *&Name, 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. + // Register constraints. + case 'Y': // 'Y' is the first character for several 2-character constraints. + // Shift the pointer to the second character of the constraint. + Name++; + switch (*Name) { + default: + return false; + case '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. + Info.setAllowsRegister(); + return true; + } + case 'f': // Any x87 floating point stack register. // Constraint 'f' cannot be used for output operands. if (Info.ConstraintStr[0] == '=') return false; - Info.setAllowsRegister(); return true; case 'a': // eax. @@ -3482,8 +3531,8 @@ X86TargetInfo::validateAsmConstraint(const char *&Name, 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 '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. @@ -3493,12 +3542,9 @@ X86TargetInfo::validateAsmConstraint(const char *&Name, // index in a base+index memory access. Info.setAllowsRegister(); return true; + // Floating point constant constraints. case 'C': // SSE floating point constant. case 'G': // x87 floating point constant. - 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; } } @@ -3530,8 +3576,30 @@ bool X86TargetInfo::validateOperandSize(StringRef Constraint, case 'u': return Size <= 128; case 'x': - // 256-bit ymm registers can be used if target supports AVX. - return Size <= (SSELevel >= AVX ? 256U : 128U); + if (SSELevel >= AVX512F) + // 512-bit zmm registers can be used if target supports AVX512F. + return Size <= 512U; + else if (SSELevel >= AVX) + // 256-bit ymm registers can be used if target supports AVX. + return Size <= 256U; + return Size <= 128U; + case 'Y': + // 'Y' is the first character for several 2-character constraints. + switch (Constraint[1]) { + default: break; + case 'm': + // 'Ym' is synonymous with 'y'. + return Size <= 64; + case 'i': + case 't': + // 'Yi' and 'Yt' are synonymous with 'x' when SSE2 is enabled. + if (SSELevel >= AVX512F) + return Size <= 512U; + else if (SSELevel >= AVX) + return Size <= 256U; + return SSELevel >= SSE2 && Size <= 128U; + } + } return true; @@ -3565,7 +3633,7 @@ public: LongDoubleWidth = 96; LongDoubleAlign = 32; SuitableAlign = 128; - DescriptionString = "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128"; + DataLayoutString = "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128"; SizeType = UnsignedInt; PtrDiffType = SignedInt; IntPtrType = SignedInt; @@ -3656,12 +3724,26 @@ public: LongDoubleAlign = 128; SuitableAlign = 128; MaxVectorAlign = 256; + // The watchOS simulator uses the builtin bool type for Objective-C. + llvm::Triple T = llvm::Triple(Triple); + if (T.isWatchOS()) + UseSignedCharForObjCBool = false; SizeType = UnsignedLong; IntPtrType = SignedLong; - DescriptionString = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128"; + DataLayoutString = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128"; HasAlignMac68kSupport = true; } + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override { + if (!DarwinTargetInfo<X86_32TargetInfo>::handleTargetFeatures(Features, + Diags)) + return false; + // We now know the features we have: we can decide how to align vectors. + MaxVectorAlign = + hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128; + return true; + } }; // x86-32 Windows target @@ -3673,9 +3755,9 @@ public: 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"; + DataLayoutString = 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 { @@ -3701,12 +3783,11 @@ public: 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. + // 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 @@ -3733,7 +3814,6 @@ static void addMinGWDefines(const LangOptions &Opts, MacroBuilder &Builder) { addCygMingDefines(Opts, Builder); } -namespace { // x86-32 MinGW target class MinGWX86_32TargetInfo : public WindowsX86_32TargetInfo { public: @@ -3754,10 +3834,9 @@ 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"; + DataLayoutString = "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 { @@ -3791,6 +3870,27 @@ public: } }; +// X86-32 MCU target +class MCUX86_32TargetInfo : public X86_32TargetInfo { +public: + MCUX86_32TargetInfo(const llvm::Triple &Triple) : X86_32TargetInfo(Triple) { + LongDoubleWidth = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble; + } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + // On MCU we support only C calling convention. + return CC == CC_C ? CCCR_OK : CCCR_Warning; + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + X86_32TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__iamcu"); + Builder.defineMacro("__iamcu__"); + } +}; + // RTEMS Target template<typename Target> class RTEMSTargetInfo : public OSTargetInfo<Target> { @@ -3864,10 +3964,10 @@ public: 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"; + DataLayoutString = 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); @@ -3875,6 +3975,9 @@ public: // Use fp2ret for _Complex long double. ComplexLongDoubleUsesFP2Ret = true; + // Make __builtin_ms_va_list available. + HasBuiltinMSVaList = true; + // x86-64 has atomics up to 16 bytes. MaxAtomicPromoteWidth = 128; MaxAtomicInlineWidth = 128; @@ -3902,6 +4005,22 @@ public: // for x32 we need it here explicitly bool hasInt128Type() const override { return true; } + + bool validateGlobalRegisterVariable(StringRef RegName, + unsigned RegSize, + bool &HasSizeMismatch) const override { + // rsp and rbp are the only 64-bit registers the x86 backend can currently + // handle. + if (RegName.equals("rsp") || RegName.equals("rbp")) { + // Check that the register size is 64-bit. + HasSizeMismatch = RegSize != 64; + return true; + } + + // Check if the register is a 32-bit register the backend can handle. + return X86TargetInfo::validateGlobalRegisterVariable(RegName, RegSize, + HasSizeMismatch); + } }; // x86-64 Windows target @@ -3959,8 +4078,8 @@ public: MacroBuilder &Builder) const override { WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder); WindowsX86_64TargetInfo::getVisualStudioDefines(Opts, Builder); - Builder.defineMacro("_M_X64"); - Builder.defineMacro("_M_AMD64"); + Builder.defineMacro("_M_X64", "100"); + Builder.defineMacro("_M_AMD64", "100"); } }; @@ -3988,17 +4107,52 @@ public: } }; +// x86-64 Cygwin target +class CygwinX86_64TargetInfo : public X86_64TargetInfo { +public: + CygwinX86_64TargetInfo(const llvm::Triple &Triple) + : X86_64TargetInfo(Triple) { + TLSSupported = false; + WCharType = UnsignedShort; + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + X86_64TargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("__x86_64__"); + Builder.defineMacro("__CYGWIN__"); + Builder.defineMacro("__CYGWIN64__"); + addCygMingDefines(Opts, Builder); + DefineStd(Builder, "unix", Opts); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + + // 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"; + DataLayoutString = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"; + } + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override { + if (!DarwinTargetInfo<X86_64TargetInfo>::handleTargetFeatures(Features, + Diags)) + return false; + // We now know the features we have: we can decide how to align vectors. + MaxVectorAlign = + hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128; + return true; } }; @@ -4045,16 +4199,23 @@ class ARMTargetInfo : public TargetInfo { std::string ABI, CPU; + StringRef CPUProfile; + StringRef CPUAttr; + enum { FP_Default, FP_VFP, FP_Neon } FPMath; + unsigned ArchISA; + unsigned ArchKind = llvm::ARM::AK_ARMV4T; + unsigned ArchProfile; + unsigned ArchVersion; + unsigned FPU : 5; unsigned IsAAPCS : 1; - unsigned IsThumb : 1; unsigned HWDiv : 2; // Initialized via features. @@ -4063,6 +4224,17 @@ class ARMTargetInfo : public TargetInfo { unsigned CRC : 1; unsigned Crypto : 1; + unsigned DSP : 1; + unsigned Unaligned : 1; + + enum { + LDREX_B = (1 << 0), /// byte (8-bit) + LDREX_H = (1 << 1), /// half (16-bit) + LDREX_W = (1 << 2), /// word (32-bit) + LDREX_D = (1 << 3), /// double (64-bit) + }; + + uint32_t LDREX; // ACLE 6.5.1 Hardware floating point enum { @@ -4074,37 +4246,6 @@ class ARMTargetInfo : public TargetInfo { 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; @@ -4139,24 +4280,24 @@ class ARMTargetInfo : public TargetInfo { // Thumb1 add sp, #imm requires the immediate value be multiple of 4, // so set preferred for small types to 32. if (T.isOSBinFormatMachO()) { - DescriptionString = + DataLayoutString = 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"; + DataLayoutString = "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"; + DataLayoutString = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S128"; } else { - DescriptionString = + DataLayoutString = 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"; } @@ -4164,12 +4305,15 @@ class ARMTargetInfo : public TargetInfo { // FIXME: Enumerated types are variable width in straight AAPCS. } - void setABIAPCS() { + void setABIAPCS(bool IsAAPCS16) { const llvm::Triple &T = getTriple(); IsAAPCS = false; - DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 32; + if (IsAAPCS16) + DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64; + else + DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 32; // size_t is unsigned int on FreeBSD. if (T.getOS() == llvm::Triple::FreeBSD) @@ -4189,13 +4333,16 @@ class ARMTargetInfo : public TargetInfo { /// gcc. ZeroLengthBitfieldBoundary = 32; - if (T.isOSBinFormatMachO()) - DescriptionString = + if (T.isOSBinFormatMachO() && IsAAPCS16) { + assert(!BigEndian && "AAPCS16 does not support big-endian"); + DataLayoutString = "e-m:o-p:32:32-i64:64-a:0:32-n32-S128"; + } else if (T.isOSBinFormatMachO()) + DataLayoutString = 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 = + DataLayoutString = 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"; @@ -4203,10 +4350,104 @@ class ARMTargetInfo : public TargetInfo { // FIXME: Override "preferred align" for double and long long. } + void setArchInfo() { + StringRef ArchName = getTriple().getArchName(); + + ArchISA = llvm::ARM::parseArchISA(ArchName); + CPU = llvm::ARM::getDefaultCPU(ArchName); + unsigned AK = llvm::ARM::parseArch(ArchName); + if (AK != llvm::ARM::AK_INVALID) + ArchKind = AK; + setArchInfo(ArchKind); + } + + void setArchInfo(unsigned Kind) { + StringRef SubArch; + + // cache TargetParser info + ArchKind = Kind; + SubArch = llvm::ARM::getSubArch(ArchKind); + ArchProfile = llvm::ARM::parseArchProfile(SubArch); + ArchVersion = llvm::ARM::parseArchVersion(SubArch); + + // cache CPU related strings + CPUAttr = getCPUAttr(); + CPUProfile = getCPUProfile(); + } + + void setAtomic() { + // when triple does not specify a sub arch, + // then we are not using inline atomics + bool ShouldUseInlineAtomic = + (ArchISA == llvm::ARM::IK_ARM && ArchVersion >= 6) || + (ArchISA == llvm::ARM::IK_THUMB && ArchVersion >= 7); + // Cortex M does not support 8 byte atomics, while general Thumb2 does. + if (ArchProfile == llvm::ARM::PK_M) { + MaxAtomicPromoteWidth = 32; + if (ShouldUseInlineAtomic) + MaxAtomicInlineWidth = 32; + } + else { + MaxAtomicPromoteWidth = 64; + if (ShouldUseInlineAtomic) + MaxAtomicInlineWidth = 64; + } + } + + bool isThumb() const { + return (ArchISA == llvm::ARM::IK_THUMB); + } + + bool supportsThumb() const { + return CPUAttr.count('T') || ArchVersion >= 6; + } + + bool supportsThumb2() const { + return CPUAttr.equals("6T2") || ArchVersion >= 7; + } + + StringRef getCPUAttr() const { + // For most sub-arches, the build attribute CPU name is enough. + // For Cortex variants, it's slightly different. + switch(ArchKind) { + default: + return llvm::ARM::getCPUAttr(ArchKind); + case llvm::ARM::AK_ARMV6M: + return "6M"; + case llvm::ARM::AK_ARMV7S: + return "7S"; + case llvm::ARM::AK_ARMV7A: + 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"; + } + } + + StringRef getCPUProfile() const { + switch(ArchProfile) { + case llvm::ARM::PK_A: + return "A"; + case llvm::ARM::PK_R: + return "R"; + case llvm::ARM::PK_M: + return "M"; + default: + return ""; + } + } + public: ARMTargetInfo(const llvm::Triple &Triple, bool IsBigEndian) - : TargetInfo(Triple), CPU("arm1136j-s"), FPMath(FP_Default), - IsAAPCS(true), HW_FP(0) { + : TargetInfo(Triple), FPMath(FP_Default), + IsAAPCS(true), LDREX(0), HW_FP(0) { BigEndian = IsBigEndian; switch (getTriple().getOS()) { @@ -4218,13 +4459,13 @@ public: break; } + // Cache arch related info. + setArchInfo(); + // {} 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. @@ -4235,6 +4476,8 @@ public: Triple.getOS() == llvm::Triple::UnknownOS || StringRef(CPU).startswith("cortex-m")) { setABI("aapcs"); + } else if (Triple.isWatchOS()) { + setABI("aapcs16"); } else { setABI("apcs-gnu"); } @@ -4254,8 +4497,8 @@ public: setABI("aapcs"); break; case llvm::Triple::GNU: - setABI("apcs-gnu"); - break; + setABI("apcs-gnu"); + break; default: if (Triple.getOS() == llvm::Triple::NetBSD) setABI("apcs-gnu"); @@ -4269,9 +4512,7 @@ public: TheCXXABI.set(TargetCXXABI::GenericARM); // ARM has atomics up to 8 bytes - MaxAtomicPromoteWidth = 64; - if (shouldUseInlineAtomic(getTriple())) - MaxAtomicInlineWidth = 64; + setAtomic(); // Do force alignment of members that follow zero length bitfields. If // the alignment of the zero-length bitfield is greater than the member @@ -4289,8 +4530,8 @@ public: // // FIXME: We need support for -meabi... we could just mangle it into the // name. - if (Name == "apcs-gnu") { - setABIAPCS(); + if (Name == "apcs-gnu" || Name == "aapcs16") { + setABIAPCS(Name == "aapcs16"); return true; } if (Name == "aapcs" || Name == "aapcs-vfp" || Name == "aapcs-linux") { @@ -4301,43 +4542,27 @@ public: } // 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 + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override { + + std::vector<const char*> TargetFeatures; + unsigned Arch = llvm::ARM::parseArch(getTriple().getArchName()); + + // get default FPU features + unsigned FPUKind = llvm::ARM::getDefaultFPU(CPU, Arch); + llvm::ARM::getFPUFeatures(FPUKind, TargetFeatures); + + // get default Extension features + unsigned Extensions = llvm::ARM::getDefaultExtensions(CPU, Arch); + llvm::ARM::getExtensionFeatures(Extensions, TargetFeatures); + + for (const char *Feature : TargetFeatures) + if (Feature[0] == '+') + Features[Feature+1] = true; + + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } bool handleTargetFeatures(std::vector<std::string> &Features, @@ -4345,6 +4570,8 @@ public: FPU = 0; CRC = 0; Crypto = 0; + DSP = 0; + Unaligned = 1; SoftFloat = SoftFloatABI = false; HWDiv = 0; @@ -4379,12 +4606,37 @@ public: CRC = 1; } else if (Feature == "+crypto") { Crypto = 1; + } else if (Feature == "+dsp") { + DSP = 1; } else if (Feature == "+fp-only-sp") { - HW_FP_remove |= HW_FP_DP | HW_FP_HP; + HW_FP_remove |= HW_FP_DP; + } else if (Feature == "+strict-align") { + Unaligned = 0; + } else if (Feature == "+fp16") { + HW_FP |= HW_FP_HP; } } HW_FP &= ~HW_FP_remove; + switch (ArchVersion) { + case 6: + if (ArchProfile == llvm::ARM::PK_M) + LDREX = 0; + else if (ArchKind == llvm::ARM::AK_ARMV6K) + LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B ; + else + LDREX = LDREX_W; + break; + case 7: + if (ArchProfile == llvm::ARM::PK_M) + LDREX = LDREX_W | LDREX_H | LDREX_B ; + else + LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B ; + break; + case 8: + LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B ; + } + if (!(FPU & NeonFPU) && FPMath == FP_Neon) { Diags.Report(diag::err_target_unsupported_fpmath) << "neon"; return false; @@ -4407,107 +4659,28 @@ public: bool hasFeature(StringRef Feature) const override { return llvm::StringSwitch<bool>(Feature) .Case("arm", true) + .Case("aarch32", true) .Case("softfloat", SoftFloat) - .Case("thumb", IsThumb) + .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; - } + if (Name != "generic") + setArchInfo(llvm::ARM::parseCPUArch(Name)); + if (ArchKind == llvm::ARM::AK_INVALID) + return false; + setAtomic(); 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. @@ -4517,21 +4690,29 @@ public: // 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 + "__"); + // Unfortunately, __ARM_ARCH_7K__ is now more of an ABI descriptor. The CPU + // happens to be Cortex-A7 though, so it should still get __ARM_ARCH_7A__. + if (getTriple().isWatchOS()) + Builder.defineMacro("__ARM_ARCH_7K__", "2"); - // ACLE 6.4.1 ARM/Thumb instruction set architecture - StringRef CPUProfile = getCPUProfile(CPU); - StringRef ArchName = getTriple().getArchName(); + if (!CPUAttr.empty()) + Builder.defineMacro("__ARM_ARCH_" + CPUAttr + "__"); + // ACLE 6.4.1 ARM/Thumb instruction set architecture // __ARM_ARCH is defined as an integer value indicating the current ARM ISA - Builder.defineMacro("__ARM_ARCH", CPUArch.substr(0, 1)); - if (CPUArch[0] >= '8') { - Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN"); - Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING"); + Builder.defineMacro("__ARM_ARCH", Twine(ArchVersion)); + + if (ArchVersion >= 8) { + // ACLE 6.5.7 Crypto Extension + if (Crypto) + Builder.defineMacro("__ARM_FEATURE_CRYPTO", "1"); + // ACLE 6.5.8 CRC32 Extension + if (CRC) + Builder.defineMacro("__ARM_FEATURE_CRC32", "1"); + // ACLE 6.5.10 Numeric Maximum and Minimum + Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN", "1"); + // ACLE 6.5.9 Directed Rounding + Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING", "1"); } // __ARM_ARCH_ISA_ARM is defined to 1 if the core supports the ARM ISA. It @@ -4543,9 +4724,9 @@ public: // __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)) + if (supportsThumb2()) Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "2"); - else if (supportsThumb(ArchName, CPUArch, CPUArchVer)) + else if (supportsThumb()) Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "1"); // __ARM_32BIT_STATE is defined to 1 if code is being generated for a 32-bit @@ -4558,6 +4739,20 @@ public: if (!CPUProfile.empty()) Builder.defineMacro("__ARM_ARCH_PROFILE", "'" + CPUProfile + "'"); + // ACLE 6.4.3 Unaligned access supported in hardware + if (Unaligned) + Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1"); + + // ACLE 6.4.4 LDREX/STREX + if (LDREX) + Builder.defineMacro("__ARM_FEATURE_LDREX", "0x" + llvm::utohexstr(LDREX)); + + // ACLE 6.4.5 CLZ + if (ArchVersion == 5 || + (ArchVersion == 6 && CPUProfile != "M") || + ArchVersion > 6) + Builder.defineMacro("__ARM_FEATURE_CLZ", "1"); + // ACLE 6.5.1 Hardware Floating Point if (HW_FP) Builder.defineMacro("__ARM_FP", "0x" + llvm::utohexstr(HW_FP)); @@ -4565,12 +4760,20 @@ public: // ACLE predefines. Builder.defineMacro("__ARM_ACLE", "200"); + // FP16 support (we currently only support IEEE format). + Builder.defineMacro("__ARM_FP16_FORMAT_IEEE", "1"); + Builder.defineMacro("__ARM_FP16_ARGS", "1"); + + // ACLE 6.5.3 Fused multiply-accumulate (FMA) + if (ArchVersion >= 7 && (CPUProfile != "M" || CPUAttr == "7EM")) + Builder.defineMacro("__ARM_FEATURE_FMA", "1"); + // Subtarget options. // FIXME: It's more complicated than this and we don't really support // interworking. // Windows on ARM does not "support" interworking - if (5 <= CPUArchVer && CPUArchVer <= 8 && !getTriple().isOSWindows()) + if (5 <= ArchVersion && ArchVersion <= 8 && !getTriple().isOSWindows()) Builder.defineMacro("__THUMB_INTERWORK__"); if (ABI == "aapcs" || ABI == "aapcs-linux" || ABI == "aapcs-vfp") { @@ -4590,14 +4793,23 @@ public: if (CPU == "xscale") Builder.defineMacro("__XSCALE__"); - if (IsThumb) { + if (isThumb()) { Builder.defineMacro("__THUMBEL__"); Builder.defineMacro("__thumb__"); - if (supportsThumb2(ArchName, CPUArch, CPUArchVer)) + if (supportsThumb2()) Builder.defineMacro("__thumb2__"); } - if (((HWDiv & HWDivThumb) && IsThumb) || ((HWDiv & HWDivARM) && !IsThumb)) + + // ACLE 6.4.9 32-bit SIMD instructions + if (ArchVersion >= 6 && (CPUProfile != "M" || CPUAttr == "7EM")) + Builder.defineMacro("__ARM_FEATURE_SIMD32", "1"); + + // ACLE 6.4.10 Hardware Integer Divide + if (((HWDiv & HWDivThumb) && isThumb()) || + ((HWDiv & HWDivARM) && !isThumb())) { + Builder.defineMacro("__ARM_FEATURE_IDIV", "1"); Builder.defineMacro("__ARM_ARCH_EXT_IDIV__", "1"); + } // Note, this is always on in gcc, even though it doesn't make sense. Builder.defineMacro("__APCS_32__"); @@ -4616,9 +4828,13 @@ public: // 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"); + if ((FPU & NeonFPU) && !SoftFloat && ArchVersion >= 7) { + Builder.defineMacro("__ARM_NEON", "1"); Builder.defineMacro("__ARM_NEON__"); + // current AArch32 NEON implementations do not support double-precision + // floating-point even when it is present in VFP. + Builder.defineMacro("__ARM_NEON_FP", + "0x" + llvm::utohexstr(HW_FP & ~HW_FP_DP)); } Builder.defineMacro("__ARM_SIZEOF_WCHAR_T", @@ -4627,39 +4843,49 @@ public: 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") { + if (ArchVersion >= 6 && CPUAttr != "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"); + // ACLE 6.4.7 DSP instructions + if (DSP) { + Builder.defineMacro("__ARM_FEATURE_DSP", "1"); + } + + // ACLE 6.4.8 Saturation instructions + bool SAT = false; + if ((ArchVersion == 6 && CPUProfile != "M") || ArchVersion > 6 ) { + Builder.defineMacro("__ARM_FEATURE_SAT", "1"); + SAT = true; + } + + // ACLE 6.4.6 Q (saturation) flag + if (DSP || SAT) + Builder.defineMacro("__ARM_FEATURE_QBIT", "1"); + + if (Opts.UnsafeFPMath) + Builder.defineMacro("__ARM_FP_FAST", "1"); + + if (ArchKind == llvm::ARM::AK_ARMV8_1A) + Builder.defineMacro("__ARM_FEATURE_QRDMX", "1"); } - void getTargetBuiltins(const Builtin::Info *&Records, - unsigned &NumRecords) const override { - Records = BuiltinInfo; - NumRecords = clang::ARM::LastTSBuiltin-Builtin::FirstTSBuiltin; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override { + return llvm::makeArrayRef(BuiltinInfo, + clang::ARM::LastTSBuiltin-Builtin::FirstTSBuiltin); } bool isCLZForZeroUndef() const override { return false; } BuiltinVaListKind getBuiltinVaListKind() const override { - return IsAAPCS ? AAPCSABIBuiltinVaList : TargetInfo::VoidPtrBuiltinVaList; + return IsAAPCS + ? AAPCSABIBuiltinVaList + : (getTriple().isWatchOS() ? TargetInfo::CharPtrBuiltinVaList + : TargetInfo::VoidPtrBuiltinVaList); } - void getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const override; - void getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const override; + ArrayRef<const char *> getGCCRegNames() const override; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { switch (*Name) { @@ -4754,6 +4980,10 @@ public: if (RegNo == 1) return 1; return -1; } + + bool hasSjLjLowering() const override { + return true; + } }; bool ARMTargetInfo::setFPMath(StringRef Name) { @@ -4790,10 +5020,8 @@ const char * const ARMTargetInfo::GCCRegNames[] = { "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); +ArrayRef<const char *> ARMTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); } const TargetInfo::GCCRegAlias ARMTargetInfo::GCCRegAliases[] = { @@ -4817,22 +5045,23 @@ const TargetInfo::GCCRegAlias ARMTargetInfo::GCCRegAliases[] = { // 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); +ArrayRef<TargetInfo::GCCRegAlias> ARMTargetInfo::getGCCRegAliases() const { + return llvm::makeArrayRef(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 }, +#define BUILTIN(ID, TYPE, ATTRS) \ + { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsNEON.def" -#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 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 }, +#define BUILTIN(ID, TYPE, ATTRS) \ + { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, +#define LANGBUILTIN(ID, TYPE, ATTRS, LANG) \ + { #ID, TYPE, ATTRS, nullptr, LANG, nullptr }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsARM.def" }; @@ -4891,6 +5120,19 @@ public: BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + switch (CC) { + case CC_X86StdCall: + case CC_X86ThisCall: + case CC_X86FastCall: + case CC_X86VectorCall: + return CCCR_Ignore; + case CC_C: + return CCCR_OK; + default: + return CCCR_Warning; + } + } }; // Windows ARM + Itanium C++ ABI Target @@ -4925,6 +5167,45 @@ public: } }; +// ARM MinGW target +class MinGWARMTargetInfo : public WindowsARMTargetInfo { +public: + MinGWARMTargetInfo(const llvm::Triple &Triple) + : WindowsARMTargetInfo(Triple) { + TheCXXABI.set(TargetCXXABI::GenericARM); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + WindowsARMTargetInfo::getTargetDefines(Opts, Builder); + DefineStd(Builder, "WIN32", Opts); + DefineStd(Builder, "WINNT", Opts); + Builder.defineMacro("_ARM_"); + addMinGWDefines(Opts, Builder); + } +}; + +// ARM Cygwin target +class CygwinARMTargetInfo : public ARMleTargetInfo { +public: + CygwinARMTargetInfo(const llvm::Triple &Triple) : ARMleTargetInfo(Triple) { + TLSSupported = false; + WCharType = UnsignedShort; + DoubleAlign = LongLongAlign = 64; + DataLayoutString = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"; + } + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + ARMleTargetInfo::getTargetDefines(Opts, Builder); + Builder.defineMacro("_ARM_"); + Builder.defineMacro("__CYGWIN__"); + Builder.defineMacro("__CYGWIN32__"); + DefineStd(Builder, "unix", Opts); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + } +}; + class DarwinARMTargetInfo : public DarwinTargetInfo<ARMleTargetInfo> { protected: @@ -4942,13 +5223,23 @@ public: // ARMleTargetInfo. MaxAtomicInlineWidth = 64; - // Darwin on iOS uses a variant of the ARM C++ ABI. - TheCXXABI.set(TargetCXXABI::iOS); + if (Triple.isWatchOS()) { + // Darwin on iOS uses a variant of the ARM C++ ABI. + TheCXXABI.set(TargetCXXABI::WatchOS); + + // The 32-bit ABI is silent on what ptrdiff_t should be, but given that + // size_t is long, it's a bit weird for it to be int. + PtrDiffType = SignedLong; + + // BOOL should be a real boolean on the new ABI + UseSignedCharForObjCBool = false; + } else + TheCXXABI.set(TargetCXXABI::iOS); } }; class AArch64TargetInfo : public TargetInfo { - virtual void setDescriptionString() = 0; + virtual void setDataLayoutString() = 0; static const TargetInfo::GCCRegAlias GCCRegAliases[]; static const char *const GCCRegNames[]; @@ -4960,6 +5251,8 @@ class AArch64TargetInfo : public TargetInfo { unsigned FPU; unsigned CRC; unsigned Crypto; + unsigned Unaligned; + unsigned V8_1A; static const Builtin::Info BuiltinInfo[]; @@ -4998,7 +5291,7 @@ public: // 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; + assert(UseBitFieldTypeAlignment && "bitfields affect type alignment"); UseZeroLengthBitfieldAlignment = true; // AArch64 targets default to using the ARM C++ ABI. @@ -5017,7 +5310,7 @@ public: bool setCPU(const std::string &Name) override { bool CPUKnown = llvm::StringSwitch<bool>(Name) .Case("generic", true) - .Cases("cortex-a53", "cortex-a57", "cortex-a72", true) + .Cases("cortex-a53", "cortex-a57", "cortex-a72", "cortex-a35", true) .Case("cyclone", true) .Default(false); return CPUKnown; @@ -5037,33 +5330,30 @@ public: 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_64BIT_STATE", "1"); + Builder.defineMacro("__ARM_PCS_AAPCS64", "1"); + Builder.defineMacro("__ARM_ARCH_ISA_A64", "1"); - 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_CLZ", "1"); + Builder.defineMacro("__ARM_FEATURE_FMA", "1"); + Builder.defineMacro("__ARM_FEATURE_LDREX", "0xF"); + Builder.defineMacro("__ARM_FEATURE_IDIV", "1"); // As specified in ACLE Builder.defineMacro("__ARM_FEATURE_DIV"); // For backwards compatibility - Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN"); - Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING"); + Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN", "1"); + Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING", "1"); Builder.defineMacro("__ARM_ALIGN_MAX_STACK_PWR", "4"); // 0xe implies support for half, single and double precision operations. - Builder.defineMacro("__ARM_FP", "0xe"); + 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"); + Builder.defineMacro("__ARM_FP16_FORMAT_IEEE", "1"); + Builder.defineMacro("__ARM_FP16_ARGS", "1"); - if (Opts.FastMath || Opts.FiniteMathOnly) - Builder.defineMacro("__ARM_FP_FAST"); - - if (Opts.C99 && !Opts.Freestanding) - Builder.defineMacro("__ARM_FP_FENV_ROUNDING"); + if (Opts.UnsafeFPMath) + Builder.defineMacro("__ARM_FP_FAST", "1"); Builder.defineMacro("__ARM_SIZEOF_WCHAR_T", Opts.ShortWChar ? "2" : "4"); @@ -5071,16 +5361,22 @@ public: Opts.ShortEnums ? "1" : "4"); if (FPU == NeonMode) { - Builder.defineMacro("__ARM_NEON"); + Builder.defineMacro("__ARM_NEON", "1"); // 64-bit NEON supports half, single and double precision operations. - Builder.defineMacro("__ARM_NEON_FP", "0xe"); + Builder.defineMacro("__ARM_NEON_FP", "0xE"); } if (CRC) - Builder.defineMacro("__ARM_FEATURE_CRC32"); + Builder.defineMacro("__ARM_FEATURE_CRC32", "1"); if (Crypto) - Builder.defineMacro("__ARM_FEATURE_CRYPTO"); + Builder.defineMacro("__ARM_FEATURE_CRYPTO", "1"); + + if (Unaligned) + Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1"); + + if (V8_1A) + Builder.defineMacro("__ARM_FEATURE_QRDMX", "1"); // All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work. Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); @@ -5089,15 +5385,15 @@ public: 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; + ArrayRef<Builtin::Info> getTargetBuiltins() const override { + return llvm::makeArrayRef(BuiltinInfo, + clang::AArch64::LastTSBuiltin - Builtin::FirstTSBuiltin); } bool hasFeature(StringRef Feature) const override { return Feature == "aarch64" || Feature == "arm64" || + Feature == "arm" || (Feature == "neon" && FPU == NeonMode); } @@ -5106,16 +5402,23 @@ public: FPU = FPUMode; CRC = 0; Crypto = 0; - for (unsigned i = 0, e = Features.size(); i != e; ++i) { - if (Features[i] == "+neon") + Unaligned = 1; + V8_1A = 0; + + for (const auto &Feature : Features) { + if (Feature == "+neon") FPU = NeonMode; - if (Features[i] == "+crc") + if (Feature == "+crc") CRC = 1; - if (Features[i] == "+crypto") + if (Feature == "+crypto") Crypto = 1; + if (Feature == "+strict-align") + Unaligned = 0; + if (Feature == "+v8.1a") + V8_1A = 1; } - setDescriptionString(); + setDataLayoutString(); return true; } @@ -5126,10 +5429,8 @@ public: return TargetInfo::AArch64ABIBuiltinVaList; } - void getGCCRegNames(const char *const *&Names, - unsigned &NumNames) const override; - void getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const override; + ArrayRef<const char *> getGCCRegNames() const override; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { @@ -5239,10 +5540,8 @@ const char *const AArch64TargetInfo::GCCRegNames[] = { "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); +ArrayRef<const char *> AArch64TargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); } const TargetInfo::GCCRegAlias AArch64TargetInfo::GCCRegAliases[] = { @@ -5254,28 +5553,26 @@ const TargetInfo::GCCRegAlias AArch64TargetInfo::GCCRegAliases[] = { // 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); +ArrayRef<TargetInfo::GCCRegAlias> AArch64TargetInfo::getGCCRegAliases() const { + return llvm::makeArrayRef(GCCRegAliases); } const Builtin::Info AArch64TargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ - { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, + { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsNEON.def" #define BUILTIN(ID, TYPE, ATTRS) \ - { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, + { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsAArch64.def" }; class AArch64leTargetInfo : public AArch64TargetInfo { - void setDescriptionString() override { + void setDataLayoutString() override { if (getTriple().isOSBinFormatMachO()) - DescriptionString = "e-m:o-i64:64-i128:128-n32:64-S128"; + DataLayoutString = "e-m:o-i64:64-i128:128-n32:64-S128"; else - DescriptionString = "e-m:e-i64:64-i128:128-n32:64-S128"; + DataLayoutString = "e-m:e-i64:64-i128:128-n32:64-S128"; } public: @@ -5291,9 +5588,9 @@ public: }; class AArch64beTargetInfo : public AArch64TargetInfo { - void setDescriptionString() override { + void setDataLayoutString() override { assert(!getTriple().isOSBinFormatMachO()); - DescriptionString = "E-m:e-i64:64-i128:128-n32:64-S128"; + DataLayoutString = "E-m:e-i64:64-i128:128-n32:64-S128"; } public: @@ -5347,20 +5644,32 @@ class HexagonTargetInfo : public TargetInfo { static const char * const GCCRegNames[]; static const TargetInfo::GCCRegAlias GCCRegAliases[]; std::string CPU; + bool HasHVX, HasHVXDouble; + public: HexagonTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { BigEndian = false; - DescriptionString = "e-m:e-p:32:32-i1:32-i64:64-a:0-n32"; + DataLayoutString = "e-m:e-p:32:32:32-" + "i64:64:64-i32:32:32-i16:16:16-i1:8:8-" + "f64:64:64-f32:32:32-v64:64:64-v32:32:32-a:0-n16:32"; + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; // {} in inline assembly are packet specifiers, not assembly variant // specifiers. NoAsmVariants = true; + + LargeArrayMinWidth = 64; + LargeArrayAlign = 64; + UseBitFieldTypeAlignment = true; + ZeroLengthBitfieldBoundary = 32; + HasHVX = HasHVXDouble = false; } - void getTargetBuiltins(const Builtin::Info *&Records, - unsigned &NumRecords) const override { - Records = BuiltinInfo; - NumRecords = clang::Hexagon::LastTSBuiltin-Builtin::FirstTSBuiltin; + ArrayRef<Builtin::Info> getTargetBuiltins() const override { + return llvm::makeArrayRef(BuiltinInfo, + clang::Hexagon::LastTSBuiltin-Builtin::FirstTSBuiltin); } bool validateAsmConstraint(const char *&Name, @@ -5371,17 +5680,28 @@ public: void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; + bool isCLZForZeroUndef() const override { return false; } + bool hasFeature(StringRef Feature) const override { - return Feature == "hexagon"; + return llvm::StringSwitch<bool>(Feature) + .Case("hexagon", true) + .Case("hvx", HasHVX) + .Case("hvx-double", HasHVXDouble) + .Default(false); } + bool initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, const std::vector<std::string> &FeaturesVec) + const override; + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override; + BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } - void getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const override; - void getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const override; + ArrayRef<const char *> getGCCRegNames() const override; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; const char *getClobbers() const override { return ""; } @@ -5390,71 +5710,77 @@ public: return llvm::StringSwitch<const char*>(Name) .Case("hexagonv4", "4") .Case("hexagonv5", "5") + .Case("hexagonv55", "55") + .Case("hexagonv60", "60") .Default(nullptr); } bool setCPU(const std::string &Name) override { if (!getHexagonCPUSuffix(Name)) return false; - CPU = Name; return true; } + + int getEHDataRegisterNumber(unsigned RegNo) const override { + return RegNo < 2 ? RegNo : -1; + } }; void HexagonTargetInfo::getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const { - Builder.defineMacro("qdsp6"); - Builder.defineMacro("__qdsp6", "1"); + MacroBuilder &Builder) const { 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") { + if (CPU == "hexagonv4") { Builder.defineMacro("__HEXAGON_V4__"); Builder.defineMacro("__HEXAGON_ARCH__", "4"); - if(Opts.HexagonQdsp6Compat) { + if (Opts.HexagonQdsp6Compat) { Builder.defineMacro("__QDSP6_V4__"); Builder.defineMacro("__QDSP6_ARCH__", "4"); } - } - else if(CPU == "hexagonv5") { + } 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"); } + } else if (CPU == "hexagonv60") { + Builder.defineMacro("__HEXAGON_V60__"); + Builder.defineMacro("__HEXAGON_ARCH__", "60"); + Builder.defineMacro("__QDSP6_V60__"); + Builder.defineMacro("__QDSP6_ARCH__", "60"); } } -const char * const HexagonTargetInfo::GCCRegNames[] = { +bool HexagonTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) { + for (auto &F : Features) { + if (F == "+hvx") + HasHVX = true; + else if (F == "-hvx") + HasHVX = HasHVXDouble = false; + else if (F == "+hvx-double") + HasHVX = HasHVXDouble = true; + else if (F == "-hvx-double") + HasHVXDouble = false; + } + return true; +} + +bool HexagonTargetInfo::initFeatureMap(llvm::StringMap<bool> &Features, + DiagnosticsEngine &Diags, StringRef CPU, + const std::vector<std::string> &FeaturesVec) const { + // Default for v60: -hvx, -hvx-double. + Features["hvx"] = false; + Features["hvx-double"] = false; + + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); +} + + +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", @@ -5463,30 +5789,26 @@ const char * const HexagonTargetInfo::GCCRegNames[] = { "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); +ArrayRef<const char*> HexagonTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(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); +ArrayRef<TargetInfo::GCCRegAlias> HexagonTargetInfo::getGCCRegAliases() const { + return llvm::makeArrayRef(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 }, +#define BUILTIN(ID, TYPE, ATTRS) \ + { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsHexagon.def" }; @@ -5526,17 +5848,15 @@ public: .Default(false); } - void getTargetBuiltins(const Builtin::Info *&Records, - unsigned &NumRecords) const override { + ArrayRef<Builtin::Info> getTargetBuiltins() const override { // FIXME: Implement! + return None; } 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; + ArrayRef<const char *> getGCCRegNames() const override; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override { // FIXME: Implement! @@ -5556,6 +5876,80 @@ public: // FIXME: Implement! return ""; } + + // No Sparc V7 for now, the backend doesn't support it anyway. + enum CPUKind { + CK_GENERIC, + CK_V8, + CK_SUPERSPARC, + CK_SPARCLITE, + CK_F934, + CK_HYPERSPARC, + CK_SPARCLITE86X, + CK_SPARCLET, + CK_TSC701, + CK_V9, + CK_ULTRASPARC, + CK_ULTRASPARC3, + CK_NIAGARA, + CK_NIAGARA2, + CK_NIAGARA3, + CK_NIAGARA4 + } CPU = CK_GENERIC; + + enum CPUGeneration { + CG_V8, + CG_V9, + }; + + CPUGeneration getCPUGeneration(CPUKind Kind) const { + switch (Kind) { + case CK_GENERIC: + case CK_V8: + case CK_SUPERSPARC: + case CK_SPARCLITE: + case CK_F934: + case CK_HYPERSPARC: + case CK_SPARCLITE86X: + case CK_SPARCLET: + case CK_TSC701: + return CG_V8; + case CK_V9: + case CK_ULTRASPARC: + case CK_ULTRASPARC3: + case CK_NIAGARA: + case CK_NIAGARA2: + case CK_NIAGARA3: + case CK_NIAGARA4: + return CG_V9; + } + llvm_unreachable("Unexpected CPU kind"); + } + + CPUKind getCPUKind(StringRef Name) const { + return llvm::StringSwitch<CPUKind>(Name) + .Case("v8", CK_V8) + .Case("supersparc", CK_SUPERSPARC) + .Case("sparclite", CK_SPARCLITE) + .Case("f934", CK_F934) + .Case("hypersparc", CK_HYPERSPARC) + .Case("sparclite86x", CK_SPARCLITE86X) + .Case("sparclet", CK_SPARCLET) + .Case("tsc701", CK_TSC701) + .Case("v9", CK_V9) + .Case("ultrasparc", CK_ULTRASPARC) + .Case("ultrasparc3", CK_ULTRASPARC3) + .Case("niagara", CK_NIAGARA) + .Case("niagara2", CK_NIAGARA2) + .Case("niagara3", CK_NIAGARA3) + .Case("niagara4", CK_NIAGARA4) + .Default(CK_GENERIC); + } + + bool setCPU(const std::string &Name) override { + CPU = getCPUKind(Name); + return CPU != CK_GENERIC; + } }; const char * const SparcTargetInfo::GCCRegNames[] = { @@ -5565,10 +5959,8 @@ const char * const SparcTargetInfo::GCCRegNames[] = { "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); +ArrayRef<const char *> SparcTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); } const TargetInfo::GCCRegAlias SparcTargetInfo::GCCRegAliases[] = { @@ -5606,33 +5998,48 @@ const TargetInfo::GCCRegAlias SparcTargetInfo::GCCRegAliases[] = { { { "i7" }, "r31" }, }; -void SparcTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const { - Aliases = GCCRegAliases; - NumAliases = llvm::array_lengthof(GCCRegAliases); +ArrayRef<TargetInfo::GCCRegAlias> SparcTargetInfo::getGCCRegAliases() const { + return llvm::makeArrayRef(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 { + DataLayoutString = "E-m:e-p:32:32-i64:64-f128:64-n32-S64"; + // NetBSD / OpenBSD use long (same as llvm default); everyone else uses int. + switch (getTriple().getOS()) { + default: SizeType = UnsignedInt; IntPtrType = SignedInt; PtrDiffType = SignedInt; + break; + case llvm::Triple::NetBSD: + case llvm::Triple::OpenBSD: + SizeType = UnsignedLong; + IntPtrType = SignedLong; + PtrDiffType = SignedLong; + break; } } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { SparcTargetInfo::getTargetDefines(Opts, Builder); - Builder.defineMacro("__sparcv8"); + switch (getCPUGeneration(CPU)) { + case CG_V8: + Builder.defineMacro("__sparcv8"); + if (getTriple().getOS() != llvm::Triple::Solaris) + Builder.defineMacro("__sparcv8__"); + break; + case CG_V9: + Builder.defineMacro("__sparcv9"); + if (getTriple().getOS() != llvm::Triple::Solaris) { + Builder.defineMacro("__sparcv9__"); + Builder.defineMacro("__sparc_v9__"); + } + break; + } } }; @@ -5640,7 +6047,7 @@ public: 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"; + DataLayoutString = "e-m:e-p:32:32-i64:64-f128:64-n32-S64"; BigEndian = false; } }; @@ -5650,7 +6057,7 @@ 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"; + DataLayoutString = "E-m:e-i64:64-n32:64-S128"; // This is an LP64 platform. LongWidth = LongAlign = PointerWidth = PointerAlign = 64; @@ -5683,19 +6090,9 @@ public: } 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; + if (!SparcTargetInfo::setCPU(Name)) + return false; + return getCPUGeneration(CPU) == CG_V9; } }; @@ -5708,7 +6105,8 @@ class SystemZTargetInfo : public TargetInfo { public: SystemZTargetInfo(const llvm::Triple &Triple) - : TargetInfo(Triple), CPU("z10"), HasTransactionalExecution(false), HasVector(false) { + : TargetInfo(Triple), CPU("z10"), HasTransactionalExecution(false), + HasVector(false) { IntMaxType = SignedLong; Int64Type = SignedLong; TLSSupported = true; @@ -5720,7 +6118,7 @@ public: 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"; + DataLayoutString = "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, @@ -5734,19 +6132,15 @@ public: 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; + ArrayRef<Builtin::Info> getTargetBuiltins() const override { + return llvm::makeArrayRef(BuiltinInfo, + clang::SystemZ::LastTSBuiltin-Builtin::FirstTSBuiltin); } - void getGCCRegNames(const char *const *&Names, - unsigned &NumNames) const override; - void getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const override { + ArrayRef<const char *> getGCCRegNames() const override; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { // No aliases. - Aliases = nullptr; - NumAliases = 0; + return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override; @@ -5768,29 +6162,33 @@ public: return CPUKnown; } - void getDefaultFeatures(llvm::StringMap<bool> &Features) const override { + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override { if (CPU == "zEC12") Features["transactional-execution"] = true; if (CPU == "z13") { Features["transactional-execution"] = true; Features["vector"] = true; } + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } 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") + for (const auto &Feature : Features) { + if (Feature == "+transactional-execution") HasTransactionalExecution = true; - if (Features[i] == "+vector") + else if (Feature == "+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"; + DataLayoutString = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64" + "-v128:64-a:8:16-n32:64"; } return true; } @@ -5816,7 +6214,7 @@ public: const Builtin::Info SystemZTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ - { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, + { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsSystemZ.def" }; @@ -5827,10 +6225,8 @@ const char *const SystemZTargetInfo::GCCRegNames[] = { "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); +ArrayRef<const char *> SystemZTargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); } bool SystemZTargetInfo:: @@ -5862,157 +6258,147 @@ validateAsmConstraint(const char *&Name, } } - 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 ""; +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; + DataLayoutString = "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 + } + ArrayRef<Builtin::Info> getTargetBuiltins() const override { + // FIXME: Implement. + return None; + } + bool hasFeature(StringRef Feature) const override { + return Feature == "msp430"; + } + ArrayRef<const char *> getGCCRegNames() const override; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + // No aliases. + return None; + } + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override { + // FIXME: implement + switch (*Name) { + case 'K': // the constant 1 + case 'L': // constant -1^20 .. 1^19 + case 'M': // constant 1-4: + return true; } - BuiltinVaListKind getBuiltinVaListKind() const override { - // FIXME: implement - return TargetInfo::CharPtrBuiltinVaList; - } - }; + // 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" - }; +const char *const MSP430TargetInfo::GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}; + +ArrayRef<const char *> MSP430TargetInfo::getGCCRegNames() const { + return llvm::makeArrayRef(GCCRegNames); +} + +// 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 +}; - void MSP430TargetInfo::getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const { - Names = GCCRegNames; - NumNames = llvm::array_lengthof(GCCRegNames); +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; + DataLayoutString = "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; } - // 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 - }; + 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"; } - 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 {} - }; + ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } + const char *getClobbers() const override { return ""; } + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + ArrayRef<const char *> getGCCRegNames() const override { return None; } + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override { + return true; + } + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; + } +}; class BPFTargetInfo : public TargetInfo { public: @@ -6026,10 +6412,10 @@ public: RegParmMax = 5; if (Triple.getArch() == llvm::Triple::bpfeb) { BigEndian = true; - DescriptionString = "E-m:e-p:64:64-i64:64-n32:64-S128"; + DataLayoutString = "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"; + DataLayoutString = "e-m:e-p:64:64-i64:64-n32:64-S128"; } MaxAtomicPromoteWidth = 64; MaxAtomicInlineWidth = 64; @@ -6044,32 +6430,27 @@ public: return Feature == "bpf"; } - void getTargetBuiltins(const Builtin::Info *&Records, - unsigned &NumRecords) const override {} + ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } 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; + ArrayRef<const char *> getGCCRegNames() const override { + return None; } 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; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; } }; class MipsTargetInfoBase : public TargetInfo { - virtual void setDescriptionString() = 0; + virtual void setDataLayoutString() = 0; static const Builtin::Info BuiltinInfo[]; std::string CPU; @@ -6132,14 +6513,19 @@ public: .Case("mips64r5", true) .Case("mips64r6", true) .Case("octeon", true) + .Case("p5600", true) .Default(false); } const std::string& getCPU() const { return CPU; } - void getDefaultFeatures(llvm::StringMap<bool> &Features) const override { + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override { if (CPU == "octeon") Features["mips64r2"] = Features["cnmips"] = true; else Features[CPU] = true; + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } void getTargetDefines(const LangOptions &Opts, @@ -6199,12 +6585,17 @@ public: Builder.defineMacro("_MIPS_ARCH", "\"" + CPU + "\""); Builder.defineMacro("_MIPS_ARCH_" + StringRef(CPU).upper()); + + // These shouldn't be defined for MIPS-I but there's no need to check + // for that since MIPS-I isn't supported. + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); } - void getTargetBuiltins(const Builtin::Info *&Records, - unsigned &NumRecords) const override { - Records = BuiltinInfo; - NumRecords = clang::Mips::LastTSBuiltin - Builtin::FirstTSBuiltin; + ArrayRef<Builtin::Info> getTargetBuiltins() const override { + return llvm::makeArrayRef(BuiltinInfo, + clang::Mips::LastTSBuiltin - Builtin::FirstTSBuiltin); } bool hasFeature(StringRef Feature) const override { return llvm::StringSwitch<bool>(Feature) @@ -6215,8 +6606,7 @@ public: BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; } - void getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const override { + ArrayRef<const char *> getGCCRegNames() const override { static const char *const GCCRegNames[] = { // CPU register names // Must match second column of GCCRegAliases @@ -6241,11 +6631,9 @@ public: "$msair", "$msacsr", "$msaaccess", "$msasave", "$msamodify", "$msarequest", "$msamap", "$msaunmap" }; - Names = GCCRegNames; - NumNames = llvm::array_lengthof(GCCRegNames); + return llvm::makeArrayRef(GCCRegNames); } - void getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const override = 0; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override = 0; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { switch (*Name) { @@ -6331,33 +6719,32 @@ public: DspRev = NoDSP; HasFP64 = isFP64Default(); - for (std::vector<std::string>::iterator it = Features.begin(), - ie = Features.end(); it != ie; ++it) { - if (*it == "+single-float") + for (const auto &Feature : Features) { + if (Feature == "+single-float") IsSingleFloat = true; - else if (*it == "+soft-float") + else if (Feature == "+soft-float") FloatABI = SoftFloat; - else if (*it == "+mips16") + else if (Feature == "+mips16") IsMips16 = true; - else if (*it == "+micromips") + else if (Feature == "+micromips") IsMicromips = true; - else if (*it == "+dsp") + else if (Feature == "+dsp") DspRev = std::max(DspRev, DSP1); - else if (*it == "+dspr2") + else if (Feature == "+dspr2") DspRev = std::max(DspRev, DSP2); - else if (*it == "+msa") + else if (Feature == "+msa") HasMSA = true; - else if (*it == "+fp64") + else if (Feature == "+fp64") HasFP64 = true; - else if (*it == "-fp64") + else if (Feature == "-fp64") HasFP64 = false; - else if (*it == "+nan2008") + else if (Feature == "+nan2008") IsNan2008 = true; - else if (*it == "-nan2008") + else if (Feature == "-nan2008") IsNan2008 = false; } - setDescriptionString(); + setDataLayoutString(); return true; } @@ -6372,9 +6759,10 @@ public: }; 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 }, +#define BUILTIN(ID, TYPE, ATTRS) \ + { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsMips.def" }; @@ -6424,8 +6812,7 @@ public: else llvm_unreachable("Invalid ABI for Mips32."); } - void getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const override { + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { static const TargetInfo::GCCRegAlias GCCRegAliases[] = { { { "at" }, "$1" }, { { "v0" }, "$2" }, @@ -6459,14 +6846,13 @@ public: { { "fp","$fp" }, "$30" }, { { "ra" }, "$31" } }; - Aliases = GCCRegAliases; - NumAliases = llvm::array_lengthof(GCCRegAliases); + return llvm::makeArrayRef(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"; + void setDataLayoutString() override { + DataLayoutString = "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64"; } public: @@ -6482,8 +6868,8 @@ public: }; class Mips32ELTargetInfo : public Mips32TargetInfoBase { - void setDescriptionString() override { - DescriptionString = "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64"; + void setDataLayoutString() override { + DataLayoutString = "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64"; } public: @@ -6579,9 +6965,10 @@ public: } else llvm_unreachable("Invalid ABI for Mips64."); + + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); } - void getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const override { + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { static const TargetInfo::GCCRegAlias GCCRegAliases[] = { { { "at" }, "$1" }, { { "v0" }, "$2" }, @@ -6615,19 +7002,18 @@ public: { { "fp","$fp" }, "$30" }, { { "ra" }, "$31" } }; - Aliases = GCCRegAliases; - NumAliases = llvm::array_lengthof(GCCRegAliases); + return llvm::makeArrayRef(GCCRegAliases); } bool hasInt128Type() const override { return true; } }; class Mips64EBTargetInfo : public Mips64TargetInfoBase { - void setDescriptionString() override { + void setDataLayoutString() override { if (ABI == "n32") - DescriptionString = "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32:64-S128"; + DataLayoutString = "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"; + DataLayoutString = "E-m:m-i8:8:32-i16:16:32-i64:64-n32:64-S128"; } @@ -6643,11 +7029,11 @@ public: }; class Mips64ELTargetInfo : public Mips64TargetInfoBase { - void setDescriptionString() override { + void setDataLayoutString() override { if (ABI == "n32") - DescriptionString = "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32:64-S128"; + DataLayoutString = "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"; + DataLayoutString = "e-m:m-i8:8:32-i16:16:32-i64:64-n32:64-S128"; } public: Mips64ELTargetInfo(const llvm::Triple &Triple) @@ -6683,8 +7069,6 @@ public: 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__"); @@ -6696,16 +7080,12 @@ public: bool hasFeature(StringRef Feature) const override { return Feature == "pnacl"; } - void getTargetBuiltins(const Builtin::Info *&Records, - unsigned &NumRecords) const override { - } + ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } 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; + ArrayRef<const char *> getGCCRegNames() const override; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { return false; @@ -6716,24 +7096,19 @@ public: } }; -void PNaClTargetInfo::getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const { - Names = nullptr; - NumNames = 0; +ArrayRef<const char *> PNaClTargetInfo::getGCCRegNames() const { + return None; } -void PNaClTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const { - Aliases = nullptr; - NumAliases = 0; +ArrayRef<TargetInfo::GCCRegAlias> PNaClTargetInfo::getGCCRegAliases() const { + return None; } // 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; + Mips32ELTargetInfo(Triple) { } BuiltinVaListKind getBuiltinVaListKind() const override { @@ -6750,8 +7125,7 @@ public: 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"; + DataLayoutString = "e-m:e-v128:32-v16:16-v32:32-v96:32-n8:16:32:64-S128"; } void getTargetDefines(const LangOptions &Opts, @@ -6760,24 +7134,19 @@ public: 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; + ArrayRef<Builtin::Info> getTargetBuiltins() const override { + return llvm::makeArrayRef(BuiltinInfo, + 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; + ArrayRef<const char *> getGCCRegNames() const override { + return None; } - void getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const override { - Aliases = nullptr; - NumAliases = 0; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { @@ -6786,107 +7155,246 @@ public: bool hasProtectedVisibility() const override { return false; } }; -} // end anonymous namespace. + +class WebAssemblyTargetInfo : public TargetInfo { + static const Builtin::Info BuiltinInfo[]; + + enum SIMDEnum { + NoSIMD, + SIMD128, + } SIMDLevel; + +public: + explicit WebAssemblyTargetInfo(const llvm::Triple &T) + : TargetInfo(T), SIMDLevel(NoSIMD) { + BigEndian = false; + NoAsmVariants = true; + SuitableAlign = 128; + LargeArrayMinWidth = 128; + LargeArrayAlign = 128; + SimdDefaultAlign = 128; + SigAtomicType = SignedLong; + LongDoubleWidth = LongDoubleAlign = 128; + LongDoubleFormat = &llvm::APFloat::IEEEquad; + } + +protected: + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + defineCPUMacros(Builder, "wasm", /*Tuning=*/false); + if (SIMDLevel >= SIMD128) + Builder.defineMacro("__wasm_simd128__"); + } + +private: + bool + initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector<std::string> &FeaturesVec) const override { + if (CPU == "bleeding-edge") + Features["simd128"] = true; + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); + } + bool hasFeature(StringRef Feature) const final { + return llvm::StringSwitch<bool>(Feature) + .Case("simd128", SIMDLevel >= SIMD128) + .Default(false); + } + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) final { + for (const auto &Feature : Features) { + if (Feature == "+simd128") { + SIMDLevel = std::max(SIMDLevel, SIMD128); + continue; + } + if (Feature == "-simd128") { + SIMDLevel = std::min(SIMDLevel, SIMDEnum(SIMD128 - 1)); + continue; + } + + Diags.Report(diag::err_opt_not_valid_with_opt) << Feature + << "-target-feature"; + return false; + } + return true; + } + bool setCPU(const std::string &Name) final { + return llvm::StringSwitch<bool>(Name) + .Case("mvp", true) + .Case("bleeding-edge", true) + .Case("generic", true) + .Default(false); + } + ArrayRef<Builtin::Info> getTargetBuiltins() const final { + return llvm::makeArrayRef(BuiltinInfo, + clang::WebAssembly::LastTSBuiltin - Builtin::FirstTSBuiltin); + } + BuiltinVaListKind getBuiltinVaListKind() const final { + return VoidPtrBuiltinVaList; + } + ArrayRef<const char *> getGCCRegNames() const final { + return None; + } + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const final { + return None; + } + bool + validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const final { + return false; + } + const char *getClobbers() const final { return ""; } + bool isCLZForZeroUndef() const final { return false; } + bool hasInt128Type() const final { return true; } + IntType getIntTypeByWidth(unsigned BitWidth, + bool IsSigned) const final { + // WebAssembly prefers long long for explicitly 64-bit integers. + return BitWidth == 64 ? (IsSigned ? SignedLongLong : UnsignedLongLong) + : TargetInfo::getIntTypeByWidth(BitWidth, IsSigned); + } + IntType getLeastIntTypeByWidth(unsigned BitWidth, + bool IsSigned) const final { + // WebAssembly uses long long for int_least64_t and int_fast64_t. + return BitWidth == 64 + ? (IsSigned ? SignedLongLong : UnsignedLongLong) + : TargetInfo::getLeastIntTypeByWidth(BitWidth, IsSigned); + } +}; + +const Builtin::Info WebAssemblyTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, +#include "clang/Basic/BuiltinsWebAssembly.def" +}; + +class WebAssembly32TargetInfo : public WebAssemblyTargetInfo { +public: + explicit WebAssembly32TargetInfo(const llvm::Triple &T) + : WebAssemblyTargetInfo(T) { + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; + DataLayoutString = "e-p:32:32-i64:64-n32:64-S128"; + } + +protected: + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + WebAssemblyTargetInfo::getTargetDefines(Opts, Builder); + defineCPUMacros(Builder, "wasm32", /*Tuning=*/false); + } +}; + +class WebAssembly64TargetInfo : public WebAssemblyTargetInfo { +public: + explicit WebAssembly64TargetInfo(const llvm::Triple &T) + : WebAssemblyTargetInfo(T) { + LongAlign = LongWidth = 64; + PointerAlign = PointerWidth = 64; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + DataLayoutString = "e-p:64:64-i64:64-n32:64-S128"; + } + +protected: + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { + WebAssemblyTargetInfo::getTargetDefines(Opts, Builder); + defineCPUMacros(Builder, "wasm64", /*Tuning=*/false); + } +}; const Builtin::Info Le64TargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ - { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, + { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #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; - } +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"; + } - CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { - return (CC == CC_SpirFunction || - CC == CC_SpirKernel) ? CCCR_OK : CCCR_Warning; - } + ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } + const char *getClobbers() const override { return ""; } + ArrayRef<const char *> getGCCRegNames() const override { return None; } + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const override { + return true; + } + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; + } + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } - CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override { - return CC_SpirFunction; - } - }; + 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 SPIR32TargetInfo : public SPIRTargetInfo { +public: + SPIR32TargetInfo(const llvm::Triple &Triple) : SPIRTargetInfo(Triple) { + PointerWidth = PointerAlign = 32; + SizeType = TargetInfo::UnsignedInt; + PtrDiffType = IntPtrType = TargetInfo::SignedInt; + DataLayoutString = "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 SPIR64TargetInfo : public SPIRTargetInfo { +public: + SPIR64TargetInfo(const llvm::Triple &Triple) : SPIRTargetInfo(Triple) { + PointerWidth = PointerAlign = 64; + SizeType = TargetInfo::UnsignedLong; + PtrDiffType = IntPtrType = TargetInfo::SignedLong; + DataLayoutString = "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[]; @@ -6903,17 +7411,16 @@ public: 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"; + DataLayoutString = "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; + ArrayRef<Builtin::Info> getTargetBuiltins() const override { + return llvm::makeArrayRef(BuiltinInfo, + clang::XCore::LastTSBuiltin-Builtin::FirstTSBuiltin); } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; @@ -6921,19 +7428,15 @@ public: const char *getClobbers() const override { return ""; } - void getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const override { + ArrayRef<const char *> getGCCRegNames() const override { static const char * const GCCRegNames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "cp", "dp", "sp", "lr" }; - Names = GCCRegNames; - NumNames = llvm::array_lengthof(GCCRegNames); + return llvm::makeArrayRef(GCCRegNames); } - void getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const override { - Aliases = nullptr; - NumAliases = 0; + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { @@ -6946,14 +7449,13 @@ public: }; 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 }, +#define BUILTIN(ID, TYPE, ATTRS) \ + { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ + { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsXCore.def" }; -} // end anonymous namespace. -namespace { // x86_32 Android target class AndroidX86_32TargetInfo : public LinuxTargetInfo<X86_32TargetInfo> { public: @@ -6964,9 +7466,7 @@ public: LongDoubleFormat = &llvm::APFloat::IEEEdouble; } }; -} // end anonymous namespace -namespace { // x86_64 Android target class AndroidX86_64TargetInfo : public LinuxTargetInfo<X86_64TargetInfo> { public: @@ -6981,7 +7481,6 @@ public: }; } // end anonymous namespace - //===----------------------------------------------------------------------===// // Driver code //===----------------------------------------------------------------------===// @@ -7004,6 +7503,8 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) { return new DarwinAArch64TargetInfo(Triple); switch (os) { + case llvm::Triple::CloudABI: + return new CloudABITargetInfo<AArch64leTargetInfo>(Triple); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo<AArch64leTargetInfo>(Triple); case llvm::Triple::Linux: @@ -7048,6 +7549,10 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) { return new NaClTargetInfo<ARMleTargetInfo>(Triple); case llvm::Triple::Win32: switch (Triple.getEnvironment()) { + case llvm::Triple::Cygnus: + return new CygwinARMTargetInfo(Triple); + case llvm::Triple::GNU: + return new MinGWARMTargetInfo(Triple); case llvm::Triple::Itanium: return new ItaniumWindowsARMleTargetInfo(Triple); case llvm::Triple::MSVC: @@ -7322,6 +7827,8 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) { return new RTEMSX86_32TargetInfo(Triple); case llvm::Triple::NaCl: return new NaClTargetInfo<X86_32TargetInfo>(Triple); + case llvm::Triple::ELFIAMCU: + return new MCUX86_32TargetInfo(Triple); default: return new X86_32TargetInfo(Triple); } @@ -7357,6 +7864,8 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) { return new SolarisTargetInfo<X86_64TargetInfo>(Triple); case llvm::Triple::Win32: { switch (Triple.getEnvironment()) { + case llvm::Triple::Cygnus: + return new CygwinX86_64TargetInfo(Triple); case llvm::Triple::GNU: return new MinGWX86_64TargetInfo(Triple); case llvm::Triple::MSVC: @@ -7384,11 +7893,19 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) { return nullptr; return new SPIR64TargetInfo(Triple); } + case llvm::Triple::wasm32: + if (!(Triple == llvm::Triple("wasm32-unknown-unknown"))) + return nullptr; + return new WebAssemblyOSTargetInfo<WebAssembly32TargetInfo>(Triple); + case llvm::Triple::wasm64: + if (!(Triple == llvm::Triple("wasm64-unknown-unknown"))) + return nullptr; + return new WebAssemblyOSTargetInfo<WebAssembly64TargetInfo>(Triple); } } /// CreateTargetInfo - Return the target info object for the specified target -/// triple. +/// options. TargetInfo * TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, const std::shared_ptr<TargetOptions> &Opts) { @@ -7423,25 +7940,15 @@ TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, // 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); - } + if (!Target->initFeatureMap(Features, Diags, Opts->CPU, + Opts->FeaturesAsWritten)) + return nullptr; // 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()); + for (const auto &F : Features) + Opts->Features.push_back((F.getValue() ? "+" : "-") + F.getKey().str()); + if (!Target->handleTargetFeatures(Opts->Features, Diags)) return nullptr; diff --git a/contrib/llvm/tools/clang/lib/Basic/Version.cpp b/contrib/llvm/tools/clang/lib/Basic/Version.cpp index 4b10dcd..6accb04 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Version.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Version.cpp @@ -36,7 +36,7 @@ std::string getClangRepositoryPath() { // 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 $"); + StringRef SVNRepository("$URL: https://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $"); if (URL.empty()) { URL = SVNRepository.slice(SVNRepository.find(':'), SVNRepository.find("/lib/Basic")); diff --git a/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp b/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp index a36102c..cf5a8d6 100644 --- a/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp @@ -10,6 +10,7 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/VirtualFileSystem.h" +#include "clang/Basic/FileManager.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" @@ -19,9 +20,17 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/YAMLParser.h" +#include "llvm/Config/llvm-config.h" #include <atomic> #include <memory> +// For chdir. +#ifdef LLVM_ON_WIN32 +# include <direct.h> +#else +# include <unistd.h> +#endif + using namespace clang; using namespace clang::vfs; using namespace llvm; @@ -35,12 +44,24 @@ Status::Status(const file_status &Status) 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) +Status::Status(StringRef Name, 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) {} +Status Status::copyWithNewName(const Status &In, StringRef NewName) { + return Status(NewName, In.getUniqueID(), In.getLastModificationTime(), + In.getUser(), In.getGroup(), In.getSize(), In.getType(), + In.getPermissions()); +} + +Status Status::copyWithNewName(const file_status &In, StringRef NewName) { + return Status(NewName, In.getUniqueID(), In.getLastModificationTime(), + In.getUser(), In.getGroup(), In.getSize(), In.type(), + In.permissions()); +} + bool Status::equivalent(const Status &Other) const { return getUniqueID() == Other.getUniqueID(); } @@ -77,6 +98,19 @@ FileSystem::getBufferForFile(const llvm::Twine &Name, int64_t FileSize, return (*F)->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile); } +std::error_code FileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const { + auto WorkingDir = getCurrentWorkingDirectory(); + if (!WorkingDir) + return WorkingDir.getError(); + + return llvm::sys::fs::make_absolute(WorkingDir.get(), Path); +} + +bool FileSystem::exists(const Twine &Path) { + auto Status = status(Path); + return Status && Status->exists(); +} + //===-----------------------------------------------------------------------===/ // RealFileSystem implementation //===-----------------------------------------------------------------------===/ @@ -87,19 +121,20 @@ class RealFile : public File { int FD; Status S; friend class RealFileSystem; - RealFile(int FD) : FD(FD) { + RealFile(int FD, StringRef NewName) + : FD(FD), S(NewName, {}, {}, {}, {}, {}, + llvm::sys::fs::file_type::status_error, {}) { 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; + ErrorOr<std::unique_ptr<MemoryBuffer>> getBuffer(const Twine &Name, + int64_t FileSize, + bool RequiresNullTerminator, + bool IsVolatile) override; std::error_code close() override; - void setName(StringRef Name) override; }; } // end anonymous namespace RealFile::~RealFile() { close(); } @@ -110,9 +145,7 @@ ErrorOr<Status> RealFile::status() { 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); + S = Status::copyWithNewName(RealStatus, S.getName()); } return S; } @@ -142,10 +175,6 @@ std::error_code RealFile::close() { 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 { @@ -153,6 +182,9 @@ 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; + + llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override; + std::error_code setCurrentWorkingDirectory(const Twine &Path) override; }; } // end anonymous namespace @@ -160,9 +192,7 @@ 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; + return Status::copyWithNewName(RealStatus, Path.str()); } ErrorOr<std::unique_ptr<File>> @@ -170,9 +200,29 @@ 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); + return std::unique_ptr<File>(new RealFile(FD, Name.str())); +} + +llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory() const { + SmallString<256> Dir; + if (std::error_code EC = llvm::sys::fs::current_path(Dir)) + return EC; + return Dir.str().str(); +} + +std::error_code RealFileSystem::setCurrentWorkingDirectory(const Twine &Path) { + // FIXME: chdir is thread hostile; on the other hand, creating the same + // behavior as chdir is complex: chdir resolves the path once, thus + // guaranteeing that all subsequent relative path operations work + // on the same path the original chdir resulted in. This makes a + // difference for example on network filesystems, where symlinks might be + // switched during runtime of the tool. Fixing this depends on having a + // file system abstraction that allows openat() style interactions. + SmallString<256> Storage; + StringRef Dir = Path.toNullTerminatedStringRef(Storage); + if (int Err = ::chdir(Dir.data())) + return std::error_code(Err, std::generic_category()); + return std::error_code(); } IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() { @@ -190,10 +240,8 @@ public: 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()); - } + if (!EC) + CurrentEntry = Status::copyWithNewName(S, Iter->path()); } } @@ -207,8 +255,7 @@ public: } else { llvm::sys::fs::file_status S; EC = Iter->status(S); - CurrentEntry = Status(S); - CurrentEntry.setName(Iter->path()); + CurrentEntry = Status::copyWithNewName(S, Iter->path()); } return EC; } @@ -224,11 +271,14 @@ directory_iterator RealFileSystem::dir_begin(const Twine &Dir, // OverlayFileSystem implementation //===-----------------------------------------------------------------------===/ OverlayFileSystem::OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> BaseFS) { - pushOverlay(BaseFS); + FSList.push_back(BaseFS); } void OverlayFileSystem::pushOverlay(IntrusiveRefCntPtr<FileSystem> FS) { FSList.push_back(FS); + // Synchronize added file systems by duplicating the working directory from + // the first one in the list. + FS->setCurrentWorkingDirectory(getCurrentWorkingDirectory().get()); } ErrorOr<Status> OverlayFileSystem::status(const Twine &Path) { @@ -252,6 +302,19 @@ OverlayFileSystem::openFileForRead(const llvm::Twine &Path) { return make_error_code(llvm::errc::no_such_file_or_directory); } +llvm::ErrorOr<std::string> +OverlayFileSystem::getCurrentWorkingDirectory() const { + // All file systems are synchronized, just take the first working directory. + return FSList.front()->getCurrentWorkingDirectory(); +} +std::error_code +OverlayFileSystem::setCurrentWorkingDirectory(const Twine &Path) { + for (auto &FS : FSList) + if (std::error_code EC = FS->setCurrentWorkingDirectory(Path)) + return EC; + return std::error_code(); +} + clang::vfs::detail::DirIterImpl::~DirIterImpl() { } namespace { @@ -320,8 +383,286 @@ directory_iterator OverlayFileSystem::dir_begin(const Twine &Dir, std::make_shared<OverlayFSDirIterImpl>(Dir, *this, EC)); } +namespace clang { +namespace vfs { +namespace detail { + +enum InMemoryNodeKind { IME_File, IME_Directory }; + +/// The in memory file system is a tree of Nodes. Every node can either be a +/// file or a directory. +class InMemoryNode { + Status Stat; + InMemoryNodeKind Kind; + +public: + InMemoryNode(Status Stat, InMemoryNodeKind Kind) + : Stat(std::move(Stat)), Kind(Kind) {} + virtual ~InMemoryNode() {} + const Status &getStatus() const { return Stat; } + InMemoryNodeKind getKind() const { return Kind; } + virtual std::string toString(unsigned Indent) const = 0; +}; + +namespace { +class InMemoryFile : public InMemoryNode { + std::unique_ptr<llvm::MemoryBuffer> Buffer; + +public: + InMemoryFile(Status Stat, std::unique_ptr<llvm::MemoryBuffer> Buffer) + : InMemoryNode(std::move(Stat), IME_File), Buffer(std::move(Buffer)) {} + + llvm::MemoryBuffer *getBuffer() { return Buffer.get(); } + std::string toString(unsigned Indent) const override { + return (std::string(Indent, ' ') + getStatus().getName() + "\n").str(); + } + static bool classof(const InMemoryNode *N) { + return N->getKind() == IME_File; + } +}; + +/// Adapt a InMemoryFile for VFS' File interface. +class InMemoryFileAdaptor : public File { + InMemoryFile &Node; + +public: + explicit InMemoryFileAdaptor(InMemoryFile &Node) : Node(Node) {} + + llvm::ErrorOr<Status> status() override { return Node.getStatus(); } + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> + getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator, + bool IsVolatile) override { + llvm::MemoryBuffer *Buf = Node.getBuffer(); + return llvm::MemoryBuffer::getMemBuffer( + Buf->getBuffer(), Buf->getBufferIdentifier(), RequiresNullTerminator); + } + std::error_code close() override { return std::error_code(); } +}; +} // end anonymous namespace + +class InMemoryDirectory : public InMemoryNode { + std::map<std::string, std::unique_ptr<InMemoryNode>> Entries; + +public: + InMemoryDirectory(Status Stat) + : InMemoryNode(std::move(Stat), IME_Directory) {} + InMemoryNode *getChild(StringRef Name) { + auto I = Entries.find(Name); + if (I != Entries.end()) + return I->second.get(); + return nullptr; + } + InMemoryNode *addChild(StringRef Name, std::unique_ptr<InMemoryNode> Child) { + return Entries.insert(make_pair(Name, std::move(Child))) + .first->second.get(); + } + + typedef decltype(Entries)::const_iterator const_iterator; + const_iterator begin() const { return Entries.begin(); } + const_iterator end() const { return Entries.end(); } + + std::string toString(unsigned Indent) const override { + std::string Result = + (std::string(Indent, ' ') + getStatus().getName() + "\n").str(); + for (const auto &Entry : Entries) { + Result += Entry.second->toString(Indent + 2); + } + return Result; + } + static bool classof(const InMemoryNode *N) { + return N->getKind() == IME_Directory; + } +}; +} + +InMemoryFileSystem::InMemoryFileSystem(bool UseNormalizedPaths) + : Root(new detail::InMemoryDirectory( + Status("", getNextVirtualUniqueID(), llvm::sys::TimeValue::MinTime(), + 0, 0, 0, llvm::sys::fs::file_type::directory_file, + llvm::sys::fs::perms::all_all))), + UseNormalizedPaths(UseNormalizedPaths) {} + +InMemoryFileSystem::~InMemoryFileSystem() {} + +std::string InMemoryFileSystem::toString() const { + return Root->toString(/*Indent=*/0); +} + +bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime, + std::unique_ptr<llvm::MemoryBuffer> Buffer) { + SmallString<128> Path; + P.toVector(Path); + + // Fix up relative paths. This just prepends the current working directory. + std::error_code EC = makeAbsolute(Path); + assert(!EC); + (void)EC; + + if (useNormalizedPaths()) + llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true); + + if (Path.empty()) + return false; + + detail::InMemoryDirectory *Dir = Root.get(); + auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path); + while (true) { + StringRef Name = *I; + detail::InMemoryNode *Node = Dir->getChild(Name); + ++I; + if (!Node) { + if (I == E) { + // End of the path, create a new file. + // FIXME: expose the status details in the interface. + Status Stat(P.str(), getNextVirtualUniqueID(), + llvm::sys::TimeValue(ModificationTime, 0), 0, 0, + Buffer->getBufferSize(), + llvm::sys::fs::file_type::regular_file, + llvm::sys::fs::all_all); + Dir->addChild(Name, llvm::make_unique<detail::InMemoryFile>( + std::move(Stat), std::move(Buffer))); + return true; + } + + // Create a new directory. Use the path up to here. + // FIXME: expose the status details in the interface. + Status Stat( + StringRef(Path.str().begin(), Name.end() - Path.str().begin()), + getNextVirtualUniqueID(), llvm::sys::TimeValue(ModificationTime, 0), + 0, 0, Buffer->getBufferSize(), + llvm::sys::fs::file_type::directory_file, llvm::sys::fs::all_all); + Dir = cast<detail::InMemoryDirectory>(Dir->addChild( + Name, llvm::make_unique<detail::InMemoryDirectory>(std::move(Stat)))); + continue; + } + + if (auto *NewDir = dyn_cast<detail::InMemoryDirectory>(Node)) { + Dir = NewDir; + } else { + assert(isa<detail::InMemoryFile>(Node) && + "Must be either file or directory!"); + + // Trying to insert a directory in place of a file. + if (I != E) + return false; + + // Return false only if the new file is different from the existing one. + return cast<detail::InMemoryFile>(Node)->getBuffer()->getBuffer() == + Buffer->getBuffer(); + } + } +} + +bool InMemoryFileSystem::addFileNoOwn(const Twine &P, time_t ModificationTime, + llvm::MemoryBuffer *Buffer) { + return addFile(P, ModificationTime, + llvm::MemoryBuffer::getMemBuffer( + Buffer->getBuffer(), Buffer->getBufferIdentifier())); +} + +static ErrorOr<detail::InMemoryNode *> +lookupInMemoryNode(const InMemoryFileSystem &FS, detail::InMemoryDirectory *Dir, + const Twine &P) { + SmallString<128> Path; + P.toVector(Path); + + // Fix up relative paths. This just prepends the current working directory. + std::error_code EC = FS.makeAbsolute(Path); + assert(!EC); + (void)EC; + + if (FS.useNormalizedPaths()) + llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true); + + if (Path.empty()) + return Dir; + + auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path); + while (true) { + detail::InMemoryNode *Node = Dir->getChild(*I); + ++I; + if (!Node) + return errc::no_such_file_or_directory; + + // Return the file if it's at the end of the path. + if (auto File = dyn_cast<detail::InMemoryFile>(Node)) { + if (I == E) + return File; + return errc::no_such_file_or_directory; + } + + // Traverse directories. + Dir = cast<detail::InMemoryDirectory>(Node); + if (I == E) + return Dir; + } +} + +llvm::ErrorOr<Status> InMemoryFileSystem::status(const Twine &Path) { + auto Node = lookupInMemoryNode(*this, Root.get(), Path); + if (Node) + return (*Node)->getStatus(); + return Node.getError(); +} + +llvm::ErrorOr<std::unique_ptr<File>> +InMemoryFileSystem::openFileForRead(const Twine &Path) { + auto Node = lookupInMemoryNode(*this, Root.get(), Path); + if (!Node) + return Node.getError(); + + // When we have a file provide a heap-allocated wrapper for the memory buffer + // to match the ownership semantics for File. + if (auto *F = dyn_cast<detail::InMemoryFile>(*Node)) + return std::unique_ptr<File>(new detail::InMemoryFileAdaptor(*F)); + + // FIXME: errc::not_a_file? + return make_error_code(llvm::errc::invalid_argument); +} + +namespace { +/// Adaptor from InMemoryDir::iterator to directory_iterator. +class InMemoryDirIterator : public clang::vfs::detail::DirIterImpl { + detail::InMemoryDirectory::const_iterator I; + detail::InMemoryDirectory::const_iterator E; + +public: + InMemoryDirIterator() {} + explicit InMemoryDirIterator(detail::InMemoryDirectory &Dir) + : I(Dir.begin()), E(Dir.end()) { + if (I != E) + CurrentEntry = I->second->getStatus(); + } + + std::error_code increment() override { + ++I; + // When we're at the end, make CurrentEntry invalid and DirIterImpl will do + // the rest. + CurrentEntry = I != E ? I->second->getStatus() : Status(); + return std::error_code(); + } +}; +} // end anonymous namespace + +directory_iterator InMemoryFileSystem::dir_begin(const Twine &Dir, + std::error_code &EC) { + auto Node = lookupInMemoryNode(*this, Root.get(), Dir); + if (!Node) { + EC = Node.getError(); + return directory_iterator(std::make_shared<InMemoryDirIterator>()); + } + + if (auto *DirNode = dyn_cast<detail::InMemoryDirectory>(*Node)) + return directory_iterator(std::make_shared<InMemoryDirIterator>(*DirNode)); + + EC = make_error_code(llvm::errc::not_a_directory); + return directory_iterator(std::make_shared<InMemoryDirIterator>()); +} +} +} + //===-----------------------------------------------------------------------===/ -// VFSFromYAML implementation +// RedirectingFileSystem implementation //===-----------------------------------------------------------------------===/ namespace { @@ -343,23 +684,24 @@ public: EntryKind getKind() const { return Kind; } }; -class DirectoryEntry : public Entry { - std::vector<Entry *> Contents; +class RedirectingDirectoryEntry : public Entry { + std::vector<std::unique_ptr<Entry>> Contents; Status S; public: - ~DirectoryEntry() override; - DirectoryEntry(StringRef Name, std::vector<Entry *> Contents, Status S) + RedirectingDirectoryEntry(StringRef Name, + std::vector<std::unique_ptr<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; + typedef decltype(Contents)::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 { +class RedirectingFileEntry : public Entry { public: enum NameKind { NK_NotSet, @@ -370,7 +712,8 @@ private: std::string ExternalContentsPath; NameKind UseName; public: - FileEntry(StringRef Name, StringRef ExternalContentsPath, NameKind UseName) + RedirectingFileEntry(StringRef Name, StringRef ExternalContentsPath, + NameKind UseName) : Entry(EK_File, Name), ExternalContentsPath(ExternalContentsPath), UseName(UseName) {} StringRef getExternalContentsPath() const { return ExternalContentsPath; } @@ -382,16 +725,18 @@ public: static bool classof(const Entry *E) { return E->getKind() == EK_File; } }; -class VFSFromYAML; +class RedirectingFileSystem; class VFSFromYamlDirIterImpl : public clang::vfs::detail::DirIterImpl { std::string Dir; - VFSFromYAML &FS; - DirectoryEntry::iterator Current, End; + RedirectingFileSystem &FS; + RedirectingDirectoryEntry::iterator Current, End; + public: - VFSFromYamlDirIterImpl(const Twine &Path, VFSFromYAML &FS, - DirectoryEntry::iterator Begin, - DirectoryEntry::iterator End, std::error_code &EC); + VFSFromYamlDirIterImpl(const Twine &Path, RedirectingFileSystem &FS, + RedirectingDirectoryEntry::iterator Begin, + RedirectingDirectoryEntry::iterator End, + std::error_code &EC); std::error_code increment() override; }; @@ -448,8 +793,9 @@ public: /// 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. +class RedirectingFileSystem : public vfs::FileSystem { + /// The root(s) of the virtual file system. + std::vector<std::unique_ptr<Entry>> Roots; /// \brief The file system to use for external references. IntrusiveRefCntPtr<FileSystem> ExternalFS; @@ -466,10 +812,10 @@ class VFSFromYAML : public vfs::FileSystem { bool UseExternalNames; /// @} - friend class VFSFromYAMLParser; + friend class RedirectingFileSystemParser; private: - VFSFromYAML(IntrusiveRefCntPtr<FileSystem> ExternalFS) + RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS) : ExternalFS(ExternalFS), CaseSensitive(true), UseExternalNames(true) {} /// \brief Looks up \p Path in \c Roots. @@ -484,18 +830,23 @@ private: 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); + static RedirectingFileSystem * + 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; + llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override { + return ExternalFS->getCurrentWorkingDirectory(); + } + std::error_code setCurrentWorkingDirectory(const Twine &Path) override { + return ExternalFS->setCurrentWorkingDirectory(Path); + } + directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override{ ErrorOr<Entry *> E = lookupPath(Dir); if (!E) { @@ -513,14 +864,14 @@ public: return directory_iterator(); } - DirectoryEntry *D = cast<DirectoryEntry>(*E); + auto *D = cast<RedirectingDirectoryEntry>(*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 { +class RedirectingFileSystemParser { yaml::Stream &Stream; void error(yaml::Node *N, const Twine &Msg) { @@ -596,7 +947,7 @@ class VFSFromYAMLParser { return true; } - Entry *parseEntry(yaml::Node *N) { + std::unique_ptr<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"); @@ -611,14 +962,13 @@ class VFSFromYAMLParser { KeyStatusPair("use-external-name", false), }; - DenseMap<StringRef, KeyStatus> Keys( - &Fields[0], Fields + sizeof(Fields)/sizeof(Fields[0])); + DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields)); bool HasContents = false; // external or otherwise - std::vector<Entry *> EntryArrayContents; + std::vector<std::unique_ptr<Entry>> EntryArrayContents; std::string ExternalContentsPath; std::string Name; - FileEntry::NameKind UseExternalName = FileEntry::NK_NotSet; + auto UseExternalName = RedirectingFileEntry::NK_NotSet; EntryKind Kind; for (yaml::MappingNode::iterator I = M->begin(), E = M->end(); I != E; @@ -667,8 +1017,8 @@ class VFSFromYAMLParser { for (yaml::SequenceNode::iterator I = Contents->begin(), E = Contents->end(); I != E; ++I) { - if (Entry *E = parseEntry(&*I)) - EntryArrayContents.push_back(E); + if (std::unique_ptr<Entry> E = parseEntry(&*I)) + EntryArrayContents.push_back(std::move(E)); else return nullptr; } @@ -686,7 +1036,8 @@ class VFSFromYAMLParser { bool Val; if (!parseScalarBool(I->getValue(), Val)) return nullptr; - UseExternalName = Val ? FileEntry::NK_External : FileEntry::NK_Virtual; + UseExternalName = Val ? RedirectingFileEntry::NK_External + : RedirectingFileEntry::NK_Virtual; } else { llvm_unreachable("key missing from Keys"); } @@ -704,7 +1055,8 @@ class VFSFromYAMLParser { return nullptr; // check invalid configuration - if (Kind == EK_Directory && UseExternalName != FileEntry::NK_NotSet) { + if (Kind == EK_Directory && + UseExternalName != RedirectingFileEntry::NK_NotSet) { error(N, "'use-external-name' is not supported for directories"); return nullptr; } @@ -718,16 +1070,17 @@ class VFSFromYAMLParser { // Get the last component StringRef LastComponent = sys::path::filename(Trimmed); - Entry *Result = nullptr; + std::unique_ptr<Entry> Result; switch (Kind) { case EK_File: - Result = new FileEntry(LastComponent, std::move(ExternalContentsPath), - UseExternalName); + Result = llvm::make_unique<RedirectingFileEntry>( + 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)); + Result = llvm::make_unique<RedirectingDirectoryEntry>( + LastComponent, std::move(EntryArrayContents), + Status("", getNextVirtualUniqueID(), sys::TimeValue::now(), 0, 0, 0, + file_type::directory_file, sys::fs::all_all)); break; } @@ -739,18 +1092,21 @@ class VFSFromYAMLParser { 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)); + std::vector<std::unique_ptr<Entry>> Entries; + Entries.push_back(std::move(Result)); + Result = llvm::make_unique<RedirectingDirectoryEntry>( + *I, std::move(Entries), + 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) {} + RedirectingFileSystemParser(yaml::Stream &S) : Stream(S) {} // false on error - bool parse(yaml::Node *Root, VFSFromYAML *FS) { + bool parse(yaml::Node *Root, RedirectingFileSystem *FS) { yaml::MappingNode *Top = dyn_cast<yaml::MappingNode>(Root); if (!Top) { error(Root, "expected mapping node"); @@ -764,8 +1120,7 @@ public: KeyStatusPair("roots", true), }; - DenseMap<StringRef, KeyStatus> Keys( - &Fields[0], Fields + sizeof(Fields)/sizeof(Fields[0])); + DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields)); // Parse configuration and 'roots' for (yaml::MappingNode::iterator I = Top->begin(), E = Top->end(); I != E; @@ -787,8 +1142,8 @@ public: for (yaml::SequenceNode::iterator I = Roots->begin(), E = Roots->end(); I != E; ++I) { - if (Entry *E = parseEntry(&*I)) - FS->Roots.push_back(E); + if (std::unique_ptr<Entry> E = parseEntry(&*I)) + FS->Roots.push_back(std::move(E)); else return false; } @@ -831,15 +1186,11 @@ public: }; } // end of anonymous namespace -Entry::~Entry() {} -DirectoryEntry::~DirectoryEntry() { llvm::DeleteContainerPointers(Contents); } +Entry::~Entry() = default; -VFSFromYAML::~VFSFromYAML() { llvm::DeleteContainerPointers(Roots); } - -VFSFromYAML *VFSFromYAML::create(std::unique_ptr<MemoryBuffer> Buffer, - SourceMgr::DiagHandlerTy DiagHandler, - void *DiagContext, - IntrusiveRefCntPtr<FileSystem> ExternalFS) { +RedirectingFileSystem *RedirectingFileSystem::create( + std::unique_ptr<MemoryBuffer> Buffer, SourceMgr::DiagHandlerTy DiagHandler, + void *DiagContext, IntrusiveRefCntPtr<FileSystem> ExternalFS) { SourceMgr SM; yaml::Stream Stream(Buffer->getMemBufferRef(), SM); @@ -852,21 +1203,22 @@ VFSFromYAML *VFSFromYAML::create(std::unique_ptr<MemoryBuffer> Buffer, return nullptr; } - VFSFromYAMLParser P(Stream); + RedirectingFileSystemParser P(Stream); - std::unique_ptr<VFSFromYAML> FS(new VFSFromYAML(ExternalFS)); + std::unique_ptr<RedirectingFileSystem> FS( + new RedirectingFileSystem(ExternalFS)); if (!P.parse(Root, FS.get())) return nullptr; return FS.release(); } -ErrorOr<Entry *> VFSFromYAML::lookupPath(const Twine &Path_) { +ErrorOr<Entry *> RedirectingFileSystem::lookupPath(const Twine &Path_) { SmallString<256> Path; Path_.toVector(Path); // Handle relative paths - if (std::error_code EC = sys::fs::make_absolute(Path)) + if (std::error_code EC = makeAbsolute(Path)) return EC; if (Path.empty()) @@ -874,18 +1226,17 @@ ErrorOr<Entry *> VFSFromYAML::lookupPath(const Twine &Path_) { 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); + for (const std::unique_ptr<Entry> &Root : Roots) { + ErrorOr<Entry *> Result = lookupPath(Start, End, Root.get()); 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) { +ErrorOr<Entry *> +RedirectingFileSystem::lookupPath(sys::path::const_iterator Start, + sys::path::const_iterator End, Entry *From) { if (Start->equals(".")) ++Start; @@ -902,52 +1253,78 @@ ErrorOr<Entry *> VFSFromYAML::lookupPath(sys::path::const_iterator Start, return From; } - DirectoryEntry *DE = dyn_cast<DirectoryEntry>(From); + auto *DE = dyn_cast<RedirectingDirectoryEntry>(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); + for (const std::unique_ptr<Entry> &DirEntry : + llvm::make_range(DE->contents_begin(), DE->contents_end())) { + ErrorOr<Entry *> Result = lookupPath(Start, End, DirEntry.get()); 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) { +static Status getRedirectedFileStatus(const Twine &Path, bool UseExternalNames, + Status ExternalStatus) { + Status S = ExternalStatus; + if (!UseExternalNames) + S = Status::copyWithNewName(S, Path.str()); + S.IsVFSMapped = true; + return S; +} + +ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path, Entry *E) { assert(E != nullptr); - std::string PathStr(Path.str()); - if (FileEntry *F = dyn_cast<FileEntry>(E)) { + if (auto *F = dyn_cast<RedirectingFileEntry>(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 getRedirectedFileStatus(Path, F->useExternalName(UseExternalNames), + *S); return S; } else { // directory - DirectoryEntry *DE = cast<DirectoryEntry>(E); - Status S = DE->getStatus(); - S.setName(PathStr); - return S; + auto *DE = cast<RedirectingDirectoryEntry>(E); + return Status::copyWithNewName(DE->getStatus(), Path.str()); } } -ErrorOr<Status> VFSFromYAML::status(const Twine &Path) { +ErrorOr<Status> RedirectingFileSystem::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) { +namespace { +/// Provide a file wrapper with an overriden status. +class FileWithFixedStatus : public File { + std::unique_ptr<File> InnerFile; + Status S; + +public: + FileWithFixedStatus(std::unique_ptr<File> InnerFile, Status S) + : InnerFile(std::move(InnerFile)), S(S) {} + + ErrorOr<Status> status() override { return S; } + ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> + getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator, + bool IsVolatile) override { + return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator, + IsVolatile); + } + std::error_code close() override { return InnerFile->close(); } +}; +} // end anonymous namespace + +ErrorOr<std::unique_ptr<File>> +RedirectingFileSystem::openFileForRead(const Twine &Path) { ErrorOr<Entry *> E = lookupPath(Path); if (!E) return E.getError(); - FileEntry *F = dyn_cast<FileEntry>(*E); + auto *F = dyn_cast<RedirectingFileEntry>(*E); if (!F) // FIXME: errc::not_a_file? return make_error_code(llvm::errc::invalid_argument); @@ -955,18 +1332,23 @@ ErrorOr<std::unique_ptr<File>> VFSFromYAML::openFileForRead(const Twine &Path) { if (!Result) return Result; - if (!F->useExternalName(UseExternalNames)) - (*Result)->setName(Path.str()); + auto ExternalStatus = (*Result)->status(); + if (!ExternalStatus) + return ExternalStatus.getError(); - return Result; + // FIXME: Update the status with the name and VFSMapped. + Status S = getRedirectedFileStatus(Path, F->useExternalName(UseExternalNames), + *ExternalStatus); + return std::unique_ptr<File>( + llvm::make_unique<FileWithFixedStatus>(std::move(*Result), S)); } 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); + return RedirectingFileSystem::create(std::move(Buffer), DiagHandler, + DiagContext, ExternalFS); } UniqueID vfs::getNextVirtualUniqueID() { @@ -1111,11 +1493,10 @@ void YAMLVFSWriter::write(llvm::raw_ostream &OS) { JSONWriter(OS).write(Mappings, IsCaseSensitive); } -VFSFromYamlDirIterImpl::VFSFromYamlDirIterImpl(const Twine &_Path, - VFSFromYAML &FS, - DirectoryEntry::iterator Begin, - DirectoryEntry::iterator End, - std::error_code &EC) +VFSFromYamlDirIterImpl::VFSFromYamlDirIterImpl( + const Twine &_Path, RedirectingFileSystem &FS, + RedirectingDirectoryEntry::iterator Begin, + RedirectingDirectoryEntry::iterator End, std::error_code &EC) : Dir(_Path.str()), FS(FS), Current(Begin), End(End) { if (Current != End) { SmallString<128> PathStr(Dir); |