diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:04:05 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-01-19 10:04:05 +0000 |
commit | 676fbe8105eeb6ff4bb2ed261cb212fcfdbe7b63 (patch) | |
tree | 02a1ac369cb734d0abfa5000dd86e5b7797e6a74 /lib/Basic | |
parent | c7e70c433efc6953dc3888b9fbf9f3512d7da2b0 (diff) |
Notes
Diffstat (limited to 'lib/Basic')
39 files changed, 953 insertions, 2734 deletions
diff --git a/lib/Basic/Attributes.cpp b/lib/Basic/Attributes.cpp index b7570d03c85ae..9a8eb3d932cc6 100644 --- a/lib/Basic/Attributes.cpp +++ b/lib/Basic/Attributes.cpp @@ -12,9 +12,16 @@ int clang::hasAttribute(AttrSyntax Syntax, const IdentifierInfo *Scope, if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__")) Name = Name.substr(2, Name.size() - 4); + // Normalize the scope name, but only for gnu and clang attributes. + StringRef ScopeName = Scope ? Scope->getName() : ""; + if (ScopeName == "__gnu__") + ScopeName = "gnu"; + else if (ScopeName == "_Clang") + ScopeName = "clang"; + #include "clang/Basic/AttrHasAttributeImpl.inc" - return 0; + return 0;
} const char *attr::getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule) { diff --git a/lib/Basic/Builtins.cpp b/lib/Basic/Builtins.cpp index a3210ba090685..7e7f67ca874ee 100644 --- a/lib/Basic/Builtins.cpp +++ b/lib/Basic/Builtins.cpp @@ -68,7 +68,7 @@ bool Builtin::Context::builtinIsSupported(const Builtin::Info &BuiltinInfo, bool GnuModeUnsupported = !LangOpts.GNUMode && (BuiltinInfo.Langs & GNU_LANG); bool MSModeUnsupported = !LangOpts.MicrosoftExt && (BuiltinInfo.Langs & MS_LANG); - bool ObjCUnsupported = !LangOpts.ObjC1 && BuiltinInfo.Langs == OBJC_LANG; + bool ObjCUnsupported = !LangOpts.ObjC && BuiltinInfo.Langs == OBJC_LANG; bool OclC1Unsupported = (LangOpts.OpenCLVersion / 100) != 1 && (BuiltinInfo.Langs & ALL_OCLC_LANGUAGES ) == OCLC1X_LANG; bool OclC2Unsupported = LangOpts.OpenCLVersion != 200 && diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt index e82f451dea170..8b3aa0f1e972c 100644 --- a/lib/Basic/CMakeLists.txt +++ b/lib/Basic/CMakeLists.txt @@ -48,12 +48,14 @@ add_clang_library(clangBasic Attributes.cpp Builtins.cpp CharInfo.cpp + CodeGenOptions.cpp Cuda.cpp Diagnostic.cpp DiagnosticIDs.cpp DiagnosticOptions.cpp FileManager.cpp FileSystemStatCache.cpp + FixedPoint.cpp IdentifierTable.cpp LangOptions.cpp MemoryBufferCache.cpp @@ -70,6 +72,7 @@ add_clang_library(clangBasic Targets.cpp Targets/AArch64.cpp Targets/AMDGPU.cpp + Targets/ARC.cpp Targets/ARM.cpp Targets/AVR.cpp Targets/BPF.cpp @@ -79,7 +82,6 @@ add_clang_library(clangBasic Targets/MSP430.cpp Targets/Mips.cpp Targets/NVPTX.cpp - Targets/Nios2.cpp Targets/OSTargets.cpp Targets/PNaCl.cpp Targets/PPC.cpp @@ -93,7 +95,6 @@ add_clang_library(clangBasic Targets/XCore.cpp TokenKinds.cpp Version.cpp - VirtualFileSystem.cpp Warnings.cpp XRayInstr.cpp XRayLists.cpp diff --git a/lib/Basic/CodeGenOptions.cpp b/lib/Basic/CodeGenOptions.cpp new file mode 100644 index 0000000000000..aface1cd4bf91 --- /dev/null +++ b/lib/Basic/CodeGenOptions.cpp @@ -0,0 +1,32 @@ +//===--- CodeGenOptions.cpp -----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/CodeGenOptions.h" +#include <string.h> + +namespace clang { + +CodeGenOptions::CodeGenOptions() { +#define CODEGENOPT(Name, Bits, Default) Name = Default; +#define ENUM_CODEGENOPT(Name, Type, Bits, Default) set##Name(Default); +#include "clang/Basic/CodeGenOptions.def" + + RelocationModel = llvm::Reloc::PIC_; + memcpy(CoverageVersion, "402*", 4); +} + +bool CodeGenOptions::isNoBuiltinFunc(const char *Name) const { + StringRef FuncName(Name); + for (unsigned i = 0, e = NoBuiltinFuncs.size(); i != e; ++i) + if (FuncName.equals(NoBuiltinFuncs[i])) + return true; + return false; +} + +} // end namespace clang diff --git a/lib/Basic/Cuda.cpp b/lib/Basic/Cuda.cpp index dc7e61c02b24b..6c34856dfdf72 100644 --- a/lib/Basic/Cuda.cpp +++ b/lib/Basic/Cuda.cpp @@ -22,6 +22,8 @@ const char *CudaVersionToString(CudaVersion V) { return "9.1"; case CudaVersion::CUDA_92: return "9.2"; + case CudaVersion::CUDA_100: + return "10.0"; } llvm_unreachable("invalid enum"); } @@ -60,6 +62,8 @@ const char *CudaArchToString(CudaArch A) { return "sm_70"; case CudaArch::SM_72: return "sm_72"; + case CudaArch::SM_75: + return "sm_75"; case CudaArch::GFX600: // tahiti return "gfx600"; case CudaArch::GFX601: // pitcairn, verde, oland,hainan @@ -86,6 +90,12 @@ const char *CudaArchToString(CudaArch A) { return "gfx900"; case CudaArch::GFX902: // TBA return "gfx902"; + case CudaArch::GFX904: // TBA + return "gfx904"; + case CudaArch::GFX906: // TBA + return "gfx906"; + case CudaArch::GFX909: // TBA + return "gfx909"; } llvm_unreachable("invalid enum"); } @@ -106,6 +116,7 @@ CudaArch StringToCudaArch(llvm::StringRef S) { .Case("sm_62", CudaArch::SM_62) .Case("sm_70", CudaArch::SM_70) .Case("sm_72", CudaArch::SM_72) + .Case("sm_75", CudaArch::SM_75) .Case("gfx600", CudaArch::GFX600) .Case("gfx601", CudaArch::GFX601) .Case("gfx700", CudaArch::GFX700) @@ -119,6 +130,9 @@ CudaArch StringToCudaArch(llvm::StringRef S) { .Case("gfx810", CudaArch::GFX810) .Case("gfx900", CudaArch::GFX900) .Case("gfx902", CudaArch::GFX902) + .Case("gfx904", CudaArch::GFX904) + .Case("gfx906", CudaArch::GFX906) + .Case("gfx909", CudaArch::GFX909) .Default(CudaArch::UNKNOWN); } @@ -152,6 +166,8 @@ const char *CudaVirtualArchToString(CudaVirtualArch A) { return "compute_70"; case CudaVirtualArch::COMPUTE_72: return "compute_72"; + case CudaVirtualArch::COMPUTE_75: + return "compute_75"; case CudaVirtualArch::COMPUTE_AMDGCN: return "compute_amdgcn"; } @@ -173,6 +189,7 @@ CudaVirtualArch StringToCudaVirtualArch(llvm::StringRef S) { .Case("compute_62", CudaVirtualArch::COMPUTE_62) .Case("compute_70", CudaVirtualArch::COMPUTE_70) .Case("compute_72", CudaVirtualArch::COMPUTE_72) + .Case("compute_75", CudaVirtualArch::COMPUTE_75) .Case("compute_amdgcn", CudaVirtualArch::COMPUTE_AMDGCN) .Default(CudaVirtualArch::UNKNOWN); } @@ -210,6 +227,8 @@ CudaVirtualArch VirtualArchForCudaArch(CudaArch A) { return CudaVirtualArch::COMPUTE_70; case CudaArch::SM_72: return CudaVirtualArch::COMPUTE_72; + case CudaArch::SM_75: + return CudaVirtualArch::COMPUTE_75; case CudaArch::GFX600: case CudaArch::GFX601: case CudaArch::GFX700: @@ -223,6 +242,9 @@ CudaVirtualArch VirtualArchForCudaArch(CudaArch A) { case CudaArch::GFX810: case CudaArch::GFX900: case CudaArch::GFX902: + case CudaArch::GFX904: + case CudaArch::GFX906: + case CudaArch::GFX909: return CudaVirtualArch::COMPUTE_AMDGCN; } llvm_unreachable("invalid enum"); @@ -252,6 +274,8 @@ CudaVersion MinVersionForCudaArch(CudaArch A) { return CudaVersion::CUDA_90; case CudaArch::SM_72: return CudaVersion::CUDA_91; + case CudaArch::SM_75: + return CudaVersion::CUDA_100; case CudaArch::GFX600: case CudaArch::GFX601: case CudaArch::GFX700: @@ -265,6 +289,9 @@ CudaVersion MinVersionForCudaArch(CudaArch A) { case CudaArch::GFX810: case CudaArch::GFX900: case CudaArch::GFX902: + case CudaArch::GFX904: + case CudaArch::GFX906: + case CudaArch::GFX909: return CudaVersion::CUDA_70; } llvm_unreachable("invalid enum"); diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index f1ebd9d38b9e5..56c54cb9070c1 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -89,6 +89,14 @@ DiagnosticsEngine::~DiagnosticsEngine() { setClient(nullptr); } +void DiagnosticsEngine::dump() const { + DiagStatesByLoc.dump(*SourceMgr); +} + +void DiagnosticsEngine::dump(StringRef DiagName) const { + DiagStatesByLoc.dump(*SourceMgr, DiagName); +} + void DiagnosticsEngine::setClient(DiagnosticConsumer *client, bool ShouldOwnClient) { Owner.reset(ShouldOwnClient ? client : nullptr); @@ -239,7 +247,7 @@ DiagnosticsEngine::DiagStateMap::getFile(SourceManager &SrcMgr, void DiagnosticsEngine::DiagStateMap::dump(SourceManager &SrcMgr, StringRef DiagName) const { llvm::errs() << "diagnostic state at "; - CurDiagStateLoc.dump(SrcMgr); + CurDiagStateLoc.print(llvm::errs(), SrcMgr); llvm::errs() << ": " << CurDiagState << "\n"; for (auto &F : Files) { @@ -261,7 +269,7 @@ void DiagnosticsEngine::DiagStateMap::dump(SourceManager &SrcMgr, << Decomp.first.getHashValue() << "> "; SrcMgr.getLocForStartOfFile(Decomp.first) .getLocWithOffset(Decomp.second) - .dump(SrcMgr); + .print(llvm::errs(), SrcMgr); } if (File.HasLocalTransitions) llvm::errs() << " has_local_transitions"; @@ -281,7 +289,7 @@ void DiagnosticsEngine::DiagStateMap::dump(SourceManager &SrcMgr, llvm::errs() << " "; SrcMgr.getLocForStartOfFile(ID) .getLocWithOffset(Transition.Offset) - .dump(SrcMgr); + .print(llvm::errs(), SrcMgr); llvm::errs() << ": state " << Transition.State << ":\n"; }; @@ -975,6 +983,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd, llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\''; break; } + case DiagnosticsEngine::ak_qual: case DiagnosticsEngine::ak_qualtype: case DiagnosticsEngine::ak_declarationname: case DiagnosticsEngine::ak_nameddecl: diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp index d339b972ae8ea..f5a2d4894c13e 100644 --- a/lib/Basic/FileManager.cpp +++ b/lib/Basic/FileManager.cpp @@ -49,7 +49,7 @@ using namespace clang; //===----------------------------------------------------------------------===// FileManager::FileManager(const FileSystemOptions &FSO, - IntrusiveRefCntPtr<vfs::FileSystem> FS) + IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) : FS(std::move(FS)), FileSystemOpts(FSO), SeenDirEntries(64), SeenFileEntries(64), NextFileUID(0) { NumDirLookups = NumFileLookups = 0; @@ -58,49 +58,17 @@ FileManager::FileManager(const FileSystemOptions &FSO, // If the caller doesn't provide a virtual file system, just grab the real // file system. if (!this->FS) - this->FS = vfs::getRealFileSystem(); + this->FS = llvm::vfs::getRealFileSystem(); } FileManager::~FileManager() = default; -void FileManager::addStatCache(std::unique_ptr<FileSystemStatCache> statCache, - bool AtBeginning) { +void FileManager::setStatCache(std::unique_ptr<FileSystemStatCache> statCache) { assert(statCache && "No stat cache provided?"); - if (AtBeginning || !StatCache.get()) { - statCache->setNextStatCache(std::move(StatCache)); - StatCache = std::move(statCache); - return; - } - - FileSystemStatCache *LastCache = StatCache.get(); - while (LastCache->getNextStatCache()) - LastCache = LastCache->getNextStatCache(); - - LastCache->setNextStatCache(std::move(statCache)); -} - -void FileManager::removeStatCache(FileSystemStatCache *statCache) { - if (!statCache) - return; - - if (StatCache.get() == statCache) { - // This is the first stat cache. - StatCache = StatCache->takeNextStatCache(); - return; - } - - // Find the stat cache in the list. - FileSystemStatCache *PrevCache = StatCache.get(); - while (PrevCache && PrevCache->getNextStatCache() != statCache) - PrevCache = PrevCache->getNextStatCache(); - - assert(PrevCache && "Stat cache not found for removal"); - PrevCache->setNextStatCache(statCache->takeNextStatCache()); + StatCache = std::move(statCache); } -void FileManager::clearStatCaches() { - StatCache.reset(); -} +void FileManager::clearStatCache() { StatCache.reset(); } /// Retrieve the directory that the given file name resides in. /// Filename can point to either a real file or a virtual file. @@ -221,15 +189,21 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile, *SeenFileEntries.insert(std::make_pair(Filename, nullptr)).first; // See if there is already an entry in the map. - if (NamedFileEnt.second) - return NamedFileEnt.second == NON_EXISTENT_FILE ? nullptr - : NamedFileEnt.second; + if (NamedFileEnt.second) { + if (NamedFileEnt.second == NON_EXISTENT_FILE) + return nullptr; + // Entry exists: return it *unless* it wasn't opened and open is requested. + if (!(NamedFileEnt.second->DeferredOpen && openFile)) + return NamedFileEnt.second; + // We previously stat()ed the file, but didn't open it: do that below. + // FIXME: the below does other redundant work too (stats the dir and file). + } else { + // By default, initialize it to invalid. + NamedFileEnt.second = NON_EXISTENT_FILE; + } ++NumFileCacheMisses; - // By default, initialize it to invalid. - NamedFileEnt.second = NON_EXISTENT_FILE; - // Get the null-terminated file name as stored as the key of the // SeenFileEntries map. StringRef InterndFileName = NamedFileEnt.first(); @@ -252,7 +226,7 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile, // FIXME: This will reduce the # syscalls. // Nope, there isn't. Check to see if the file exists. - std::unique_ptr<vfs::File> F; + std::unique_ptr<llvm::vfs::File> F; FileData Data; if (getStatValue(InterndFileName, Data, true, openFile ? &F : nullptr)) { // There's no real file at the given path. @@ -267,6 +241,7 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile, // It exists. See if we have already opened a file with the same inode. // This occurs when one dir is symlinked to another, for example. FileEntry &UFE = UniqueRealFiles[Data.UniqueID]; + UFE.DeferredOpen = !openFile; NamedFileEnt.second = &UFE; @@ -283,6 +258,15 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile, InterndFileName = NamedFileEnt.first().data(); } + // If we opened the file for the first time, record the resulting info. + // Do this even if the cache entry was valid, maybe we didn't previously open. + if (F && !UFE.File) { + if (auto PathName = F->getName()) + fillRealPathName(&UFE, *PathName); + UFE.File = std::move(F); + assert(!UFE.DeferredOpen && "we just opened it!"); + } + if (UFE.isValid()) { // Already have an entry with this inode, return it. // FIXME: this hack ensures that if we look up a file by a virtual path in @@ -313,11 +297,9 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile, UFE.UniqueID = Data.UniqueID; UFE.IsNamedPipe = Data.IsNamedPipe; UFE.InPCH = Data.InPCH; - UFE.File = std::move(F); UFE.IsValid = true; - if (UFE.File) - if (auto RealPathName = UFE.File->getName()) - UFE.RealPathName = *RealPathName; + // Note File and DeferredOpen were initialized above. + return &UFE; } @@ -373,6 +355,7 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size, UFE->UniqueID = Data.UniqueID; UFE->IsNamedPipe = Data.IsNamedPipe; UFE->InPCH = Data.InPCH; + fillRealPathName(UFE, Data.Name); } if (!UFE) { @@ -388,6 +371,7 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size, UFE->UID = NextFileUID++; UFE->IsValid = true; UFE->File.reset(); + UFE->DeferredOpen = false; return UFE; } @@ -415,6 +399,17 @@ bool FileManager::makeAbsolutePath(SmallVectorImpl<char> &Path) const { return Changed; } +void FileManager::fillRealPathName(FileEntry *UFE, llvm::StringRef FileName) { + llvm::SmallString<128> AbsPath(FileName); + // This is not the same as `VFS::getRealPath()`, which resolves symlinks + // but can be very expensive on real file systems. + // FIXME: the semantic of RealPathName is unclear, and the name might be + // misleading. We need to clean up the interface here. + makeAbsolutePath(AbsPath); + llvm::sys::path::remove_dots(AbsPath, /*remove_dot_dot=*/true); + UFE->RealPathName = AbsPath.str(); +} + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileManager::getBufferForFile(const FileEntry *Entry, bool isVolatile, bool ShouldCloseOpenFile) { @@ -465,7 +460,7 @@ FileManager::getBufferForFile(StringRef Filename, bool isVolatile) { /// false if it's an existent real file. If FileDescriptor is NULL, /// do directory look-up instead of file look-up. bool FileManager::getStatValue(StringRef Path, FileData &Data, bool isFile, - std::unique_ptr<vfs::File> *F) { + std::unique_ptr<llvm::vfs::File> *F) { // FIXME: FileSystemOpts shouldn't be passed in here, all paths should be // absolute! if (FileSystemOpts.WorkingDir.empty()) @@ -479,11 +474,11 @@ bool FileManager::getStatValue(StringRef Path, FileData &Data, bool isFile, } bool FileManager::getNoncachedStatValue(StringRef Path, - vfs::Status &Result) { + llvm::vfs::Status &Result) { SmallString<128> FilePath(Path); FixupRelativePath(FilePath); - llvm::ErrorOr<vfs::Status> S = FS->status(FilePath.c_str()); + llvm::ErrorOr<llvm::vfs::Status> S = FS->status(FilePath.c_str()); if (!S) return true; Result = *S; diff --git a/lib/Basic/FileSystemStatCache.cpp b/lib/Basic/FileSystemStatCache.cpp index f5856cb6542a8..6f2eef4e2062f 100644 --- a/lib/Basic/FileSystemStatCache.cpp +++ b/lib/Basic/FileSystemStatCache.cpp @@ -12,17 +12,17 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/FileSystemStatCache.h" -#include "clang/Basic/VirtualFileSystem.h" #include "llvm/Support/Chrono.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/Path.h" +#include "llvm/Support/VirtualFileSystem.h" #include <utility> using namespace clang; void FileSystemStatCache::anchor() {} -static void copyStatusToFileData(const vfs::Status &Status, +static void copyStatusToFileData(const llvm::vfs::Status &Status, FileData &Data) { Data.Name = Status.getName(); Data.Size = Status.getSize(); @@ -44,8 +44,9 @@ static void copyStatusToFileData(const vfs::Status &Status, /// implementation can optionally fill in FileDescriptor with a valid /// descriptor and the client guarantees that it will close it. bool FileSystemStatCache::get(StringRef Path, FileData &Data, bool isFile, - std::unique_ptr<vfs::File> *F, - FileSystemStatCache *Cache, vfs::FileSystem &FS) { + std::unique_ptr<llvm::vfs::File> *F, + FileSystemStatCache *Cache, + llvm::vfs::FileSystem &FS) { LookupResult R; bool isForDir = !isFile; @@ -55,7 +56,7 @@ bool FileSystemStatCache::get(StringRef Path, FileData &Data, bool isFile, else if (isForDir || !F) { // If this is a directory or a file descriptor is not needed and we have // no cache, just go to the file system. - llvm::ErrorOr<vfs::Status> Status = FS.status(Path); + llvm::ErrorOr<llvm::vfs::Status> Status = FS.status(Path); if (!Status) { R = CacheMissing; } else { @@ -79,7 +80,7 @@ bool FileSystemStatCache::get(StringRef Path, FileData &Data, bool isFile, // Otherwise, the open succeeded. Do an fstat to get the information // about the file. We'll end up returning the open file descriptor to the // client to do what they please with it. - llvm::ErrorOr<vfs::Status> Status = (*OwnedFile)->status(); + llvm::ErrorOr<llvm::vfs::Status> Status = (*OwnedFile)->status(); if (Status) { R = CacheExists; copyStatusToFileData(*Status, Data); @@ -111,19 +112,19 @@ bool FileSystemStatCache::get(StringRef Path, FileData &Data, bool isFile, MemorizeStatCalls::LookupResult MemorizeStatCalls::getStat(StringRef Path, FileData &Data, bool isFile, - std::unique_ptr<vfs::File> *F, vfs::FileSystem &FS) { - LookupResult Result = statChained(Path, Data, isFile, F, FS); - - // Do not cache failed stats, it is easy to construct common inconsistent - // situations if we do, and they are not important for PCH performance (which - // currently only needs the stats to construct the initial FileManager - // entries). - if (Result == CacheMissing) - return Result; + std::unique_ptr<llvm::vfs::File> *F, + llvm::vfs::FileSystem &FS) { + if (get(Path, Data, isFile, F, nullptr, FS)) { + // Do not cache failed stats, it is easy to construct common inconsistent + // situations if we do, and they are not important for PCH performance + // (which currently only needs the stats to construct the initial + // FileManager entries). + return CacheMissing; + } // Cache file 'stat' results and directories with absolutely paths. if (!Data.IsDirectory || llvm::sys::path::is_absolute(Path)) StatCalls[Path] = Data; - return Result; + return CacheExists; } diff --git a/lib/Basic/FixedPoint.cpp b/lib/Basic/FixedPoint.cpp new file mode 100644 index 0000000000000..bfff0fc212e0a --- /dev/null +++ b/lib/Basic/FixedPoint.cpp @@ -0,0 +1,115 @@ +//===- FixedPoint.cpp - Fixed point constant handling -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Defines the implementation for the fixed point number interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/FixedPoint.h" + +namespace clang { + +APFixedPoint APFixedPoint::convert(const FixedPointSemantics &DstSema) const { + llvm::APSInt NewVal = Val; + unsigned DstWidth = DstSema.getWidth(); + unsigned DstScale = DstSema.getScale(); + bool Upscaling = DstScale > getScale(); + + if (Upscaling) { + NewVal = NewVal.extend(NewVal.getBitWidth() + DstScale - getScale()); + NewVal <<= (DstScale - getScale()); + } else { + NewVal >>= (getScale() - DstScale); + } + + if (DstSema.isSaturated()) { + auto Mask = llvm::APInt::getBitsSetFrom( + NewVal.getBitWidth(), + std::min(DstScale + DstSema.getIntegralBits(), NewVal.getBitWidth())); + llvm::APInt Masked(NewVal & Mask); + + // Change in the bits above the sign + if (!(Masked == Mask || Masked == 0)) + NewVal = NewVal.isNegative() ? Mask : ~Mask; + + if (!DstSema.isSigned() && NewVal.isNegative()) + NewVal = 0; + } + + NewVal = NewVal.extOrTrunc(DstWidth); + NewVal.setIsSigned(DstSema.isSigned()); + return APFixedPoint(NewVal, DstSema); +} + +int APFixedPoint::compare(const APFixedPoint &Other) const { + llvm::APSInt ThisVal = getValue(); + llvm::APSInt OtherVal = Other.getValue(); + bool ThisSigned = Val.isSigned(); + bool OtherSigned = OtherVal.isSigned(); + unsigned OtherScale = Other.getScale(); + unsigned OtherWidth = OtherVal.getBitWidth(); + + unsigned CommonWidth = std::max(Val.getBitWidth(), OtherWidth); + + // Prevent overflow in the event the widths are the same but the scales differ + CommonWidth += getScale() >= OtherScale ? getScale() - OtherScale + : OtherScale - getScale(); + + ThisVal = ThisVal.extOrTrunc(CommonWidth); + OtherVal = OtherVal.extOrTrunc(CommonWidth); + + unsigned CommonScale = std::max(getScale(), OtherScale); + ThisVal = ThisVal.shl(CommonScale - getScale()); + OtherVal = OtherVal.shl(CommonScale - OtherScale); + + if (ThisSigned && OtherSigned) { + if (ThisVal.sgt(OtherVal)) + return 1; + else if (ThisVal.slt(OtherVal)) + return -1; + } else if (!ThisSigned && !OtherSigned) { + if (ThisVal.ugt(OtherVal)) + return 1; + else if (ThisVal.ult(OtherVal)) + return -1; + } else if (ThisSigned && !OtherSigned) { + if (ThisVal.isSignBitSet()) + return -1; + else if (ThisVal.ugt(OtherVal)) + return 1; + else if (ThisVal.ult(OtherVal)) + return -1; + } else { + // !ThisSigned && OtherSigned + if (OtherVal.isSignBitSet()) + return 1; + else if (ThisVal.ugt(OtherVal)) + return 1; + else if (ThisVal.ult(OtherVal)) + return -1; + } + + return 0; +} + +APFixedPoint APFixedPoint::getMax(const FixedPointSemantics &Sema) { + bool IsUnsigned = !Sema.isSigned(); + auto Val = llvm::APSInt::getMaxValue(Sema.getWidth(), IsUnsigned); + if (IsUnsigned && Sema.hasUnsignedPadding()) + Val = Val.lshr(1); + return APFixedPoint(Val, Sema); +} + +APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) { + auto Val = llvm::APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned()); + return APFixedPoint(Val, Sema); +} + +} // namespace clang diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 7ec3cb7dd65b6..b961c8333bd71 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -34,28 +34,6 @@ using namespace clang; //===----------------------------------------------------------------------===// -// IdentifierInfo Implementation -//===----------------------------------------------------------------------===// - -IdentifierInfo::IdentifierInfo() { - TokenID = tok::identifier; - ObjCOrBuiltinID = 0; - HasMacro = false; - HadMacro = false; - IsExtension = false; - IsFutureCompatKeyword = false; - IsPoisoned = false; - IsCPPOperatorKeyword = false; - NeedsHandleIdentifier = false; - IsFromAST = false; - ChangedAfterLoad = false; - FEChangedAfterLoad = false; - RevertedTokenID = false; - OutOfDate = false; - IsModulesImport = false; -} - -//===----------------------------------------------------------------------===// // IdentifierTable Implementation //===----------------------------------------------------------------------===// @@ -99,30 +77,29 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts, namespace { enum { - KEYC99 = 0x1, - KEYCXX = 0x2, - KEYCXX11 = 0x4, - KEYGNU = 0x8, - KEYMS = 0x10, - BOOLSUPPORT = 0x20, - KEYALTIVEC = 0x40, - KEYNOCXX = 0x80, - KEYBORLAND = 0x100, - KEYOPENCLC = 0x200, - KEYC11 = 0x400, - KEYARC = 0x800, - KEYNOMS18 = 0x01000, - KEYNOOPENCL = 0x02000, - WCHARSUPPORT = 0x04000, - HALFSUPPORT = 0x08000, - CHAR8SUPPORT = 0x10000, - KEYCONCEPTS = 0x20000, - KEYOBJC2 = 0x40000, - KEYZVECTOR = 0x80000, - KEYCOROUTINES = 0x100000, - KEYMODULES = 0x200000, - KEYCXX2A = 0x400000, - KEYOPENCLCXX = 0x800000, + KEYC99 = 0x1, + KEYCXX = 0x2, + KEYCXX11 = 0x4, + KEYGNU = 0x8, + KEYMS = 0x10, + BOOLSUPPORT = 0x20, + KEYALTIVEC = 0x40, + KEYNOCXX = 0x80, + KEYBORLAND = 0x100, + KEYOPENCLC = 0x200, + KEYC11 = 0x400, + KEYNOMS18 = 0x800, + KEYNOOPENCL = 0x1000, + WCHARSUPPORT = 0x2000, + HALFSUPPORT = 0x4000, + CHAR8SUPPORT = 0x8000, + KEYCONCEPTS = 0x10000, + KEYOBJC = 0x20000, + KEYZVECTOR = 0x40000, + KEYCOROUTINES = 0x80000, + KEYMODULES = 0x100000, + KEYCXX2A = 0x200000, + KEYOPENCLCXX = 0x400000, KEYALLCXX = KEYCXX | KEYCXX11 | KEYCXX2A, KEYALL = (0xffffff & ~KEYNOMS18 & ~KEYNOOPENCL) // KEYNOMS18 and KEYNOOPENCL are used to exclude. @@ -155,6 +132,7 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts, if (LangOpts.WChar && (Flags & WCHARSUPPORT)) return KS_Enabled; if (LangOpts.Char8 && (Flags & CHAR8SUPPORT)) return KS_Enabled; if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) return KS_Enabled; + if (LangOpts.ZVector && (Flags & KEYZVECTOR)) return KS_Enabled; if (LangOpts.OpenCL && !LangOpts.OpenCLCPlusPlus && (Flags & KEYOPENCLC)) return KS_Enabled; if (LangOpts.OpenCLCPlusPlus && (Flags & KEYOPENCLCXX)) return KS_Enabled; @@ -162,8 +140,7 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts, if (LangOpts.C11 && (Flags & KEYC11)) return KS_Enabled; // We treat bridge casts as objective-C keywords so we can warn on them // in non-arc mode. - if (LangOpts.ObjC2 && (Flags & KEYARC)) return KS_Enabled; - if (LangOpts.ObjC2 && (Flags & KEYOBJC2)) return KS_Enabled; + if (LangOpts.ObjC && (Flags & KEYOBJC)) return KS_Enabled; if (LangOpts.ConceptsTS && (Flags & KEYCONCEPTS)) return KS_Enabled; if (LangOpts.CoroutinesTS && (Flags & KEYCOROUTINES)) return KS_Enabled; if (LangOpts.ModulesTS && (Flags & KEYMODULES)) return KS_Enabled; @@ -227,11 +204,8 @@ void IdentifierTable::AddKeywords(const LangOptions &LangOpts) { #define CXX_KEYWORD_OPERATOR(NAME, ALIAS) \ if (LangOpts.CXXOperatorNames) \ AddCXXOperatorKeyword(StringRef(#NAME), tok::ALIAS, *this); -#define OBJC1_AT_KEYWORD(NAME) \ - if (LangOpts.ObjC1) \ - AddObjCKeyword(StringRef(#NAME), tok::objc_##NAME, *this); -#define OBJC2_AT_KEYWORD(NAME) \ - if (LangOpts.ObjC2) \ +#define OBJC_AT_KEYWORD(NAME) \ + if (LangOpts.ObjC) \ AddObjCKeyword(StringRef(#NAME), tok::objc_##NAME, *this); #define TESTING_KEYWORD(NAME, FLAGS) #include "clang/Basic/TokenKinds.def" @@ -382,24 +356,23 @@ unsigned llvm::DenseMapInfo<clang::Selector>::getHashValue(clang::Selector S) { namespace clang { -/// MultiKeywordSelector - One of these variable length records is kept for each +/// One of these variable length records is kept for each /// selector containing more than one keyword. We use a folding set /// to unique aggregate names (keyword selectors in ObjC parlance). Access to /// this class is provided strictly through Selector. -class MultiKeywordSelector - : public DeclarationNameExtra, public llvm::FoldingSetNode { - MultiKeywordSelector(unsigned nKeys) { - ExtraKindOrNumArgs = NUM_EXTRA_KINDS + nKeys; - } +class alignas(IdentifierInfoAlignment) MultiKeywordSelector + : public detail::DeclarationNameExtra, + public llvm::FoldingSetNode { + MultiKeywordSelector(unsigned nKeys) : DeclarationNameExtra(nKeys) {} public: // Constructor for keyword selectors. - MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV) { + MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV) + : DeclarationNameExtra(nKeys) { assert((nKeys > 1) && "not a multi-keyword selector"); - ExtraKindOrNumArgs = NUM_EXTRA_KINDS + nKeys; // Fill in the trailing keyword array. - IdentifierInfo **KeyInfo = reinterpret_cast<IdentifierInfo **>(this+1); + IdentifierInfo **KeyInfo = reinterpret_cast<IdentifierInfo **>(this + 1); for (unsigned i = 0; i != nKeys; ++i) KeyInfo[i] = IIV[i]; } @@ -407,16 +380,16 @@ public: // getName - Derive the full selector name and return it. std::string getName() const; - unsigned getNumArgs() const { return ExtraKindOrNumArgs - NUM_EXTRA_KINDS; } + using DeclarationNameExtra::getNumArgs; using keyword_iterator = IdentifierInfo *const *; keyword_iterator keyword_begin() const { - return reinterpret_cast<keyword_iterator>(this+1); + return reinterpret_cast<keyword_iterator>(this + 1); } keyword_iterator keyword_end() const { - return keyword_begin()+getNumArgs(); + return keyword_begin() + getNumArgs(); } IdentifierInfo *getIdentifierInfoForSlot(unsigned i) const { @@ -424,8 +397,8 @@ public: return keyword_begin()[i]; } - static void Profile(llvm::FoldingSetNodeID &ID, - keyword_iterator ArgTys, unsigned NumArgs) { + static void Profile(llvm::FoldingSetNodeID &ID, keyword_iterator ArgTys, + unsigned NumArgs) { ID.AddInteger(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) ID.AddPointer(ArgTys[i]); @@ -462,7 +435,7 @@ IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const { StringRef Selector::getNameForSlot(unsigned int argIndex) const { IdentifierInfo *II = getIdentifierInfoForSlot(argIndex); - return II? II->getName() : StringRef(); + return II ? II->getName() : StringRef(); } std::string MultiKeywordSelector::getName() const { @@ -584,6 +557,7 @@ ObjCInstanceTypeFamily Selector::getInstTypeMethodFamily(Selector sel) { break; case 'i': if (startsWithWord(name, "init")) return OIT_Init; + break; default: break; } diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp index 1a0c190590589..fd552f2baaca3 100644 --- a/lib/Basic/Module.cpp +++ b/lib/Basic/Module.cpp @@ -71,6 +71,37 @@ Module::~Module() { } } +static bool isPlatformEnvironment(const TargetInfo &Target, StringRef Feature) { + StringRef Platform = Target.getPlatformName(); + StringRef Env = Target.getTriple().getEnvironmentName(); + + // Attempt to match platform and environment. + if (Platform == Feature || Target.getTriple().getOSName() == Feature || + Env == Feature) + return true; + + auto CmpPlatformEnv = [](StringRef LHS, StringRef RHS) { + auto Pos = LHS.find("-"); + if (Pos == StringRef::npos) + return false; + SmallString<128> NewLHS = LHS.slice(0, Pos); + NewLHS += LHS.slice(Pos+1, LHS.size()); + return NewLHS == RHS; + }; + + SmallString<128> PlatformEnv = Target.getTriple().getOSAndEnvironmentName(); + // Darwin has different but equivalent variants for simulators, example: + // 1. x86_64-apple-ios-simulator + // 2. x86_64-apple-iossimulator + // where both are valid examples of the same platform+environment but in the + // variant (2) the simulator is hardcoded as part of the platform name. Both + // forms above should match for "iossimulator" requirement. + if (Target.getTriple().isOSDarwin() && PlatformEnv.endswith("simulator")) + return PlatformEnv == Feature || CmpPlatformEnv(PlatformEnv, Feature); + + return PlatformEnv == Feature; +} + /// Determine whether a translation unit built using the current /// language options has the given feature. static bool hasFeature(StringRef Feature, const LangOptions &LangOpts, @@ -88,12 +119,13 @@ static bool hasFeature(StringRef Feature, const LangOptions &LangOpts, .Case("c17", LangOpts.C17) .Case("freestanding", LangOpts.Freestanding) .Case("gnuinlineasm", LangOpts.GNUAsm) - .Case("objc", LangOpts.ObjC1) + .Case("objc", LangOpts.ObjC) .Case("objc_arc", LangOpts.ObjCAutoRefCount) .Case("opencl", LangOpts.OpenCL) .Case("tls", Target.isTLSSupported()) .Case("zvector", LangOpts.ZVector) - .Default(Target.hasFeature(Feature)); + .Default(Target.hasFeature(Feature) || + isPlatformEnvironment(Target, Feature)); if (!HasFeature) HasFeature = std::find(LangOpts.ModuleFeatures.begin(), LangOpts.ModuleFeatures.end(), @@ -577,10 +609,6 @@ void VisibleModuleSet::setVisible(Module *M, SourceLocation Loc, }; std::function<void(Visiting)> VisitModule = [&](Visiting V) { - // Modules that aren't available cannot be made visible. - if (!V.M->isAvailable()) - return; - // Nothing to do for a module that's already visible. unsigned ID = V.M->getVisibilityID(); if (ImportLocs.size() <= ID) @@ -594,8 +622,11 @@ void VisibleModuleSet::setVisible(Module *M, SourceLocation Loc, // Make any exported modules visible. SmallVector<Module *, 16> Exports; V.M->getExportedModules(Exports); - for (Module *E : Exports) - VisitModule({E, &V}); + for (Module *E : Exports) { + // Don't recurse to unavailable submodules. + if (E->isAvailable()) + VisitModule({E, &V}); + } for (auto &C : V.M->Conflicts) { if (isVisible(C.Other)) { diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp index 67b7d91e62926..a5bfac86e6109 100644 --- a/lib/Basic/OpenMPKinds.cpp +++ b/lib/Basic/OpenMPKinds.cpp @@ -108,8 +108,11 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, #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) + return llvm::StringSwitch<unsigned>(Str) +#define OPENMP_MAP_KIND(Name) \ + .Case(#Name, static_cast<unsigned>(OMPC_MAP_##Name)) +#define OPENMP_MAP_MODIFIER_KIND(Name) \ + .Case(#Name, static_cast<unsigned>(OMPC_MAP_MODIFIER_##Name)) #include "clang/Basic/OpenMPKinds.def" .Default(OMPC_MAP_unknown); case OMPC_dist_schedule: @@ -125,6 +128,12 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, .Case(#Name, static_cast<unsigned>(OMPC_DEFAULTMAP_MODIFIER_##Name)) #include "clang/Basic/OpenMPKinds.def" .Default(OMPC_DEFAULTMAP_unknown); + case OMPC_atomic_default_mem_order: + return llvm::StringSwitch<OpenMPAtomicDefaultMemOrderClauseKind>(Str) +#define OPENMP_ATOMIC_DEFAULT_MEM_ORDER_KIND(Name) \ + .Case(#Name, OMPC_ATOMIC_DEFAULT_MEM_ORDER_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_ATOMIC_DEFAULT_MEM_ORDER_unknown); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: @@ -168,6 +177,10 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, case OMPC_from: case OMPC_use_device_ptr: case OMPC_is_device_ptr: + case OMPC_unified_address: + case OMPC_unified_shared_memory: + case OMPC_reverse_offload: + case OMPC_dynamic_allocators: break; } llvm_unreachable("Invalid OpenMP simple clause kind"); @@ -233,10 +246,14 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, case OMPC_map: switch (Type) { case OMPC_MAP_unknown: + case OMPC_MAP_MODIFIER_last: return "unknown"; #define OPENMP_MAP_KIND(Name) \ case OMPC_MAP_##Name: \ return #Name; +#define OPENMP_MAP_MODIFIER_KIND(Name) \ + case OMPC_MAP_MODIFIER_##Name: \ + return #Name; #include "clang/Basic/OpenMPKinds.def" default: break; @@ -266,6 +283,16 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, #include "clang/Basic/OpenMPKinds.def" } llvm_unreachable("Invalid OpenMP 'schedule' clause type"); + case OMPC_atomic_default_mem_order: + switch (Type) { + case OMPC_ATOMIC_DEFAULT_MEM_ORDER_unknown: + return "unknown"; +#define OPENMP_ATOMIC_DEFAULT_MEM_ORDER_KIND(Name) \ + case OMPC_ATOMIC_DEFAULT_MEM_ORDER_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" +} + llvm_unreachable("Invalid OpenMP 'atomic_default_mem_order' clause type"); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: @@ -309,6 +336,10 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, case OMPC_from: case OMPC_use_device_ptr: case OMPC_is_device_ptr: + case OMPC_unified_address: + case OMPC_unified_shared_memory: + case OMPC_reverse_offload: + case OMPC_dynamic_allocators: break; } llvm_unreachable("Invalid OpenMP simple clause kind"); @@ -442,6 +473,16 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, break; } break; + case OMPD_requires: + switch (CKind) { +#define OPENMP_REQUIRES_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; case OMPD_target_data: switch (CKind) { #define OPENMP_TARGET_DATA_CLAUSE(Name) \ @@ -961,6 +1002,7 @@ void clang::getOpenMPCaptureRegions( case OMPD_declare_simd: case OMPD_declare_target: case OMPD_end_declare_target: + case OMPD_requires: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp index eb916ec76fdcf..aa844f2cd26ca 100644 --- a/lib/Basic/SourceLocation.cpp +++ b/lib/Basic/SourceLocation.cpp @@ -77,6 +77,61 @@ SourceLocation::printToString(const SourceManager &SM) const { LLVM_DUMP_METHOD void SourceLocation::dump(const SourceManager &SM) const { print(llvm::errs(), SM); + llvm::errs() << '\n'; +} + +LLVM_DUMP_METHOD void SourceRange::dump(const SourceManager &SM) const { + print(llvm::errs(), SM); + llvm::errs() << '\n'; +} + +static PresumedLoc PrintDifference(raw_ostream &OS, const SourceManager &SM, + SourceLocation Loc, PresumedLoc Previous) { + if (Loc.isFileID()) { + + PresumedLoc PLoc = SM.getPresumedLoc(Loc); + + if (PLoc.isInvalid()) { + OS << "<invalid sloc>"; + return Previous; + } + + if (Previous.isInvalid() || + strcmp(PLoc.getFilename(), Previous.getFilename()) != 0) { + OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':' + << PLoc.getColumn(); + } else if (Previous.isInvalid() || PLoc.getLine() != Previous.getLine()) { + OS << "line" << ':' << PLoc.getLine() << ':' << PLoc.getColumn(); + } else { + OS << "col" << ':' << PLoc.getColumn(); + } + return PLoc; + } + auto PrintedLoc = PrintDifference(OS, SM, SM.getExpansionLoc(Loc), Previous); + + OS << " <Spelling="; + PrintedLoc = PrintDifference(OS, SM, SM.getSpellingLoc(Loc), PrintedLoc); + OS << '>'; + return PrintedLoc; +} + +void SourceRange::print(raw_ostream &OS, const SourceManager &SM) const { + + OS << '<'; + auto PrintedLoc = PrintDifference(OS, SM, B, {}); + if (B != E) { + OS << ", "; + PrintDifference(OS, SM, E, PrintedLoc); + } + OS << '>'; +} + +LLVM_DUMP_METHOD std::string +SourceRange::printToString(const SourceManager &SM) const { + std::string S; + llvm::raw_string_ostream OS(S); + print(OS, SM); + return OS.str(); } //===----------------------------------------------------------------------===// diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index efa6ad2493b20..ce8aa5d112b36 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -195,8 +195,7 @@ llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag, } unsigned LineTableInfo::getLineTableFilenameID(StringRef Name) { - auto IterBool = - FilenameIDs.insert(std::make_pair(Name, FilenamesByID.size())); + auto IterBool = FilenameIDs.try_emplace(Name, FilenamesByID.size()); if (IterBool.second) FilenamesByID.push_back(&*IterBool.first); return IterBool.first->second; @@ -1217,65 +1216,22 @@ static void ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI, const unsigned char *Buf = (const unsigned char *)Buffer->getBufferStart(); const unsigned char *End = (const unsigned char *)Buffer->getBufferEnd(); - unsigned Offs = 0; + unsigned I = 0; while (true) { // Skip over the contents of the line. - const unsigned char *NextBuf = (const unsigned char *)Buf; - -#ifdef __SSE2__ - // Try to skip to the next newline using SSE instructions. This is very - // performance sensitive for programs with lots of diagnostics and in -E - // mode. - __m128i CRs = _mm_set1_epi8('\r'); - __m128i LFs = _mm_set1_epi8('\n'); - - // First fix up the alignment to 16 bytes. - while (((uintptr_t)NextBuf & 0xF) != 0) { - if (*NextBuf == '\n' || *NextBuf == '\r' || *NextBuf == '\0') - goto FoundSpecialChar; - ++NextBuf; - } - - // Scan 16 byte chunks for '\r' and '\n'. Ignore '\0'. - while (NextBuf+16 <= End) { - const __m128i Chunk = *(const __m128i*)NextBuf; - __m128i Cmp = _mm_or_si128(_mm_cmpeq_epi8(Chunk, CRs), - _mm_cmpeq_epi8(Chunk, LFs)); - unsigned Mask = _mm_movemask_epi8(Cmp); - - // If we found a newline, adjust the pointer and jump to the handling code. - if (Mask != 0) { - NextBuf += llvm::countTrailingZeros(Mask); - goto FoundSpecialChar; - } - NextBuf += 16; - } -#endif - - while (*NextBuf != '\n' && *NextBuf != '\r' && *NextBuf != '\0') - ++NextBuf; - -#ifdef __SSE2__ -FoundSpecialChar: -#endif - Offs += NextBuf-Buf; - Buf = NextBuf; - - if (Buf[0] == '\n' || Buf[0] == '\r') { - // If this is \n\r or \r\n, skip both characters. - if ((Buf[1] == '\n' || Buf[1] == '\r') && Buf[0] != Buf[1]) { - ++Offs; - ++Buf; - } - ++Offs; - ++Buf; - LineOffsets.push_back(Offs); + while (Buf[I] != '\n' && Buf[I] != '\r' && Buf[I] != '\0') + ++I; + + if (Buf[I] == '\n' || Buf[I] == '\r') { + // If this is \r\n, skip both characters. + if (Buf[I] == '\r' && Buf[I+1] == '\n') + ++I; + ++I; + LineOffsets.push_back(I); } else { - // Otherwise, this is a null. If end of file, exit. - if (Buf == End) break; - // Otherwise, skip the null. - ++Offs; - ++Buf; + // Otherwise, this is a NUL. If end of file, exit. + if (Buf+I == End) break; + ++I; } } @@ -1965,9 +1921,7 @@ SourceManager::getDecomposedIncludedLoc(FileID FID) const { // Uses IncludedLocMap to retrieve/cache the decomposed loc. using DecompTy = std::pair<FileID, unsigned>; - using MapTy = llvm::DenseMap<FileID, DecompTy>; - std::pair<MapTy::iterator, bool> - InsertOp = IncludedLocMap.insert(std::make_pair(FID, DecompTy())); + auto InsertOp = IncludedLocMap.try_emplace(FID); DecompTy &DecompLoc = InsertOp.first->second; if (!InsertOp.second) return DecompLoc; // already in map. @@ -2263,8 +2217,8 @@ SourceManagerForFile::SourceManagerForFile(StringRef FileName, StringRef Content) { // This is referenced by `FileMgr` and will be released by `FileMgr` when it // is deleted. - IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem( - new vfs::InMemoryFileSystem); + IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( + new llvm::vfs::InMemoryFileSystem); InMemoryFileSystem->addFile( FileName, 0, llvm::MemoryBuffer::getMemBuffer(Content, FileName, diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index 3400c8721f7a4..269fad38b8d57 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -63,8 +63,9 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) { MinGlobalAlign = 0; // From the glibc documentation, on GNU systems, malloc guarantees 16-byte // alignment on 64-bit systems and 8-byte alignment on 32-bit systems. See - // https://www.gnu.org/software/libc/manual/html_node/Malloc-Examples.html - if (T.isGNUEnvironment() || T.isWindowsMSVCEnvironment()) + // https://www.gnu.org/software/libc/manual/html_node/Malloc-Examples.html. + // This alignment guarantee also applies to Windows and Android. + if (T.isGNUEnvironment() || T.isWindowsMSVCEnvironment() || T.isAndroid()) NewAlign = Triple.isArch64Bit() ? 128 : Triple.isArch32Bit() ? 64 : 0; else NewAlign = 0; // Infer from basic type alignment. @@ -684,7 +685,9 @@ bool TargetInfo::validateInputConstraint( // FIXME: Fail if % is used with the last operand. break; case 'i': // immediate integer. + break; case 'n': // immediate integer with a known value. + Info.setRequiresImmediate(); break; case 'I': // Various constant constraints with target-specific meanings. case 'J': diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 1ef2fe3b81416..cf87bc484621c 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -16,6 +16,7 @@ #include "Targets/AArch64.h" #include "Targets/AMDGPU.h" +#include "Targets/ARC.h" #include "Targets/ARM.h" #include "Targets/AVR.h" #include "Targets/BPF.h" @@ -25,7 +26,6 @@ #include "Targets/MSP430.h" #include "Targets/Mips.h" #include "Targets/NVPTX.h" -#include "Targets/Nios2.h" #include "Targets/OSTargets.h" #include "Targets/PNaCl.h" #include "Targets/PPC.h" @@ -124,6 +124,9 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple, default: return nullptr; + case llvm::Triple::arc: + return new ARCTargetInfo(Triple, Opts); + case llvm::Triple::xcore: return new XCoreTargetInfo(Triple, Opts); @@ -243,9 +246,6 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple, case llvm::Triple::msp430: return new MSP430TargetInfo(Triple, Opts); - case llvm::Triple::nios2: - return new LinuxTargetInfo<Nios2TargetInfo>(Triple, Opts); - case llvm::Triple::mips: switch (os) { case llvm::Triple::Linux: @@ -495,6 +495,8 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple, return new NaClTargetInfo<X86_32TargetInfo>(Triple, Opts); case llvm::Triple::ELFIAMCU: return new MCUX86_32TargetInfo(Triple, Opts); + case llvm::Triple::Hurd: + return new HurdTargetInfo<X86_32TargetInfo>(Triple, Opts); default: return new X86_32TargetInfo(Triple, Opts); } @@ -566,17 +568,19 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple, case llvm::Triple::wasm32: if (Triple.getSubArch() != llvm::Triple::NoSubArch || Triple.getVendor() != llvm::Triple::UnknownVendor || - Triple.getOS() != llvm::Triple::UnknownOS || - Triple.getEnvironment() != llvm::Triple::UnknownEnvironment || - !(Triple.isOSBinFormatELF() || Triple.isOSBinFormatWasm())) + !Triple.isOSBinFormatWasm()) + return nullptr; + if (Triple.getOS() != llvm::Triple::UnknownOS && + Triple.getOS() != llvm::Triple::WASI) return nullptr; return new WebAssemblyOSTargetInfo<WebAssembly32TargetInfo>(Triple, Opts); case llvm::Triple::wasm64: if (Triple.getSubArch() != llvm::Triple::NoSubArch || Triple.getVendor() != llvm::Triple::UnknownVendor || - Triple.getOS() != llvm::Triple::UnknownOS || - Triple.getEnvironment() != llvm::Triple::UnknownEnvironment || - !(Triple.isOSBinFormatELF() || Triple.isOSBinFormatWasm())) + !Triple.isOSBinFormatWasm()) + return nullptr; + if (Triple.getOS() != llvm::Triple::UnknownOS && + Triple.getOS() != llvm::Triple::WASI) return nullptr; return new WebAssemblyOSTargetInfo<WebAssembly64TargetInfo>(Triple, Opts); @@ -640,7 +644,7 @@ TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, Opts->Features.push_back((F.getValue() ? "+" : "-") + F.getKey().str()); // Sort here, so we handle the features in a predictable order. (This matters // when we're dealing with features that overlap.) - llvm::sort(Opts->Features.begin(), Opts->Features.end()); + llvm::sort(Opts->Features); if (!Target->handleTargetFeatures(Opts->Features, Diags)) return nullptr; diff --git a/lib/Basic/Targets/AArch64.cpp b/lib/Basic/Targets/AArch64.cpp index 3444591ac5933..62919a02dcb9f 100644 --- a/lib/Basic/Targets/AArch64.cpp +++ b/lib/Basic/Targets/AArch64.cpp @@ -37,11 +37,11 @@ const Builtin::Info AArch64TargetInfo::BuiltinInfo[] = { AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : TargetInfo(Triple), ABI("aapcs") { - if (getTriple().getOS() == llvm::Triple::OpenBSD) { + if (getTriple().isOSOpenBSD()) { Int64Type = SignedLongLong; IntMaxType = SignedLongLong; } else { - if (!getTriple().isOSDarwin() && getTriple().getOS() != llvm::Triple::NetBSD) + if (!getTriple().isOSDarwin() && !getTriple().isOSNetBSD()) WCharType = UnsignedInt; Int64Type = SignedLong; @@ -122,10 +122,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { // Target identification. Builder.defineMacro("__aarch64__"); - // For bare-metal none-eabi. + // For bare-metal. if (getTriple().getOS() == llvm::Triple::UnknownOS && - (getTriple().getEnvironment() == llvm::Triple::EABI || - getTriple().getEnvironment() == llvm::Triple::EABIHF)) + getTriple().isOSBinFormatELF()) Builder.defineMacro("__ELF__"); // Target properties. @@ -195,6 +194,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, if (HasDotProd) Builder.defineMacro("__ARM_FEATURE_DOTPROD", "1"); + if ((FPU & NeonMode) && HasFP16FML) + Builder.defineMacro("__ARM_FEATURE_FP16FML", "1"); + switch (ArchKind) { default: break; @@ -232,6 +234,7 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, Unaligned = 1; HasFullFP16 = 0; HasDotProd = 0; + HasFP16FML = 0; ArchKind = llvm::AArch64::ArchKind::ARMV8A; for (const auto &Feature : Features) { @@ -253,6 +256,8 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, HasFullFP16 = 1; if (Feature == "+dotprod") HasDotProd = 1; + if (Feature == "+fp16fml") + HasFP16FML = 1; } setDataLayout(); @@ -268,6 +273,7 @@ AArch64TargetInfo::checkCallingConvention(CallingConv CC) const { case CC_PreserveMost: case CC_PreserveAll: case CC_OpenCLKernel: + case CC_AArch64VectorCall: case CC_Win64: return CCCR_OK; default: @@ -508,6 +514,7 @@ WindowsARM64TargetInfo::checkCallingConvention(CallingConv CC) const { case CC_OpenCLKernel: case CC_PreserveMost: case CC_PreserveAll: + case CC_Swift: case CC_Win64: return CCCR_OK; default: diff --git a/lib/Basic/Targets/AArch64.h b/lib/Basic/Targets/AArch64.h index a9df895e4dad3..d7f767abd4d10 100644 --- a/lib/Basic/Targets/AArch64.h +++ b/lib/Basic/Targets/AArch64.h @@ -34,6 +34,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo { unsigned Unaligned; unsigned HasFullFP16; unsigned HasDotProd; + unsigned HasFP16FML; llvm::AArch64::ArchKind ArchKind; static const Builtin::Info BuiltinInfo[]; diff --git a/lib/Basic/Targets/AMDGPU.cpp b/lib/Basic/Targets/AMDGPU.cpp index b6b9aa2f1244c..7313a692f46ba 100644 --- a/lib/Basic/Targets/AMDGPU.cpp +++ b/lib/Basic/Targets/AMDGPU.cpp @@ -13,10 +13,10 @@ #include "AMDGPU.h" #include "clang/Basic/Builtins.h" +#include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/MacroBuilder.h" #include "clang/Basic/TargetBuiltins.h" -#include "clang/Frontend/CodeGenOptions.h" #include "llvm/ADT/StringSwitch.h" using namespace clang; @@ -127,15 +127,19 @@ bool AMDGPUTargetInfo::initFeatureMap( llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector<std::string> &FeatureVec) const { + using namespace llvm::AMDGPU; + // XXX - What does the member GPU mean if device name string passed here? if (isAMDGCN(getTriple())) { if (CPU.empty()) CPU = "gfx600"; - switch (parseAMDGCNName(CPU).Kind) { + switch (llvm::AMDGPU::parseArchAMDGCN(CPU)) { case GK_GFX906: Features["dl-insts"] = true; + Features["dot-insts"] = true; LLVM_FALLTHROUGH; + case GK_GFX909: case GK_GFX904: case GK_GFX902: case GK_GFX900: @@ -145,15 +149,18 @@ bool AMDGPUTargetInfo::initFeatureMap( case GK_GFX803: case GK_GFX802: case GK_GFX801: + Features["vi-insts"] = true; Features["16-bit-insts"] = true; Features["dpp"] = true; Features["s-memrealtime"] = true; - break; + LLVM_FALLTHROUGH; case GK_GFX704: case GK_GFX703: case GK_GFX702: case GK_GFX701: case GK_GFX700: + Features["ci-insts"] = true; + LLVM_FALLTHROUGH; case GK_GFX601: case GK_GFX600: break; @@ -166,7 +173,7 @@ bool AMDGPUTargetInfo::initFeatureMap( if (CPU.empty()) CPU = "r600"; - switch (parseR600Name(CPU).Kind) { + switch (llvm::AMDGPU::parseArchR600(CPU)) { case GK_CAYMAN: case GK_CYPRESS: case GK_RV770: @@ -198,7 +205,7 @@ void AMDGPUTargetInfo::adjustTargetOptions(const CodeGenOptions &CGOpts, TargetOptions &TargetOpts) const { bool hasFP32Denormals = false; bool hasFP64Denormals = false; - GPUInfo CGOptsGPU = parseGPUName(TargetOpts.CPU); + for (auto &I : TargetOpts.FeaturesAsWritten) { if (I == "+fp32-denormals" || I == "-fp32-denormals") hasFP32Denormals = true; @@ -207,53 +214,20 @@ void AMDGPUTargetInfo::adjustTargetOptions(const CodeGenOptions &CGOpts, } if (!hasFP32Denormals) TargetOpts.Features.push_back( - (Twine(CGOptsGPU.HasFastFMAF && !CGOpts.FlushDenorm - ? '+' - : '-') + - Twine("fp32-denormals")) + (Twine(hasFastFMAF() && hasFullRateDenormalsF32() && !CGOpts.FlushDenorm + ? '+' : '-') + Twine("fp32-denormals")) .str()); // Always do not flush fp64 or fp16 denorms. - if (!hasFP64Denormals && CGOptsGPU.HasFP64) + if (!hasFP64Denormals && hasFP64()) TargetOpts.Features.push_back("+fp64-fp16-denormals"); } -constexpr AMDGPUTargetInfo::GPUInfo AMDGPUTargetInfo::InvalidGPU; -constexpr AMDGPUTargetInfo::GPUInfo AMDGPUTargetInfo::R600GPUs[]; -constexpr AMDGPUTargetInfo::GPUInfo AMDGPUTargetInfo::AMDGCNGPUs[]; - -AMDGPUTargetInfo::GPUInfo AMDGPUTargetInfo::parseR600Name(StringRef Name) { - const auto *Result = llvm::find_if( - R600GPUs, [Name](const GPUInfo &GPU) { return GPU.Name == Name; }); - - if (Result == std::end(R600GPUs)) - return InvalidGPU; - return *Result; -} - -AMDGPUTargetInfo::GPUInfo AMDGPUTargetInfo::parseAMDGCNName(StringRef Name) { - const auto *Result = llvm::find_if( - AMDGCNGPUs, [Name](const GPUInfo &GPU) { return GPU.Name == Name; }); - - if (Result == std::end(AMDGCNGPUs)) - return InvalidGPU; - return *Result; -} - -AMDGPUTargetInfo::GPUInfo AMDGPUTargetInfo::parseGPUName(StringRef Name) const { - if (isAMDGCN(getTriple())) - return parseAMDGCNName(Name); - else - return parseR600Name(Name); -} - void AMDGPUTargetInfo::fillValidCPUList( SmallVectorImpl<StringRef> &Values) const { if (isAMDGCN(getTriple())) - llvm::for_each(AMDGCNGPUs, [&Values](const GPUInfo &GPU) { - Values.emplace_back(GPU.Name);}); + llvm::AMDGPU::fillValidArchListAMDGCN(Values); else - llvm::for_each(R600GPUs, [&Values](const GPUInfo &GPU) { - Values.emplace_back(GPU.Name);}); + llvm::AMDGPU::fillValidArchListR600(Values); } void AMDGPUTargetInfo::setAddressSpaceMap(bool DefaultIsPrivate) { @@ -263,7 +237,12 @@ void AMDGPUTargetInfo::setAddressSpaceMap(bool DefaultIsPrivate) { AMDGPUTargetInfo::AMDGPUTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : TargetInfo(Triple), - GPU(isAMDGCN(Triple) ? AMDGCNGPUs[0] : parseR600Name(Opts.CPU)) { + GPUKind(isAMDGCN(Triple) ? + llvm::AMDGPU::parseArchAMDGCN(Opts.CPU) : + llvm::AMDGPU::parseArchR600(Opts.CPU)), + GPUFeatures(isAMDGCN(Triple) ? + llvm::AMDGPU::getArchAttrAMDGCN(GPUKind) : + llvm::AMDGPU::getArchAttrR600(GPUKind)) { resetDataLayout(isAMDGCN(getTriple()) ? DataLayoutStringAMDGCN : DataLayoutStringR600); assert(DataLayout->getAllocaAddrSpace() == Private); @@ -308,19 +287,22 @@ void AMDGPUTargetInfo::getTargetDefines(const LangOptions &Opts, else Builder.defineMacro("__R600__"); - if (GPU.Kind != GK_NONE) - Builder.defineMacro(Twine("__") + Twine(GPU.CanonicalName) + Twine("__")); + if (GPUKind != llvm::AMDGPU::GK_NONE) { + StringRef CanonName = isAMDGCN(getTriple()) ? + getArchNameAMDGCN(GPUKind) : getArchNameR600(GPUKind); + Builder.defineMacro(Twine("__") + Twine(CanonName) + Twine("__")); + } // TODO: __HAS_FMAF__, __HAS_LDEXPF__, __HAS_FP64__ are deprecated and will be // removed in the near future. - if (GPU.HasFMAF) + if (hasFMAF()) Builder.defineMacro("__HAS_FMAF__"); - if (GPU.HasFastFMAF) + if (hasFastFMAF()) Builder.defineMacro("FP_FAST_FMAF"); - if (GPU.HasLDEXPF) + if (hasLDEXPF()) Builder.defineMacro("__HAS_LDEXPF__"); - if (GPU.HasFP64) + if (hasFP64()) Builder.defineMacro("__HAS_FP64__"); - if (GPU.HasFastFMA) + if (hasFastFMA()) Builder.defineMacro("FP_FAST_FMA"); } diff --git a/lib/Basic/Targets/AMDGPU.h b/lib/Basic/Targets/AMDGPU.h index b0221031addf2..926772809aa77 100644 --- a/lib/Basic/Targets/AMDGPU.h +++ b/lib/Basic/Targets/AMDGPU.h @@ -19,6 +19,7 @@ #include "llvm/ADT/StringSet.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/TargetParser.h" namespace clang { namespace targets { @@ -38,147 +39,47 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo { static const LangASMap AMDGPUDefIsGenMap; static const LangASMap AMDGPUDefIsPrivMap; - /// GPU kinds supported by the AMDGPU target. - enum GPUKind : uint32_t { - // Not specified processor. - GK_NONE = 0, - - // R600-based processors. - GK_R600, - GK_R630, - GK_RS880, - GK_RV670, - GK_RV710, - GK_RV730, - GK_RV770, - GK_CEDAR, - GK_CYPRESS, - GK_JUNIPER, - GK_REDWOOD, - GK_SUMO, - GK_BARTS, - GK_CAICOS, - GK_CAYMAN, - GK_TURKS, - - GK_R600_FIRST = GK_R600, - GK_R600_LAST = GK_TURKS, - - // AMDGCN-based processors. - GK_GFX600, - GK_GFX601, - GK_GFX700, - GK_GFX701, - GK_GFX702, - GK_GFX703, - GK_GFX704, - GK_GFX801, - GK_GFX802, - GK_GFX803, - GK_GFX810, - GK_GFX900, - GK_GFX902, - GK_GFX904, - GK_GFX906, - - GK_AMDGCN_FIRST = GK_GFX600, - GK_AMDGCN_LAST = GK_GFX906, - }; + llvm::AMDGPU::GPUKind GPUKind; + unsigned GPUFeatures; - struct GPUInfo { - llvm::StringLiteral Name; - llvm::StringLiteral CanonicalName; - AMDGPUTargetInfo::GPUKind Kind; - bool HasFMAF; - bool HasFastFMAF; - bool HasLDEXPF; - bool HasFP64; - bool HasFastFMA; - }; - static constexpr GPUInfo InvalidGPU = - {{""}, {""}, GK_NONE, false, false, false, false, false}; - static constexpr GPUInfo R600GPUs[26] = { - // Name Canonical Kind Has Has Has Has Has - // Name FMAF Fast LDEXPF FP64 Fast - // FMAF FMA - {{"r600"}, {"r600"}, GK_R600, false, false, false, false, false}, - {{"rv630"}, {"r600"}, GK_R600, false, false, false, false, false}, - {{"rv635"}, {"r600"}, GK_R600, false, false, false, false, false}, - {{"r630"}, {"r630"}, GK_R630, false, false, false, false, false}, - {{"rs780"}, {"rs880"}, GK_RS880, false, false, false, false, false}, - {{"rs880"}, {"rs880"}, GK_RS880, false, false, false, false, false}, - {{"rv610"}, {"rs880"}, GK_RS880, false, false, false, false, false}, - {{"rv620"}, {"rs880"}, GK_RS880, false, false, false, false, false}, - {{"rv670"}, {"rv670"}, GK_RV670, false, false, false, false, false}, - {{"rv710"}, {"rv710"}, GK_RV710, false, false, false, false, false}, - {{"rv730"}, {"rv730"}, GK_RV730, false, false, false, false, false}, - {{"rv740"}, {"rv770"}, GK_RV770, false, false, false, false, false}, - {{"rv770"}, {"rv770"}, GK_RV770, false, false, false, false, false}, - {{"cedar"}, {"cedar"}, GK_CEDAR, false, false, false, false, false}, - {{"palm"}, {"cedar"}, GK_CEDAR, false, false, false, false, false}, - {{"cypress"}, {"cypress"}, GK_CYPRESS, true, false, false, false, false}, - {{"hemlock"}, {"cypress"}, GK_CYPRESS, true, false, false, false, false}, - {{"juniper"}, {"juniper"}, GK_JUNIPER, false, false, false, false, false}, - {{"redwood"}, {"redwood"}, GK_REDWOOD, false, false, false, false, false}, - {{"sumo"}, {"sumo"}, GK_SUMO, false, false, false, false, false}, - {{"sumo2"}, {"sumo"}, GK_SUMO, false, false, false, false, false}, - {{"barts"}, {"barts"}, GK_BARTS, false, false, false, false, false}, - {{"caicos"}, {"caicos"}, GK_BARTS, false, false, false, false, false}, - {{"aruba"}, {"cayman"}, GK_CAYMAN, true, false, false, false, false}, - {{"cayman"}, {"cayman"}, GK_CAYMAN, true, false, false, false, false}, - {{"turks"}, {"turks"}, GK_TURKS, false, false, false, false, false}, - }; - static constexpr GPUInfo AMDGCNGPUs[32] = { - // Name Canonical Kind Has Has Has Has Has - // Name FMAF Fast LDEXPF FP64 Fast - // FMAF FMA - {{"gfx600"}, {"gfx600"}, GK_GFX600, true, true, true, true, true}, - {{"tahiti"}, {"gfx600"}, GK_GFX600, true, true, true, true, true}, - {{"gfx601"}, {"gfx601"}, GK_GFX601, true, false, true, true, true}, - {{"hainan"}, {"gfx601"}, GK_GFX601, true, false, true, true, true}, - {{"oland"}, {"gfx601"}, GK_GFX601, true, false, true, true, true}, - {{"pitcairn"}, {"gfx601"}, GK_GFX601, true, false, true, true, true}, - {{"verde"}, {"gfx601"}, GK_GFX601, true, false, true, true, true}, - {{"gfx700"}, {"gfx700"}, GK_GFX700, true, false, true, true, true}, - {{"kaveri"}, {"gfx700"}, GK_GFX700, true, false, true, true, true}, - {{"gfx701"}, {"gfx701"}, GK_GFX701, true, true, true, true, true}, - {{"hawaii"}, {"gfx701"}, GK_GFX701, true, true, true, true, true}, - {{"gfx702"}, {"gfx702"}, GK_GFX702, true, true, true, true, true}, - {{"gfx703"}, {"gfx703"}, GK_GFX703, true, false, true, true, true}, - {{"kabini"}, {"gfx703"}, GK_GFX703, true, false, true, true, true}, - {{"mullins"}, {"gfx703"}, GK_GFX703, true, false, true, true, true}, - {{"gfx704"}, {"gfx704"}, GK_GFX704, true, false, true, true, true}, - {{"bonaire"}, {"gfx704"}, GK_GFX704, true, false, true, true, true}, - {{"gfx801"}, {"gfx801"}, GK_GFX801, true, true, true, true, true}, - {{"carrizo"}, {"gfx801"}, GK_GFX801, true, true, true, true, true}, - {{"gfx802"}, {"gfx802"}, GK_GFX802, true, false, true, true, true}, - {{"iceland"}, {"gfx802"}, GK_GFX802, true, false, true, true, true}, - {{"tonga"}, {"gfx802"}, GK_GFX802, true, false, true, true, true}, - {{"gfx803"}, {"gfx803"}, GK_GFX803, true, false, true, true, true}, - {{"fiji"}, {"gfx803"}, GK_GFX803, true, false, true, true, true}, - {{"polaris10"}, {"gfx803"}, GK_GFX803, true, false, true, true, true}, - {{"polaris11"}, {"gfx803"}, GK_GFX803, true, false, true, true, true}, - {{"gfx810"}, {"gfx810"}, GK_GFX810, true, false, true, true, true}, - {{"stoney"}, {"gfx810"}, GK_GFX810, true, false, true, true, true}, - {{"gfx900"}, {"gfx900"}, GK_GFX900, true, true, true, true, true}, - {{"gfx902"}, {"gfx902"}, GK_GFX900, true, true, true, true, true}, - {{"gfx904"}, {"gfx904"}, GK_GFX904, true, true, true, true, true}, - {{"gfx906"}, {"gfx906"}, GK_GFX906, true, true, true, true, true}, - }; + bool hasFP64() const { + return getTriple().getArch() == llvm::Triple::amdgcn || + !!(GPUFeatures & llvm::AMDGPU::FEATURE_FP64); + } - static GPUInfo parseR600Name(StringRef Name); + /// Has fast fma f32 + bool hasFastFMAF() const { + return !!(GPUFeatures & llvm::AMDGPU::FEATURE_FAST_FMA_F32); + } - static GPUInfo parseAMDGCNName(StringRef Name); + /// Has fast fma f64 + bool hasFastFMA() const { + return getTriple().getArch() == llvm::Triple::amdgcn; + } - GPUInfo parseGPUName(StringRef Name) const; + bool hasFMAF() const { + return getTriple().getArch() == llvm::Triple::amdgcn || + !!(GPUFeatures & llvm::AMDGPU::FEATURE_FMA); + } - GPUInfo GPU; + bool hasFullRateDenormalsF32() const { + return !!(GPUFeatures & llvm::AMDGPU::FEATURE_FAST_DENORMAL_F32); + } + + bool hasLDEXPF() const { + return getTriple().getArch() == llvm::Triple::amdgcn || + !!(GPUFeatures & llvm::AMDGPU::FEATURE_LDEXP); + } static bool isAMDGCN(const llvm::Triple &TT) { return TT.getArch() == llvm::Triple::amdgcn; } + static bool isR600(const llvm::Triple &TT) { + return TT.getArch() == llvm::Triple::r600; + } + public: AMDGPUTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); @@ -187,10 +88,12 @@ public: void adjust(LangOptions &Opts) override; uint64_t getPointerWidthV(unsigned AddrSpace) const override { - if (GPU.Kind <= GK_R600_LAST) + if (isR600(getTriple())) return 32; + if (AddrSpace == Private || AddrSpace == Local) return 32; + return 64; } @@ -321,20 +224,22 @@ public: bool isValidCPUName(StringRef Name) const override { if (getTriple().getArch() == llvm::Triple::amdgcn) - return GK_NONE != parseAMDGCNName(Name).Kind; - else - return GK_NONE != parseR600Name(Name).Kind; + return llvm::AMDGPU::parseArchAMDGCN(Name) != llvm::AMDGPU::GK_NONE; + return llvm::AMDGPU::parseArchR600(Name) != llvm::AMDGPU::GK_NONE; } void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; bool setCPU(const std::string &Name) override { - if (getTriple().getArch() == llvm::Triple::amdgcn) - GPU = parseAMDGCNName(Name); - else - GPU = parseR600Name(Name); + if (getTriple().getArch() == llvm::Triple::amdgcn) { + GPUKind = llvm::AMDGPU::parseArchAMDGCN(Name); + GPUFeatures = llvm::AMDGPU::getArchAttrAMDGCN(GPUKind); + } else { + GPUKind = llvm::AMDGPU::parseArchR600(Name); + GPUFeatures = llvm::AMDGPU::getArchAttrR600(GPUKind); + } - return GK_NONE != GPU.Kind; + return GPUKind != llvm::AMDGPU::GK_NONE; } void setSupportedOpenCLOpts() override { @@ -342,16 +247,20 @@ public: Opts.support("cl_clang_storage_class_specifiers"); Opts.support("cl_khr_icd"); - if (GPU.HasFP64) + bool IsAMDGCN = isAMDGCN(getTriple()); + + if (hasFP64()) Opts.support("cl_khr_fp64"); - if (GPU.Kind >= GK_CEDAR) { + + if (IsAMDGCN || GPUKind >= llvm::AMDGPU::GK_CEDAR) { Opts.support("cl_khr_byte_addressable_store"); Opts.support("cl_khr_global_int32_base_atomics"); Opts.support("cl_khr_global_int32_extended_atomics"); Opts.support("cl_khr_local_int32_base_atomics"); Opts.support("cl_khr_local_int32_extended_atomics"); } - if (GPU.Kind >= GK_AMDGCN_FIRST) { + + if (IsAMDGCN) { Opts.support("cl_khr_fp16"); Opts.support("cl_khr_int64_base_atomics"); Opts.support("cl_khr_int64_extended_atomics"); @@ -378,6 +287,27 @@ public: } } + LangAS getOpenCLBuiltinAddressSpace(unsigned AS) const override { + switch (AS) { + case 0: + return LangAS::opencl_generic; + case 1: + return LangAS::opencl_global; + case 3: + return LangAS::opencl_local; + case 4: + return LangAS::opencl_constant; + case 5: + return LangAS::opencl_private; + default: + return getLangASFromTargetAS(AS); + } + } + + LangAS getCUDABuiltinAddressSpace(unsigned AS) const override { + return LangAS::Default; + } + llvm::Optional<LangAS> getConstantAddressSpace() const override { return getLangASFromTargetAS(Constant); } diff --git a/lib/Basic/Targets/ARC.cpp b/lib/Basic/Targets/ARC.cpp new file mode 100644 index 0000000000000..2159ab8e20207 --- /dev/null +++ b/lib/Basic/Targets/ARC.cpp @@ -0,0 +1,25 @@ +//===--- ARC.cpp - Implement ARC target feature support -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements ARC TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#include "ARC.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" + +using namespace clang; +using namespace clang::targets; + +void ARCTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__arc__"); +}
diff --git a/lib/Basic/Targets/ARC.h b/lib/Basic/Targets/ARC.h new file mode 100644 index 0000000000000..ee20568f3d5b1 --- /dev/null +++ b/lib/Basic/Targets/ARC.h @@ -0,0 +1,74 @@ +//===--- ARC.h - Declare ARC target feature support -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares ARC TargetInfo objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_ARC_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_ARC_H + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace targets { + +class LLVM_LIBRARY_VISIBILITY ARCTargetInfo : public TargetInfo { +public: + ARCTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + NoAsmVariants = true; + LongLongAlign = 32; + SuitableAlign = 32; + DoubleAlign = LongDoubleAlign = 32; + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + UseZeroLengthBitfieldAlignment = true; + resetDataLayout("e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-" + "i32:32:32-f32:32:32-i64:32-f64:32-a:0:32-n32"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + ArrayRef<Builtin::Info> getTargetBuiltins() const override { return None; } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + const char *getClobbers() const override { return ""; } + + ArrayRef<const char *> getGCCRegNames() const override { + static const char *const GCCRegNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "gp", "sp", "fp", "ilink1", "r30", "blink"}; + return llvm::makeArrayRef(GCCRegNames); + } + + ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { + return None; + } + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + return false; + } +}; + +} // namespace targets +} // namespace clang + +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_ARC_H diff --git a/lib/Basic/Targets/ARM.cpp b/lib/Basic/Targets/ARM.cpp index 19fcc5abea97e..16644ace108b7 100644 --- a/lib/Basic/Targets/ARM.cpp +++ b/lib/Basic/Targets/ARM.cpp @@ -28,8 +28,8 @@ void ARMTargetInfo::setABIAAPCS() { DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64; const llvm::Triple &T = getTriple(); - bool IsNetBSD = T.getOS() == llvm::Triple::NetBSD; - bool IsOpenBSD = T.getOS() == llvm::Triple::OpenBSD; + bool IsNetBSD = T.isOSNetBSD(); + bool IsOpenBSD = T.isOSOpenBSD(); if (!T.isOSWindows() && !IsNetBSD && !IsOpenBSD) WCharType = UnsignedInt; @@ -189,6 +189,8 @@ StringRef ARMTargetInfo::getCPUAttr() const { return "8_3A"; case llvm::ARM::ArchKind::ARMV8_4A: return "8_4A"; + case llvm::ARM::ArchKind::ARMV8_5A: + return "8_5A"; case llvm::ARM::ArchKind::ARMV8MBaseline: return "8M_BASE"; case llvm::ARM::ArchKind::ARMV8MMainline: @@ -215,8 +217,8 @@ ARMTargetInfo::ARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : TargetInfo(Triple), FPMath(FP_Default), IsAAPCS(true), LDREX(0), HW_FP(0) { - bool IsOpenBSD = Triple.getOS() == llvm::Triple::OpenBSD; - bool IsNetBSD = Triple.getOS() == llvm::Triple::NetBSD; + bool IsOpenBSD = Triple.isOSOpenBSD(); + bool IsNetBSD = Triple.isOSNetBSD(); // FIXME: the isOSBinFormatMachO is a workaround for identifying a Darwin-like // environment where size_t is `unsigned long` rather than `unsigned int` @@ -280,9 +282,9 @@ ARMTargetInfo::ARMTargetInfo(const llvm::Triple &Triple, setABI("apcs-gnu"); break; default: - if (Triple.getOS() == llvm::Triple::NetBSD) + if (IsNetBSD) setABI("apcs-gnu"); - else if (Triple.getOS() == llvm::Triple::OpenBSD) + else if (IsOpenBSD) setABI("aapcs-linux"); else setABI("aapcs"); @@ -661,7 +663,7 @@ void ARMTargetInfo::getTargetDefines(const LangOptions &Opts, } // ACLE 6.4.9 32-bit SIMD instructions - if (ArchVersion >= 6 && (CPUProfile != "M" || CPUAttr == "7EM")) + if ((CPUProfile != "M" && ArchVersion >= 6) || (CPUProfile == "M" && DSP)) Builder.defineMacro("__ARM_FEATURE_SIMD32", "1"); // ACLE 6.4.10 Hardware Integer Divide @@ -994,6 +996,7 @@ WindowsARMTargetInfo::checkCallingConvention(CallingConv CC) const { case CC_OpenCLKernel: case CC_PreserveMost: case CC_PreserveAll: + case CC_Swift: return CCCR_OK; default: return CCCR_Warning; diff --git a/lib/Basic/Targets/Hexagon.cpp b/lib/Basic/Targets/Hexagon.cpp index 0ef1f6db281ea..94e1388e381e0 100644 --- a/lib/Basic/Targets/Hexagon.cpp +++ b/lib/Basic/Targets/Hexagon.cpp @@ -25,14 +25,7 @@ void HexagonTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__qdsp6__", "1"); Builder.defineMacro("__hexagon__", "1"); - if (CPU == "hexagonv4") { - Builder.defineMacro("__HEXAGON_V4__"); - Builder.defineMacro("__HEXAGON_ARCH__", "4"); - if (Opts.HexagonQdsp6Compat) { - Builder.defineMacro("__QDSP6_V4__"); - Builder.defineMacro("__QDSP6_ARCH__", "4"); - } - } else if (CPU == "hexagonv5") { + if (CPU == "hexagonv5") { Builder.defineMacro("__HEXAGON_V5__"); Builder.defineMacro("__HEXAGON_ARCH__", "5"); if (Opts.HexagonQdsp6Compat) { @@ -55,6 +48,9 @@ void HexagonTargetInfo::getTargetDefines(const LangOptions &Opts, } else if (CPU == "hexagonv65") { Builder.defineMacro("__HEXAGON_V65__"); Builder.defineMacro("__HEXAGON_ARCH__", "65"); + } else if (CPU == "hexagonv66") { + Builder.defineMacro("__HEXAGON_V66__"); + Builder.defineMacro("__HEXAGON_ARCH__", "66"); } if (hasFeature("hvx-length64b")) { @@ -150,9 +146,9 @@ struct CPUSuffix { }; static constexpr CPUSuffix Suffixes[] = { - {{"hexagonv4"}, {"4"}}, {{"hexagonv5"}, {"5"}}, - {{"hexagonv55"}, {"55"}}, {{"hexagonv60"}, {"60"}}, - {{"hexagonv62"}, {"62"}}, {{"hexagonv65"}, {"65"}}, + {{"hexagonv5"}, {"5"}}, {{"hexagonv55"}, {"55"}}, + {{"hexagonv60"}, {"60"}}, {{"hexagonv62"}, {"62"}}, + {{"hexagonv65"}, {"65"}}, {{"hexagonv66"}, {"66"}}, }; const char *HexagonTargetInfo::getHexagonCPUSuffix(StringRef Name) { diff --git a/lib/Basic/Targets/Mips.cpp b/lib/Basic/Targets/Mips.cpp index cbd5a01c3da8c..d43edeae608f2 100644 --- a/lib/Basic/Targets/Mips.cpp +++ b/lib/Basic/Targets/Mips.cpp @@ -59,6 +59,16 @@ void MipsTargetInfo::fillValidCPUList( Values.append(std::begin(ValidCPUNames), std::end(ValidCPUNames)); } +unsigned MipsTargetInfo::getISARev() const { + return llvm::StringSwitch<unsigned>(getCPU()) + .Cases("mips32", "mips64", 1) + .Cases("mips32r2", "mips64r2", 2) + .Cases("mips32r3", "mips64r3", 3) + .Cases("mips32r5", "mips64r5", 5) + .Cases("mips32r6", "mips64r6", 6) + .Default(0); +} + void MipsTargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { if (BigEndian) { @@ -84,13 +94,8 @@ void MipsTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("_MIPS_ISA", "_MIPS_ISA_MIPS64"); } - const std::string ISARev = llvm::StringSwitch<std::string>(getCPU()) - .Cases("mips32", "mips64", "1") - .Cases("mips32r2", "mips64r2", "2") - .Cases("mips32r3", "mips64r3", "3") - .Cases("mips32r5", "mips64r5", "5") - .Cases("mips32r6", "mips64r6", "6") - .Default(""); + const std::string ISARev = std::to_string(getISARev()); + if (!ISARev.empty()) Builder.defineMacro("__mips_isa_rev", ISARev); @@ -129,9 +134,22 @@ void MipsTargetInfo::getTargetDefines(const LangOptions &Opts, if (IsSingleFloat) Builder.defineMacro("__mips_single_float", Twine(1)); - Builder.defineMacro("__mips_fpr", HasFP64 ? Twine(64) : Twine(32)); - Builder.defineMacro("_MIPS_FPSET", - Twine(32 / (HasFP64 || IsSingleFloat ? 1 : 2))); + switch (FPMode) { + case FPXX: + Builder.defineMacro("__mips_fpr", Twine(0)); + break; + case FP32: + Builder.defineMacro("__mips_fpr", Twine(32)); + break; + case FP64: + Builder.defineMacro("__mips_fpr", Twine(64)); + break; +} + + if (FPMode == FP64 || IsSingleFloat) + Builder.defineMacro("_MIPS_FPSET", Twine(32)); + else + Builder.defineMacro("_MIPS_FPSET", Twine(16)); if (IsMips16) Builder.defineMacro("__mips16", Twine(1)); @@ -189,7 +207,7 @@ void MipsTargetInfo::getTargetDefines(const LangOptions &Opts, bool MipsTargetInfo::hasFeature(StringRef Feature) const { return llvm::StringSwitch<bool>(Feature) .Case("mips", true) - .Case("fp64", HasFP64) + .Case("fp64", FPMode == FP64) .Default(false); } @@ -235,5 +253,30 @@ bool MipsTargetInfo::validateTarget(DiagnosticsEngine &Diags) const { return false; } + // -fpxx is valid only for the o32 ABI + if (FPMode == FPXX && (ABI == "n32" || ABI == "n64")) { + Diags.Report(diag::err_unsupported_abi_for_opt) << "-mfpxx" << "o32"; + return false; + } + + // -mfp32 and n32/n64 ABIs are incompatible + if (FPMode != FP64 && FPMode != FPXX && !IsSingleFloat && + (ABI == "n32" || ABI == "n64")) { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfpxx" << CPU; + return false; + } + // Mips revision 6 and -mfp32 are incompatible + if (FPMode != FP64 && FPMode != FPXX && (CPU == "mips32r6" || + CPU == "mips64r6")) { + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfp32" << CPU; + return false; + } + // Option -mfp64 permitted on Mips32 iff revision 2 or higher is present + if (FPMode == FP64 && (CPU == "mips1" || CPU == "mips2" || + getISARev() < 2) && ABI == "o32") { + Diags.Report(diag::err_mips_fp64_req) << "-mfp64"; + return false; + } + return true; } diff --git a/lib/Basic/Targets/Mips.h b/lib/Basic/Targets/Mips.h index 11e9ac914430e..d49f49888b0c7 100644 --- a/lib/Basic/Targets/Mips.h +++ b/lib/Basic/Targets/Mips.h @@ -57,7 +57,7 @@ class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public TargetInfo { bool UseIndirectJumpHazard; protected: - bool HasFP64; + enum FPModeEnum { FPXX, FP32, FP64 } FPMode; std::string ABI; public: @@ -66,15 +66,20 @@ public: IsNan2008(false), IsAbs2008(false), IsSingleFloat(false), IsNoABICalls(false), CanUseBSDABICalls(false), FloatABI(HardFloat), DspRev(NoDSP), HasMSA(false), DisableMadd4(false), - UseIndirectJumpHazard(false), HasFP64(false) { + UseIndirectJumpHazard(false), FPMode(FPXX) { TheCXXABI.set(TargetCXXABI::GenericMIPS); - setABI(getTriple().isMIPS32() ? "o32" : "n64"); + if (Triple.isMIPS32()) + setABI("o32"); + else if (Triple.getEnvironment() == llvm::Triple::GNUABIN32) + setABI("n32"); + else + setABI("n64"); CPU = ABI == "o32" ? "mips32r2" : "mips64r2"; - CanUseBSDABICalls = Triple.getOS() == llvm::Triple::FreeBSD || - Triple.getOS() == llvm::Triple::OpenBSD; + CanUseBSDABICalls = Triple.isOSFreeBSD() || + Triple.isOSOpenBSD(); } bool isIEEE754_2008Default() const { @@ -127,7 +132,7 @@ public: void setN32N64ABITypes() { LongDoubleWidth = LongDoubleAlign = 128; LongDoubleFormat = &llvm::APFloat::IEEEquad(); - if (getTriple().getOS() == llvm::Triple::FreeBSD) { + if (getTriple().isOSFreeBSD()) { LongDoubleWidth = LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble(); } @@ -137,7 +142,7 @@ public: void setN64ABITypes() { setN32N64ABITypes(); - if (getTriple().getOS() == llvm::Triple::OpenBSD) { + if (getTriple().isOSOpenBSD()) { Int64Type = SignedLongLong; } else { Int64Type = SignedLong; @@ -181,6 +186,8 @@ public: return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } + unsigned getISARev() const; + void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; @@ -305,7 +312,7 @@ public: IsSingleFloat = false; FloatABI = HardFloat; DspRev = NoDSP; - HasFP64 = isFP64Default(); + FPMode = isFP64Default() ? FP64 : FPXX; for (const auto &Feature : Features) { if (Feature == "+single-float") @@ -325,9 +332,11 @@ public: else if (Feature == "+nomadd4") DisableMadd4 = true; else if (Feature == "+fp64") - HasFP64 = true; + FPMode = FP64; else if (Feature == "-fp64") - HasFP64 = false; + FPMode = FP32; + else if (Feature == "+fpxx") + FPMode = FPXX; else if (Feature == "+nan2008") IsNan2008 = true; else if (Feature == "-nan2008") diff --git a/lib/Basic/Targets/NVPTX.cpp b/lib/Basic/Targets/NVPTX.cpp index fd4ee16060611..ca41c4d14ca32 100644 --- a/lib/Basic/Targets/NVPTX.cpp +++ b/lib/Basic/Targets/NVPTX.cpp @@ -188,6 +188,9 @@ void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts, case CudaArch::GFX810: case CudaArch::GFX900: case CudaArch::GFX902: + case CudaArch::GFX904: + case CudaArch::GFX906: + case CudaArch::GFX909: case CudaArch::LAST: break; case CudaArch::UNKNOWN: @@ -221,6 +224,8 @@ void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts, return "700"; case CudaArch::SM_72: return "720"; + case CudaArch::SM_75: + return "750"; } llvm_unreachable("unhandled CudaArch"); }(); diff --git a/lib/Basic/Targets/Nios2.cpp b/lib/Basic/Targets/Nios2.cpp deleted file mode 100644 index 48f662dd98c1d..0000000000000 --- a/lib/Basic/Targets/Nios2.cpp +++ /dev/null @@ -1,56 +0,0 @@ -//===--- Nios2.cpp - Implement Nios2 target feature support ---------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements Nios2 TargetInfo objects. -// -//===----------------------------------------------------------------------===// - -#include "Nios2.h" -#include "Targets.h" -#include "clang/Basic/MacroBuilder.h" -#include "clang/Basic/TargetBuiltins.h" -#include "llvm/ADT/StringSwitch.h" - -using namespace clang; -using namespace clang::targets; - -const Builtin::Info Nios2TargetInfo::BuiltinInfo[] = { -#define BUILTIN(ID, TYPE, ATTRS) \ - {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, -#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ - {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, -#include "clang/Basic/BuiltinsNios2.def" -}; - -bool Nios2TargetInfo::isFeatureSupportedByCPU(StringRef Feature, - StringRef CPU) const { - const bool isR2 = CPU == "nios2r2"; - return llvm::StringSwitch<bool>(Feature) - .Case("nios2r2mandatory", isR2) - .Case("nios2r2bmx", isR2) - .Case("nios2r2mpx", isR2) - .Case("nios2r2cdx", isR2) - .Default(false); -} - -void Nios2TargetInfo::getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const { - DefineStd(Builder, "nios2", Opts); - DefineStd(Builder, "NIOS2", Opts); - - Builder.defineMacro("__nios2"); - Builder.defineMacro("__NIOS2"); - Builder.defineMacro("__nios2__"); - Builder.defineMacro("__NIOS2__"); -} - -ArrayRef<Builtin::Info> Nios2TargetInfo::getTargetBuiltins() const { - return llvm::makeArrayRef(BuiltinInfo, clang::Nios2::LastTSBuiltin - - Builtin::FirstTSBuiltin); -} diff --git a/lib/Basic/Targets/Nios2.h b/lib/Basic/Targets/Nios2.h deleted file mode 100644 index ffeb414d47789..0000000000000 --- a/lib/Basic/Targets/Nios2.h +++ /dev/null @@ -1,151 +0,0 @@ -//===--- Nios2.h - Declare Nios2 target feature support ---------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares Nios2 TargetInfo objects. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_NIOS2_H -#define LLVM_CLANG_LIB_BASIC_TARGETS_NIOS2_H - -#include "clang/Basic/TargetInfo.h" -#include "clang/Basic/TargetOptions.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Support/Compiler.h" - -namespace clang { -namespace targets { - -class LLVM_LIBRARY_VISIBILITY Nios2TargetInfo : public TargetInfo { - void setDataLayout() { - if (BigEndian) - resetDataLayout("E-p:32:32:32-i8:8:32-i16:16:32-n32"); - else - resetDataLayout("e-p:32:32:32-i8:8:32-i16:16:32-n32"); - } - - static const Builtin::Info BuiltinInfo[]; - std::string CPU; - std::string ABI; - -public: - Nios2TargetInfo(const llvm::Triple &triple, const TargetOptions &opts) - : TargetInfo(triple), CPU(opts.CPU), ABI(opts.ABI) { - SizeType = UnsignedInt; - PtrDiffType = SignedInt; - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; - setDataLayout(); - } - - StringRef getABI() const override { return ABI; } - bool setABI(const std::string &Name) override { - if (Name == "o32" || Name == "eabi") { - ABI = Name; - return true; - } - return false; - } - - bool isValidCPUName(StringRef Name) const override { - return Name == "nios2r1" || Name == "nios2r2"; - } - - void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override { - Values.append({"nios2r1", "nios2r2"}); - } - - bool setCPU(const std::string &Name) override { - if (isValidCPUName(Name)) { - CPU = Name; - return true; - } - return false; - } - - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override; - - ArrayRef<Builtin::Info> getTargetBuiltins() const override; - - bool isFeatureSupportedByCPU(StringRef Feature, StringRef CPU) const; - - bool - initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, - StringRef CPU, - const std::vector<std::string> &FeatureVec) const override { - static const char *allFeatures[] = {"nios2r2mandatory", "nios2r2bmx", - "nios2r2mpx", "nios2r2cdx" - }; - for (const char *feature : allFeatures) { - Features[feature] = isFeatureSupportedByCPU(feature, CPU); - } - return true; - } - - bool hasFeature(StringRef Feature) const override { - return isFeatureSupportedByCPU(Feature, CPU); - } - - BuiltinVaListKind getBuiltinVaListKind() const override { - return TargetInfo::VoidPtrBuiltinVaList; - } - - ArrayRef<const char *> getGCCRegNames() const override { - static const char *const GCCRegNames[] = { - // CPU register names - // Must match second column of GCCRegAliases - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", - "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", - "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", - "r31", - // Floating point register names - "ctl0", "ctl1", "ctl2", "ctl3", "ctl4", "ctl5", "ctl6", "ctl7", "ctl8", - "ctl9", "ctl10", "ctl11", "ctl12", "ctl13", "ctl14", "ctl15" - }; - return llvm::makeArrayRef(GCCRegNames); - } - - bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { - switch (*Name) { - default: - return false; - - case 'r': // CPU registers. - case 'd': // Equivalent to "r" unless generating MIPS16 code. - case 'y': // Equivalent to "r", backwards compatibility only. - case 'f': // floating-point registers. - case 'c': // $25 for indirect jumps - case 'l': // lo register - case 'x': // hilo register pair - Info.setAllowsRegister(); - return true; - } - } - - const char *getClobbers() const override { return ""; } - - ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override { - static const TargetInfo::GCCRegAlias aliases[] = { - {{"zero"}, "r0"}, {{"at"}, "r1"}, {{"et"}, "r24"}, - {{"bt"}, "r25"}, {{"gp"}, "r26"}, {{"sp"}, "r27"}, - {{"fp"}, "r28"}, {{"ea"}, "r29"}, {{"ba"}, "r30"}, - {{"ra"}, "r31"}, {{"status"}, "ctl0"}, {{"estatus"}, "ctl1"}, - {{"bstatus"}, "ctl2"}, {{"ienable"}, "ctl3"}, {{"ipending"}, "ctl4"}, - {{"cpuid"}, "ctl5"}, {{"exception"}, "ctl7"}, {{"pteaddr"}, "ctl8"}, - {{"tlbacc"}, "ctl9"}, {{"tlbmisc"}, "ctl10"}, {{"badaddr"}, "ctl12"}, - {{"config"}, "ctl13"}, {{"mpubase"}, "ctl14"}, {{"mpuacc"}, "ctl15"}, - }; - return llvm::makeArrayRef(aliases); - } -}; - -} // namespace targets -} // namespace clang -#endif // LLVM_CLANG_LIB_BASIC_TARGETS_NIOS2_H diff --git a/lib/Basic/Targets/OSTargets.cpp b/lib/Basic/Targets/OSTargets.cpp index 50abd4ce0c8c3..6252a51ef7105 100644 --- a/lib/Basic/Targets/OSTargets.cpp +++ b/lib/Basic/Targets/OSTargets.cpp @@ -33,7 +33,7 @@ void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, Builder.defineMacro("_FORTIFY_SOURCE", "0"); // Darwin defines __weak, __strong, and __unsafe_unretained even in C mode. - if (!Opts.ObjC1) { + if (!Opts.ObjC) { // __weak is always defined, for use in blocks and with objc pointers. Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))"); Builder.defineMacro("__strong", ""); diff --git a/lib/Basic/Targets/OSTargets.h b/lib/Basic/Targets/OSTargets.h index d0354784acf9b..085efa02cc5f1 100644 --- a/lib/Basic/Targets/OSTargets.h +++ b/lib/Basic/Targets/OSTargets.h @@ -133,6 +133,15 @@ public: /// is very similar to ELF's "protected"; Darwin requires a "weak" /// attribute on declarations that can be dynamically replaced. bool hasProtectedVisibility() const override { return false; } + + TargetInfo::IntType getLeastIntTypeByWidth(unsigned BitWidth, + bool IsSigned) const final { + // Darwin uses `long long` for `int_least64_t` and `int_fast64_t`. + return BitWidth == 64 + ? (IsSigned ? TargetInfo::SignedLongLong + : TargetInfo::UnsignedLongLong) + : TargetInfo::getLeastIntTypeByWidth(BitWidth, IsSigned); + } }; // DragonFlyBSD Target @@ -257,6 +266,8 @@ protected: Builder.defineMacro("__HAIKU__"); Builder.defineMacro("__ELF__"); DefineStd(Builder, "unix", Opts); + if (this->HasFloat128) + Builder.defineMacro("__FLOAT128__"); } public: @@ -267,7 +278,38 @@ public: this->PtrDiffType = TargetInfo::SignedLong; this->ProcessIDType = TargetInfo::SignedLong; this->TLSSupported = false; + switch (Triple.getArch()) { + default: + break; + case llvm::Triple::x86: + case llvm::Triple::x86_64: + this->HasFloat128 = true; + break; + } + } +}; + +// Hurd target +template <typename Target> +class LLVM_LIBRARY_VISIBILITY HurdTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // Hurd defines; list based off of gcc output. + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__GNU__"); + Builder.defineMacro("__gnu_hurd__"); + Builder.defineMacro("__MACH__"); + Builder.defineMacro("__GLIBC__"); + Builder.defineMacro("__ELF__"); + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); } +public: + HurdTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo<Target>(Triple, Opts) {} }; // Minix Target @@ -303,7 +345,6 @@ protected: // Linux defines; list based off of gcc output DefineStd(Builder, "unix", Opts); DefineStd(Builder, "linux", Opts); - Builder.defineMacro("__gnu_linux__"); Builder.defineMacro("__ELF__"); if (Triple.isAndroid()) { Builder.defineMacro("__ANDROID__", "1"); @@ -313,6 +354,8 @@ protected: this->PlatformMinVersion = VersionTuple(Maj, Min, Rev); if (Maj) Builder.defineMacro("__ANDROID_API__", Twine(Maj)); + } else { + Builder.defineMacro("__gnu_linux__"); } if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); @@ -341,7 +384,6 @@ public: break; case llvm::Triple::x86: case llvm::Triple::x86_64: - case llvm::Triple::systemz: this->HasFloat128 = true; break; } @@ -397,7 +439,7 @@ public: case llvm::Triple::x86: case llvm::Triple::x86_64: this->HasFloat128 = true; - // FALLTHROUGH + LLVM_FALLTHROUGH; default: this->MCountName = "__mcount"; break; @@ -643,6 +685,7 @@ public: WindowsTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OSTargetInfo<Target>(Triple, Opts) { this->WCharType = TargetInfo::UnsignedShort; + this->WIntType = TargetInfo::UnsignedShort; } }; diff --git a/lib/Basic/Targets/PPC.cpp b/lib/Basic/Targets/PPC.cpp index b4eb3b1b97b78..6cfbed1713e13 100644 --- a/lib/Basic/Targets/PPC.cpp +++ b/lib/Basic/Targets/PPC.cpp @@ -83,8 +83,8 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts, if (getTriple().getArch() == llvm::Triple::ppc64le) { Builder.defineMacro("_LITTLE_ENDIAN"); } else { - if (getTriple().getOS() != llvm::Triple::NetBSD && - getTriple().getOS() != llvm::Triple::OpenBSD) + if (!getTriple().isOSNetBSD() && + !getTriple().isOSOpenBSD()) Builder.defineMacro("_BIG_ENDIAN"); } @@ -412,6 +412,36 @@ ArrayRef<TargetInfo::GCCRegAlias> PPCTargetInfo::getGCCRegAliases() const { return llvm::makeArrayRef(GCCRegAliases); } +// PPC ELFABIv2 DWARF Definitoin "Table 2.26. Mappings of Common Registers". +// vs0 ~ vs31 is mapping to 32 - 63, +// vs32 ~ vs63 is mapping to 77 - 108. +const TargetInfo::AddlRegName GCCAddlRegNames[] = { + // Table of additional register names to use in user input. + {{"vs0"}, 32}, {{"vs1"}, 33}, {{"vs2"}, 34}, {{"vs3"}, 35}, + {{"vs4"}, 36}, {{"vs5"}, 37}, {{"vs6"}, 38}, {{"vs7"}, 39}, + {{"vs8"}, 40}, {{"vs9"}, 41}, {{"vs10"}, 42}, {{"vs11"}, 43}, + {{"vs12"}, 44}, {{"vs13"}, 45}, {{"vs14"}, 46}, {{"vs15"}, 47}, + {{"vs16"}, 48}, {{"vs17"}, 49}, {{"vs18"}, 50}, {{"vs19"}, 51}, + {{"vs20"}, 52}, {{"vs21"}, 53}, {{"vs22"}, 54}, {{"vs23"}, 55}, + {{"vs24"}, 56}, {{"vs25"}, 57}, {{"vs26"}, 58}, {{"vs27"}, 59}, + {{"vs28"}, 60}, {{"vs29"}, 61}, {{"vs30"}, 62}, {{"vs31"}, 63}, + {{"vs32"}, 77}, {{"vs33"}, 78}, {{"vs34"}, 79}, {{"vs35"}, 80}, + {{"vs36"}, 81}, {{"vs37"}, 82}, {{"vs38"}, 83}, {{"vs39"}, 84}, + {{"vs40"}, 85}, {{"vs41"}, 86}, {{"vs42"}, 87}, {{"vs43"}, 88}, + {{"vs44"}, 89}, {{"vs45"}, 90}, {{"vs46"}, 91}, {{"vs47"}, 92}, + {{"vs48"}, 93}, {{"vs49"}, 94}, {{"vs50"}, 95}, {{"vs51"}, 96}, + {{"vs52"}, 97}, {{"vs53"}, 98}, {{"vs54"}, 99}, {{"vs55"}, 100}, + {{"vs56"}, 101}, {{"vs57"}, 102}, {{"vs58"}, 103}, {{"vs59"}, 104}, + {{"vs60"}, 105}, {{"vs61"}, 106}, {{"vs62"}, 107}, {{"vs63"}, 108}, +}; + +ArrayRef<TargetInfo::AddlRegName> PPCTargetInfo::getGCCAddlRegNames() const { + if (ABI == "elfv2") + return llvm::makeArrayRef(GCCAddlRegNames); + else + return TargetInfo::getGCCAddlRegNames(); +} + static constexpr llvm::StringLiteral ValidCPUNames[] = { {"generic"}, {"440"}, {"450"}, {"601"}, {"602"}, {"603"}, {"603e"}, {"603ev"}, {"604"}, {"604e"}, diff --git a/lib/Basic/Targets/PPC.h b/lib/Basic/Targets/PPC.h index 439c73a0e3264..058970a0e098b 100644 --- a/lib/Basic/Targets/PPC.h +++ b/lib/Basic/Targets/PPC.h @@ -176,6 +176,8 @@ public: ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override; + ArrayRef<TargetInfo::AddlRegName> getGCCAddlRegNames() const override; + bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { switch (*Name) { @@ -201,6 +203,7 @@ public: case 's': // VSX vector register to hold scalar float data case 'a': // Any VSX register case 'c': // An individual CR bit + case 'i': // FP or VSX register to hold 64-bit integers data break; default: return false; @@ -328,7 +331,7 @@ public: break; } - if (getTriple().getOS() == llvm::Triple::FreeBSD) { + if (getTriple().isOSFreeBSD()) { LongDoubleWidth = LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble(); } diff --git a/lib/Basic/Targets/Sparc.h b/lib/Basic/Targets/Sparc.h index af2189f214687..5ae305bffb43a 100644 --- a/lib/Basic/Targets/Sparc.h +++ b/lib/Basic/Targets/Sparc.h @@ -199,7 +199,7 @@ public: LongWidth = LongAlign = PointerWidth = PointerAlign = 64; // OpenBSD uses long long for int64_t and intmax_t. - if (getTriple().getOS() == llvm::Triple::OpenBSD) + if (getTriple().isOSOpenBSD()) IntMaxType = SignedLongLong; else IntMaxType = SignedLong; diff --git a/lib/Basic/Targets/WebAssembly.cpp b/lib/Basic/Targets/WebAssembly.cpp index b8a2a092aff4a..2fdc84bb8cc8c 100644 --- a/lib/Basic/Targets/WebAssembly.cpp +++ b/lib/Basic/Targets/WebAssembly.cpp @@ -24,6 +24,8 @@ using namespace clang::targets; const Builtin::Info WebAssemblyTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ {#ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr}, #include "clang/Basic/BuiltinsWebAssembly.def" @@ -35,6 +37,7 @@ static constexpr llvm::StringLiteral ValidCPUNames[] = { bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const { return llvm::StringSwitch<bool>(Feature) .Case("simd128", SIMDLevel >= SIMD128) + .Case("unimplemented-simd128", SIMDLevel >= UnimplementedSIMD128) .Case("nontrapping-fptoint", HasNontrappingFPToInt) .Case("sign-ext", HasSignExt) .Case("exception-handling", HasExceptionHandling) @@ -55,6 +58,44 @@ void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts, defineCPUMacros(Builder, "wasm", /*Tuning=*/false); if (SIMDLevel >= SIMD128) Builder.defineMacro("__wasm_simd128__"); + if (SIMDLevel >= UnimplementedSIMD128) + Builder.defineMacro("__wasm_unimplemented_simd128__"); +} + +void WebAssemblyTargetInfo::setSIMDLevel(llvm::StringMap<bool> &Features, + SIMDEnum Level) { + switch (Level) { + case UnimplementedSIMD128: + Features["unimplemented-simd128"] = true; + LLVM_FALLTHROUGH; + case SIMD128: + Features["simd128"] = true; + LLVM_FALLTHROUGH; + case NoSIMD: + break; + } +} + +bool WebAssemblyTargetInfo::initFeatureMap( + llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, + const std::vector<std::string> &FeaturesVec) const { + if (CPU == "bleeding-edge") { + Features["nontrapping-fptoint"] = true; + Features["sign-ext"] = true; + setSIMDLevel(Features, SIMD128); + } + // Other targets do not consider user-configured features here, but while we + // are actively developing new features it is useful to let user-configured + // features control availability of builtins + setSIMDLevel(Features, SIMDLevel); + if (HasNontrappingFPToInt) + Features["nontrapping-fptoint"] = true; + if (HasSignExt) + Features["sign-ext"] = true; + if (HasExceptionHandling) + Features["exception-handling"] = true; + + return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } bool WebAssemblyTargetInfo::handleTargetFeatures( @@ -68,6 +109,14 @@ bool WebAssemblyTargetInfo::handleTargetFeatures( SIMDLevel = std::min(SIMDLevel, SIMDEnum(SIMD128 - 1)); continue; } + if (Feature == "+unimplemented-simd128") { + SIMDLevel = std::max(SIMDLevel, SIMDEnum(UnimplementedSIMD128)); + continue; + } + if (Feature == "-unimplemented-simd128") { + SIMDLevel = std::min(SIMDLevel, SIMDEnum(UnimplementedSIMD128 - 1)); + continue; + } if (Feature == "+nontrapping-fptoint") { HasNontrappingFPToInt = true; continue; diff --git a/lib/Basic/Targets/WebAssembly.h b/lib/Basic/Targets/WebAssembly.h index c04c5cb6fb3a9..3dea9a373cb4f 100644 --- a/lib/Basic/Targets/WebAssembly.h +++ b/lib/Basic/Targets/WebAssembly.h @@ -28,7 +28,8 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo { enum SIMDEnum { NoSIMD, SIMD128, - } SIMDLevel; + UnimplementedSIMD128, + } SIMDLevel = NoSIMD; bool HasNontrappingFPToInt; bool HasSignExt; @@ -59,18 +60,12 @@ protected: MacroBuilder &Builder) const override; private: + static void setSIMDLevel(llvm::StringMap<bool> &Features, SIMDEnum Level); + bool initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, - const std::vector<std::string> &FeaturesVec) const override { - if (CPU == "bleeding-edge") { - Features["simd128"] = true; - Features["nontrapping-fptoint"] = true; - Features["sign-ext"] = true; - } - return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); - } - + const std::vector<std::string> &FeaturesVec) const override; bool hasFeature(StringRef Feature) const final; bool handleTargetFeatures(std::vector<std::string> &Features, diff --git a/lib/Basic/Targets/X86.cpp b/lib/Basic/Targets/X86.cpp index e295cff9d5d2c..53b4c153e952c 100644 --- a/lib/Basic/Targets/X86.cpp +++ b/lib/Basic/Targets/X86.cpp @@ -142,7 +142,6 @@ bool X86TargetInfo::initFeatureMap( setFeatureEnabledImpl(Features, "gfni", true); setFeatureEnabledImpl(Features, "vpclmulqdq", true); setFeatureEnabledImpl(Features, "avx512bitalg", true); - setFeatureEnabledImpl(Features, "avx512vnni", true); setFeatureEnabledImpl(Features, "avx512vbmi2", true); setFeatureEnabledImpl(Features, "avx512vpopcntdq", true); setFeatureEnabledImpl(Features, "rdpid", true); @@ -152,6 +151,12 @@ bool X86TargetInfo::initFeatureMap( setFeatureEnabledImpl(Features, "avx512vbmi", true); setFeatureEnabledImpl(Features, "sha", true); LLVM_FALLTHROUGH; + case CK_Cascadelake: + //Cannonlake has no VNNI feature inside while Icelake has + if (Kind != CK_Cannonlake) + // CLK inherits all SKX features plus AVX512_VNNI + setFeatureEnabledImpl(Features, "avx512vnni", true); + LLVM_FALLTHROUGH; case CK_SkylakeServer: setFeatureEnabledImpl(Features, "avx512f", true); setFeatureEnabledImpl(Features, "avx512cd", true); @@ -166,10 +171,12 @@ bool X86TargetInfo::initFeatureMap( setFeatureEnabledImpl(Features, "xsavec", true); setFeatureEnabledImpl(Features, "xsaves", true); setFeatureEnabledImpl(Features, "mpx", true); - if (Kind != CK_SkylakeServer) // SKX inherits all SKL features, except SGX + if (Kind != CK_SkylakeServer + && Kind != CK_Cascadelake) + // SKX/CLX inherits all SKL features, except SGX setFeatureEnabledImpl(Features, "sgx", true); setFeatureEnabledImpl(Features, "clflushopt", true); - setFeatureEnabledImpl(Features, "rtm", true); + setFeatureEnabledImpl(Features, "aes", true); LLVM_FALLTHROUGH; case CK_Broadwell: setFeatureEnabledImpl(Features, "rdseed", true); @@ -196,7 +203,6 @@ bool X86TargetInfo::initFeatureMap( setFeatureEnabledImpl(Features, "xsaveopt", true); LLVM_FALLTHROUGH; case CK_Westmere: - setFeatureEnabledImpl(Features, "aes", true); setFeatureEnabledImpl(Features, "pclmul", true); LLVM_FALLTHROUGH; case CK_Nehalem: @@ -248,10 +254,10 @@ bool X86TargetInfo::initFeatureMap( setFeatureEnabledImpl(Features, "clflushopt", true); setFeatureEnabledImpl(Features, "mpx", true); setFeatureEnabledImpl(Features, "fsgsbase", true); + setFeatureEnabledImpl(Features, "aes", true); LLVM_FALLTHROUGH; case CK_Silvermont: setFeatureEnabledImpl(Features, "rdrnd", true); - setFeatureEnabledImpl(Features, "aes", true); setFeatureEnabledImpl(Features, "pclmul", true); setFeatureEnabledImpl(Features, "sse4.2", true); setFeatureEnabledImpl(Features, "prfchw", true); @@ -281,7 +287,6 @@ bool X86TargetInfo::initFeatureMap( setFeatureEnabledImpl(Features, "lzcnt", true); setFeatureEnabledImpl(Features, "bmi", true); setFeatureEnabledImpl(Features, "bmi2", true); - setFeatureEnabledImpl(Features, "rtm", true); setFeatureEnabledImpl(Features, "fma", true); setFeatureEnabledImpl(Features, "rdrnd", true); setFeatureEnabledImpl(Features, "f16c", true); @@ -796,8 +801,6 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, HasCLDEMOTE = true; } else if (Feature == "+rdpid") { HasRDPID = true; - } else if (Feature == "+retpoline") { - HasRetpoline = true; } else if (Feature == "+retpoline-external-thunk") { HasRetpolineExternalThunk = true; } else if (Feature == "+sahf") { @@ -862,6 +865,11 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, /// definitions for this particular subtarget. void X86TargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { + std::string CodeModel = getTargetOpts().CodeModel; + if (CodeModel == "default") + CodeModel = "small"; + Builder.defineMacro("__code_model_" + CodeModel + "_"); + // Target identification. if (getTriple().getArch() == llvm::Triple::x86_64) { Builder.defineMacro("__amd64__"); @@ -948,6 +956,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, case CK_Broadwell: case CK_SkylakeClient: case CK_SkylakeServer: + case CK_Cascadelake: case CK_Cannonlake: case CK_IcelakeClient: case CK_IcelakeServer: @@ -1083,6 +1092,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, if (HasMWAITX) Builder.defineMacro("__MWAITX__"); + if (HasMOVBE) + Builder.defineMacro("__MOVBE__"); + switch (XOPLevel) { case XOP: Builder.defineMacro("__XOP__"); @@ -1397,7 +1409,6 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const { .Case("rdpid", HasRDPID) .Case("rdrnd", HasRDRND) .Case("rdseed", HasRDSEED) - .Case("retpoline", HasRetpoline) .Case("retpoline-external-thunk", HasRetpolineExternalThunk) .Case("rtm", HasRTM) .Case("sahf", HasLAHFSAHF) @@ -1678,6 +1689,7 @@ bool X86TargetInfo::validateOperandSize(StringRef Constraint, return false; break; } + LLVM_FALLTHROUGH; case 'v': case 'x': if (SSELevel >= AVX512F) diff --git a/lib/Basic/Targets/X86.h b/lib/Basic/Targets/X86.h index 019bc8d51a634..05930ae9eec00 100644 --- a/lib/Basic/Targets/X86.h +++ b/lib/Basic/Targets/X86.h @@ -98,7 +98,6 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo { bool HasMOVBE = false; bool HasPREFETCHWT1 = false; bool HasRDPID = false; - bool HasRetpoline = false; bool HasRetpolineExternalThunk = false; bool HasLAHFSAHF = false; bool HasWBNOINVD = false; @@ -226,6 +225,7 @@ public: case 'Y': if ((++I != E) && ((*I == '0') || (*I == 'z'))) return "xmm0"; + break; default: break; } @@ -291,9 +291,6 @@ public: return checkCPUKind(CPU = getCPUKind(Name)); } - bool supportsMultiVersioning() const override { - return getTriple().isOSBinFormatELF(); - } unsigned multiVersionSortPriority(StringRef Name) const override; bool setFPMath(StringRef Name) override; @@ -350,11 +347,9 @@ public: (1 << TargetInfo::LongDouble)); // x86-32 has atomics up to 8 bytes - CPUKind Kind = getCPUKind(Opts.CPU); - if (Kind >= CK_i586 || Kind == CK_Generic) - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; - else if (Kind >= CK_i486) - MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; + // FIXME: Check that we actually have cmpxchg8b before setting + // MaxAtomicInlineWidth. (cmpxchg8b is an i586 instruction.) + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; } BuiltinVaListKind getBuiltinVaListKind() const override { diff --git a/lib/Basic/VirtualFileSystem.cpp b/lib/Basic/VirtualFileSystem.cpp deleted file mode 100644 index bcfcbdbb90149..0000000000000 --- a/lib/Basic/VirtualFileSystem.cpp +++ /dev/null @@ -1,2026 +0,0 @@ -//===- VirtualFileSystem.cpp - Virtual File System Layer ------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the VirtualFileSystem interface. -// -//===----------------------------------------------------------------------===// - -#include "clang/Basic/VirtualFileSystem.h" -#include "clang/Basic/LLVM.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/IntrusiveRefCntPtr.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSet.h" -#include "llvm/ADT/Twine.h" -#include "llvm/ADT/iterator_range.h" -#include "llvm/Config/llvm-config.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/Chrono.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Errc.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/ErrorOr.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/SMLoc.h" -#include "llvm/Support/SourceMgr.h" -#include "llvm/Support/YAMLParser.h" -#include "llvm/Support/raw_ostream.h" -#include <algorithm> -#include <atomic> -#include <cassert> -#include <cstdint> -#include <iterator> -#include <limits> -#include <map> -#include <memory> -#include <string> -#include <system_error> -#include <utility> -#include <vector> - -using namespace clang; -using namespace vfs; -using namespace llvm; - -using llvm::sys::fs::file_status; -using llvm::sys::fs::file_type; -using llvm::sys::fs::perms; -using llvm::sys::fs::UniqueID; - -Status::Status(const file_status &Status) - : UID(Status.getUniqueID()), MTime(Status.getLastModificationTime()), - User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()), - Type(Status.type()), Perms(Status.permissions()) {} - -Status::Status(StringRef Name, UniqueID UID, sys::TimePoint<> 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) {} - -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 { - assert(isStatusKnown() && Other.isStatusKnown()); - return getUniqueID() == Other.getUniqueID(); -} - -bool Status::isDirectory() const { - return Type == file_type::directory_file; -} - -bool Status::isRegularFile() const { - return Type == file_type::regular_file; -} - -bool Status::isOther() const { - return exists() && !isRegularFile() && !isDirectory() && !isSymlink(); -} - -bool Status::isSymlink() const { - return Type == file_type::symlink_file; -} - -bool Status::isStatusKnown() const { - return Type != file_type::status_error; -} - -bool Status::exists() const { - return isStatusKnown() && Type != file_type::file_not_found; -} - -File::~File() = default; - -FileSystem::~FileSystem() = default; - -ErrorOr<std::unique_ptr<MemoryBuffer>> -FileSystem::getBufferForFile(const llvm::Twine &Name, int64_t FileSize, - bool RequiresNullTerminator, bool IsVolatile) { - auto F = openFileForRead(Name); - if (!F) - return F.getError(); - - return (*F)->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile); -} - -std::error_code FileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const { - if (llvm::sys::path::is_absolute(Path)) - return {}; - - auto WorkingDir = getCurrentWorkingDirectory(); - if (!WorkingDir) - return WorkingDir.getError(); - - return llvm::sys::fs::make_absolute(WorkingDir.get(), Path); -} - -std::error_code FileSystem::getRealPath(const Twine &Path, - SmallVectorImpl<char> &Output) const { - return errc::operation_not_permitted; -} - -bool FileSystem::exists(const Twine &Path) { - auto Status = status(Path); - return Status && Status->exists(); -} - -#ifndef NDEBUG -static bool isTraversalComponent(StringRef Component) { - return Component.equals("..") || Component.equals("."); -} - -static bool pathHasTraversal(StringRef Path) { - using namespace llvm::sys; - - for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path))) - if (isTraversalComponent(Comp)) - return true; - return false; -} -#endif - -//===-----------------------------------------------------------------------===/ -// RealFileSystem implementation -//===-----------------------------------------------------------------------===/ - -namespace { - -/// Wrapper around a raw file descriptor. -class RealFile : public File { - friend class RealFileSystem; - - int FD; - Status S; - std::string RealName; - - RealFile(int FD, StringRef NewName, StringRef NewRealPathName) - : FD(FD), S(NewName, {}, {}, {}, {}, {}, - llvm::sys::fs::file_type::status_error, {}), - RealName(NewRealPathName.str()) { - assert(FD >= 0 && "Invalid or inactive file descriptor"); - } - -public: - ~RealFile() override; - - ErrorOr<Status> status() override; - ErrorOr<std::string> getName() override; - ErrorOr<std::unique_ptr<MemoryBuffer>> getBuffer(const Twine &Name, - int64_t FileSize, - bool RequiresNullTerminator, - bool IsVolatile) override; - std::error_code close() override; -}; - -} // namespace - -RealFile::~RealFile() { close(); } - -ErrorOr<Status> RealFile::status() { - assert(FD != -1 && "cannot stat closed file"); - if (!S.isStatusKnown()) { - file_status RealStatus; - if (std::error_code EC = sys::fs::status(FD, RealStatus)) - return EC; - S = Status::copyWithNewName(RealStatus, S.getName()); - } - return S; -} - -ErrorOr<std::string> RealFile::getName() { - return RealName.empty() ? S.getName().str() : RealName; -} - -ErrorOr<std::unique_ptr<MemoryBuffer>> -RealFile::getBuffer(const Twine &Name, int64_t FileSize, - bool RequiresNullTerminator, bool IsVolatile) { - assert(FD != -1 && "cannot get buffer for closed file"); - return MemoryBuffer::getOpenFile(FD, Name, FileSize, RequiresNullTerminator, - IsVolatile); -} - -std::error_code RealFile::close() { - std::error_code EC = sys::Process::SafelyCloseFileDescriptor(FD); - FD = -1; - return EC; -} - -namespace { - -/// The file system according to your operating system. -class RealFileSystem : public FileSystem { -public: - ErrorOr<Status> status(const Twine &Path) override; - ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override; - directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override; - - llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override; - std::error_code setCurrentWorkingDirectory(const Twine &Path) override; - std::error_code getRealPath(const Twine &Path, - SmallVectorImpl<char> &Output) const override; -}; - -} // namespace - -ErrorOr<Status> RealFileSystem::status(const Twine &Path) { - sys::fs::file_status RealStatus; - if (std::error_code EC = sys::fs::status(Path, RealStatus)) - return EC; - return Status::copyWithNewName(RealStatus, Path.str()); -} - -ErrorOr<std::unique_ptr<File>> -RealFileSystem::openFileForRead(const Twine &Name) { - int FD; - SmallString<256> RealName; - if (std::error_code EC = - sys::fs::openFileForRead(Name, FD, sys::fs::OF_None, &RealName)) - return EC; - return std::unique_ptr<File>(new RealFile(FD, Name.str(), RealName.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. - return llvm::sys::fs::set_current_path(Path); -} - -std::error_code -RealFileSystem::getRealPath(const Twine &Path, - SmallVectorImpl<char> &Output) const { - return llvm::sys::fs::real_path(Path, Output); -} - -IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() { - static IntrusiveRefCntPtr<FileSystem> FS = new RealFileSystem(); - return FS; -} - -namespace { - -class RealFSDirIter : public clang::vfs::detail::DirIterImpl { - llvm::sys::fs::directory_iterator Iter; - -public: - RealFSDirIter(const Twine &Path, std::error_code &EC) : Iter(Path, EC) { - if (Iter != llvm::sys::fs::directory_iterator()) { - llvm::sys::fs::file_status S; - std::error_code ErrorCode = llvm::sys::fs::status(Iter->path(), S, true); - CurrentEntry = Status::copyWithNewName(S, Iter->path()); - if (!EC) - EC = ErrorCode; - } - } - - std::error_code increment() override { - std::error_code EC; - Iter.increment(EC); - if (Iter == llvm::sys::fs::directory_iterator()) { - CurrentEntry = Status(); - } else { - llvm::sys::fs::file_status S; - std::error_code ErrorCode = llvm::sys::fs::status(Iter->path(), S, true); - CurrentEntry = Status::copyWithNewName(S, Iter->path()); - if (!EC) - EC = ErrorCode; - } - return EC; - } -}; - -} // namespace - -directory_iterator RealFileSystem::dir_begin(const Twine &Dir, - std::error_code &EC) { - return directory_iterator(std::make_shared<RealFSDirIter>(Dir, EC)); -} - -//===-----------------------------------------------------------------------===/ -// OverlayFileSystem implementation -//===-----------------------------------------------------------------------===/ - -OverlayFileSystem::OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> BaseFS) { - FSList.push_back(std::move(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) { - // FIXME: handle symlinks that cross file systems - for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) { - ErrorOr<Status> Status = (*I)->status(Path); - if (Status || Status.getError() != llvm::errc::no_such_file_or_directory) - return Status; - } - return make_error_code(llvm::errc::no_such_file_or_directory); -} - -ErrorOr<std::unique_ptr<File>> -OverlayFileSystem::openFileForRead(const llvm::Twine &Path) { - // FIXME: handle symlinks that cross file systems - for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) { - auto Result = (*I)->openFileForRead(Path); - if (Result || Result.getError() != llvm::errc::no_such_file_or_directory) - return Result; - } - return make_error_code(llvm::errc::no_such_file_or_directory); -} - -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 -OverlayFileSystem::getRealPath(const Twine &Path, - SmallVectorImpl<char> &Output) const { - for (auto &FS : FSList) - if (FS->exists(Path)) - return FS->getRealPath(Path, Output); - return errc::no_such_file_or_directory; -} - -clang::vfs::detail::DirIterImpl::~DirIterImpl() = default; - -namespace { - -class OverlayFSDirIterImpl : public clang::vfs::detail::DirIterImpl { - OverlayFileSystem &Overlays; - std::string Path; - OverlayFileSystem::iterator CurrentFS; - directory_iterator CurrentDirIter; - llvm::StringSet<> SeenNames; - - std::error_code incrementFS() { - assert(CurrentFS != Overlays.overlays_end() && "incrementing past end"); - ++CurrentFS; - for (auto E = Overlays.overlays_end(); CurrentFS != E; ++CurrentFS) { - std::error_code EC; - CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC); - if (EC && EC != errc::no_such_file_or_directory) - return EC; - if (CurrentDirIter != directory_iterator()) - break; // found - } - return {}; - } - - std::error_code incrementDirIter(bool IsFirstTime) { - assert((IsFirstTime || CurrentDirIter != directory_iterator()) && - "incrementing past end"); - std::error_code EC; - if (!IsFirstTime) - CurrentDirIter.increment(EC); - if (!EC && CurrentDirIter == directory_iterator()) - EC = incrementFS(); - return EC; - } - - std::error_code incrementImpl(bool IsFirstTime) { - while (true) { - std::error_code EC = incrementDirIter(IsFirstTime); - if (EC || CurrentDirIter == directory_iterator()) { - CurrentEntry = Status(); - return EC; - } - CurrentEntry = *CurrentDirIter; - StringRef Name = llvm::sys::path::filename(CurrentEntry.getName()); - if (SeenNames.insert(Name).second) - return EC; // name not seen before - } - llvm_unreachable("returned above"); - } - -public: - OverlayFSDirIterImpl(const Twine &Path, OverlayFileSystem &FS, - std::error_code &EC) - : Overlays(FS), Path(Path.str()), CurrentFS(Overlays.overlays_begin()) { - CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC); - EC = incrementImpl(true); - } - - std::error_code increment() override { return incrementImpl(false); } -}; - -} // namespace - -directory_iterator OverlayFileSystem::dir_begin(const Twine &Dir, - std::error_code &EC) { - return directory_iterator( - 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() = default; - - 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 {}; } -}; - -} // 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(); - } - - using const_iterator = decltype(Entries)::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; - } -}; - -} // namespace detail - -InMemoryFileSystem::InMemoryFileSystem(bool UseNormalizedPaths) - : Root(new detail::InMemoryDirectory( - Status("", getNextVirtualUniqueID(), llvm::sys::TimePoint<>(), 0, 0, - 0, llvm::sys::fs::file_type::directory_file, - llvm::sys::fs::perms::all_all))), - UseNormalizedPaths(UseNormalizedPaths) {} - -InMemoryFileSystem::~InMemoryFileSystem() = default; - -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, - Optional<uint32_t> User, - Optional<uint32_t> Group, - Optional<llvm::sys::fs::file_type> Type, - Optional<llvm::sys::fs::perms> Perms) { - 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 = sys::path::end(Path); - const auto ResolvedUser = User.getValueOr(0); - const auto ResolvedGroup = Group.getValueOr(0); - const auto ResolvedType = Type.getValueOr(sys::fs::file_type::regular_file); - const auto ResolvedPerms = Perms.getValueOr(sys::fs::all_all); - // Any intermediate directories we create should be accessible by - // the owner, even if Perms says otherwise for the final path. - const auto NewDirectoryPerms = ResolvedPerms | sys::fs::owner_all; - 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 or directory. - Status Stat(P.str(), getNextVirtualUniqueID(), - llvm::sys::toTimePoint(ModificationTime), ResolvedUser, - ResolvedGroup, Buffer->getBufferSize(), ResolvedType, - ResolvedPerms); - std::unique_ptr<detail::InMemoryNode> Child; - if (ResolvedType == sys::fs::file_type::directory_file) { - Child.reset(new detail::InMemoryDirectory(std::move(Stat))); - } else { - Child.reset(new detail::InMemoryFile(std::move(Stat), - std::move(Buffer))); - } - Dir->addChild(Name, std::move(Child)); - return true; - } - - // Create a new directory. Use the path up to here. - Status Stat( - StringRef(Path.str().begin(), Name.end() - Path.str().begin()), - getNextVirtualUniqueID(), llvm::sys::toTimePoint(ModificationTime), - ResolvedUser, ResolvedGroup, Buffer->getBufferSize(), - sys::fs::file_type::directory_file, NewDirectoryPerms); - 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, - Optional<uint32_t> User, - Optional<uint32_t> Group, - Optional<llvm::sys::fs::file_type> Type, - Optional<llvm::sys::fs::perms> Perms) { - return addFile(P, ModificationTime, - llvm::MemoryBuffer::getMemBuffer( - Buffer->getBuffer(), Buffer->getBufferIdentifier()), - std::move(User), std::move(Group), std::move(Type), - std::move(Perms)); -} - -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() = default; - - 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 {}; - } -}; - -} // 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>()); -} - -std::error_code InMemoryFileSystem::setCurrentWorkingDirectory(const Twine &P) { - 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()) - WorkingDirectory = Path.str(); - return {}; -} - -std::error_code -InMemoryFileSystem::getRealPath(const Twine &Path, - SmallVectorImpl<char> &Output) const { - auto CWD = getCurrentWorkingDirectory(); - if (!CWD || CWD->empty()) - return errc::operation_not_permitted; - Path.toVector(Output); - if (auto EC = makeAbsolute(Output)) - return EC; - llvm::sys::path::remove_dots(Output, /*remove_dot_dot=*/true); - return {}; -} - -} // namespace vfs -} // namespace clang - -//===-----------------------------------------------------------------------===/ -// RedirectingFileSystem implementation -//===-----------------------------------------------------------------------===/ - -namespace { - -enum EntryKind { - EK_Directory, - EK_File -}; - -/// A single file or directory in the VFS. -class Entry { - EntryKind Kind; - std::string Name; - -public: - Entry(EntryKind K, StringRef Name) : Kind(K), Name(Name) {} - virtual ~Entry() = default; - - StringRef getName() const { return Name; } - EntryKind getKind() const { return Kind; } -}; - -class RedirectingDirectoryEntry : public Entry { - std::vector<std::unique_ptr<Entry>> Contents; - Status S; - -public: - RedirectingDirectoryEntry(StringRef Name, - std::vector<std::unique_ptr<Entry>> Contents, - Status S) - : Entry(EK_Directory, Name), Contents(std::move(Contents)), - S(std::move(S)) {} - RedirectingDirectoryEntry(StringRef Name, Status S) - : Entry(EK_Directory, Name), S(std::move(S)) {} - - Status getStatus() { return S; } - - void addContent(std::unique_ptr<Entry> Content) { - Contents.push_back(std::move(Content)); - } - - Entry *getLastContent() const { return Contents.back().get(); } - - using iterator = decltype(Contents)::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 RedirectingFileEntry : public Entry { -public: - enum NameKind { - NK_NotSet, - NK_External, - NK_Virtual - }; - -private: - std::string ExternalContentsPath; - NameKind UseName; - -public: - RedirectingFileEntry(StringRef Name, StringRef ExternalContentsPath, - NameKind UseName) - : Entry(EK_File, Name), ExternalContentsPath(ExternalContentsPath), - UseName(UseName) {} - - StringRef getExternalContentsPath() const { return ExternalContentsPath; } - - /// whether to use the external path as the name for this file. - bool useExternalName(bool GlobalUseExternalName) const { - return UseName == NK_NotSet ? GlobalUseExternalName - : (UseName == NK_External); - } - - NameKind getUseName() const { return UseName; } - - static bool classof(const Entry *E) { return E->getKind() == EK_File; } -}; - -class RedirectingFileSystem; - -class VFSFromYamlDirIterImpl : public clang::vfs::detail::DirIterImpl { - std::string Dir; - RedirectingFileSystem &FS; - RedirectingDirectoryEntry::iterator Current, End; - -public: - VFSFromYamlDirIterImpl(const Twine &Path, RedirectingFileSystem &FS, - RedirectingDirectoryEntry::iterator Begin, - RedirectingDirectoryEntry::iterator End, - std::error_code &EC); - - std::error_code increment() override; -}; - -/// A virtual file system parsed from a YAML file. -/// -/// Currently, this class allows creating virtual directories and mapping -/// virtual file paths to existing external files, available in \c ExternalFS. -/// -/// The basic structure of the parsed file is: -/// \verbatim -/// { -/// 'version': <version number>, -/// <optional configuration> -/// 'roots': [ -/// <directory entries> -/// ] -/// } -/// \endverbatim -/// -/// All configuration options are optional. -/// 'case-sensitive': <boolean, default=true> -/// 'use-external-names': <boolean, default=true> -/// 'overlay-relative': <boolean, default=false> -/// 'ignore-non-existent-contents': <boolean, default=true> -/// -/// Virtual directories are represented as -/// \verbatim -/// { -/// 'type': 'directory', -/// 'name': <string>, -/// 'contents': [ <file or directory entries> ] -/// } -/// \endverbatim -/// -/// The default attributes for virtual directories are: -/// \verbatim -/// MTime = now() when created -/// Perms = 0777 -/// User = Group = 0 -/// Size = 0 -/// UniqueID = unspecified unique value -/// \endverbatim -/// -/// Re-mapped files are represented as -/// \verbatim -/// { -/// 'type': 'file', -/// 'name': <string>, -/// 'use-external-name': <boolean> # Optional -/// 'external-contents': <path to external file>) -/// } -/// \endverbatim -/// -/// and inherit their attributes from the external contents. -/// -/// In both cases, the 'name' field may contain multiple path components (e.g. -/// /path/to/file). However, any directory that contains more than one child -/// must be uniquely represented by a directory entry. -class RedirectingFileSystem : public vfs::FileSystem { - friend class RedirectingFileSystemParser; - - /// The root(s) of the virtual file system. - std::vector<std::unique_ptr<Entry>> Roots; - - /// The file system to use for external references. - IntrusiveRefCntPtr<FileSystem> ExternalFS; - - /// If IsRelativeOverlay is set, this represents the directory - /// path that should be prefixed to each 'external-contents' entry - /// when reading from YAML files. - std::string ExternalContentsPrefixDir; - - /// @name Configuration - /// @{ - - /// Whether to perform case-sensitive comparisons. - /// - /// Currently, case-insensitive matching only works correctly with ASCII. - bool CaseSensitive = true; - - /// IsRelativeOverlay marks whether a IsExternalContentsPrefixDir path must - /// be prefixed in every 'external-contents' when reading from YAML files. - bool IsRelativeOverlay = false; - - /// Whether to use to use the value of 'external-contents' for the - /// names of files. This global value is overridable on a per-file basis. - bool UseExternalNames = true; - - /// Whether an invalid path obtained via 'external-contents' should - /// cause iteration on the VFS to stop. If 'true', the VFS should ignore - /// the entry and continue with the next. Allows YAML files to be shared - /// across multiple compiler invocations regardless of prior existent - /// paths in 'external-contents'. This global value is overridable on a - /// per-file basis. - bool IgnoreNonExistentContents = true; - /// @} - - /// Virtual file paths and external files could be canonicalized without "..", - /// "." and "./" in their paths. FIXME: some unittests currently fail on - /// win32 when using remove_dots and remove_leading_dotslash on paths. - bool UseCanonicalizedPaths = -#ifdef _WIN32 - false; -#else - true; -#endif - -private: - RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS) - : ExternalFS(std::move(ExternalFS)) {} - - /// Looks up the path <tt>[Start, End)</tt> in \p From, possibly - /// recursing into the contents of \p From if it is a directory. - ErrorOr<Entry *> lookupPath(sys::path::const_iterator Start, - sys::path::const_iterator End, Entry *From); - - /// Get the status of a given an \c Entry. - ErrorOr<Status> status(const Twine &Path, Entry *E); - -public: - /// Looks up \p Path in \c Roots. - ErrorOr<Entry *> lookupPath(const Twine &Path); - - /// Parses \p Buffer, which is expected to be in YAML format and - /// returns a virtual file system representing its contents. - static RedirectingFileSystem * - create(std::unique_ptr<MemoryBuffer> Buffer, - SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, - 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) { - EC = E.getError(); - return {}; - } - ErrorOr<Status> S = status(Dir, *E); - if (!S) { - EC = S.getError(); - return {}; - } - if (!S->isDirectory()) { - EC = std::error_code(static_cast<int>(errc::not_a_directory), - std::system_category()); - return {}; - } - - auto *D = cast<RedirectingDirectoryEntry>(*E); - return directory_iterator(std::make_shared<VFSFromYamlDirIterImpl>(Dir, - *this, D->contents_begin(), D->contents_end(), EC)); - } - - void setExternalContentsPrefixDir(StringRef PrefixDir) { - ExternalContentsPrefixDir = PrefixDir.str(); - } - - StringRef getExternalContentsPrefixDir() const { - return ExternalContentsPrefixDir; - } - - bool ignoreNonExistentContents() const { - return IgnoreNonExistentContents; - } - -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -LLVM_DUMP_METHOD void dump() const { - for (const auto &Root : Roots) - dumpEntry(Root.get()); - } - -LLVM_DUMP_METHOD void dumpEntry(Entry *E, int NumSpaces = 0) const { - StringRef Name = E->getName(); - for (int i = 0, e = NumSpaces; i < e; ++i) - dbgs() << " "; - dbgs() << "'" << Name.str().c_str() << "'" << "\n"; - - if (E->getKind() == EK_Directory) { - auto *DE = dyn_cast<RedirectingDirectoryEntry>(E); - assert(DE && "Should be a directory"); - - for (std::unique_ptr<Entry> &SubEntry : - llvm::make_range(DE->contents_begin(), DE->contents_end())) - dumpEntry(SubEntry.get(), NumSpaces+2); - } - } -#endif -}; - -/// A helper class to hold the common YAML parsing state. -class RedirectingFileSystemParser { - yaml::Stream &Stream; - - void error(yaml::Node *N, const Twine &Msg) { - Stream.printError(N, Msg); - } - - // false on error - bool parseScalarString(yaml::Node *N, StringRef &Result, - SmallVectorImpl<char> &Storage) { - const auto *S = dyn_cast<yaml::ScalarNode>(N); - - if (!S) { - error(N, "expected string"); - return false; - } - Result = S->getValue(Storage); - return true; - } - - // false on error - bool parseScalarBool(yaml::Node *N, bool &Result) { - SmallString<5> Storage; - StringRef Value; - if (!parseScalarString(N, Value, Storage)) - return false; - - if (Value.equals_lower("true") || Value.equals_lower("on") || - Value.equals_lower("yes") || Value == "1") { - Result = true; - return true; - } else if (Value.equals_lower("false") || Value.equals_lower("off") || - Value.equals_lower("no") || Value == "0") { - Result = false; - return true; - } - - error(N, "expected boolean value"); - return false; - } - - struct KeyStatus { - bool Required; - bool Seen = false; - - KeyStatus(bool Required = false) : Required(Required) {} - }; - - using KeyStatusPair = std::pair<StringRef, KeyStatus>; - - // false on error - bool checkDuplicateOrUnknownKey(yaml::Node *KeyNode, StringRef Key, - DenseMap<StringRef, KeyStatus> &Keys) { - if (!Keys.count(Key)) { - error(KeyNode, "unknown key"); - return false; - } - KeyStatus &S = Keys[Key]; - if (S.Seen) { - error(KeyNode, Twine("duplicate key '") + Key + "'"); - return false; - } - S.Seen = true; - return true; - } - - // false on error - bool checkMissingKeys(yaml::Node *Obj, DenseMap<StringRef, KeyStatus> &Keys) { - for (const auto &I : Keys) { - if (I.second.Required && !I.second.Seen) { - error(Obj, Twine("missing key '") + I.first + "'"); - return false; - } - } - return true; - } - - Entry *lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name, - Entry *ParentEntry = nullptr) { - if (!ParentEntry) { // Look for a existent root - for (const auto &Root : FS->Roots) { - if (Name.equals(Root->getName())) { - ParentEntry = Root.get(); - return ParentEntry; - } - } - } else { // Advance to the next component - auto *DE = dyn_cast<RedirectingDirectoryEntry>(ParentEntry); - for (std::unique_ptr<Entry> &Content : - llvm::make_range(DE->contents_begin(), DE->contents_end())) { - auto *DirContent = dyn_cast<RedirectingDirectoryEntry>(Content.get()); - if (DirContent && Name.equals(Content->getName())) - return DirContent; - } - } - - // ... or create a new one - std::unique_ptr<Entry> E = llvm::make_unique<RedirectingDirectoryEntry>( - Name, - Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(), - 0, 0, 0, file_type::directory_file, sys::fs::all_all)); - - if (!ParentEntry) { // Add a new root to the overlay - FS->Roots.push_back(std::move(E)); - ParentEntry = FS->Roots.back().get(); - return ParentEntry; - } - - auto *DE = dyn_cast<RedirectingDirectoryEntry>(ParentEntry); - DE->addContent(std::move(E)); - return DE->getLastContent(); - } - - void uniqueOverlayTree(RedirectingFileSystem *FS, Entry *SrcE, - Entry *NewParentE = nullptr) { - StringRef Name = SrcE->getName(); - switch (SrcE->getKind()) { - case EK_Directory: { - auto *DE = dyn_cast<RedirectingDirectoryEntry>(SrcE); - assert(DE && "Must be a directory"); - // Empty directories could be present in the YAML as a way to - // describe a file for a current directory after some of its subdir - // is parsed. This only leads to redundant walks, ignore it. - if (!Name.empty()) - NewParentE = lookupOrCreateEntry(FS, Name, NewParentE); - for (std::unique_ptr<Entry> &SubEntry : - llvm::make_range(DE->contents_begin(), DE->contents_end())) - uniqueOverlayTree(FS, SubEntry.get(), NewParentE); - break; - } - case EK_File: { - auto *FE = dyn_cast<RedirectingFileEntry>(SrcE); - assert(FE && "Must be a file"); - assert(NewParentE && "Parent entry must exist"); - auto *DE = dyn_cast<RedirectingDirectoryEntry>(NewParentE); - DE->addContent(llvm::make_unique<RedirectingFileEntry>( - Name, FE->getExternalContentsPath(), FE->getUseName())); - break; - } - } - } - - std::unique_ptr<Entry> parseEntry(yaml::Node *N, RedirectingFileSystem *FS) { - auto *M = dyn_cast<yaml::MappingNode>(N); - if (!M) { - error(N, "expected mapping node for file or directory entry"); - return nullptr; - } - - KeyStatusPair Fields[] = { - KeyStatusPair("name", true), - KeyStatusPair("type", true), - KeyStatusPair("contents", false), - KeyStatusPair("external-contents", false), - KeyStatusPair("use-external-name", false), - }; - - DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields)); - - bool HasContents = false; // external or otherwise - std::vector<std::unique_ptr<Entry>> EntryArrayContents; - std::string ExternalContentsPath; - std::string Name; - auto UseExternalName = RedirectingFileEntry::NK_NotSet; - EntryKind Kind; - - for (auto &I : *M) { - StringRef Key; - // Reuse the buffer for key and value, since we don't look at key after - // parsing value. - SmallString<256> Buffer; - if (!parseScalarString(I.getKey(), Key, Buffer)) - return nullptr; - - if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys)) - return nullptr; - - StringRef Value; - if (Key == "name") { - if (!parseScalarString(I.getValue(), Value, Buffer)) - return nullptr; - - if (FS->UseCanonicalizedPaths) { - SmallString<256> Path(Value); - // Guarantee that old YAML files containing paths with ".." and "." - // are properly canonicalized before read into the VFS. - Path = sys::path::remove_leading_dotslash(Path); - sys::path::remove_dots(Path, /*remove_dot_dot=*/true); - Name = Path.str(); - } else { - Name = Value; - } - } else if (Key == "type") { - if (!parseScalarString(I.getValue(), Value, Buffer)) - return nullptr; - if (Value == "file") - Kind = EK_File; - else if (Value == "directory") - Kind = EK_Directory; - else { - error(I.getValue(), "unknown value for 'type'"); - return nullptr; - } - } else if (Key == "contents") { - if (HasContents) { - error(I.getKey(), - "entry already has 'contents' or 'external-contents'"); - return nullptr; - } - HasContents = true; - auto *Contents = dyn_cast<yaml::SequenceNode>(I.getValue()); - if (!Contents) { - // FIXME: this is only for directories, what about files? - error(I.getValue(), "expected array"); - return nullptr; - } - - for (auto &I : *Contents) { - if (std::unique_ptr<Entry> E = parseEntry(&I, FS)) - EntryArrayContents.push_back(std::move(E)); - else - return nullptr; - } - } else if (Key == "external-contents") { - if (HasContents) { - error(I.getKey(), - "entry already has 'contents' or 'external-contents'"); - return nullptr; - } - HasContents = true; - if (!parseScalarString(I.getValue(), Value, Buffer)) - return nullptr; - - SmallString<256> FullPath; - if (FS->IsRelativeOverlay) { - FullPath = FS->getExternalContentsPrefixDir(); - assert(!FullPath.empty() && - "External contents prefix directory must exist"); - llvm::sys::path::append(FullPath, Value); - } else { - FullPath = Value; - } - - if (FS->UseCanonicalizedPaths) { - // Guarantee that old YAML files containing paths with ".." and "." - // are properly canonicalized before read into the VFS. - FullPath = sys::path::remove_leading_dotslash(FullPath); - sys::path::remove_dots(FullPath, /*remove_dot_dot=*/true); - } - ExternalContentsPath = FullPath.str(); - } else if (Key == "use-external-name") { - bool Val; - if (!parseScalarBool(I.getValue(), Val)) - return nullptr; - UseExternalName = Val ? RedirectingFileEntry::NK_External - : RedirectingFileEntry::NK_Virtual; - } else { - llvm_unreachable("key missing from Keys"); - } - } - - if (Stream.failed()) - return nullptr; - - // check for missing keys - if (!HasContents) { - error(N, "missing key 'contents' or 'external-contents'"); - return nullptr; - } - if (!checkMissingKeys(N, Keys)) - return nullptr; - - // check invalid configuration - if (Kind == EK_Directory && - UseExternalName != RedirectingFileEntry::NK_NotSet) { - error(N, "'use-external-name' is not supported for directories"); - return nullptr; - } - - // Remove trailing slash(es), being careful not to remove the root path - StringRef Trimmed(Name); - size_t RootPathLen = sys::path::root_path(Trimmed).size(); - while (Trimmed.size() > RootPathLen && - sys::path::is_separator(Trimmed.back())) - Trimmed = Trimmed.slice(0, Trimmed.size()-1); - // Get the last component - StringRef LastComponent = sys::path::filename(Trimmed); - - std::unique_ptr<Entry> Result; - switch (Kind) { - case EK_File: - Result = llvm::make_unique<RedirectingFileEntry>( - LastComponent, std::move(ExternalContentsPath), UseExternalName); - break; - case EK_Directory: - Result = llvm::make_unique<RedirectingDirectoryEntry>( - LastComponent, std::move(EntryArrayContents), - Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(), - 0, 0, 0, file_type::directory_file, sys::fs::all_all)); - break; - } - - StringRef Parent = sys::path::parent_path(Trimmed); - if (Parent.empty()) - return Result; - - // if 'name' contains multiple components, create implicit directory entries - for (sys::path::reverse_iterator I = sys::path::rbegin(Parent), - E = sys::path::rend(Parent); - I != E; ++I) { - std::vector<std::unique_ptr<Entry>> Entries; - Entries.push_back(std::move(Result)); - Result = llvm::make_unique<RedirectingDirectoryEntry>( - *I, std::move(Entries), - Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(), - 0, 0, 0, file_type::directory_file, sys::fs::all_all)); - } - return Result; - } - -public: - RedirectingFileSystemParser(yaml::Stream &S) : Stream(S) {} - - // false on error - bool parse(yaml::Node *Root, RedirectingFileSystem *FS) { - auto *Top = dyn_cast<yaml::MappingNode>(Root); - if (!Top) { - error(Root, "expected mapping node"); - return false; - } - - KeyStatusPair Fields[] = { - KeyStatusPair("version", true), - KeyStatusPair("case-sensitive", false), - KeyStatusPair("use-external-names", false), - KeyStatusPair("overlay-relative", false), - KeyStatusPair("ignore-non-existent-contents", false), - KeyStatusPair("roots", true), - }; - - DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields)); - std::vector<std::unique_ptr<Entry>> RootEntries; - - // Parse configuration and 'roots' - for (auto &I : *Top) { - SmallString<10> KeyBuffer; - StringRef Key; - if (!parseScalarString(I.getKey(), Key, KeyBuffer)) - return false; - - if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys)) - return false; - - if (Key == "roots") { - auto *Roots = dyn_cast<yaml::SequenceNode>(I.getValue()); - if (!Roots) { - error(I.getValue(), "expected array"); - return false; - } - - for (auto &I : *Roots) { - if (std::unique_ptr<Entry> E = parseEntry(&I, FS)) - RootEntries.push_back(std::move(E)); - else - return false; - } - } else if (Key == "version") { - StringRef VersionString; - SmallString<4> Storage; - if (!parseScalarString(I.getValue(), VersionString, Storage)) - return false; - int Version; - if (VersionString.getAsInteger<int>(10, Version)) { - error(I.getValue(), "expected integer"); - return false; - } - if (Version < 0) { - error(I.getValue(), "invalid version number"); - return false; - } - if (Version != 0) { - error(I.getValue(), "version mismatch, expected 0"); - return false; - } - } else if (Key == "case-sensitive") { - if (!parseScalarBool(I.getValue(), FS->CaseSensitive)) - return false; - } else if (Key == "overlay-relative") { - if (!parseScalarBool(I.getValue(), FS->IsRelativeOverlay)) - return false; - } else if (Key == "use-external-names") { - if (!parseScalarBool(I.getValue(), FS->UseExternalNames)) - return false; - } else if (Key == "ignore-non-existent-contents") { - if (!parseScalarBool(I.getValue(), FS->IgnoreNonExistentContents)) - return false; - } else { - llvm_unreachable("key missing from Keys"); - } - } - - if (Stream.failed()) - return false; - - if (!checkMissingKeys(Top, Keys)) - return false; - - // Now that we sucessefully parsed the YAML file, canonicalize the internal - // representation to a proper directory tree so that we can search faster - // inside the VFS. - for (auto &E : RootEntries) - uniqueOverlayTree(FS, E.get()); - - return true; - } -}; - -} // namespace - -RedirectingFileSystem * -RedirectingFileSystem::create(std::unique_ptr<MemoryBuffer> Buffer, - SourceMgr::DiagHandlerTy DiagHandler, - StringRef YAMLFilePath, void *DiagContext, - IntrusiveRefCntPtr<FileSystem> ExternalFS) { - SourceMgr SM; - yaml::Stream Stream(Buffer->getMemBufferRef(), SM); - - SM.setDiagHandler(DiagHandler, DiagContext); - yaml::document_iterator DI = Stream.begin(); - yaml::Node *Root = DI->getRoot(); - if (DI == Stream.end() || !Root) { - SM.PrintMessage(SMLoc(), SourceMgr::DK_Error, "expected root node"); - return nullptr; - } - - RedirectingFileSystemParser P(Stream); - - std::unique_ptr<RedirectingFileSystem> FS( - new RedirectingFileSystem(std::move(ExternalFS))); - - if (!YAMLFilePath.empty()) { - // Use the YAML path from -ivfsoverlay to compute the dir to be prefixed - // to each 'external-contents' path. - // - // Example: - // -ivfsoverlay dummy.cache/vfs/vfs.yaml - // yields: - // FS->ExternalContentsPrefixDir => /<absolute_path_to>/dummy.cache/vfs - // - SmallString<256> OverlayAbsDir = sys::path::parent_path(YAMLFilePath); - std::error_code EC = llvm::sys::fs::make_absolute(OverlayAbsDir); - assert(!EC && "Overlay dir final path must be absolute"); - (void)EC; - FS->setExternalContentsPrefixDir(OverlayAbsDir); - } - - if (!P.parse(Root, FS.get())) - return nullptr; - - return FS.release(); -} - -ErrorOr<Entry *> RedirectingFileSystem::lookupPath(const Twine &Path_) { - SmallString<256> Path; - Path_.toVector(Path); - - // Handle relative paths - if (std::error_code EC = makeAbsolute(Path)) - return EC; - - // Canonicalize path by removing ".", "..", "./", etc components. This is - // a VFS request, do bot bother about symlinks in the path components - // but canonicalize in order to perform the correct entry search. - if (UseCanonicalizedPaths) { - Path = sys::path::remove_leading_dotslash(Path); - sys::path::remove_dots(Path, /*remove_dot_dot=*/true); - } - - if (Path.empty()) - return make_error_code(llvm::errc::invalid_argument); - - sys::path::const_iterator Start = sys::path::begin(Path); - sys::path::const_iterator End = sys::path::end(Path); - for (const auto &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 *> -RedirectingFileSystem::lookupPath(sys::path::const_iterator Start, - sys::path::const_iterator End, Entry *From) { -#ifndef _WIN32 - assert(!isTraversalComponent(*Start) && - !isTraversalComponent(From->getName()) && - "Paths should not contain traversal components"); -#else - // FIXME: this is here to support windows, remove it once canonicalized - // paths become globally default. - if (Start->equals(".")) - ++Start; -#endif - - StringRef FromName = From->getName(); - - // Forward the search to the next component in case this is an empty one. - if (!FromName.empty()) { - if (CaseSensitive ? !Start->equals(FromName) - : !Start->equals_lower(FromName)) - // failure to match - return make_error_code(llvm::errc::no_such_file_or_directory); - - ++Start; - - if (Start == End) { - // Match! - return From; - } - } - - auto *DE = dyn_cast<RedirectingDirectoryEntry>(From); - if (!DE) - return make_error_code(llvm::errc::not_a_directory); - - 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); -} - -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); - if (auto *F = dyn_cast<RedirectingFileEntry>(E)) { - ErrorOr<Status> S = ExternalFS->status(F->getExternalContentsPath()); - assert(!S || S->getName() == F->getExternalContentsPath()); - if (S) - return getRedirectedFileStatus(Path, F->useExternalName(UseExternalNames), - *S); - return S; - } else { // directory - auto *DE = cast<RedirectingDirectoryEntry>(E); - return Status::copyWithNewName(DE->getStatus(), Path.str()); - } -} - -ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path) { - ErrorOr<Entry *> Result = lookupPath(Path); - if (!Result) - return Result.getError(); - return status(Path, *Result); -} - -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(std::move(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(); } -}; - -} // namespace - -ErrorOr<std::unique_ptr<File>> -RedirectingFileSystem::openFileForRead(const Twine &Path) { - ErrorOr<Entry *> E = lookupPath(Path); - if (!E) - return E.getError(); - - auto *F = dyn_cast<RedirectingFileEntry>(*E); - if (!F) // FIXME: errc::not_a_file? - return make_error_code(llvm::errc::invalid_argument); - - auto Result = ExternalFS->openFileForRead(F->getExternalContentsPath()); - if (!Result) - return Result; - - auto ExternalStatus = (*Result)->status(); - if (!ExternalStatus) - return ExternalStatus.getError(); - - // 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, - StringRef YAMLFilePath, - void *DiagContext, - IntrusiveRefCntPtr<FileSystem> ExternalFS) { - return RedirectingFileSystem::create(std::move(Buffer), DiagHandler, - YAMLFilePath, DiagContext, - std::move(ExternalFS)); -} - -static void getVFSEntries(Entry *SrcE, SmallVectorImpl<StringRef> &Path, - SmallVectorImpl<YAMLVFSEntry> &Entries) { - auto Kind = SrcE->getKind(); - if (Kind == EK_Directory) { - auto *DE = dyn_cast<RedirectingDirectoryEntry>(SrcE); - assert(DE && "Must be a directory"); - for (std::unique_ptr<Entry> &SubEntry : - llvm::make_range(DE->contents_begin(), DE->contents_end())) { - Path.push_back(SubEntry->getName()); - getVFSEntries(SubEntry.get(), Path, Entries); - Path.pop_back(); - } - return; - } - - assert(Kind == EK_File && "Must be a EK_File"); - auto *FE = dyn_cast<RedirectingFileEntry>(SrcE); - assert(FE && "Must be a file"); - SmallString<128> VPath; - for (auto &Comp : Path) - llvm::sys::path::append(VPath, Comp); - Entries.push_back(YAMLVFSEntry(VPath.c_str(), FE->getExternalContentsPath())); -} - -void vfs::collectVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer, - SourceMgr::DiagHandlerTy DiagHandler, - StringRef YAMLFilePath, - SmallVectorImpl<YAMLVFSEntry> &CollectedEntries, - void *DiagContext, - IntrusiveRefCntPtr<FileSystem> ExternalFS) { - RedirectingFileSystem *VFS = RedirectingFileSystem::create( - std::move(Buffer), DiagHandler, YAMLFilePath, DiagContext, - std::move(ExternalFS)); - ErrorOr<Entry *> RootE = VFS->lookupPath("/"); - if (!RootE) - return; - SmallVector<StringRef, 8> Components; - Components.push_back("/"); - getVFSEntries(*RootE, Components, CollectedEntries); -} - -UniqueID vfs::getNextVirtualUniqueID() { - static std::atomic<unsigned> UID; - unsigned ID = ++UID; - // The following assumes that uint64_t max will never collide with a real - // dev_t value from the OS. - return UniqueID(std::numeric_limits<uint64_t>::max(), ID); -} - -void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) { - assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute"); - assert(sys::path::is_absolute(RealPath) && "real path not absolute"); - assert(!pathHasTraversal(VirtualPath) && "path traversal is not supported"); - Mappings.emplace_back(VirtualPath, RealPath); -} - -namespace { - -class JSONWriter { - llvm::raw_ostream &OS; - SmallVector<StringRef, 16> DirStack; - - unsigned getDirIndent() { return 4 * DirStack.size(); } - unsigned getFileIndent() { return 4 * (DirStack.size() + 1); } - bool containedIn(StringRef Parent, StringRef Path); - StringRef containedPart(StringRef Parent, StringRef Path); - void startDirectory(StringRef Path); - void endDirectory(); - void writeEntry(StringRef VPath, StringRef RPath); - -public: - JSONWriter(llvm::raw_ostream &OS) : OS(OS) {} - - void write(ArrayRef<YAMLVFSEntry> Entries, Optional<bool> UseExternalNames, - Optional<bool> IsCaseSensitive, Optional<bool> IsOverlayRelative, - Optional<bool> IgnoreNonExistentContents, StringRef OverlayDir); -}; - -} // namespace - -bool JSONWriter::containedIn(StringRef Parent, StringRef Path) { - using namespace llvm::sys; - - // Compare each path component. - auto IParent = path::begin(Parent), EParent = path::end(Parent); - for (auto IChild = path::begin(Path), EChild = path::end(Path); - IParent != EParent && IChild != EChild; ++IParent, ++IChild) { - if (*IParent != *IChild) - return false; - } - // Have we exhausted the parent path? - return IParent == EParent; -} - -StringRef JSONWriter::containedPart(StringRef Parent, StringRef Path) { - assert(!Parent.empty()); - assert(containedIn(Parent, Path)); - return Path.slice(Parent.size() + 1, StringRef::npos); -} - -void JSONWriter::startDirectory(StringRef Path) { - StringRef Name = - DirStack.empty() ? Path : containedPart(DirStack.back(), Path); - DirStack.push_back(Path); - unsigned Indent = getDirIndent(); - OS.indent(Indent) << "{\n"; - OS.indent(Indent + 2) << "'type': 'directory',\n"; - OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(Name) << "\",\n"; - OS.indent(Indent + 2) << "'contents': [\n"; -} - -void JSONWriter::endDirectory() { - unsigned Indent = getDirIndent(); - OS.indent(Indent + 2) << "]\n"; - OS.indent(Indent) << "}"; - - DirStack.pop_back(); -} - -void JSONWriter::writeEntry(StringRef VPath, StringRef RPath) { - unsigned Indent = getFileIndent(); - OS.indent(Indent) << "{\n"; - OS.indent(Indent + 2) << "'type': 'file',\n"; - OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(VPath) << "\",\n"; - OS.indent(Indent + 2) << "'external-contents': \"" - << llvm::yaml::escape(RPath) << "\"\n"; - OS.indent(Indent) << "}"; -} - -void JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries, - Optional<bool> UseExternalNames, - Optional<bool> IsCaseSensitive, - Optional<bool> IsOverlayRelative, - Optional<bool> IgnoreNonExistentContents, - StringRef OverlayDir) { - using namespace llvm::sys; - - OS << "{\n" - " 'version': 0,\n"; - if (IsCaseSensitive.hasValue()) - OS << " 'case-sensitive': '" - << (IsCaseSensitive.getValue() ? "true" : "false") << "',\n"; - if (UseExternalNames.hasValue()) - OS << " 'use-external-names': '" - << (UseExternalNames.getValue() ? "true" : "false") << "',\n"; - bool UseOverlayRelative = false; - if (IsOverlayRelative.hasValue()) { - UseOverlayRelative = IsOverlayRelative.getValue(); - OS << " 'overlay-relative': '" - << (UseOverlayRelative ? "true" : "false") << "',\n"; - } - if (IgnoreNonExistentContents.hasValue()) - OS << " 'ignore-non-existent-contents': '" - << (IgnoreNonExistentContents.getValue() ? "true" : "false") << "',\n"; - OS << " 'roots': [\n"; - - if (!Entries.empty()) { - const YAMLVFSEntry &Entry = Entries.front(); - startDirectory(path::parent_path(Entry.VPath)); - - StringRef RPath = Entry.RPath; - if (UseOverlayRelative) { - unsigned OverlayDirLen = OverlayDir.size(); - assert(RPath.substr(0, OverlayDirLen) == OverlayDir && - "Overlay dir must be contained in RPath"); - RPath = RPath.slice(OverlayDirLen, RPath.size()); - } - - writeEntry(path::filename(Entry.VPath), RPath); - - for (const auto &Entry : Entries.slice(1)) { - StringRef Dir = path::parent_path(Entry.VPath); - if (Dir == DirStack.back()) - OS << ",\n"; - else { - while (!DirStack.empty() && !containedIn(DirStack.back(), Dir)) { - OS << "\n"; - endDirectory(); - } - OS << ",\n"; - startDirectory(Dir); - } - StringRef RPath = Entry.RPath; - if (UseOverlayRelative) { - unsigned OverlayDirLen = OverlayDir.size(); - assert(RPath.substr(0, OverlayDirLen) == OverlayDir && - "Overlay dir must be contained in RPath"); - RPath = RPath.slice(OverlayDirLen, RPath.size()); - } - writeEntry(path::filename(Entry.VPath), RPath); - } - - while (!DirStack.empty()) { - OS << "\n"; - endDirectory(); - } - OS << "\n"; - } - - OS << " ]\n" - << "}\n"; -} - -void YAMLVFSWriter::write(llvm::raw_ostream &OS) { - llvm::sort(Mappings.begin(), Mappings.end(), - [](const YAMLVFSEntry &LHS, const YAMLVFSEntry &RHS) { - return LHS.VPath < RHS.VPath; - }); - - JSONWriter(OS).write(Mappings, UseExternalNames, IsCaseSensitive, - IsOverlayRelative, IgnoreNonExistentContents, - OverlayDir); -} - -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) { - while (Current != End) { - SmallString<128> PathStr(Dir); - llvm::sys::path::append(PathStr, (*Current)->getName()); - llvm::ErrorOr<vfs::Status> S = FS.status(PathStr); - if (S) { - CurrentEntry = *S; - return; - } - // Skip entries which do not map to a reliable external content. - if (FS.ignoreNonExistentContents() && - S.getError() == llvm::errc::no_such_file_or_directory) { - ++Current; - continue; - } else { - EC = S.getError(); - break; - } - } -} - -std::error_code VFSFromYamlDirIterImpl::increment() { - assert(Current != End && "cannot iterate past end"); - while (++Current != End) { - SmallString<128> PathStr(Dir); - llvm::sys::path::append(PathStr, (*Current)->getName()); - llvm::ErrorOr<vfs::Status> S = FS.status(PathStr); - if (!S) { - // Skip entries which do not map to a reliable external content. - if (FS.ignoreNonExistentContents() && - S.getError() == llvm::errc::no_such_file_or_directory) { - continue; - } else { - return S.getError(); - } - } - CurrentEntry = *S; - break; - } - - if (Current == End) - CurrentEntry = Status(); - return {}; -} - -vfs::recursive_directory_iterator::recursive_directory_iterator(FileSystem &FS_, - const Twine &Path, - std::error_code &EC) - : FS(&FS_) { - directory_iterator I = FS->dir_begin(Path, EC); - if (I != directory_iterator()) { - State = std::make_shared<IterState>(); - State->push(I); - } -} - -vfs::recursive_directory_iterator & -recursive_directory_iterator::increment(std::error_code &EC) { - assert(FS && State && !State->empty() && "incrementing past end"); - assert(State->top()->isStatusKnown() && "non-canonical end iterator"); - vfs::directory_iterator End; - if (State->top()->isDirectory()) { - vfs::directory_iterator I = FS->dir_begin(State->top()->getName(), EC); - if (I != End) { - State->push(I); - return *this; - } - } - - while (!State->empty() && State->top().increment(EC) == End) - State->pop(); - - if (State->empty()) - State.reset(); // end iterator - - return *this; -} |