diff --git a/clang-tools-extra/clangd/CMakeLists.txt b/clang-tools-extra/clangd/CMakeLists.txt index ad50a4be9f26..f617f7931de1 100644 --- a/clang-tools-extra/clangd/CMakeLists.txt +++ b/clang-tools-extra/clangd/CMakeLists.txt @@ -73,6 +73,7 @@ add_clang_library(clangDaemon XRefs.cpp index/Background.cpp + index/BackgroundIndexLoader.cpp index/BackgroundIndexStorage.cpp index/BackgroundQueue.cpp index/BackgroundRebuild.cpp diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp index 10949ef001c0..8cb72696f863 100644 --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -38,9 +38,11 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" +#include #include #include #include +#include namespace clang { namespace clangd { @@ -101,8 +103,7 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB, : nullptr), GetClangTidyOptions(Opts.GetClangTidyOptions), SuggestMissingIncludes(Opts.SuggestMissingIncludes), - TweakFilter(Opts.TweakFilter), - WorkspaceRoot(Opts.WorkspaceRoot), + TweakFilter(Opts.TweakFilter), WorkspaceRoot(Opts.WorkspaceRoot), // Pass a callback into `WorkScheduler` to extract symbols from a newly // parsed file and rebuild the file index synchronously each time an AST // is parsed. @@ -127,7 +128,9 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB, if (Opts.BackgroundIndex) { BackgroundIdx = llvm::make_unique( Context::current().clone(), FSProvider, CDB, - BackgroundIndexStorage::createDiskBackedStorageFactory()); + BackgroundIndexStorage::createDiskBackedStorageFactory( + [&CDB](llvm::StringRef File) { return CDB.getProjectInfo(File); }), + std::max(Opts.AsyncThreadsCount, 1u)); AddIndex(BackgroundIdx.get()); } if (DynamicIdx) diff --git a/clang-tools-extra/clangd/ClangdUnit.cpp b/clang-tools-extra/clangd/ClangdUnit.cpp index b337d851d0f7..3e9db706cfad 100644 --- a/clang-tools-extra/clangd/ClangdUnit.cpp +++ b/clang-tools-extra/clangd/ClangdUnit.cpp @@ -68,7 +68,7 @@ class DeclTrackingASTConsumer : public ASTConsumer { bool HandleTopLevelDecl(DeclGroupRef DG) override { for (Decl *D : DG) { auto &SM = D->getASTContext().getSourceManager(); - if (!SM.isWrittenInMainFile(SM.getExpansionLoc(D->getLocation()))) + if (!isInsideMainFile(D->getLocation(), SM)) continue; // ObjCMethodDecl are not actually top-level decls. @@ -355,8 +355,7 @@ ParsedAST::build(std::unique_ptr CI, // those might take us into a preamble file as well. bool IsInsideMainFile = Info.hasSourceManager() && - Info.getSourceManager().isWrittenInMainFile( - Info.getSourceManager().getFileLoc(Info.getLocation())); + isInsideMainFile(Info.getLocation(), Info.getSourceManager()); if (IsInsideMainFile && tidy::ShouldSuppressDiagnostic( DiagLevel, Info, *CTContext, /* CheckMacroExpansion = */ false)) { diff --git a/clang-tools-extra/clangd/Diagnostics.cpp b/clang-tools-extra/clangd/Diagnostics.cpp index 88bd6fdcad11..7f1ab06db9d1 100644 --- a/clang-tools-extra/clangd/Diagnostics.cpp +++ b/clang-tools-extra/clangd/Diagnostics.cpp @@ -20,6 +20,7 @@ #include "clang/Lex/Lexer.h" #include "clang/Lex/Token.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Capacity.h" @@ -107,8 +108,13 @@ Range diagnosticRange(const clang::Diagnostic &D, const LangOptions &L) { return halfOpenToRange(M, R); } -void adjustDiagFromHeader(Diag &D, const clang::Diagnostic &Info, +// Returns whether the \p D is modified. +bool adjustDiagFromHeader(Diag &D, const clang::Diagnostic &Info, const LangOptions &LangOpts) { + // We only report diagnostics with at least error severity from headers. + if (D.Severity < DiagnosticsEngine::Level::Error) + return false; + const SourceLocation &DiagLoc = Info.getLocation(); const SourceManager &SM = Info.getSourceManager(); SourceLocation IncludeInMainFile; @@ -116,16 +122,21 @@ void adjustDiagFromHeader(Diag &D, const clang::Diagnostic &Info, return SM.getIncludeLoc(SM.getFileID(SLoc)); }; for (auto IncludeLocation = GetIncludeLoc(DiagLoc); IncludeLocation.isValid(); - IncludeLocation = GetIncludeLoc(IncludeLocation)) - IncludeInMainFile = IncludeLocation; + IncludeLocation = GetIncludeLoc(IncludeLocation)) { + if (clangd::isInsideMainFile(IncludeLocation, SM)) { + IncludeInMainFile = IncludeLocation; + break; + } + } if (IncludeInMainFile.isInvalid()) - return; + return false; // Update diag to point at include inside main file. D.File = SM.getFileEntryForID(SM.getMainFileID())->getName().str(); D.Range.start = sourceLocToPosition(SM, IncludeInMainFile); D.Range.end = sourceLocToPosition( SM, Lexer::getLocForEndOfToken(IncludeInMainFile, 0, SM, LangOpts)); + D.InsideMainFile = true; // Add a note that will point to real diagnostic. const auto *FE = SM.getFileEntryForID(SM.getFileID(DiagLoc)); @@ -138,17 +149,14 @@ void adjustDiagFromHeader(Diag &D, const clang::Diagnostic &Info, // Update message to mention original file. D.Message = llvm::Twine("in included file: ", D.Message).str(); -} - -bool isInsideMainFile(const SourceLocation Loc, const SourceManager &M) { - return Loc.isValid() && M.isWrittenInMainFile(M.getFileLoc(Loc)); + return true; } bool isInsideMainFile(const clang::Diagnostic &D) { if (!D.hasSourceManager()) return false; - return isInsideMainFile(D.getLocation(), D.getSourceManager()); + return clangd::isInsideMainFile(D.getLocation(), D.getSourceManager()); } bool isNote(DiagnosticsEngine::Level L) { @@ -469,6 +477,7 @@ void StoreDiags::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, } bool InsideMainFile = isInsideMainFile(Info); + SourceManager &SM = Info.getSourceManager(); auto FillDiagBase = [&](DiagBase &D) { D.Range = diagnosticRange(Info, *LangOpts); @@ -476,8 +485,7 @@ void StoreDiags::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, Info.FormatDiagnostic(Message); D.Message = Message.str(); D.InsideMainFile = InsideMainFile; - D.File = Info.getSourceManager().getFilename(Info.getLocation()); - auto &SM = Info.getSourceManager(); + D.File = SM.getFilename(Info.getLocation()); D.AbsFile = getCanonicalPath( SM.getFileEntryForID(SM.getFileID(Info.getLocation())), SM); D.Severity = DiagLevel; @@ -500,10 +508,9 @@ void StoreDiags::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, if (FixIt.RemoveRange.getBegin().isMacroID() || FixIt.RemoveRange.getEnd().isMacroID()) return false; - if (!isInsideMainFile(FixIt.RemoveRange.getBegin(), - Info.getSourceManager())) + if (!isInsideMainFile(FixIt.RemoveRange.getBegin(), SM)) return false; - Edits.push_back(toTextEdit(FixIt, Info.getSourceManager(), *LangOpts)); + Edits.push_back(toTextEdit(FixIt, SM, *LangOpts)); } llvm::SmallString<64> Message; @@ -511,8 +518,8 @@ void StoreDiags::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, if (SyntheticMessage && Info.getNumFixItHints() == 1) { const auto &FixIt = Info.getFixItHint(0); bool Invalid = false; - llvm::StringRef Remove = Lexer::getSourceText( - FixIt.RemoveRange, Info.getSourceManager(), *LangOpts, &Invalid); + llvm::StringRef Remove = + Lexer::getSourceText(FixIt.RemoveRange, SM, *LangOpts, &Invalid); llvm::StringRef Insert = FixIt.CodeToInsert; if (!Invalid) { llvm::raw_svector_ostream M(Message); @@ -557,7 +564,9 @@ void StoreDiags::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, LastDiag = Diag(); LastDiag->ID = Info.getID(); FillDiagBase(*LastDiag); - adjustDiagFromHeader(*LastDiag, Info, *LangOpts); + LastDiagWasAdjusted = false; + if (!InsideMainFile) + LastDiagWasAdjusted = adjustDiagFromHeader(*LastDiag, Info, *LangOpts); if (!Info.getFixItHints().empty()) AddFix(true /* try to invent a message instead of repeating the diag */); @@ -599,10 +608,9 @@ void StoreDiags::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, void StoreDiags::flushLastDiag() { if (!LastDiag) return; - // Only keeps diagnostics inside main file or the first one coming from a - // header. - if (mentionsMainFile(*LastDiag) || - (LastDiag->Severity >= DiagnosticsEngine::Level::Error && + if (mentionsMainFile(*LastDiag) && + (!LastDiagWasAdjusted || + // Only report the first diagnostic coming from each particular header. IncludeLinesWithErrors.insert(LastDiag->Range.start.line).second)) { Output.push_back(std::move(*LastDiag)); } else { diff --git a/clang-tools-extra/clangd/Diagnostics.h b/clang-tools-extra/clangd/Diagnostics.h index b6cfe895504c..6d848ce2a3c0 100644 --- a/clang-tools-extra/clangd/Diagnostics.h +++ b/clang-tools-extra/clangd/Diagnostics.h @@ -145,6 +145,8 @@ class StoreDiags : public DiagnosticConsumer { std::vector Output; llvm::Optional LangOpts; llvm::Optional LastDiag; + /// Set iff adjustDiagFromHeader resulted in changes to LastDiag. + bool LastDiagWasAdjusted = false; llvm::DenseSet IncludeLinesWithErrors; bool LastPrimaryDiagnosticWasSuppressed = false; }; diff --git a/clang-tools-extra/clangd/FS.cpp b/clang-tools-extra/clangd/FS.cpp index aca9061d5c53..4f04fb089ae1 100644 --- a/clang-tools-extra/clangd/FS.cpp +++ b/clang-tools-extra/clangd/FS.cpp @@ -111,5 +111,11 @@ PreambleFileStatusCache::getConsumingFS( return llvm::IntrusiveRefCntPtr(new CacheVFS(std::move(FS), *this)); } +Path removeDots(PathRef File) { + llvm::SmallString<128> CanonPath(File); + llvm::sys::path::remove_dots(CanonPath, /*remove_dot_dot=*/true); + return CanonPath.str().str(); +} + } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/FS.h b/clang-tools-extra/clangd/FS.h index e23b3ff17d24..d8cc4438ef7f 100644 --- a/clang-tools-extra/clangd/FS.h +++ b/clang-tools-extra/clangd/FS.h @@ -9,6 +9,7 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FS_H #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FS_H +#include "Path.h" #include "clang/Basic/LLVM.h" #include "llvm/ADT/Optional.h" #include "llvm/Support/VirtualFileSystem.h" @@ -65,6 +66,13 @@ class PreambleFileStatusCache { llvm::StringMap StatCache; }; +/// Returns a version of \p File that doesn't contain dots and dot dots. +/// e.g /a/b/../c -> /a/c +/// /a/b/./c -> /a/b/c +/// FIXME: We should avoid encountering such paths in clangd internals by +/// filtering everything we get over LSP, CDB, etc. +Path removeDots(PathRef File); + } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/FormattedString.cpp b/clang-tools-extra/clangd/FormattedString.cpp index 102612af03a1..27fd37b9ae62 100644 --- a/clang-tools-extra/clangd/FormattedString.cpp +++ b/clang-tools-extra/clangd/FormattedString.cpp @@ -112,15 +112,20 @@ void FormattedString::appendInlineCode(std::string Code) { std::string FormattedString::renderAsMarkdown() const { std::string R; + auto EnsureWhitespace = [&R]() { + // Adds a space for nicer rendering. + if (!R.empty() && !isWhitespace(R.back())) + R += " "; + }; for (const auto &C : Chunks) { switch (C.Kind) { case ChunkKind::PlainText: + if (!C.Contents.empty() && !isWhitespace(C.Contents.front())) + EnsureWhitespace(); R += renderText(C.Contents); continue; case ChunkKind::InlineCodeBlock: - // Make sure we don't glue two backticks together. - if (llvm::StringRef(R).endswith("`")) - R += " "; + EnsureWhitespace(); R += renderInlineBlock(C.Contents); continue; case ChunkKind::CodeBlock: diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp index 51f0e7d015ed..ed3b86f0f55b 100644 --- a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp +++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "GlobalCompilationDatabase.h" +#include "FS.h" #include "Logger.h" #include "Path.h" #include "clang/Frontend/CompilerInvocation.h" @@ -15,6 +16,7 @@ #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include @@ -115,20 +117,41 @@ DirectoryBasedGlobalCompilationDatabase::getCompileCommand(PathRef File) const { return None; } -std::pair -DirectoryBasedGlobalCompilationDatabase::getCDBInDirLocked(PathRef Dir) const { - // FIXME(ibiryukov): Invalidate cached compilation databases on changes - auto CachedIt = CompilationDatabases.find(Dir); - if (CachedIt != CompilationDatabases.end()) - return {CachedIt->second.CDB.get(), CachedIt->second.SentBroadcast}; - std::string Error = ""; +// For platforms where paths are case-insensitive (but case-preserving), +// we need to do case-insensitive comparisons and use lowercase keys. +// FIXME: Make Path a real class with desired semantics instead. +// This class is not the only place this problem exists. +// FIXME: Mac filesystems default to case-insensitive, but may be sensitive. + +static std::string maybeCaseFoldPath(PathRef Path) { +#if defined(_WIN32) || defined(__APPLE__) + return Path.lower(); +#else + return Path; +#endif +} - CachedCDB Entry; - Entry.CDB = tooling::CompilationDatabase::loadFromDirectory(Dir, Error); - auto Result = Entry.CDB.get(); - CompilationDatabases[Dir] = std::move(Entry); +static bool pathEqual(PathRef A, PathRef B) { +#if defined(_WIN32) || defined(__APPLE__) + return A.equals_lower(B); +#else + return A == B; +#endif +} - return {Result, false}; +DirectoryBasedGlobalCompilationDatabase::CachedCDB & +DirectoryBasedGlobalCompilationDatabase::getCDBInDirLocked(PathRef Dir) const { + // FIXME(ibiryukov): Invalidate cached compilation databases on changes + // FIXME(sammccall): this function hot, avoid copying key when hitting cache. + auto Key = maybeCaseFoldPath(Dir); + auto R = CompilationDatabases.try_emplace(Key); + if (R.second) { // Cache miss, try to load CDB. + CachedCDB &Entry = R.first->second; + std::string Error = ""; + Entry.CDB = tooling::CompilationDatabase::loadFromDirectory(Dir, Error); + Entry.Path = Dir; + } + return R.first->second; } llvm::Optional @@ -137,35 +160,41 @@ DirectoryBasedGlobalCompilationDatabase::lookupCDB( assert(llvm::sys::path::is_absolute(Request.FileName) && "path must be absolute"); + bool ShouldBroadcast = false; CDBLookupResult Result; - bool SentBroadcast = false; { std::lock_guard Lock(Mutex); + CachedCDB *Entry = nullptr; if (CompileCommandsDir) { - std::tie(Result.CDB, SentBroadcast) = - getCDBInDirLocked(*CompileCommandsDir); - Result.PI.SourceRoot = *CompileCommandsDir; + Entry = &getCDBInDirLocked(*CompileCommandsDir); } else { - actOnAllParentDirectories( - Request.FileName, [this, &SentBroadcast, &Result](PathRef Path) { - std::tie(Result.CDB, SentBroadcast) = getCDBInDirLocked(Path); - Result.PI.SourceRoot = Path; - return Result.CDB != nullptr; - }); + // Traverse the canonical version to prevent false positives. i.e.: + // src/build/../a.cc can detect a CDB in /src/build if not canonicalized. + // FIXME(sammccall): this loop is hot, use a union-find-like structure. + actOnAllParentDirectories(removeDots(Request.FileName), + [&](PathRef Path) { + Entry = &getCDBInDirLocked(Path); + return Entry->CDB != nullptr; + }); } - if (!Result.CDB) + if (!Entry || !Entry->CDB) return llvm::None; // Mark CDB as broadcasted to make sure discovery is performed once. - if (Request.ShouldBroadcast && !SentBroadcast) - CompilationDatabases[Result.PI.SourceRoot].SentBroadcast = true; + if (Request.ShouldBroadcast && !Entry->SentBroadcast) { + Entry->SentBroadcast = true; + ShouldBroadcast = true; + } + + Result.CDB = Entry->CDB.get(); + Result.PI.SourceRoot = Entry->Path; } // FIXME: Maybe make the following part async, since this can block retrieval // of compile commands. - if (Request.ShouldBroadcast && !SentBroadcast) + if (ShouldBroadcast) broadcastCDB(Result); return Result; } @@ -195,9 +224,9 @@ void DirectoryBasedGlobalCompilationDatabase::broadcastCDB( if (!It.second) return true; - auto Res = getCDBInDirLocked(Path); - It.first->second = Res.first != nullptr; - return Path == Result.PI.SourceRoot; + CachedCDB &Entry = getCDBInDirLocked(Path); + It.first->second = Entry.CDB != nullptr; + return pathEqual(Path, Result.PI.SourceRoot); }); } } @@ -208,8 +237,9 @@ void DirectoryBasedGlobalCompilationDatabase::broadcastCDB( // Independent of whether it has an entry for that file or not. actOnAllParentDirectories(File, [&](PathRef Path) { if (DirectoryHasCDB.lookup(Path)) { - if (Path == Result.PI.SourceRoot) - GovernedFiles.push_back(File); + if (pathEqual(Path, Result.PI.SourceRoot)) + // Make sure listeners always get a canonical path for the file. + GovernedFiles.push_back(removeDots(File)); // Stop as soon as we hit a CDB. return true; } @@ -248,7 +278,7 @@ OverlayCDB::getCompileCommand(PathRef File) const { llvm::Optional Cmd; { std::lock_guard Lock(Mutex); - auto It = Commands.find(File); + auto It = Commands.find(removeDots(File)); if (It != Commands.end()) Cmd = It->second; } @@ -272,20 +302,24 @@ tooling::CompileCommand OverlayCDB::getFallbackCommand(PathRef File) const { void OverlayCDB::setCompileCommand( PathRef File, llvm::Optional Cmd) { + // We store a canonical version internally to prevent mismatches between set + // and get compile commands. Also it assures clients listening to broadcasts + // doesn't receive different names for the same file. + std::string CanonPath = removeDots(File); { std::unique_lock Lock(Mutex); if (Cmd) - Commands[File] = std::move(*Cmd); + Commands[CanonPath] = std::move(*Cmd); else - Commands.erase(File); + Commands.erase(CanonPath); } - OnCommandChanged.broadcast({File}); + OnCommandChanged.broadcast({CanonPath}); } llvm::Optional OverlayCDB::getProjectInfo(PathRef File) const { { std::lock_guard Lock(Mutex); - auto It = Commands.find(File); + auto It = Commands.find(removeDots(File)); if (It != Commands.end()) return ProjectInfo{}; } diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.h b/clang-tools-extra/clangd/GlobalCompilationDatabase.h index 35708c8e3024..7acca43d1bb9 100644 --- a/clang-tools-extra/clangd/GlobalCompilationDatabase.h +++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.h @@ -80,8 +80,13 @@ class DirectoryBasedGlobalCompilationDatabase llvm::Optional getProjectInfo(PathRef File) const override; private: - std::pair - getCDBInDirLocked(PathRef File) const; + /// Caches compilation databases loaded from directories. + struct CachedCDB { + std::string Path; // Not case-folded. + std::unique_ptr CDB = nullptr; + bool SentBroadcast = false; + }; + CachedCDB &getCDBInDirLocked(PathRef File) const; struct CDBLookupRequest { PathRef FileName; @@ -98,12 +103,7 @@ class DirectoryBasedGlobalCompilationDatabase void broadcastCDB(CDBLookupResult Res) const; mutable std::mutex Mutex; - /// Caches compilation databases loaded from directories(keys are - /// directories). - struct CachedCDB { - std::unique_ptr CDB = nullptr; - bool SentBroadcast = false; - }; + // Keyed by possibly-case-folded directory path. mutable llvm::StringMap CompilationDatabases; /// Used for command argument pointing to folder where compile_commands.json diff --git a/clang-tools-extra/clangd/Headers.cpp b/clang-tools-extra/clangd/Headers.cpp index 877301ee2d92..7caaebaa6f30 100644 --- a/clang-tools-extra/clangd/Headers.cpp +++ b/clang-tools-extra/clangd/Headers.cpp @@ -35,7 +35,7 @@ class RecordHeaders : public PPCallbacks { llvm::StringRef /*RelativePath*/, const Module * /*Imported*/, SrcMgr::CharacteristicKind FileKind) override { - if (SM.isWrittenInMainFile(HashLoc)) { + if (isInsideMainFile(HashLoc, SM)) { Out->MainFileIncludes.emplace_back(); auto &Inc = Out->MainFileIncludes.back(); Inc.R = halfOpenToRange(SM, FilenameRange); diff --git a/clang-tools-extra/clangd/IncludeFixer.cpp b/clang-tools-extra/clangd/IncludeFixer.cpp index edf86504d139..081dad83583b 100644 --- a/clang-tools-extra/clangd/IncludeFixer.cpp +++ b/clang-tools-extra/clangd/IncludeFixer.cpp @@ -16,6 +16,7 @@ #include "index/Symbol.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" +#include "clang/AST/DeclarationName.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/Type.h" #include "clang/Basic/Diagnostic.h" @@ -34,6 +35,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Error.h" @@ -301,6 +303,24 @@ llvm::Optional extractUnresolvedNameCheaply( return Result; } +/// Returns all namespace scopes that the unqualified lookup would visit. +std::vector +collectAccessibleScopes(Sema &Sem, const DeclarationNameInfo &Typo, Scope *S, + Sema::LookupNameKind LookupKind) { + std::vector Scopes; + VisitedContextCollector Collector; + Sem.LookupVisibleDecls(S, LookupKind, Collector, + /*IncludeGlobalScope=*/false, + /*LoadExternal=*/false); + + Scopes.push_back(""); + for (const auto *Ctx : Collector.takeVisitedContexts()) { + if (isa(Ctx)) + Scopes.push_back(printNamespaceScope(*Ctx)); + } + return Scopes; +} + class IncludeFixer::UnresolvedNameRecorder : public ExternalSemaSource { public: UnresolvedNameRecorder(llvm::Optional &LastUnresolvedName) @@ -318,51 +338,33 @@ class IncludeFixer::UnresolvedNameRecorder : public ExternalSemaSource { assert(SemaPtr && "Sema must have been set."); if (SemaPtr->isSFINAEContext()) return TypoCorrection(); - if (!SemaPtr->SourceMgr.isWrittenInMainFile(Typo.getLoc())) + if (!isInsideMainFile(Typo.getLoc(), SemaPtr->SourceMgr)) return clang::TypoCorrection(); - // This is not done lazily because `SS` can get out of scope and it's - // relatively cheap. auto Extracted = extractUnresolvedNameCheaply( SemaPtr->SourceMgr, Typo, SS, SemaPtr->LangOpts, static_cast(LookupKind) == Sema::LookupNameKind::LookupNestedNameSpecifierName); if (!Extracted) return TypoCorrection(); - auto CheapUnresolved = std::move(*Extracted); + UnresolvedName Unresolved; - Unresolved.Name = CheapUnresolved.Name; + Unresolved.Name = Extracted->Name; Unresolved.Loc = Typo.getBeginLoc(); - - if (!CheapUnresolved.ResolvedScope && !S) // Give up if no scope available. + if (!Extracted->ResolvedScope && !S) // Give up if no scope available. return TypoCorrection(); - auto *Sem = SemaPtr; // Avoid capturing `this`. - Unresolved.GetScopes = [Sem, CheapUnresolved, S, LookupKind]() { - std::vector Scopes; - if (CheapUnresolved.ResolvedScope) { - Scopes.push_back(*CheapUnresolved.ResolvedScope); - } else { - assert(S); - // No scope specifier is specified. Collect all accessible scopes in the - // context. - VisitedContextCollector Collector; - Sem->LookupVisibleDecls( - S, static_cast(LookupKind), Collector, - /*IncludeGlobalScope=*/false, - /*LoadExternal=*/false); - - Scopes.push_back(""); - for (const auto *Ctx : Collector.takeVisitedContexts()) - if (isa(Ctx)) - Scopes.push_back(printNamespaceScope(*Ctx)); - } + if (Extracted->ResolvedScope) + Unresolved.Scopes.push_back(*Extracted->ResolvedScope); + else // no qualifier or qualifier is unresolved. + Unresolved.Scopes = collectAccessibleScopes( + *SemaPtr, Typo, S, static_cast(LookupKind)); + + if (Extracted->UnresolvedScope) { + for (std::string &Scope : Unresolved.Scopes) + Scope += *Extracted->UnresolvedScope; + } - if (CheapUnresolved.UnresolvedScope) - for (auto &Scope : Scopes) - Scope.append(*CheapUnresolved.UnresolvedScope); - return Scopes; - }; LastUnresolvedName = std::move(Unresolved); // Never return a valid correction to try to recover. Our suggested fixes @@ -384,14 +386,13 @@ IncludeFixer::unresolvedNameRecorder() { std::vector IncludeFixer::fixUnresolvedName() const { assert(LastUnresolvedName.hasValue()); auto &Unresolved = *LastUnresolvedName; - std::vector Scopes = Unresolved.GetScopes(); vlog("Trying to fix unresolved name \"{0}\" in scopes: [{1}]", - Unresolved.Name, llvm::join(Scopes.begin(), Scopes.end(), ", ")); + Unresolved.Name, llvm::join(Unresolved.Scopes, ", ")); FuzzyFindRequest Req; Req.AnyScope = false; Req.Query = Unresolved.Name; - Req.Scopes = Scopes; + Req.Scopes = Unresolved.Scopes; Req.RestrictForCodeCompletion = true; Req.Limit = 100; diff --git a/clang-tools-extra/clangd/IncludeFixer.h b/clang-tools-extra/clangd/IncludeFixer.h index aafb384bfe9a..ba2a59fb3fb5 100644 --- a/clang-tools-extra/clangd/IncludeFixer.h +++ b/clang-tools-extra/clangd/IncludeFixer.h @@ -58,9 +58,7 @@ class IncludeFixer { struct UnresolvedName { std::string Name; // E.g. "X" in foo::X. SourceLocation Loc; // Start location of the unresolved name. - // Lazily get the possible scopes of the unresolved name. `Sema` must be - // alive when this is called. - std::function()> GetScopes; + std::vector Scopes; // Namespace scopes we should search in. }; /// Records the last unresolved name seen by Sema. diff --git a/clang-tools-extra/clangd/Quality.cpp b/clang-tools-extra/clangd/Quality.cpp index 6ab05293274f..bd25256904cd 100644 --- a/clang-tools-extra/clangd/Quality.cpp +++ b/clang-tools-extra/clangd/Quality.cpp @@ -9,6 +9,7 @@ #include "Quality.h" #include "AST.h" #include "FileDistance.h" +#include "SourceCode.h" #include "URI.h" #include "index/Symbol.h" #include "clang/AST/ASTContext.h" @@ -42,8 +43,7 @@ static bool isReserved(llvm::StringRef Name) { static bool hasDeclInMainFile(const Decl &D) { auto &SourceMgr = D.getASTContext().getSourceManager(); for (auto *Redecl : D.redecls()) { - auto Loc = SourceMgr.getSpellingLoc(Redecl->getLocation()); - if (SourceMgr.isWrittenInMainFile(Loc)) + if (isInsideMainFile(Redecl->getLocation(), SourceMgr)) return true; } return false; @@ -53,8 +53,7 @@ static bool hasUsingDeclInMainFile(const CodeCompletionResult &R) { const auto &Context = R.Declaration->getASTContext(); const auto &SourceMgr = Context.getSourceManager(); if (R.ShadowDecl) { - const auto Loc = SourceMgr.getExpansionLoc(R.ShadowDecl->getLocation()); - if (SourceMgr.isWrittenInMainFile(Loc)) + if (isInsideMainFile(R.ShadowDecl->getLocation(), SourceMgr)) return true; } return false; diff --git a/clang-tools-extra/clangd/QueryDriverDatabase.cpp b/clang-tools-extra/clangd/QueryDriverDatabase.cpp index 28596dafb601..bec6ea7186b2 100644 --- a/clang-tools-extra/clangd/QueryDriverDatabase.cpp +++ b/clang-tools-extra/clangd/QueryDriverDatabase.cpp @@ -59,7 +59,7 @@ namespace { std::vector parseDriverOutput(llvm::StringRef Output) { std::vector SystemIncludes; const char SIS[] = "#include <...> search starts here:"; - constexpr char const *SIE = "End of search list."; + const char SIE[] = "End of search list."; llvm::SmallVector Lines; Output.split(Lines, '\n', /*MaxSplit=*/-1, /*KeepEmpty=*/false); @@ -70,7 +70,9 @@ std::vector parseDriverOutput(llvm::StringRef Output) { return {}; } ++StartIt; - const auto EndIt = std::find(StartIt, Lines.end(), SIE); + const auto EndIt = + llvm::find_if(llvm::make_range(StartIt, Lines.end()), + [SIE](llvm::StringRef Line) { return Line.trim() == SIE; }); if (EndIt == Lines.end()) { elog("System include extraction: end marker missing: {0}", Output); return {}; diff --git a/clang-tools-extra/clangd/SourceCode.cpp b/clang-tools-extra/clangd/SourceCode.cpp index fb1183aef511..5370a8d88479 100644 --- a/clang-tools-extra/clangd/SourceCode.cpp +++ b/clang-tools-extra/clangd/SourceCode.cpp @@ -296,14 +296,52 @@ static SourceRange unionTokenRange(SourceRange R1, SourceRange R2, E1 < E2 ? R2.getEnd() : R1.getEnd()); } -// Returns the tokenFileRange for a given Location as a Token Range +// Check if two locations have the same file id. +static bool inSameFile(SourceLocation Loc1, SourceLocation Loc2, + const SourceManager &SM) { + return SM.getFileID(Loc1) == SM.getFileID(Loc2); +} + +// Find an expansion range (not necessarily immediate) the ends of which are in +// the same file id. +static SourceRange +getExpansionTokenRangeInSameFile(SourceLocation Loc, const SourceManager &SM, + const LangOptions &LangOpts) { + SourceRange ExpansionRange = + toTokenRange(SM.getImmediateExpansionRange(Loc), SM, LangOpts); + // Fast path for most common cases. + if (inSameFile(ExpansionRange.getBegin(), ExpansionRange.getEnd(), SM)) + return ExpansionRange; + // Record the stack of expansion locations for the beginning, keyed by FileID. + llvm::DenseMap BeginExpansions; + for (SourceLocation Begin = ExpansionRange.getBegin(); Begin.isValid(); + Begin = Begin.isFileID() + ? SourceLocation() + : SM.getImmediateExpansionRange(Begin).getBegin()) { + BeginExpansions[SM.getFileID(Begin)] = Begin; + } + // Move up the stack of expansion locations for the end until we find the + // location in BeginExpansions with that has the same file id. + for (SourceLocation End = ExpansionRange.getEnd(); End.isValid(); + End = End.isFileID() ? SourceLocation() + : toTokenRange(SM.getImmediateExpansionRange(End), + SM, LangOpts) + .getEnd()) { + auto It = BeginExpansions.find(SM.getFileID(End)); + if (It != BeginExpansions.end()) + return {It->second, End}; + } + llvm_unreachable( + "We should able to find a common ancestor in the expansion tree."); +} +// Returns the file range for a given Location as a Token Range // This is quite similar to getFileLoc in SourceManager as both use // getImmediateExpansionRange and getImmediateSpellingLoc (for macro IDs). // However: // - We want to maintain the full range information as we move from one file to // the next. getFileLoc only uses the BeginLoc of getImmediateExpansionRange. -// - We want to split '>>' tokens as the lexer parses the '>>' in template -// instantiations as a '>>' instead of a '>'. +// - We want to split '>>' tokens as the lexer parses the '>>' in nested +// template instantiations as a '>>' instead of two '>'s. // There is also getExpansionRange but it simply calls // getImmediateExpansionRange on the begin and ends separately which is wrong. static SourceRange getTokenFileRange(SourceLocation Loc, @@ -311,16 +349,19 @@ static SourceRange getTokenFileRange(SourceLocation Loc, const LangOptions &LangOpts) { SourceRange FileRange = Loc; while (!FileRange.getBegin().isFileID()) { - assert(!FileRange.getEnd().isFileID() && - "Both Begin and End should be MacroIDs."); if (SM.isMacroArgExpansion(FileRange.getBegin())) { - FileRange.setBegin(SM.getImmediateSpellingLoc(FileRange.getBegin())); - FileRange.setEnd(SM.getImmediateSpellingLoc(FileRange.getEnd())); + FileRange = unionTokenRange( + SM.getImmediateSpellingLoc(FileRange.getBegin()), + SM.getImmediateSpellingLoc(FileRange.getEnd()), SM, LangOpts); + assert(inSameFile(FileRange.getBegin(), FileRange.getEnd(), SM)); } else { - SourceRange ExpansionRangeForBegin = toTokenRange( - SM.getImmediateExpansionRange(FileRange.getBegin()), SM, LangOpts); - SourceRange ExpansionRangeForEnd = toTokenRange( - SM.getImmediateExpansionRange(FileRange.getEnd()), SM, LangOpts); + SourceRange ExpansionRangeForBegin = + getExpansionTokenRangeInSameFile(FileRange.getBegin(), SM, LangOpts); + SourceRange ExpansionRangeForEnd = + getExpansionTokenRangeInSameFile(FileRange.getEnd(), SM, LangOpts); + assert(inSameFile(ExpansionRangeForBegin.getBegin(), + ExpansionRangeForEnd.getBegin(), SM) && + "Both Expansion ranges should be in same file."); FileRange = unionTokenRange(ExpansionRangeForBegin, ExpansionRangeForEnd, SM, LangOpts); } @@ -328,6 +369,10 @@ static SourceRange getTokenFileRange(SourceLocation Loc, return FileRange; } +bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM) { + return Loc.isValid() && SM.isWrittenInMainFile(SM.getExpansionLoc(Loc)); +} + llvm::Optional toHalfOpenFileRange(const SourceManager &SM, const LangOptions &LangOpts, SourceRange R) { diff --git a/clang-tools-extra/clangd/SourceCode.h b/clang-tools-extra/clangd/SourceCode.h index 8e58e66f4db8..4bbf3cf49fcd 100644 --- a/clang-tools-extra/clangd/SourceCode.h +++ b/clang-tools-extra/clangd/SourceCode.h @@ -75,6 +75,14 @@ llvm::Optional getTokenRange(const SourceManager &SM, llvm::Expected sourceLocationInMainFile(const SourceManager &SM, Position P); +/// Returns true iff \p Loc is inside the main file. This function handles +/// file & macro locations. For macro locations, returns iff the macro is being +/// expanded inside the main file. +/// +/// The function is usually used to check whether a declaration is inside the +/// the main file. +bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM); + /// Turns a token range into a half-open range and checks its correctness. /// The resulting range will have only valid source location on both sides, both /// of which are file locations. diff --git a/clang-tools-extra/clangd/TUScheduler.cpp b/clang-tools-extra/clangd/TUScheduler.cpp index a77d226902c9..573c83140755 100644 --- a/clang-tools-extra/clangd/TUScheduler.cpp +++ b/clang-tools-extra/clangd/TUScheduler.cpp @@ -54,6 +54,7 @@ #include "llvm/ADT/ScopeExit.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Threading.h" #include #include #include @@ -799,10 +800,10 @@ std::string renderTUAction(const TUAction &Action) { } // namespace unsigned getDefaultAsyncThreadsCount() { - unsigned HardwareConcurrency = std::thread::hardware_concurrency(); - // C++ standard says that hardware_concurrency() - // may return 0, fallback to 1 worker thread in - // that case. + unsigned HardwareConcurrency = llvm::heavyweight_hardware_concurrency(); + // heavyweight_hardware_concurrency may fall back to hardware_concurrency. + // C++ standard says that hardware_concurrency() may return 0; fallback to 1 + // worker thread in that case. if (HardwareConcurrency == 0) return 1; return HardwareConcurrency; diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp index 6339f8643f74..6d4f6f1fb292 100644 --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -406,7 +406,7 @@ class ReferenceFinder : public index::IndexDataConsumer { assert(D->isCanonicalDecl() && "expect D to be a canonical declaration"); const SourceManager &SM = AST.getSourceManager(); Loc = SM.getFileLoc(Loc); - if (SM.isWrittenInMainFile(Loc) && CanonicalTargets.count(D)) + if (isInsideMainFile(Loc, SM) && CanonicalTargets.count(D)) References.push_back({D, Loc, Roles}); return true; } @@ -716,7 +716,7 @@ static HoverInfo getHoverContents(const Decl *D, const SymbolIndex *Index) { HI.Value.emplace(); llvm::raw_string_ostream ValueOS(*HI.Value); Result.Val.printPretty(ValueOS, const_cast(Ctx), - Var->getType()); + Init->getType()); } } } diff --git a/clang-tools-extra/clangd/clients/clangd-vscode/package-lock.json b/clang-tools-extra/clangd/clients/clangd-vscode/package-lock.json index 8108e789b2e3..07ae3525525d 100644 --- a/clang-tools-extra/clangd/clients/clangd-vscode/package-lock.json +++ b/clang-tools-extra/clangd/clients/clangd-vscode/package-lock.json @@ -1,6 +1,6 @@ { "name": "vscode-clangd", - "version": "0.0.13", + "version": "0.0.15", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -28,6 +28,12 @@ "uri-js": "^4.2.2" } }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, "ansi-cyan": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz", @@ -46,12 +52,45 @@ "ansi-wrap": "0.1.0" } }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, "ansi-wrap": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", "dev": true }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "dependencies": { + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + } + } + }, "append-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", @@ -61,6 +100,12 @@ "buffer-equal": "^1.0.0" } }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "arr-diff": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", @@ -152,8 +197,7 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "bcrypt-pbkdf": { "version": "1.0.2", @@ -164,6 +208,12 @@ "tweetnacl": "^0.14.3" } }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, "block-stream": { "version": "0.0.9", "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", @@ -183,6 +233,15 @@ "concat-map": "0.0.1" } }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, "browser-stdout": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", @@ -207,12 +266,98 @@ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + } + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "clone": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", @@ -242,6 +387,21 @@ "readable-stream": "^2.3.5" } }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "combined-stream": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", @@ -251,12 +411,6 @@ "delayed-stream": "~1.0.0" } }, - "commander": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", - "dev": true - }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -288,14 +442,28 @@ } }, "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } } }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, "deep-assign": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/deep-assign/-/deep-assign-1.0.0.tgz", @@ -321,9 +489,9 @@ "dev": true }, "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", "dev": true }, "duplexer": { @@ -354,6 +522,12 @@ "safer-buffer": "^2.1.0" } }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", @@ -363,10 +537,16 @@ "once": "^1.4.0" } }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, "event-stream": { @@ -426,6 +606,31 @@ "pend": "~1.2.0" } }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, "flush-write-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.0.tgz", @@ -488,6 +693,13 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, "fstream": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", @@ -506,6 +718,12 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -516,9 +734,9 @@ } }, "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -527,6 +745,17 @@ "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } } }, "glob-parent": { @@ -572,9 +801,9 @@ } }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -588,12 +817,6 @@ "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", "dev": true }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, "gulp-chmod": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/gulp-chmod/-/gulp-chmod-2.0.0.tgz", @@ -870,6 +1093,15 @@ "is-windows": "^1.0.1" } }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", @@ -882,6 +1114,12 @@ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, "is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", @@ -897,12 +1135,24 @@ "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", "dev": true }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, "is-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", "dev": true }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, "is-relative": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", @@ -927,6 +1177,12 @@ "unc-path-regex": "^0.1.2" } }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, "is-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", @@ -957,6 +1213,15 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", @@ -1023,6 +1288,25 @@ "flush-write-stream": "^1.0.2" } }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, "map-stream": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", @@ -1045,12 +1329,23 @@ } }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + } } }, "minimist": { @@ -1069,36 +1364,60 @@ } }, "mocha": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", - "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.1.0.tgz", + "integrity": "sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg==", "dev": true, "requires": { + "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", - "commander": "2.15.1", - "debug": "3.1.0", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "glob": "7.1.2", - "growl": "1.10.5", - "he": "1.1.1", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "supports-color": "5.4.0" + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" }, "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true } } }, "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "multimatch": { @@ -1114,9 +1433,9 @@ }, "dependencies": { "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -1124,6 +1443,12 @@ } } }, + "nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true + }, "node.extend": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/node.extend/-/node.extend-1.1.8.tgz", @@ -1194,12 +1519,36 @@ "readable-stream": "^2.0.1" } }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, "path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", "dev": true }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -1227,6 +1576,12 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, "plugin-error": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", @@ -1300,6 +1655,15 @@ "inherits": "~2.0.0" } }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, "readable-stream": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", @@ -1315,6 +1679,15 @@ "util-deprecate": "~1.0.1" } }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, "remove-bom-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", @@ -1376,6 +1749,12 @@ "uuid": "^3.3.2" } }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -1413,6 +1792,15 @@ "once": "^1.3.0", "path-is-absolute": "^1.0.0" } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } } } }, @@ -1433,6 +1821,15 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -1511,6 +1908,17 @@ "integrity": "sha1-l+mNj6TRBdYqJpHR3AfoINuN/E8=", "dev": true }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -1520,19 +1928,34 @@ "safe-buffer": "~5.1.0" } }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" }, "dependencies": { "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true } } @@ -1584,6 +2007,15 @@ "is-negated-glob": "^1.0.0" } }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, "to-through": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", @@ -1882,9 +2314,9 @@ "dev": true }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -1983,6 +2415,23 @@ "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.6.tgz", "integrity": "sha512-sLI2L0uGov3wKVb9EB+vIQBl9tVP90nqRvxSoJ35vI3NjxE8jfsE5DSOhWgSunHSZmKS4OCi2jrtfxK7uyp2ww==" }, + "workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -1995,6 +2444,45 @@ "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", "dev": true }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } + }, "yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", @@ -2013,6 +2501,12 @@ "requires": { "buffer-crc32": "~0.2.3" } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true } } } diff --git a/clang-tools-extra/clangd/clients/clangd-vscode/package.json b/clang-tools-extra/clangd/clients/clangd-vscode/package.json index 1bc6f4cb4621..12a6afec9b1c 100644 --- a/clang-tools-extra/clangd/clients/clangd-vscode/package.json +++ b/clang-tools-extra/clangd/clients/clangd-vscode/package.json @@ -41,7 +41,7 @@ "devDependencies": { "@types/mocha": "^2.2.32", "@types/node": "^6.0.40", - "mocha": "^5.2.0", + "mocha": "^10.1.0", "typescript": "^2.0.3", "vscode": "^1.1.0" }, diff --git a/clang-tools-extra/clangd/index/Background.cpp b/clang-tools-extra/clangd/index/Background.cpp index 23445e16b2f3..a9e28f8de99a 100644 --- a/clang-tools-extra/clangd/index/Background.cpp +++ b/clang-tools-extra/clangd/index/Background.cpp @@ -10,6 +10,7 @@ #include "ClangdUnit.h" #include "Compiler.h" #include "Context.h" +#include "FSProvider.h" #include "Headers.h" #include "Logger.h" #include "Path.h" @@ -18,6 +19,7 @@ #include "Threading.h" #include "Trace.h" #include "URI.h" +#include "index/BackgroundIndexLoader.h" #include "index/FileIndex.h" #include "index/IndexAction.h" #include "index/MemIndex.h" @@ -28,6 +30,8 @@ #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Driver/Types.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ScopeExit.h" @@ -42,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +54,8 @@ #include #include #include +#include +#include namespace clang { namespace clangd { @@ -119,6 +126,18 @@ llvm::SmallString<128> getAbsolutePath(const tooling::CompileCommand &Cmd) { } return AbsolutePath; } + +bool shardIsStale(const LoadedShard &LS, llvm::vfs::FileSystem *FS) { + auto Buf = FS->getBufferForFile(LS.AbsolutePath); + if (!Buf) { + elog("Background-index: Couldn't read {0} to validate stored index: {1}", + LS.AbsolutePath, Buf.getError().message()); + // There is no point in indexing an unreadable file. + return false; + } + return digest(Buf->get()->getBuffer()) != LS.Digest; +} + } // namespace BackgroundIndex::BackgroundIndex( @@ -156,14 +175,14 @@ BackgroundQueue::Task BackgroundIndex::changedFilesTask( log("Enqueueing {0} commands for indexing", ChangedFiles.size()); SPAN_ATTACH(Tracer, "files", int64_t(ChangedFiles.size())); - auto NeedsReIndexing = loadShards(std::move(ChangedFiles)); + auto NeedsReIndexing = loadProject(std::move(ChangedFiles)); // Run indexing for files that need to be updated. std::shuffle(NeedsReIndexing.begin(), NeedsReIndexing.end(), std::mt19937(std::random_device{}())); std::vector Tasks; Tasks.reserve(NeedsReIndexing.size()); - for (auto &Elem : NeedsReIndexing) - Tasks.push_back(indexFileTask(std::move(Elem.first), Elem.second)); + for (auto &Cmd : NeedsReIndexing) + Tasks.push_back(indexFileTask(std::move(Cmd))); Queue.append(std::move(Tasks)); }); @@ -178,13 +197,12 @@ static llvm::StringRef filenameWithoutExtension(llvm::StringRef Path) { } BackgroundQueue::Task -BackgroundIndex::indexFileTask(tooling::CompileCommand Cmd, - BackgroundIndexStorage *Storage) { - BackgroundQueue::Task T([this, Storage, Cmd] { +BackgroundIndex::indexFileTask(tooling::CompileCommand Cmd) { + BackgroundQueue::Task T([this, Cmd] { // We can't use llvm::StringRef here since we are going to // move from Cmd during the call below. const std::string FileName = Cmd.Filename; - if (auto Error = index(std::move(Cmd), Storage)) + if (auto Error = index(std::move(Cmd))) elog("Indexing {0} failed: {1}", FileName, std::move(Error)); }); T.QueuePri = IndexFile; @@ -207,7 +225,7 @@ void BackgroundIndex::boostRelated(llvm::StringRef Path) { void BackgroundIndex::update( llvm::StringRef MainFile, IndexFileIn Index, const llvm::StringMap &ShardVersionsSnapshot, - BackgroundIndexStorage *IndexStorage, bool HadErrors) { + bool HadErrors) { // Partition symbols/references into files. struct File { llvm::DenseSet Symbols; @@ -291,22 +309,21 @@ void BackgroundIndex::update( // We need to store shards before updating the index, since the latter // consumes slabs. // FIXME: Also skip serializing the shard if it is already up-to-date. - if (IndexStorage) { - IndexFileOut Shard; - Shard.Symbols = SS.get(); - Shard.Refs = RS.get(); - Shard.Relations = RelS.get(); - Shard.Sources = IG.get(); - - // Only store command line hash for main files of the TU, since our - // current model keeps only one version of a header file. - if (Path == MainFile) - Shard.Cmd = Index.Cmd.getPointer(); - - if (auto Error = IndexStorage->storeShard(Path, Shard)) - elog("Failed to write background-index shard for file {0}: {1}", Path, - std::move(Error)); - } + BackgroundIndexStorage *IndexStorage = IndexStorageFactory(Path); + IndexFileOut Shard; + Shard.Symbols = SS.get(); + Shard.Refs = RS.get(); + Shard.Relations = RelS.get(); + Shard.Sources = IG.get(); + + // Only store command line hash for main files of the TU, since our + // current model keeps only one version of a header file. + if (Path == MainFile) + Shard.Cmd = Index.Cmd.getPointer(); + + if (auto Error = IndexStorage->storeShard(Path, Shard)) + elog("Failed to write background-index shard for file {0}: {1}", Path, + std::move(Error)); { std::lock_guard Lock(ShardVersionsMu); @@ -329,8 +346,7 @@ void BackgroundIndex::update( } } -llvm::Error BackgroundIndex::index(tooling::CompileCommand Cmd, - BackgroundIndexStorage *IndexStorage) { +llvm::Error BackgroundIndex::index(tooling::CompileCommand Cmd) { trace::Span Tracer("BackgroundIndex"); SPAN_ATTACH(Tracer, "file", Cmd.Filename); auto AbsolutePath = getAbsolutePath(Cmd); @@ -424,176 +440,78 @@ llvm::Error BackgroundIndex::index(tooling::CompileCommand Cmd, for (auto &It : *Index.Sources) It.second.Flags |= IncludeGraphNode::SourceFlag::HadErrors; } - update(AbsolutePath, std::move(Index), ShardVersionsSnapshot, IndexStorage, - HadErrors); + update(AbsolutePath, std::move(Index), ShardVersionsSnapshot, HadErrors); Rebuilder.indexedTU(); return llvm::Error::success(); } -std::vector -BackgroundIndex::loadShard(const tooling::CompileCommand &Cmd, - BackgroundIndexStorage *IndexStorage, - llvm::StringSet<> &LoadedShards) { - struct ShardInfo { - std::string AbsolutePath; - std::unique_ptr Shard; - FileDigest Digest = {}; - bool CountReferences = false; - bool HadErrors = false; - }; - std::vector IntermediateSymbols; - // Make sure we don't have duplicate elements in the queue. Keys are absolute - // paths. - llvm::StringSet<> InQueue; - auto FS = FSProvider.getFileSystem(); - // Dependencies of this TU, paired with the information about whether they - // need to be re-indexed or not. - std::vector Dependencies; - std::queue ToVisit; - std::string AbsolutePath = getAbsolutePath(Cmd).str(); - // Up until we load the shard related to a dependency it needs to be - // re-indexed. - ToVisit.emplace(AbsolutePath, true); - InQueue.insert(AbsolutePath); - // Goes over each dependency. - while (!ToVisit.empty()) { - Dependencies.push_back(std::move(ToVisit.front())); - // Dependencies is not modified during the rest of the loop, so it is safe - // to keep the reference. - auto &CurDependency = Dependencies.back(); - ToVisit.pop(); - // If we have already seen this shard before(either loaded or failed) don't - // re-try again. Since the information in the shard won't change from one TU - // to another. - if (!LoadedShards.try_emplace(CurDependency.Path).second) { - // If the dependency needs to be re-indexed, first occurence would already - // have detected that, so we don't need to issue it again. - CurDependency.NeedsReIndexing = false; - continue; - } +// Restores shards for \p MainFiles from index storage. Then checks staleness of +// those shards and returns a list of TUs that needs to be indexed to update +// staleness. +std::vector +BackgroundIndex::loadProject(std::vector MainFiles) { + std::vector NeedsReIndexing; - auto Shard = IndexStorage->loadShard(CurDependency.Path); - if (!Shard || !Shard->Sources) { - // File will be returned as requiring re-indexing to caller. - vlog("Failed to load shard: {0}", CurDependency.Path); - continue; - } - // These are the edges in the include graph for current dependency. - for (const auto &I : *Shard->Sources) { - auto U = URI::parse(I.getKey()); - if (!U) - continue; - auto AbsolutePath = URI::resolve(*U, CurDependency.Path); - if (!AbsolutePath) - continue; - // Add file as dependency if haven't seen before. - if (InQueue.try_emplace(*AbsolutePath).second) - ToVisit.emplace(*AbsolutePath, true); - // The node contains symbol information only for current file, the rest is - // just edges. - if (*AbsolutePath != CurDependency.Path) - continue; - - // We found source file info for current dependency. - assert(I.getValue().Digest != FileDigest{{0}} && "Digest is empty?"); - ShardInfo SI; - SI.AbsolutePath = CurDependency.Path; - SI.Shard = std::move(Shard); - SI.Digest = I.getValue().Digest; - SI.CountReferences = - I.getValue().Flags & IncludeGraphNode::SourceFlag::IsTU; - SI.HadErrors = - I.getValue().Flags & IncludeGraphNode::SourceFlag::HadErrors; - IntermediateSymbols.push_back(std::move(SI)); - // Check if the source needs re-indexing. - // Get the digest, skip it if file doesn't exist. - auto Buf = FS->getBufferForFile(CurDependency.Path); - if (!Buf) { - elog("Couldn't get buffer for file: {0}: {1}", CurDependency.Path, - Buf.getError().message()); - continue; - } - // If digests match then dependency doesn't need re-indexing. - // FIXME: Also check for dependencies(sources) of this shard and compile - // commands for cache invalidation. - CurDependency.NeedsReIndexing = - digest(Buf->get()->getBuffer()) != I.getValue().Digest; - } - } - // Load shard information into background-index. + Rebuilder.startLoading(); + // Load shards for all of the mainfiles. + const std::vector Result = + loadIndexShards(MainFiles, IndexStorageFactory, CDB); + size_t LoadedShards = 0; { + // Update in-memory state. std::lock_guard Lock(ShardVersionsMu); - // This can override a newer version that is added in another thread, - // if this thread sees the older version but finishes later. This - // should be rare in practice. - for (const ShardInfo &SI : IntermediateSymbols) { + for (auto &LS : Result) { + if (!LS.Shard) + continue; auto SS = - SI.Shard->Symbols - ? llvm::make_unique(std::move(*SI.Shard->Symbols)) + LS.Shard->Symbols + ? llvm::make_unique(std::move(*LS.Shard->Symbols)) : nullptr; - auto RS = SI.Shard->Refs - ? llvm::make_unique(std::move(*SI.Shard->Refs)) + auto RS = LS.Shard->Refs + ? llvm::make_unique(std::move(*LS.Shard->Refs)) : nullptr; auto RelS = - SI.Shard->Relations - ? llvm::make_unique(std::move(*SI.Shard->Relations)) + LS.Shard->Relations + ? llvm::make_unique(std::move(*LS.Shard->Relations)) : nullptr; - ShardVersion &SV = ShardVersions[SI.AbsolutePath]; - SV.Digest = SI.Digest; - SV.HadErrors = SI.HadErrors; + ShardVersion &SV = ShardVersions[LS.AbsolutePath]; + SV.Digest = LS.Digest; + SV.HadErrors = LS.HadErrors; + ++LoadedShards; - IndexedSymbols.update(SI.AbsolutePath, std::move(SS), std::move(RS), - std::move(RelS), SI.CountReferences); + IndexedSymbols.update(LS.AbsolutePath, std::move(SS), std::move(RS), + std::move(RelS), LS.CountReferences); } } - if (!IntermediateSymbols.empty()) - Rebuilder.loadedTU(); + Rebuilder.loadedShard(LoadedShards); + Rebuilder.doneLoading(); - return Dependencies; -} + auto FS = FSProvider.getFileSystem(); + llvm::DenseSet TUsToIndex; + // We'll accept data from stale shards, but ensure the files get reindexed + // soon. + for (auto &LS : Result) { + if (!shardIsStale(LS, FS.get())) + continue; + PathRef TUForFile = LS.DependentTU; + assert(!TUForFile.empty() && "File without a TU!"); + + // FIXME: Currently, we simply schedule indexing on a TU whenever any of + // its dependencies needs re-indexing. We might do it smarter by figuring + // out a minimal set of TUs that will cover all the stale dependencies. + // FIXME: Try looking at other TUs if no compile commands are available + // for this TU, i.e TU was deleted after we performed indexing. + TUsToIndex.insert(TUForFile); + } -// Goes over each changed file and loads them from index. Returns the list of -// TUs that had out-of-date/no shards. -std::vector> -BackgroundIndex::loadShards(std::vector ChangedFiles) { - std::vector> - NeedsReIndexing; - // Keeps track of the files that will be reindexed, to make sure we won't - // re-index same dependencies more than once. Keys are AbsolutePaths. - llvm::StringSet<> FilesToIndex; - // Keeps track of the loaded shards to make sure we don't perform redundant - // disk IO. Keys are absolute paths. - llvm::StringSet<> LoadedShards; - Rebuilder.startLoading(); - for (const auto &File : ChangedFiles) { - auto Cmd = CDB.getCompileCommand(File); + for (PathRef TU : TUsToIndex) { + auto Cmd = CDB.getCompileCommand(TU); if (!Cmd) continue; - - std::string ProjectRoot; - if (auto PI = CDB.getProjectInfo(File)) - ProjectRoot = std::move(PI->SourceRoot); - - BackgroundIndexStorage *IndexStorage = IndexStorageFactory(ProjectRoot); - auto Dependencies = loadShard(*Cmd, IndexStorage, LoadedShards); - for (const auto &Dependency : Dependencies) { - if (!Dependency.NeedsReIndexing || FilesToIndex.count(Dependency.Path)) - continue; - // FIXME: Currently, we simply schedule indexing on a TU whenever any of - // its dependencies needs re-indexing. We might do it smarter by figuring - // out a minimal set of TUs that will cover all the stale dependencies. - vlog("Enqueueing TU {0} because its dependency {1} needs re-indexing.", - Cmd->Filename, Dependency.Path); - NeedsReIndexing.push_back({std::move(*Cmd), IndexStorage}); - // Mark all of this TU's dependencies as to-be-indexed so that we won't - // try to re-index those. - for (const auto &Dependency : Dependencies) - FilesToIndex.insert(Dependency.Path); - break; - } + NeedsReIndexing.emplace_back(std::move(*Cmd)); } - Rebuilder.doneLoading(); + return NeedsReIndexing; } diff --git a/clang-tools-extra/clangd/index/Background.h b/clang-tools-extra/clangd/index/Background.h index 39fe8daeba8f..7ce9e7bf17be 100644 --- a/clang-tools-extra/clangd/index/Background.h +++ b/clang-tools-extra/clangd/index/Background.h @@ -12,6 +12,7 @@ #include "Context.h" #include "FSProvider.h" #include "GlobalCompilationDatabase.h" +#include "Path.h" #include "SourceCode.h" #include "Threading.h" #include "index/BackgroundRebuild.h" @@ -49,15 +50,17 @@ class BackgroundIndexStorage { virtual std::unique_ptr loadShard(llvm::StringRef ShardIdentifier) const = 0; - // The factory provides storage for each CDB. + // The factory provides storage for each File. // It keeps ownership of the storage instances, and should manage caching // itself. Factory must be threadsafe and never returns nullptr. - using Factory = - llvm::unique_function; + using Factory = llvm::unique_function; // Creates an Index Storage that saves shards into disk. Index storage uses - // CDBDirectory + ".clangd/index/" as the folder to save shards. - static Factory createDiskBackedStorageFactory(); + // CDBDirectory + ".clangd/index/" as the folder to save shards. CDBDirectory + // is the first directory containing a CDB in parent directories of a file, or + // user's home directory if none was found, e.g. standard library headers. + static Factory createDiskBackedStorageFactory( + std::function(PathRef)> GetProjectInfo); }; // A priority queue of tasks which can be run on (external) worker threads. @@ -157,15 +160,14 @@ class BackgroundIndex : public SwapIndex { /// information on IndexStorage. void update(llvm::StringRef MainFile, IndexFileIn Index, const llvm::StringMap &ShardVersionsSnapshot, - BackgroundIndexStorage *IndexStorage, bool HadErrors); + bool HadErrors); // configuration const FileSystemProvider &FSProvider; const GlobalCompilationDatabase &CDB; Context BackgroundContext; - llvm::Error index(tooling::CompileCommand, - BackgroundIndexStorage *IndexStorage); + llvm::Error index(tooling::CompileCommand); FileSymbols IndexedSymbols; BackgroundIndexRebuilder Rebuilder; @@ -173,25 +175,13 @@ class BackgroundIndex : public SwapIndex { std::mutex ShardVersionsMu; BackgroundIndexStorage::Factory IndexStorageFactory; - struct Source { - std::string Path; - bool NeedsReIndexing; - Source(llvm::StringRef Path, bool NeedsReIndexing) - : Path(Path), NeedsReIndexing(NeedsReIndexing) {} - }; - // Loads the shards for a single TU and all of its dependencies. Returns the - // list of sources and whether they need to be re-indexed. - std::vector loadShard(const tooling::CompileCommand &Cmd, - BackgroundIndexStorage *IndexStorage, - llvm::StringSet<> &LoadedShards); - // Tries to load shards for the ChangedFiles. - std::vector> - loadShards(std::vector ChangedFiles); + // Tries to load shards for the MainFiles and their dependencies. + std::vector + loadProject(std::vector MainFiles); BackgroundQueue::Task changedFilesTask(const std::vector &ChangedFiles); - BackgroundQueue::Task indexFileTask(tooling::CompileCommand Cmd, - BackgroundIndexStorage *Storage); + BackgroundQueue::Task indexFileTask(tooling::CompileCommand Cmd); // from lowest to highest priority enum QueuePriority { diff --git a/clang-tools-extra/clangd/index/BackgroundIndexLoader.cpp b/clang-tools-extra/clangd/index/BackgroundIndexLoader.cpp new file mode 100644 index 000000000000..585d36716d29 --- /dev/null +++ b/clang-tools-extra/clangd/index/BackgroundIndexLoader.cpp @@ -0,0 +1,143 @@ +//===-- BackgroundIndexLoader.cpp - ---------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "index/BackgroundIndexLoader.h" +#include "GlobalCompilationDatabase.h" +#include "Logger.h" +#include "Path.h" +#include "index/Background.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Path.h" +#include +#include +#include + +namespace clang { +namespace clangd { +namespace { + +llvm::Optional uriToAbsolutePath(llvm::StringRef URI, PathRef HintPath) { + auto U = URI::parse(URI); + if (!U) + return llvm::None; + auto AbsolutePath = URI::resolve(*U, HintPath); + if (!AbsolutePath) + return llvm::None; + return *AbsolutePath; +} + +/// A helper class to cache BackgroundIndexStorage operations and keep the +/// inverse dependency mapping. +class BackgroundIndexLoader { +public: + BackgroundIndexLoader(BackgroundIndexStorage::Factory &IndexStorageFactory) + : IndexStorageFactory(IndexStorageFactory) {} + /// Load the shards for \p MainFile and all of its dependencies. + void load(PathRef MainFile); + + /// Consumes the loader and returns all shards. + std::vector takeResult() &&; + +private: + /// Returns the Shard for \p StartSourceFile from cache or loads it from \p + /// Storage. Also returns paths for dependencies of \p StartSourceFile if it + /// wasn't cached yet. + std::pair> + loadShard(PathRef StartSourceFile, PathRef DependentTU); + + /// Cache for Storage lookups. + llvm::StringMap LoadedShards; + + BackgroundIndexStorage::Factory &IndexStorageFactory; +}; + +std::pair> +BackgroundIndexLoader::loadShard(PathRef StartSourceFile, PathRef DependentTU) { + auto It = LoadedShards.try_emplace(StartSourceFile); + LoadedShard &LS = It.first->getValue(); + std::vector Edges = {}; + // Return the cached shard. + if (!It.second) + return {LS, Edges}; + + LS.AbsolutePath = StartSourceFile.str(); + LS.DependentTU = DependentTU; + BackgroundIndexStorage *Storage = IndexStorageFactory(LS.AbsolutePath); + auto Shard = Storage->loadShard(StartSourceFile); + if (!Shard || !Shard->Sources) { + vlog("Failed to load shard: {0}", StartSourceFile); + return {LS, Edges}; + } + + LS.Shard = std::move(Shard); + for (const auto &It : *LS.Shard->Sources) { + auto AbsPath = uriToAbsolutePath(It.getKey(), StartSourceFile); + if (!AbsPath) + continue; + // A shard contains only edges for non main-file sources. + if (*AbsPath != StartSourceFile) { + Edges.push_back(*AbsPath); + continue; + } + + // Fill in shard metadata. + const IncludeGraphNode &IGN = It.getValue(); + LS.Digest = IGN.Digest; + LS.CountReferences = IGN.Flags & IncludeGraphNode::SourceFlag::IsTU; + LS.HadErrors = IGN.Flags & IncludeGraphNode::SourceFlag::HadErrors; + } + assert(LS.Digest != FileDigest{{0}} && "Digest is empty?"); + return {LS, Edges}; +} + +void BackgroundIndexLoader::load(PathRef MainFile) { + llvm::StringSet<> InQueue; + // Following containers points to strings inside InQueue. + std::queue ToVisit; + InQueue.insert(MainFile); + ToVisit.push(MainFile); + + while (!ToVisit.empty()) { + PathRef SourceFile = ToVisit.front(); + ToVisit.pop(); + + auto ShardAndEdges = loadShard(SourceFile, MainFile); + for (PathRef Edge : ShardAndEdges.second) { + auto It = InQueue.insert(Edge); + if (It.second) + ToVisit.push(It.first->getKey()); + } + } +} + +std::vector BackgroundIndexLoader::takeResult() && { + std::vector Result; + Result.reserve(LoadedShards.size()); + for (auto &It : LoadedShards) + Result.push_back(std::move(It.getValue())); + return Result; +} +} // namespace + +std::vector +loadIndexShards(llvm::ArrayRef MainFiles, + BackgroundIndexStorage::Factory &IndexStorageFactory, + const GlobalCompilationDatabase &CDB) { + BackgroundIndexLoader Loader(IndexStorageFactory); + for (llvm::StringRef MainFile : MainFiles) { + assert(llvm::sys::path::is_absolute(MainFile)); + Loader.load(MainFile); + } + return std::move(Loader).takeResult(); +} + +} // namespace clangd +} // namespace clang diff --git a/clang-tools-extra/clangd/index/BackgroundIndexLoader.h b/clang-tools-extra/clangd/index/BackgroundIndexLoader.h new file mode 100644 index 000000000000..0caf1b463525 --- /dev/null +++ b/clang-tools-extra/clangd/index/BackgroundIndexLoader.h @@ -0,0 +1,54 @@ +//===--- BackgroundIndexLoader.h - Load shards from index storage-*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_BACKGROUND_INDEX_LOADER_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_BACKGROUND_INDEX_LOADER_H + +#include "Path.h" +#include "index/Background.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VirtualFileSystem.h" +#include +#include + +namespace clang { +namespace clangd { + +/// Represents a shard loaded from storage, stores contents in \p Shard and +/// metadata about the source file that generated this shard. +struct LoadedShard { + /// Path of the source file that produced this shard. + Path AbsolutePath; + /// Digest of the source file contents that produced this shard. + FileDigest Digest = {}; + /// Whether the RefSlab in Shard should be used for updating symbol reference + /// counts when building an index. + bool CountReferences = false; + /// Whether the indexing action producing that shard had errors. + bool HadErrors = false; + /// Path to a TU that is depending on this shard. + Path DependentTU; + /// Will be nullptr when index storage couldn't provide a valid shard for + /// AbsolutePath. + std::unique_ptr Shard; +}; + +/// Loads all shards for the TU \p MainFile from \p Storage. +std::vector +loadIndexShards(llvm::ArrayRef MainFiles, + BackgroundIndexStorage::Factory &IndexStorageFactory, + const GlobalCompilationDatabase &CDB); + +} // namespace clangd +} // namespace clang + +#endif diff --git a/clang-tools-extra/clangd/index/BackgroundIndexStorage.cpp b/clang-tools-extra/clangd/index/BackgroundIndexStorage.cpp index 80246b9ceea2..8b2c411a1666 100644 --- a/clang-tools-extra/clangd/index/BackgroundIndexStorage.cpp +++ b/clang-tools-extra/clangd/index/BackgroundIndexStorage.cpp @@ -6,13 +6,21 @@ // //===----------------------------------------------------------------------===// +#include "GlobalCompilationDatabase.h" #include "Logger.h" +#include "Path.h" #include "index/Background.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ScopeExit.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" +#include namespace clang { namespace clangd { @@ -118,12 +126,21 @@ class NullStorage : public BackgroundIndexStorage { // Creates and owns IndexStorages for multiple CDBs. class DiskBackedIndexStorageManager { public: - DiskBackedIndexStorageManager() - : IndexStorageMapMu(llvm::make_unique()) {} + DiskBackedIndexStorageManager( + std::function(PathRef)> GetProjectInfo) + : IndexStorageMapMu(llvm::make_unique()), + GetProjectInfo(std::move(GetProjectInfo)) { + llvm::SmallString<128> HomeDir; + llvm::sys::path::home_directory(HomeDir); + this->HomeDir = HomeDir.str().str(); + } - // Creates or fetches to storage from cache for the specified CDB. - BackgroundIndexStorage *operator()(llvm::StringRef CDBDirectory) { + // Creates or fetches to storage from cache for the specified project. + BackgroundIndexStorage *operator()(PathRef File) { std::lock_guard Lock(*IndexStorageMapMu); + Path CDBDirectory = HomeDir; + if (auto PI = GetProjectInfo(File)) + CDBDirectory = PI->SourceRoot; auto &IndexStorage = IndexStorageMap[CDBDirectory]; if (!IndexStorage) IndexStorage = create(CDBDirectory); @@ -131,21 +148,28 @@ class DiskBackedIndexStorageManager { } private: - std::unique_ptr create(llvm::StringRef CDBDirectory) { - if (CDBDirectory.empty()) + std::unique_ptr create(PathRef CDBDirectory) { + if (CDBDirectory.empty()) { + elog("Tried to create storage for empty directory!"); return llvm::make_unique(); + } return llvm::make_unique(CDBDirectory); } + Path HomeDir; + llvm::StringMap> IndexStorageMap; std::unique_ptr IndexStorageMapMu; + + std::function(PathRef)> GetProjectInfo; }; } // namespace BackgroundIndexStorage::Factory -BackgroundIndexStorage::createDiskBackedStorageFactory() { - return DiskBackedIndexStorageManager(); +BackgroundIndexStorage::createDiskBackedStorageFactory( + std::function(PathRef)> GetProjectInfo) { + return DiskBackedIndexStorageManager(std::move(GetProjectInfo)); } } // namespace clangd diff --git a/clang-tools-extra/clangd/index/BackgroundRebuild.cpp b/clang-tools-extra/clangd/index/BackgroundRebuild.cpp index 4233e5c92a04..cb6ac0fc8bf7 100644 --- a/clang-tools-extra/clangd/index/BackgroundRebuild.cpp +++ b/clang-tools-extra/clangd/index/BackgroundRebuild.cpp @@ -78,13 +78,13 @@ void BackgroundIndexRebuilder::idle() { void BackgroundIndexRebuilder::startLoading() { std::lock_guard Lock(Mu); if (!Loading) - LoadedTUs = 0; + LoadedShards = 0; ++Loading; } -void BackgroundIndexRebuilder::loadedTU() { +void BackgroundIndexRebuilder::loadedShard(size_t ShardCount) { std::lock_guard Lock(Mu); assert(Loading); - ++LoadedTUs; + LoadedShards += ShardCount; } void BackgroundIndexRebuilder::doneLoading() { maybeRebuild("after loading index from disk", [this] { @@ -93,7 +93,7 @@ void BackgroundIndexRebuilder::doneLoading() { if (Loading) // was loading multiple batches concurrently return false; // rebuild once the last batch is done. // Rebuild if we loaded any shards, or if we stopped an indexedTU rebuild. - return LoadedTUs > 0 || enoughTUsToRebuild(); + return LoadedShards > 0 || enoughTUsToRebuild(); }); } diff --git a/clang-tools-extra/clangd/index/BackgroundRebuild.h b/clang-tools-extra/clangd/index/BackgroundRebuild.h index f660957f6241..d74c28be5cfb 100644 --- a/clang-tools-extra/clangd/index/BackgroundRebuild.h +++ b/clang-tools-extra/clangd/index/BackgroundRebuild.h @@ -17,6 +17,7 @@ #include "index/FileIndex.h" #include "index/Index.h" #include "llvm/Support/Threading.h" +#include namespace clang { namespace clangd { @@ -61,7 +62,7 @@ class BackgroundIndexRebuilder { // sessions may happen concurrently. void startLoading(); // Called to indicate some shards were actually loaded from disk. - void loadedTU(); + void loadedShard(size_t ShardCount); // Called to indicate we're finished loading shards from disk. // May rebuild (if any were loaded). void doneLoading(); @@ -89,7 +90,7 @@ class BackgroundIndexRebuilder { unsigned IndexedTUsAtLastRebuild = 0; // Are we loading shards? May be multiple concurrent sessions. unsigned Loading = 0; - unsigned LoadedTUs; // In the current loading session. + unsigned LoadedShards; // In the current loading session. SwapIndex *Target; FileSymbols *Source; diff --git a/clang-tools-extra/clangd/index/IndexAction.cpp b/clang-tools-extra/clangd/index/IndexAction.cpp index 84b69e9cbaf1..a7429484300a 100644 --- a/clang-tools-extra/clangd/index/IndexAction.cpp +++ b/clang-tools-extra/clangd/index/IndexAction.cpp @@ -11,9 +11,17 @@ #include "Logger.h" #include "index/Relation.h" #include "index/SymbolOrigin.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" #include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/MultiplexConsumer.h" #include "clang/Index/IndexingAction.h" #include "clang/Tooling/Tooling.h" +#include "llvm/ADT/STLExtras.h" +#include +#include #include namespace clang { @@ -113,6 +121,40 @@ struct IncludeGraphCollector : public PPCallbacks { IncludeGraph &IG; }; +/// Returns an ASTConsumer that wraps \p Inner and additionally instructs the +/// parser to skip bodies of functions in the files that should not be +/// processed. +static std::unique_ptr +skipProcessedFunctions(std::unique_ptr Inner, + std::function ShouldIndexFile) { + class SkipProcessedFunctions : public ASTConsumer { + public: + SkipProcessedFunctions(std::function FileFilter) + : ShouldIndexFile(std::move(FileFilter)), Context(nullptr) { + assert(this->ShouldIndexFile); + } + + void Initialize(ASTContext &Context) override { this->Context = &Context; } + bool shouldSkipFunctionBody(Decl *D) override { + assert(Context && "Initialize() was never called."); + auto &SM = Context->getSourceManager(); + auto FID = SM.getFileID(SM.getExpansionLoc(D->getLocation())); + if (!FID.isValid()) + return false; + return !ShouldIndexFile(FID); + } + + private: + std::function ShouldIndexFile; + const ASTContext *Context; + }; + std::vector> Consumers; + Consumers.push_back( + llvm::make_unique(ShouldIndexFile)); + Consumers.push_back(std::move(Inner)); + return llvm::make_unique(std::move(Consumers)); +} + // Wraps the index action and reports index data after each translation unit. class IndexAction : public WrapperFrontendAction { public: @@ -137,7 +179,9 @@ class IndexAction : public WrapperFrontendAction { if (IncludeGraphCallback != nullptr) CI.getPreprocessor().addPPCallbacks( llvm::make_unique(CI.getSourceManager(), IG)); - return WrapperFrontendAction::CreateASTConsumer(CI, InFile); + return skipProcessedFunctions( + WrapperFrontendAction::CreateASTConsumer(CI, InFile), + [this](FileID FID) { return Collector->shouldIndexFile(FID); }); } bool BeginInvocation(CompilerInstance &CI) override { @@ -147,6 +191,10 @@ class IndexAction : public WrapperFrontendAction { // Avoids some analyses too. Set in two places as we're late to the party. CI.getDiagnosticOpts().IgnoreWarnings = true; CI.getDiagnostics().setIgnoreAllWarnings(true); + // Instruct the parser to ask our ASTConsumer if it should skip function + // bodies. The ASTConsumer will take care of skipping only functions inside + // the files that we have already processed. + CI.getFrontendOpts().SkipFunctionBodies = true; return WrapperFrontendAction::BeginInvocation(CI); } diff --git a/clang-tools-extra/clangd/index/Serialization.cpp b/clang-tools-extra/clangd/index/Serialization.cpp index 188a5cc1862d..90520fdc2cea 100644 --- a/clang-tools-extra/clangd/index/Serialization.cpp +++ b/clang-tools-extra/clangd/index/Serialization.cpp @@ -690,7 +690,7 @@ std::unique_ptr loadIndex(llvm::StringRef SymbolFilename, trace::Span OverallTracer("LoadIndex"); auto Buffer = llvm::MemoryBuffer::getFile(SymbolFilename); if (!Buffer) { - llvm::errs() << "Can't open " << SymbolFilename << "\n"; + elog("Can't open {0}", SymbolFilename); return nullptr; } @@ -707,7 +707,7 @@ std::unique_ptr loadIndex(llvm::StringRef SymbolFilename, if (I->Relations) Relations = std::move(*I->Relations); } else { - llvm::errs() << "Bad Index: " << llvm::toString(I.takeError()) << "\n"; + elog("Bad Index: {0}", I.takeError()); return nullptr; } } diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp index 8b2d40b3d389..269a2f564e24 100644 --- a/clang-tools-extra/clangd/index/SymbolCollector.cpp +++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp @@ -146,17 +146,6 @@ getTokenRange(SourceLocation TokLoc, const SourceManager &SM, CreatePosition(TokLoc.getLocWithOffset(TokenLength))}; } -bool shouldIndexFile(const SourceManager &SM, FileID FID, - const SymbolCollector::Options &Opts, - llvm::DenseMap *FilesToIndexCache) { - if (!Opts.FileFilter) - return true; - auto I = FilesToIndexCache->try_emplace(FID); - if (I.second) - I.first->second = Opts.FileFilter(SM, FID); - return I.first->second; -} - // Return the symbol location of the token at \p TokLoc. llvm::Optional getTokenLocation(SourceLocation TokLoc, const SourceManager &SM, @@ -185,8 +174,7 @@ getTokenLocation(SourceLocation TokLoc, const SourceManager &SM, bool isPreferredDeclaration(const NamedDecl &ND, index::SymbolRoleSet Roles) { const auto &SM = ND.getASTContext().getSourceManager(); return (Roles & static_cast(index::SymbolRole::Definition)) && - isa(&ND) && - !SM.isWrittenInMainFile(SM.getExpansionLoc(ND.getLocation())); + isa(&ND) && !isInsideMainFile(ND.getLocation(), SM); } RefKind toRefKind(index::SymbolRoleSet Roles) { @@ -410,7 +398,7 @@ bool SymbolCollector::handleMacroOccurence(const IdentifierInfo *Name, S.SymInfo = index::getSymbolInfoForMacro(*MI); std::string FileURI; // FIXME: use the result to filter out symbols. - shouldIndexFile(SM, SM.getFileID(Loc), Opts, &FilesToIndexCache); + shouldIndexFile(SM.getFileID(Loc)); if (auto DeclLoc = getTokenLocation(DefLoc, SM, Opts, PP->getLangOpts(), FileURI)) S.CanonicalDeclaration = *DeclLoc; @@ -540,7 +528,7 @@ void SymbolCollector::finish() { for (const auto &LocAndRole : It.second) { auto FileID = SM.getFileID(LocAndRole.first); // FIXME: use the result to filter out references. - shouldIndexFile(SM, FileID, Opts, &FilesToIndexCache); + shouldIndexFile(FileID); if (auto FileURI = GetURI(FileID)) { auto Range = getTokenRange(LocAndRole.first, SM, ASTCtx->getLangOpts()); @@ -590,7 +578,7 @@ const Symbol *SymbolCollector::addDeclaration(const NamedDecl &ND, SymbolID ID, auto Loc = findNameLoc(&ND); assert(Loc.isValid() && "Invalid source location for NamedDecl"); // FIXME: use the result to filter out symbols. - shouldIndexFile(SM, SM.getFileID(Loc), Opts, &FilesToIndexCache); + shouldIndexFile(SM.getFileID(Loc)); if (auto DeclLoc = getTokenLocation(Loc, SM, Opts, ASTCtx->getLangOpts(), FileURI)) S.CanonicalDeclaration = *DeclLoc; @@ -650,7 +638,7 @@ void SymbolCollector::addDefinition(const NamedDecl &ND, auto Loc = findNameLoc(&ND); const auto &SM = ND.getASTContext().getSourceManager(); // FIXME: use the result to filter out symbols. - shouldIndexFile(SM, SM.getFileID(Loc), Opts, &FilesToIndexCache); + shouldIndexFile(SM.getFileID(Loc)); if (auto DefLoc = getTokenLocation(Loc, SM, Opts, ASTCtx->getLangOpts(), FileURI)) S.Definition = *DefLoc; @@ -742,5 +730,14 @@ bool SymbolCollector::isDontIncludeMeHeader(llvm::StringRef Content) { return false; } +bool SymbolCollector::shouldIndexFile(FileID FID) { + if (!Opts.FileFilter) + return true; + auto I = FilesToIndexCache.try_emplace(FID); + if (I.second) + I.first->second = Opts.FileFilter(ASTCtx->getSourceManager(), FID); + return I.first->second; +} + } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/index/SymbolCollector.h b/clang-tools-extra/clangd/index/SymbolCollector.h index e97485ec418e..87acf3418677 100644 --- a/clang-tools-extra/clangd/index/SymbolCollector.h +++ b/clang-tools-extra/clangd/index/SymbolCollector.h @@ -112,6 +112,11 @@ class SymbolCollector : public index::IndexDataConsumer { RefSlab takeRefs() { return std::move(Refs).build(); } RelationSlab takeRelations() { return std::move(Relations).build(); } + /// Returns true if we are interested in references and declarations from \p + /// FID. If this function return false, bodies of functions inside those files + /// will be skipped to decrease indexing time. + bool shouldIndexFile(FileID FID); + void finish() override; private: diff --git a/clang-tools-extra/clangd/refactor/Rename.cpp b/clang-tools-extra/clangd/refactor/Rename.cpp index d54fae519140..b66eac4ee8da 100644 --- a/clang-tools-extra/clangd/refactor/Rename.cpp +++ b/clang-tools-extra/clangd/refactor/Rename.cpp @@ -104,8 +104,7 @@ llvm::Optional renamableWithinFile(const Decl &RenameDecl, auto &ASTCtx = RenameDecl.getASTContext(); const auto &SM = ASTCtx.getSourceManager(); bool MainFileIsHeader = ASTCtx.getLangOpts().IsHeaderFile; - bool DeclaredInMainFile = - SM.isWrittenInMainFile(SM.getExpansionLoc(RenameDecl.getLocation())); + bool DeclaredInMainFile = isInsideMainFile(RenameDecl.getBeginLoc(), SM); // If the symbol is declared in the main file (which is not a header), we // rename it. diff --git a/clang-tools-extra/clangd/refactor/Tweak.cpp b/clang-tools-extra/clangd/refactor/Tweak.cpp index a6d70dbd38c9..b80f75300ddc 100644 --- a/clang-tools-extra/clangd/refactor/Tweak.cpp +++ b/clang-tools-extra/clangd/refactor/Tweak.cpp @@ -40,7 +40,8 @@ void validateRegistry() { Tweak::Selection::Selection(ParsedAST &AST, unsigned RangeBegin, unsigned RangeEnd) - : AST(AST), ASTSelection(AST.getASTContext(), RangeBegin, RangeEnd) { + : AST(AST), SelectionBegin(RangeBegin), SelectionEnd(RangeEnd), + ASTSelection(AST.getASTContext(), RangeBegin, RangeEnd) { auto &SM = AST.getSourceManager(); Code = SM.getBufferData(SM.getMainFileID()); Cursor = SM.getComposedLoc(SM.getMainFileID(), RangeBegin); diff --git a/clang-tools-extra/clangd/refactor/Tweak.h b/clang-tools-extra/clangd/refactor/Tweak.h index 79e0f3eceee8..9b20d151589a 100644 --- a/clang-tools-extra/clangd/refactor/Tweak.h +++ b/clang-tools-extra/clangd/refactor/Tweak.h @@ -46,7 +46,12 @@ class Tweak { /// Parsed AST of the active file. ParsedAST &AST; /// A location of the cursor in the editor. + // FIXME: Cursor is redundant and should be removed SourceLocation Cursor; + /// The begin offset of the selection + unsigned SelectionBegin; + /// The end offset of the selection + unsigned SelectionEnd; /// The AST nodes that were selected. SelectionTree ASTSelection; // FIXME: provide a way to get sources and ASTs for other files. diff --git a/clang-tools-extra/clangd/refactor/tweaks/DumpAST.cpp b/clang-tools-extra/clangd/refactor/tweaks/DumpAST.cpp index 4bba9cec9d5d..985993a3d93b 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/DumpAST.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/DumpAST.cpp @@ -128,6 +128,11 @@ class DumpRecordLayout : public Tweak { TypeWithKeyword::getTagTypeKindName(Record->getTagKind())); } Intent intent() const override { return Info; } + // FIXME: this is interesting to most users. However: + // - triggering is too broad (e.g. triggers on comments within a class) + // - showMessage has inconsistent UX (e.g. newlines are stripped in VSCode) + // - the output itself is a bit hard to decipher. + bool hidden() const override { return true; } private: const RecordDecl *Record = nullptr; diff --git a/clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp b/clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp index 447110d3e90b..525c259b7a5d 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/ExtractVariable.cpp @@ -219,7 +219,8 @@ bool ExtractVariable::prepare(const Selection &Inputs) { const ASTContext &Ctx = Inputs.AST.getASTContext(); const SourceManager &SM = Inputs.AST.getSourceManager(); const SelectionTree::Node *N = Inputs.ASTSelection.commonAncestor(); - if (!N) + // we don't trigger on empty selections for now + if (!N || Inputs.SelectionBegin == Inputs.SelectionEnd) return false; Target = llvm::make_unique(N, SM, Ctx); return Target->isExtractable(); diff --git a/clang-tools-extra/clangd/test/Inputs/background-index/definition.jsonrpc b/clang-tools-extra/clangd/test/Inputs/background-index/definition.jsonrpc index 933e7791320e..de99072b6a4c 100644 --- a/clang-tools-extra/clangd/test/Inputs/background-index/definition.jsonrpc +++ b/clang-tools-extra/clangd/test/Inputs/background-index/definition.jsonrpc @@ -18,7 +18,7 @@ "uri": "file://DIRECTORY/bar.cpp", "languageId": "cpp", "version": 1, - "text": "#include \"foo.h\"\nint main(){\nreturn foo();\n}" + "text": "#include \"sub_dir/foo.h\"\nint main(){\nreturn foo();\n}" } } } diff --git a/clang-tools-extra/clangd/test/Inputs/background-index/foo.cpp b/clang-tools-extra/clangd/test/Inputs/background-index/foo.cpp index c42ca4d07374..21fc589166a4 100644 --- a/clang-tools-extra/clangd/test/Inputs/background-index/foo.cpp +++ b/clang-tools-extra/clangd/test/Inputs/background-index/foo.cpp @@ -1,2 +1,2 @@ -#include "foo.h" +#include "sub_dir/foo.h" int foo() { return 42; } diff --git a/clang-tools-extra/clangd/test/Inputs/background-index/sub_dir/compile_flags.txt b/clang-tools-extra/clangd/test/Inputs/background-index/sub_dir/compile_flags.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang-tools-extra/clangd/test/Inputs/background-index/foo.h b/clang-tools-extra/clangd/test/Inputs/background-index/sub_dir/foo.h similarity index 100% rename from clang-tools-extra/clangd/test/Inputs/background-index/foo.h rename to clang-tools-extra/clangd/test/Inputs/background-index/sub_dir/foo.h diff --git a/clang-tools-extra/clangd/test/background-index.test b/clang-tools-extra/clangd/test/background-index.test index eabca2bcaf76..57118f2159a6 100644 --- a/clang-tools-extra/clangd/test/background-index.test +++ b/clang-tools-extra/clangd/test/background-index.test @@ -5,7 +5,8 @@ # RUN: rm -rf %t # RUN: cp -r %S/Inputs/background-index %t # Need to embed the correct temp path in the actual JSON-RPC requests. -# RUN: sed -i -e "s|DIRECTORY|%t|" %t/* +# RUN: sed -i -e "s|DIRECTORY|%t|" %t/definition.jsonrpc +# RUN: sed -i -e "s|DIRECTORY|%t|" %t/compile_commands.json # We're editing bar.cpp, which includes foo.h. # foo() is declared in foo.h and defined in foo.cpp. @@ -14,6 +15,7 @@ # Test that the index is writing files in the expected location. # RUN: ls %t/.clangd/index/foo.cpp.*.idx +# RUN: ls %t/sub_dir/.clangd/index/foo.h.*.idx # Test the index is read from disk: delete code and restart clangd. # RUN: rm %t/foo.cpp diff --git a/clang-tools-extra/clangd/test/log.test b/clang-tools-extra/clangd/test/log.test new file mode 100644 index 000000000000..7f17f072fd89 --- /dev/null +++ b/clang-tools-extra/clangd/test/log.test @@ -0,0 +1,9 @@ +# RUN: not env CLANGD_FLAGS=-index-file=no-such-index clangd -lit-test &1 >/dev/null | FileCheck %s +CHECK: I[{{.*}}] clangd version {{.*}} +CHECK: Working directory: {{.*}} +CHECK: argv[0]: clangd +CHECK: argv[1]: -lit-test +CHECK: CLANGD_FLAGS: -index-file=no-such-index +CHECK: E[{{.*}}] Can't open no-such-index +CHECK: Starting LSP over stdin/stdout + diff --git a/clang-tools-extra/clangd/test/system-include-extractor.test b/clang-tools-extra/clangd/test/system-include-extractor.test index 8f99db9122a6..9f1a3de48bc5 100644 --- a/clang-tools-extra/clangd/test/system-include-extractor.test +++ b/clang-tools-extra/clangd/test/system-include-extractor.test @@ -8,7 +8,7 @@ # RUN: echo 'echo -e "#include <...> search starts here:\r" >&2' >> %t.dir/my_driver.sh # RUN: echo 'echo %t.dir/my/dir/ >&2' >> %t.dir/my_driver.sh # RUN: echo 'echo %t.dir/my/dir2/ >&2' >> %t.dir/my_driver.sh -# RUN: echo 'echo End of search list. >&2' >> %t.dir/my_driver.sh +# RUN: echo 'echo -e "End of search list.\r" >&2' >> %t.dir/my_driver.sh # RUN: chmod +x %t.dir/my_driver.sh # Create header files my/dir/a.h and my/dir2/b.h diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp index 5db3d5c23065..7336daa253ad 100644 --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -22,6 +22,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" #include "llvm/Support/Program.h" #include "llvm/Support/Signals.h" #include "llvm/Support/TargetSelect.h" @@ -35,129 +36,164 @@ namespace clang { namespace clangd { +namespace { + +using llvm::cl::cat; +using llvm::cl::CommaSeparated; +using llvm::cl::desc; +using llvm::cl::Hidden; +using llvm::cl::init; +using llvm::cl::list; +using llvm::cl::opt; +using llvm::cl::OptionCategory; +using llvm::cl::values; + +// All flags must be placed in a category, or they will be shown neither in +// --help, nor --help-hidden! +OptionCategory CompileCommands("clangd compilation flags options"); +OptionCategory Features("clangd feature options"); +OptionCategory Misc("clangd miscellaneous options"); +OptionCategory Protocol("clangd protocol and logging options"); +const OptionCategory *ClangdCategories[] = {&Features, &Protocol, + &CompileCommands, &Misc}; -static llvm::cl::opt CompileCommandsDir( +enum CompileArgsFrom { LSPCompileArgs, FilesystemCompileArgs }; +opt CompileArgsFrom{ + "compile_args_from", + cat(CompileCommands), + desc("The source of compile commands"), + values(clEnumValN(LSPCompileArgs, "lsp", + "All compile commands come from LSP and " + "'compile_commands.json' files are ignored"), + clEnumValN(FilesystemCompileArgs, "filesystem", + "All compile commands come from the " + "'compile_commands.json' files")), + init(FilesystemCompileArgs), + Hidden, +}; + +opt CompileCommandsDir{ "compile-commands-dir", - llvm::cl::desc("Specify a path to look for compile_commands.json. If path " - "is invalid, clangd will look in the current directory and " - "parent paths of each source file")); + cat(CompileCommands), + desc("Specify a path to look for compile_commands.json. If path " + "is invalid, clangd will look in the current directory and " + "parent paths of each source file"), +}; -static llvm::cl::opt - WorkerThreadsCount("j", - llvm::cl::desc("Number of async workers used by clangd"), - llvm::cl::init(getDefaultAsyncThreadsCount())); +opt ResourceDir{ + "resource-dir", + cat(CompileCommands), + desc("Directory for system clang headers"), + init(""), + Hidden, +}; -// FIXME: also support "plain" style where signatures are always omitted. -enum CompletionStyleFlag { Detailed, Bundled }; -static llvm::cl::opt CompletionStyle( - "completion-style", - llvm::cl::desc("Granularity of code completion suggestions"), - llvm::cl::values( - clEnumValN(Detailed, "detailed", - "One completion item for each semantically distinct " - "completion, with full type information"), - clEnumValN(Bundled, "bundled", - "Similar completion items (e.g. function overloads) are " - "combined. Type information shown where possible"))); +list QueryDriverGlobs{ + "query-driver", + cat(CompileCommands), + desc( + "Comma separated list of globs for white-listing gcc-compatible " + "drivers that are safe to execute. Drivers matching any of these globs " + "will be used to extract system includes. e.g. " + "/usr/bin/**/clang-*,/path/to/repo/**/g++-*"), + CommaSeparated, +}; // FIXME: Flags are the wrong mechanism for user preferences. // We should probably read a dotfile or similar. -static llvm::cl::opt IncludeIneligibleResults( - "include-ineligible-results", - llvm::cl::desc( - "Include ineligible completion results (e.g. private members)"), - llvm::cl::init(CodeCompleteOptions().IncludeIneligibleResults), - llvm::cl::Hidden); - -static llvm::cl::opt InputStyle( - "input-style", llvm::cl::desc("Input JSON stream encoding"), - llvm::cl::values( - clEnumValN(JSONStreamStyle::Standard, "standard", "usual LSP protocol"), - clEnumValN(JSONStreamStyle::Delimited, "delimited", - "messages delimited by --- lines, with # comment support")), - llvm::cl::init(JSONStreamStyle::Standard), llvm::cl::Hidden); - -static llvm::cl::opt - PrettyPrint("pretty", llvm::cl::desc("Pretty-print JSON output"), - llvm::cl::init(false)); - -static llvm::cl::opt LogLevel( - "log", llvm::cl::desc("Verbosity of log messages written to stderr"), - llvm::cl::values(clEnumValN(Logger::Error, "error", "Error messages only"), - clEnumValN(Logger::Info, "info", - "High level execution tracing"), - clEnumValN(Logger::Debug, "verbose", "Low level details")), - llvm::cl::init(Logger::Info)); - -static llvm::cl::opt - Test("lit-test", - llvm::cl::desc("Abbreviation for -input-style=delimited -pretty -sync " - "-enable-test-scheme -log=verbose." - "Intended to simplify lit tests"), - llvm::cl::init(false), llvm::cl::Hidden); - -static llvm::cl::opt EnableTestScheme( - "enable-test-uri-scheme", - llvm::cl::desc("Enable 'test:' URI scheme. Only use in lit tests"), - llvm::cl::init(false), llvm::cl::Hidden); +opt AllScopesCompletion{ + "all-scopes-completion", + cat(Features), + desc("If set to true, code completion will include index symbols that are " + "not defined in the scopes (e.g. " + "namespaces) visible from the code completion point. Such completions " + "can insert scope qualifiers"), + init(true), +}; -enum PCHStorageFlag { Disk, Memory }; -static llvm::cl::opt PCHStorage( - "pch-storage", - llvm::cl::desc("Storing PCHs in memory increases memory usages, but may " - "improve performance"), - llvm::cl::values( - clEnumValN(PCHStorageFlag::Disk, "disk", "store PCHs on disk"), - clEnumValN(PCHStorageFlag::Memory, "memory", "store PCHs in memory")), - llvm::cl::init(PCHStorageFlag::Disk)); +opt ShowOrigins{ + "debug-origin", + cat(Features), + desc("Show origins of completion items"), + init(CodeCompleteOptions().ShowOrigins), + Hidden, +}; -static llvm::cl::opt LimitResults( - "limit-results", - llvm::cl::desc("Limit the number of results returned by clangd. " - "0 means no limit (default=100)"), - llvm::cl::init(100)); +opt EnableBackgroundIndex{ + "background-index", + cat(Features), + desc("Index project code in the background and persist index on disk."), + init(true), +}; -static llvm::cl::opt - Sync("sync", llvm::cl::desc("Parse on main thread. If set, -j is ignored"), - llvm::cl::init(false), llvm::cl::Hidden); +opt EnableClangTidy{ + "clang-tidy", + cat(Features), + desc("Enable clang-tidy diagnostics"), + init(true), +}; -static llvm::cl::opt - ResourceDir("resource-dir", - llvm::cl::desc("Directory for system clang headers"), - llvm::cl::init(""), llvm::cl::Hidden); +opt ClangTidyChecks{ + "clang-tidy-checks", + cat(Features), + desc("List of clang-tidy checks to run (this will override " + ".clang-tidy files). Only meaningful when -clang-tidy flag is on"), + init(""), +}; -static llvm::cl::opt InputMirrorFile( - "input-mirror-file", - llvm::cl::desc( - "Mirror all LSP input to the specified file. Useful for debugging"), - llvm::cl::init(""), llvm::cl::Hidden); +opt CodeCompletionParse{ + "completion-parse", + cat(Features), + desc("Whether the clang-parser is used for code-completion"), + values(clEnumValN(CodeCompleteOptions::AlwaysParse, "always", + "Block until the parser can be used"), + clEnumValN(CodeCompleteOptions::ParseIfReady, "auto", + "Use text-based completion if the parser " + "is not ready"), + clEnumValN(CodeCompleteOptions::NeverParse, "never", + "Always used text-based completion")), + init(CodeCompleteOptions().RunParser), + Hidden, +}; -static llvm::cl::opt EnableIndex( - "index", - llvm::cl::desc( - "Enable index-based features. By default, clangd maintains an index " - "built from symbols in opened files. Global index support needs to " - "enabled separatedly"), - llvm::cl::init(true), llvm::cl::Hidden); +// FIXME: also support "plain" style where signatures are always omitted. +enum CompletionStyleFlag { Detailed, Bundled }; +opt CompletionStyle{ + "completion-style", + cat(Features), + desc("Granularity of code completion suggestions"), + values(clEnumValN(Detailed, "detailed", + "One completion item for each semantically distinct " + "completion, with full type information"), + clEnumValN(Bundled, "bundled", + "Similar completion items (e.g. function overloads) are " + "combined. Type information shown where possible")), +}; -static llvm::cl::opt AllScopesCompletion( - "all-scopes-completion", - llvm::cl::desc( - "If set to true, code completion will include index symbols that are " - "not defined in the scopes (e.g. " - "namespaces) visible from the code completion point. Such completions " - "can insert scope qualifiers"), - llvm::cl::init(true)); - -static llvm::cl::opt ShowOrigins( - "debug-origin", llvm::cl::desc("Show origins of completion items"), - llvm::cl::init(CodeCompleteOptions().ShowOrigins), llvm::cl::Hidden); - -static llvm::cl::opt HeaderInsertion( +opt FallbackStyle{ + "fallback-style", + cat(Features), + desc("clang-format style to apply by default when " + "no .clang-format file is found"), + init(clang::format::DefaultFallbackStyle), +}; + +opt EnableFunctionArgSnippets{ + "function-arg-placeholders", + cat(Features), + desc("When disabled, completions contain only parentheses for " + "function calls. When enabled, completions also contain " + "placeholders for method parameters"), + init(CodeCompleteOptions().EnableFunctionArgSnippets), + Hidden, +}; + +opt HeaderInsertion{ "header-insertion", - llvm::cl::desc("Add #include directives when accepting code completions"), - llvm::cl::init(CodeCompleteOptions().InsertIncludes), - llvm::cl::values( + cat(Features), + desc("Add #include directives when accepting code completions"), + init(CodeCompleteOptions().InsertIncludes), + values( clEnumValN(CodeCompleteOptions::IWYU, "iwyu", "Include what you use. " "Insert the owning header for top-level symbols, unless the " @@ -165,118 +201,175 @@ static llvm::cl::opt HeaderInsertion( "forward-declared"), clEnumValN( CodeCompleteOptions::NeverInsert, "never", - "Never insert #include directives as part of code completion"))); + "Never insert #include directives as part of code completion")), +}; -static llvm::cl::opt HeaderInsertionDecorators( +opt HeaderInsertionDecorators{ "header-insertion-decorators", - llvm::cl::desc("Prepend a circular dot or space before the completion " - "label, depending on whether " - "an include line will be inserted or not"), - llvm::cl::init(true)); + cat(Features), + desc("Prepend a circular dot or space before the completion " + "label, depending on whether " + "an include line will be inserted or not"), + init(true), +}; + +opt HiddenFeatures{ + "hidden-features", + cat(Features), + desc("Enable hidden features mostly useful to clangd developers"), + init(false), + Hidden, +}; + +opt IncludeIneligibleResults{ + "include-ineligible-results", + cat(Features), + desc("Include ineligible completion results (e.g. private members)"), + init(CodeCompleteOptions().IncludeIneligibleResults), + Hidden, +}; + +opt EnableIndex{ + "index", + cat(Features), + desc("Enable index-based features. By default, clangd maintains an index " + "built from symbols in opened files. Global index support needs to " + "enabled separatedly"), + init(true), + Hidden, +}; + +opt LimitResults{ + "limit-results", + cat(Features), + desc("Limit the number of results returned by clangd. " + "0 means no limit (default=100)"), + init(100), +}; + +opt SuggestMissingIncludes{ + "suggest-missing-includes", + cat(Features), + desc("Attempts to fix diagnostic errors caused by missing " + "includes using index"), + init(true), +}; + +list TweakList{ + "tweaks", + cat(Features), + desc("Specify a list of Tweaks to enable (only for clangd developers)."), + Hidden, + CommaSeparated, +}; -static llvm::cl::opt IndexFile( +opt WorkerThreadsCount{ + "j", + cat(Misc), + desc("Number of async workers used by clangd. Background index also " + "uses this many workers."), + init(getDefaultAsyncThreadsCount()), +}; + +opt IndexFile{ "index-file", - llvm::cl::desc( + cat(Misc), + desc( "Index file to build the static index. The file must have been created " "by a compatible clangd-indexer\n" "WARNING: This option is experimental only, and will be removed " "eventually. Don't rely on it"), - llvm::cl::init(""), llvm::cl::Hidden); + init(""), + Hidden, +}; -static llvm::cl::opt EnableBackgroundIndex( - "background-index", - llvm::cl::desc( - "Index project code in the background and persist index on disk. " - "Experimental"), - llvm::cl::init(true)); +opt Test{ + "lit-test", + cat(Misc), + desc("Abbreviation for -input-style=delimited -pretty -sync " + "-enable-test-scheme -log=verbose. " + "Intended to simplify lit tests"), + init(false), + Hidden, +}; -enum CompileArgsFrom { LSPCompileArgs, FilesystemCompileArgs }; -static llvm::cl::opt CompileArgsFrom( - "compile_args_from", llvm::cl::desc("The source of compile commands"), - llvm::cl::values(clEnumValN(LSPCompileArgs, "lsp", - "All compile commands come from LSP and " - "'compile_commands.json' files are ignored"), - clEnumValN(FilesystemCompileArgs, "filesystem", - "All compile commands come from the " - "'compile_commands.json' files")), - llvm::cl::init(FilesystemCompileArgs), llvm::cl::Hidden); - -static llvm::cl::opt EnableFunctionArgSnippets( - "function-arg-placeholders", - llvm::cl::desc("When disabled, completions contain only parentheses for " - "function calls. When enabled, completions also contain " - "placeholders for method parameters"), - llvm::cl::init(CodeCompleteOptions().EnableFunctionArgSnippets), - llvm::cl::Hidden); +enum PCHStorageFlag { Disk, Memory }; +opt PCHStorage{ + "pch-storage", + cat(Misc), + desc("Storing PCHs in memory increases memory usages, but may " + "improve performance"), + values( + clEnumValN(PCHStorageFlag::Disk, "disk", "store PCHs on disk"), + clEnumValN(PCHStorageFlag::Memory, "memory", "store PCHs in memory")), + init(PCHStorageFlag::Disk), +}; -static llvm::cl::opt ClangTidyChecks( - "clang-tidy-checks", - llvm::cl::desc( - "List of clang-tidy checks to run (this will override " - ".clang-tidy files). Only meaningful when -clang-tidy flag is on"), - llvm::cl::init("")); - -static llvm::cl::opt - EnableClangTidy("clang-tidy", - llvm::cl::desc("Enable clang-tidy diagnostics"), - llvm::cl::init(true)); - -static llvm::cl::opt - FallbackStyle("fallback-style", - llvm::cl::desc("clang-format style to apply by default when " - "no .clang-format file is found"), - llvm::cl::init(clang::format::DefaultFallbackStyle)); - -static llvm::cl::opt SuggestMissingIncludes( - "suggest-missing-includes", - llvm::cl::desc("Attempts to fix diagnostic errors caused by missing " - "includes using index"), - llvm::cl::init(true)); +opt Sync{ + "sync", + cat(Misc), + desc("Handle client requests on main thread. Background index still uses " + "its own thread."), + init(false), + Hidden, +}; -static llvm::cl::opt ForceOffsetEncoding( - "offset-encoding", - llvm::cl::desc("Force the offsetEncoding used for character positions. " - "This bypasses negotiation via client capabilities"), - llvm::cl::values(clEnumValN(OffsetEncoding::UTF8, "utf-8", - "Offsets are in UTF-8 bytes"), - clEnumValN(OffsetEncoding::UTF16, "utf-16", - "Offsets are in UTF-16 code units")), - llvm::cl::init(OffsetEncoding::UnsupportedEncoding)); - -static llvm::cl::opt - CodeCompletionParse( - "completion-parse", - llvm::cl::desc("Whether the clang-parser is used for code-completion"), - llvm::cl::values(clEnumValN(CodeCompleteOptions::AlwaysParse, "always", - "Block until the parser can be used"), - clEnumValN(CodeCompleteOptions::ParseIfReady, "auto", - "Use text-based completion if the parser " - "is not ready"), - clEnumValN(CodeCompleteOptions::NeverParse, "never", - "Always used text-based completion")), - llvm::cl::init(CodeCompleteOptions().RunParser), llvm::cl::Hidden); - -static llvm::cl::opt HiddenFeatures( - "hidden-features", - llvm::cl::desc("Enable hidden features mostly useful to clangd developers"), - llvm::cl::init(false), llvm::cl::Hidden); +opt InputStyle{ + "input-style", + cat(Protocol), + desc("Input JSON stream encoding"), + values( + clEnumValN(JSONStreamStyle::Standard, "standard", "usual LSP protocol"), + clEnumValN(JSONStreamStyle::Delimited, "delimited", + "messages delimited by --- lines, with # comment support")), + init(JSONStreamStyle::Standard), + Hidden, +}; -static llvm::cl::list QueryDriverGlobs( - "query-driver", - llvm::cl::desc( - "Comma separated list of globs for white-listing gcc-compatible " - "drivers that are safe to execute. Drivers matching any of these globs " - "will be used to extract system includes. e.g. " - "/usr/bin/**/clang-*,/path/to/repo/**/g++-*"), - llvm::cl::CommaSeparated); +opt EnableTestScheme{ + "enable-test-uri-scheme", + cat(Protocol), + desc("Enable 'test:' URI scheme. Only use in lit tests"), + init(false), + Hidden, +}; -static llvm::cl::list TweakList( - "tweaks", - llvm::cl::desc( - "Specify a list of Tweaks to enable (only for clangd developers)."), - llvm::cl::Hidden, llvm::cl::CommaSeparated); +opt InputMirrorFile{ + "input-mirror-file", + cat(Protocol), + desc("Mirror all LSP input to the specified file. Useful for debugging"), + init(""), + Hidden, +}; -namespace { +opt LogLevel{ + "log", + cat(Protocol), + desc("Verbosity of log messages written to stderr"), + values(clEnumValN(Logger::Error, "error", "Error messages only"), + clEnumValN(Logger::Info, "info", "High level execution tracing"), + clEnumValN(Logger::Debug, "verbose", "Low level details")), + init(Logger::Info), +}; + +opt ForceOffsetEncoding{ + "offset-encoding", + cat(Protocol), + desc("Force the offsetEncoding used for character positions. " + "This bypasses negotiation via client capabilities"), + values( + clEnumValN(OffsetEncoding::UTF8, "utf-8", "Offsets are in UTF-8 bytes"), + clEnumValN(OffsetEncoding::UTF16, "utf-16", + "Offsets are in UTF-16 code units")), + init(OffsetEncoding::UnsupportedEncoding), +}; + +opt PrettyPrint{ + "pretty", + cat(Protocol), + desc("Pretty-print JSON output"), + init(false), +}; /// \brief Supports a test URI scheme with relaxed constraints for lit tests. /// The path in a test URI will be combined with a platform-specific fake @@ -342,14 +435,19 @@ int main(int argc, char *argv[]) { llvm::cl::SetVersionPrinter([](llvm::raw_ostream &OS) { OS << clang::getClangToolFullVersion("clangd") << "\n"; }); - llvm::cl::ParseCommandLineOptions( - argc, argv, - "clangd is a language server that provides IDE-like features to editors. " - "\n\nIt should be used via an editor plugin rather than invoked " - "directly. " - "For more information, see:" - "\n\thttps://clang.llvm.org/extra/clangd.html" - "\n\thttps://microsoft.github.io/language-server-protocol/"); + const char *FlagsEnvVar = "CLANGD_FLAGS"; + const char *Overview = + R"(clangd is a language server that provides IDE-like features to editors. + +It should be used via an editor plugin rather than invoked directly. For more information, see: + https://clang.llvm.org/extra/clangd/ + https://microsoft.github.io/language-server-protocol/ + +clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment variable. +)"; + llvm::cl::HideUnrelatedOptions(ClangdCategories); + llvm::cl::ParseCommandLineOptions(argc, argv, Overview, + /*Errs=*/nullptr, FlagsEnvVar); if (Test) { Sync = true; InputStyle = JSONStreamStyle::Delimited; @@ -414,11 +512,29 @@ int main(int argc, char *argv[]) { if (Tracer) TracingSession.emplace(*Tracer); + // If a user ran `clangd` in a terminal without redirecting anything, + // it's somewhat likely they're confused about how to use clangd. + // Show them the help overview, which explains. + if (llvm::outs().is_displayed() && llvm::errs().is_displayed()) + llvm::errs() << Overview << "\n"; // Use buffered stream to stderr (we still flush each log message). Unbuffered // stream can cause significant (non-deterministic) latency for the logger. llvm::errs().SetBuffered(); StreamLogger Logger(llvm::errs(), LogLevel); LoggingSession LoggingSession(Logger); + // Write some initial logs before we start doing any real work. + log("{0}", clang::getClangToolFullVersion("clangd")); + { + SmallString<128> CWD; + if (auto Err = llvm::sys::fs::current_path(CWD)) + log("Working directory unknown: {0}", Err.message()); + else + log("Working directory: {0}", CWD); + } + for (int I = 0; I < argc; ++I) + log("argv[{0}]: {1}", I, argv[I]); + if (auto EnvFlags = llvm::sys::Process::GetEnv(FlagsEnvVar)) + log("{0}: {1}", FlagsEnvVar, *EnvFlags); // If --compile-commands-dir arg was invoked, check value and override default // path. @@ -497,12 +613,14 @@ int main(int argc, char *argv[]) { std::unique_ptr TransportLayer; if (getenv("CLANGD_AS_XPC_SERVICE")) { #if CLANGD_BUILD_XPC + log("Starting LSP over XPC service"); TransportLayer = newXPCTransport(); #else llvm::errs() << "This clangd binary wasn't built with XPC support.\n"; return (int)ErrorResultCode::CantRunAsXPCService; #endif } else { + log("Starting LSP over stdin/stdout"); TransportLayer = newJSONTransport( stdin, llvm::outs(), InputMirrorStream ? InputMirrorStream.getPointer() : nullptr, diff --git a/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp b/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp index 79e081bd6789..0401aeb19231 100644 --- a/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp +++ b/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp @@ -211,7 +211,7 @@ TEST_F(BackgroundIndexTest, ShardStorageTest) { OverlayCDB CDB(/*Base=*/nullptr); BackgroundIndex Idx(Context::empty(), FS, CDB, [&](llvm::StringRef) { return &MSS; }); - CDB.setCompileCommand(testPath("root"), Cmd); + CDB.setCompileCommand(testPath("root/A.cc"), Cmd); ASSERT_TRUE(Idx.blockUntilIdleForTest()); } EXPECT_EQ(CacheHits, 2U); // Check both A.cc and A.h loaded from cache. @@ -335,7 +335,7 @@ TEST_F(BackgroundIndexTest, ShardStorageLoad) { OverlayCDB CDB(/*Base=*/nullptr); BackgroundIndex Idx(Context::empty(), FS, CDB, [&](llvm::StringRef) { return &MSS; }); - CDB.setCompileCommand(testPath("root"), Cmd); + CDB.setCompileCommand(testPath("root/A.cc"), Cmd); ASSERT_TRUE(Idx.blockUntilIdleForTest()); } EXPECT_EQ(CacheHits, 2U); // Check both A.cc and A.h loaded from cache. @@ -353,7 +353,7 @@ TEST_F(BackgroundIndexTest, ShardStorageLoad) { OverlayCDB CDB(/*Base=*/nullptr); BackgroundIndex Idx(Context::empty(), FS, CDB, [&](llvm::StringRef) { return &MSS; }); - CDB.setCompileCommand(testPath("root"), Cmd); + CDB.setCompileCommand(testPath("root/A.cc"), Cmd); ASSERT_TRUE(Idx.blockUntilIdleForTest()); } EXPECT_EQ(CacheHits, 2U); // Check both A.cc and A.h loaded from cache. @@ -621,8 +621,8 @@ TEST_F(BackgroundIndexRebuilderTest, IndexingTUs) { TEST_F(BackgroundIndexRebuilderTest, LoadingShards) { Rebuilder.startLoading(); - Rebuilder.loadedTU(); - Rebuilder.loadedTU(); + Rebuilder.loadedShard(10); + Rebuilder.loadedShard(20); EXPECT_TRUE(checkRebuild([&] { Rebuilder.doneLoading(); })); // No rebuild for no shards. @@ -631,11 +631,11 @@ TEST_F(BackgroundIndexRebuilderTest, LoadingShards) { // Loads can overlap. Rebuilder.startLoading(); - Rebuilder.loadedTU(); + Rebuilder.loadedShard(1); Rebuilder.startLoading(); - Rebuilder.loadedTU(); + Rebuilder.loadedShard(1); EXPECT_FALSE(checkRebuild([&] { Rebuilder.doneLoading(); })); - Rebuilder.loadedTU(); + Rebuilder.loadedShard(1); EXPECT_TRUE(checkRebuild([&] { Rebuilder.doneLoading(); })); // No rebuilding for indexed files while loading. diff --git a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp index 71aa148d6b62..2089c89e0664 100644 --- a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp +++ b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp @@ -797,6 +797,27 @@ namespace c { "Add include \"x.h\" for symbol a::X"))))); } +TEST(IncludeFixerTest, NoCrashOnTemplateInstantiations) { + Annotations Test(R"cpp( + template struct Templ { + template + typename U::type operator=(const U &); + }; + + struct A { + Templ s; + A() { [[a]]; } // this caused crashes if we compute scopes lazily. + }; + )cpp"); + + auto TU = TestTU::withCode(Test.code()); + auto Index = buildIndexWithSymbol({}); + TU.ExternalIndex = Index.get(); + + EXPECT_THAT(TU.build().getDiagnostics(), + ElementsAre(Diag(Test.range(), "use of undeclared identifier 'a'"))); +} + TEST(DiagsInHeaders, DiagInsideHeader) { Annotations Main(R"cpp( #include [["a.h"]] @@ -907,7 +928,6 @@ TEST(DiagsInHeaders, OnlyErrorOrFatal) { int x = 5/0;)cpp"); TestTU TU = TestTU::withCode(Main.code()); TU.AdditionalFiles = {{"a.h", Header.code()}}; - auto diags = TU.build().getDiagnostics(); EXPECT_THAT(TU.build().getDiagnostics(), UnorderedElementsAre(AllOf( Diag(Main.range(), "in included file: C++ requires " @@ -915,6 +935,28 @@ TEST(DiagsInHeaders, OnlyErrorOrFatal) { WithNote(Diag(Header.range(), "error occurred here"))))); } +TEST(IgnoreDiags, FromNonWrittenSources) { + Annotations Main(R"cpp( + #include [["a.h"]] + void foo() {})cpp"); + Annotations Header(R"cpp( + int x = 5/0; + int b = [[FOO]];)cpp"); + TestTU TU = TestTU::withCode(Main.code()); + TU.AdditionalFiles = {{"a.h", Header.code()}}; + TU.ExtraArgs = {"-DFOO=NOOO"}; + EXPECT_THAT(TU.build().getDiagnostics(), UnorderedElementsAre()); +} + +TEST(IgnoreDiags, FromNonWrittenInclude) { + TestTU TU = TestTU::withCode(""); + TU.ExtraArgs.push_back("--include=a.h"); + TU.AdditionalFiles = {{"a.h", "void main();"}}; + // The diagnostic "main must return int" is from the header, we don't attempt + // to render it in the main file as there is no written location there. + EXPECT_THAT(TU.build().getDiagnostics(), UnorderedElementsAre()); +} + } // namespace } // namespace clangd diff --git a/clang-tools-extra/clangd/unittests/FormattedStringTests.cpp b/clang-tools-extra/clangd/unittests/FormattedStringTests.cpp index da19f890dadb..e8077563df1a 100644 --- a/clang-tools-extra/clangd/unittests/FormattedStringTests.cpp +++ b/clang-tools-extra/clangd/unittests/FormattedStringTests.cpp @@ -72,7 +72,7 @@ after)md"; S.appendText("baz"); EXPECT_EQ(S.renderAsPlainText(), "foo bar baz"); - EXPECT_EQ(S.renderAsMarkdown(), "foo`bar`baz"); + EXPECT_EQ(S.renderAsMarkdown(), "foo `bar` baz"); } TEST(FormattedString, Escaping) { @@ -158,6 +158,42 @@ TEST(FormattedString, Escaping) { "`````\n"); } +TEST(FormattedString, MarkdownWhitespace) { + // Whitespace should be added as separators between blocks. + FormattedString S; + S.appendText("foo"); + S.appendText("bar"); + EXPECT_EQ(S.renderAsMarkdown(), "foo bar"); + + S = FormattedString(); + S.appendInlineCode("foo"); + S.appendInlineCode("bar"); + EXPECT_EQ(S.renderAsMarkdown(), "`foo` `bar`"); + + // However, we don't want to add any extra whitespace. + S = FormattedString(); + S.appendText("foo "); + S.appendInlineCode("bar"); + EXPECT_EQ(S.renderAsMarkdown(), "foo `bar`"); + + S = FormattedString(); + S.appendText("foo\n"); + S.appendInlineCode("bar"); + EXPECT_EQ(S.renderAsMarkdown(), "foo\n`bar`"); + + S = FormattedString(); + S.appendInlineCode("foo"); + S.appendText(" bar"); + EXPECT_EQ(S.renderAsMarkdown(), "`foo` bar"); + + S = FormattedString(); + S.appendText("foo"); + S.appendCodeBlock("bar"); + S.appendText("baz"); + EXPECT_EQ(S.renderAsMarkdown(), "foo\n```cpp\nbar\n```\nbaz"); +} + + } // namespace } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp b/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp index 3436e63e3032..d535532ada71 100644 --- a/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp +++ b/clang-tools-extra/clangd/unittests/GlobalCompilationDatabaseTests.cpp @@ -10,6 +10,7 @@ #include "Path.h" #include "TestFS.h" +#include "clang/Tooling/CompilationDatabase.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" @@ -31,6 +32,7 @@ using ::testing::AllOf; using ::testing::Contains; using ::testing::ElementsAre; using ::testing::EndsWith; +using ::testing::HasSubstr; using ::testing::IsEmpty; using ::testing::Not; using ::testing::StartsWith; @@ -247,9 +249,10 @@ TEST(GlobalCompilationDatabaseTest, DiscoveryWithNestedCDBs) { }); File = FS.Root; - llvm::sys::path::append(File, "a.cc"); + llvm::sys::path::append(File, "build", "..", "a.cc"); DB.getCompileCommand(File.str()); - EXPECT_THAT(DiscoveredFiles, UnorderedElementsAre(EndsWith("a.cc"))); + EXPECT_THAT(DiscoveredFiles, UnorderedElementsAre(AllOf( + EndsWith("a.cc"), Not(HasSubstr(".."))))); DiscoveredFiles.clear(); File = FS.Root; @@ -282,6 +285,27 @@ TEST(GlobalCompilationDatabaseTest, DiscoveryWithNestedCDBs) { } } +TEST(GlobalCompilationDatabaseTest, NonCanonicalFilenames) { + OverlayCDB DB(nullptr); + std::vector DiscoveredFiles; + auto Sub = + DB.watch([&DiscoveredFiles](const std::vector Changes) { + DiscoveredFiles = Changes; + }); + + llvm::SmallString<128> Root(testRoot()); + llvm::sys::path::append(Root, "build", "..", "a.cc"); + DB.setCompileCommand(Root.str(), tooling::CompileCommand()); + EXPECT_THAT(DiscoveredFiles, UnorderedElementsAre(testPath("a.cc"))); + DiscoveredFiles.clear(); + + llvm::SmallString<128> File(testRoot()); + llvm::sys::path::append(File, "blabla", "..", "a.cc"); + + EXPECT_TRUE(DB.getCompileCommand(File)); + EXPECT_TRUE(DB.getProjectInfo(File)); +} + } // namespace } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp b/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp index 29eda85bc458..47d1f802cb7d 100644 --- a/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp +++ b/clang-tools-extra/clangd/unittests/SourceCodeTests.cpp @@ -422,6 +422,36 @@ TEST(SourceCodeTests, GetMacros) { EXPECT_THAT(*Result, MacroName("MACRO")); } +TEST(SourceCodeTests, IsInsideMainFile){ + TestTU TU; + TU.HeaderCode = R"cpp( + #define DEFINE_CLASS(X) class X {}; + #define DEFINE_YY DEFINE_CLASS(YY) + + class Header1 {}; + DEFINE_CLASS(Header2) + class Header {}; + )cpp"; + TU.Code = R"cpp( + class Main1 {}; + DEFINE_CLASS(Main2) + DEFINE_YY + class Main {}; + )cpp"; + TU.ExtraArgs.push_back("-DHeader=Header3"); + TU.ExtraArgs.push_back("-DMain=Main3"); + auto AST = TU.build(); + const auto& SM = AST.getSourceManager(); + auto DeclLoc = [&AST](llvm::StringRef Name) { + return findDecl(AST, Name).getLocation(); + }; + for (const auto *HeaderDecl : {"Header1", "Header2", "Header3"}) + EXPECT_FALSE(isInsideMainFile(DeclLoc(HeaderDecl), SM)); + + for (const auto *MainDecl : {"Main1", "Main2", "Main3", "YY"}) + EXPECT_TRUE(isInsideMainFile(DeclLoc(MainDecl), SM)); +} + // Test for functions toHalfOpenFileRange and getHalfOpenFileRange TEST(SourceCodeTests, HalfOpenFileRange) { // Each marked range should be the file range of the decl with the same name @@ -430,15 +460,22 @@ TEST(SourceCodeTests, HalfOpenFileRange) { #define FOO(X, Y) int Y = ++X #define BAR(X) X + 1 #define ECHO(X) X + + #define BUZZ BAZZ(ADD) + #define BAZZ(m) m(1) + #define ADD(a) int f = a + 1; template class P {}; - void f() { + + int main() { $a[[P>>>> a]]; $b[[int b = 1]]; $c[[FOO(b, c)]]; $d[[FOO(BAR(BAR(b)), d)]]; // FIXME: We might want to select everything inside the outer ECHO. ECHO(ECHO($e[[int) ECHO(e]])); + // Shouldn't crash. + $f[[BUZZ]]; } )cpp"); @@ -465,6 +502,7 @@ TEST(SourceCodeTests, HalfOpenFileRange) { CheckRange("c"); CheckRange("d"); CheckRange("e"); + CheckRange("f"); } } // namespace diff --git a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp index 8c88fe5169d8..8caa1c5aa732 100644 --- a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp +++ b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp @@ -124,8 +124,7 @@ class ShouldCollectSymbolTest : public ::testing::Test { const NamedDecl &ND = Qualified ? findDecl(*AST, Name) : findUnqualifiedDecl(*AST, Name); const SourceManager &SM = AST->getSourceManager(); - bool MainFile = - SM.isWrittenInMainFile(SM.getExpansionLoc(ND.getBeginLoc())); + bool MainFile = isInsideMainFile(ND.getBeginLoc(), SM); return SymbolCollector::shouldCollectSymbol( ND, AST->getASTContext(), SymbolCollector::Options(), MainFile); } diff --git a/clang-tools-extra/clangd/unittests/TweakTests.cpp b/clang-tools-extra/clangd/unittests/TweakTests.cpp index 69f74e9d41b9..1ac5bb16e262 100644 --- a/clang-tools-extra/clangd/unittests/TweakTests.cpp +++ b/clang-tools-extra/clangd/unittests/TweakTests.cpp @@ -296,35 +296,36 @@ TEST(TweakTest, ExtractVariable) { checkAvailable(ID, R"cpp( int xyz() { // return statement - return ^1; + return [[1]]; } void f() { - int a = 5 + [[4 ^* ^xyz^()]]; + int a = [[5 +]] [[4 * [[[[xyz]]()]]]]; // multivariable initialization if(1) - int x = ^1, y = ^a + 1, a = ^1, z = a + 1; + int x = [[1]], y = [[a]] + 1, a = [[1]], z = a + 1; // if without else - if(^1) {} + if([[1]]) + a = [[1]]; // if with else - if(a < ^3) - if(a == ^4) - a = ^5; + if(a < [[3]]) + if(a == [[4]]) + a = [[5]]; else - a = ^6; - else if (a < ^4) - a = ^4; + a = [[5]]; + else if (a < [[4]]) + a = [[4]]; else - a = ^5; + a = [[5]]; // for loop - for(a = ^1; a > ^3^+^4; a++) - a = ^2; + for(a = [[1]]; a > [[[[3]] + [[4]]]]; a++) + a = [[2]]; // while - while(a < ^1) - ^a++; + while(a < [[1]]) + [[a]]++; // do while do - a = ^1; - while(a < ^3); + a = [[1]]; + while(a < [[3]]); } )cpp"); // Should not crash. @@ -336,29 +337,31 @@ TEST(TweakTest, ExtractVariable) { }; )cpp"); checkNotAvailable(ID, R"cpp( - int xyz(int a = ^1) { + int xyz(int a = [[1]]) { return 1; class T { - T(int a = ^1) {}; - int xyz = ^1; + T(int a = [[1]]) {}; + int xyz = [[1]]; }; } // function default argument - void f(int b = ^1) { + void f(int b = [[1]]) { + // empty selection + int a = ^1 ^+ ^2; // void expressions auto i = new int, j = new int; - de^lete i^, del^ete j; + [[[[delete i]], delete j]]; // if if(1) - int x = 1, y = a + 1, a = 1, z = ^a + 1; + int x = 1, y = a + 1, a = 1, z = [[a + 1]]; if(int a = 1) - if(^a == 4) - a = ^a ^+ 1; + if([[a]] == 4) + a = [[[[a]] +]] 1; // for loop - for(int a = 1, b = 2, c = 3; ^a > ^b ^+ ^c; ^a++) - a = ^a ^+ 1; + for(int a = 1, b = 2, c = 3; [[a]] > [[b + c]]; [[a]]++) + a = [[a + 1]]; // lambda - auto lamb = [&^a, &^b](int r = ^1) {return 1;} + auto lamb = [&[[a]], &[[b]]](int r = [[1]]) {return 1;} } )cpp"); // vector of pairs of input and output strings @@ -398,7 +401,7 @@ TEST(TweakTest, ExtractVariable) { {R"cpp(#define LOOP(x) {int a = x + 1;} void f(int a) { if(1) - LOOP(5 + ^3) + LOOP(5 + [[3]]) })cpp", R"cpp(#define LOOP(x) {int a = x + 1;} void f(int a) { @@ -407,7 +410,7 @@ TEST(TweakTest, ExtractVariable) { })cpp"}, // label and attribute testing {R"cpp(void f(int a) { - label: [ [gsl::suppress("type")] ] for (;;) a = ^1; + label: [ [gsl::suppress("type")] ] for (;;) a = [[1]]; })cpp", R"cpp(void f(int a) { auto dummy = 1; label: [ [gsl::suppress("type")] ] for (;;) a = dummy; @@ -415,14 +418,14 @@ TEST(TweakTest, ExtractVariable) { // FIXME: Doesn't work because bug in selection tree /*{R"cpp(#define PLUS(x) x++ void f(int a) { - PLUS(^a); + PLUS([[a]]); })cpp", R"cpp(#define PLUS(x) x++ void f(int a) { auto dummy = a; PLUS(dummy); })cpp"},*/ - // FIXME: Doesn't work correctly for \[\[clang::uninitialized\]\] int b - // = 1; since the attr is inside the DeclStmt and the bounds of + // FIXME: Doesn't work correctly for \[\[clang::uninitialized\]\] int + // b = [[1]]; since the attr is inside the DeclStmt and the bounds of // DeclStmt don't cover the attribute }; for (const auto &IO : InputOutputs) { diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp index 3439bc7d15d3..4a95a9935f2f 100644 --- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -1793,6 +1793,16 @@ TEST(Hover, All) { "int\n" "]", }, + { + R"cpp(// Should not crash when evaluating the initializer. + struct Test {}; + void test() { Test && te^st = {}; } + )cpp", + "text[Declared in]code[test]\n" + "codeblock(cpp) [\n" + "struct Test &&test = {}\n" + "]", + }, }; // Create a tiny index, so tests above can verify documentation is fetched. diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 0f52c53d443c..b2de68be4087 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -1,6 +1,6 @@ -=================================================== -Extra Clang Tools 9.0.0 (In-Progress) Release Notes -=================================================== +===================================== +Extra Clang Tools 9.0.0 Release Notes +===================================== .. contents:: :local: @@ -8,12 +8,6 @@ Extra Clang Tools 9.0.0 (In-Progress) Release Notes Written by the `LLVM Team `_ -.. warning:: - - These are in-progress notes for the upcoming Extra Clang Tools 9 release. - Release notes for previous releases can be found on - `the Download Page `_. - Introduction ============ @@ -27,10 +21,6 @@ For more information about Clang or LLVM, including information about the latest release, please see the `Clang Web Site `_ or the `LLVM Web Site `_. -Note that if you are reading this file from a Subversion checkout or the -main Clang web page, this document applies to the *next* release, not -the current one. To see the release notes for a specific release, please -see the `releases page `_. What's New in Extra Clang Tools 9.0.0? ====================================== @@ -39,30 +29,103 @@ Some of the major new features and improvements to Extra Clang Tools are listed here. Generic improvements to Extra Clang Tools as a whole or to its underlying infrastructure are described first, followed by tool-specific sections. -Major New Features ------------------- - -... Improvements to clangd ---------------------- -The improvements are... +- Background indexing is on by default + + When using clangd, it will build an index of your code base (all files listed + in your compile database). This index enables go-to-definition, + find-references, and even code completion to find symbols across your project. + + This feature can consume a lot of CPU. It can be disabled using the + ``--background-index=false`` flag, and respects ``-j`` to use fewer threads. + The index is written to ``.clangd/index`` in the project root. + +- Contextual code actions + + Extract variable, expand ``auto``, expand macro, convert string to raw string. + More to come in the future! + +- Clang-tidy warnings are available + + These will be produced for projects that have a ``.clang-tidy`` file in their + source tree, as described in the :doc:`clang-tidy documentation `. + +- Improved diagnostics + + Errors from headers are now shown (on the #including line). + The message now indicates if fixes are available. + Navigation between errors and associated notes is improved (for editors that + support ``Diagnostic.relatedInformation``). + +- Suggested includes + + When a class or other name is not found, clangd may suggest to fix this by + adding the corresponding ``#include`` directive. + +- Semantic highlighting + + clangd can push syntax information to the editor, allowing it to highlight + e.g. member variables differently from locals. (requires editor support) + + This implements the proposed protocol from + https://github.com/microsoft/vscode-languageserver-node/pull/367 + +- Type hierachy + + Navigation to base/derived types is possible in editors that support the + proposed protocol from + https://github.com/microsoft/vscode-languageserver-node/pull/426 -Improvements to clang-doc -------------------------- +- Improvements to include insertion -The improvements are... + Only headers with ``#include``-guards will be inserted, and the feature can + be disabled with the ``--header-insertion=never`` flag. -Improvements to clang-query ---------------------------- + Standard library headers should now be inserted more accurately, particularly + for C++ other than libstdc++, and for the C standard library. -The improvements are... +- Code completion -Improvements to clang-rename ----------------------------- + Overloads are bundled into a single completion item by default. (for editors + that support signature-help). + + Redundant const/non-const overloads are no longer shown. + + Before clangd is warmed up (during preamble build), limited identifier- and + index-based code completion is available. + +- Format-on-type + + A new implementation of format-on-type is triggered by hitting enter: it + attempts to reformat the previous line and reindent the new line. + (Requires editor support). + +- Toolchain header detection + + Projects that use an embedded gcc toolchain may only work when used with the + corresponding standard library. clangd can now query the toolchain to find + these headers. + The compilation database must correctly specify this toolchain, and the + ``--query-driver=/path/to/toolchain/bin/*`` flag must be passed to clangd. + +- Miscellaneous improvements + + Hover now produces richer Markdown-formatted text (for supported editors). + + Rename is safer and more helpful, though is still within one file only. + + Files without extensions (e.g. C++ standard library) are handled better. + + clangd can understand offsets in UTF-8 or UTF-32 through command-line flags or + protocol extensions. (Useful with editors/platforms that don't speak UTF-16). + + Editors that support edits near the cursor in code-completion can set the + ``textDocument.completion.editsNearCursor`` capability to ``true``, and clangd + will provide completions that correct ``.`` to ``->``, and vice-versa. -The improvements are... Improvements to clang-tidy -------------------------- @@ -249,20 +312,6 @@ Improvements to clang-tidy :doc:`objc-property-declaration ` check have been removed. -Improvements to include-fixer ------------------------------ - -The improvements are... - -Improvements to clang-include-fixer ------------------------------------ - -The improvements are... - -Improvements to modularize --------------------------- - -The improvements are... Improvements to pp-trace ------------------------ diff --git a/clang-tools-extra/docs/clang-tidy/checks/cert-dcl21-cpp.rst b/clang-tools-extra/docs/clang-tidy/checks/cert-dcl21-cpp.rst index d5c294823626..818ae8fea71c 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/cert-dcl21-cpp.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/cert-dcl21-cpp.rst @@ -7,6 +7,18 @@ This check flags postfix ``operator++`` and ``operator--`` declarations if the return type is not a const object. This also warns if the return type is a reference type. +The object returned by a postfix increment or decrement operator is supposed +to be a snapshot of the object's value prior to modification. With such an +implementation, any modifications made to the resulting object from calling +operator++(int) would be modifying a temporary object. Thus, such an +implementation of a postfix increment or decrement operator should instead +return a const object, prohibiting accidental mutation of a temporary object. +Similarly, it is unexpected for the postfix operator to return a reference to +its previous state, and any subsequent modifications would be operating on a +stale object. + This check corresponds to the CERT C++ Coding Standard recommendation -`DCL21-CPP. Overloaded postfix increment and decrement operators should return a const object -`_. +DCL21-CPP. Overloaded postfix increment and decrement operators should return a +const object. However, all of the CERT recommendations have been removed from +public view, and so their justification for the behavior of this check requires +an account on their wiki to view. \ No newline at end of file diff --git a/clang-tools-extra/docs/clang-tidy/checks/cert-err09-cpp.rst b/clang-tools-extra/docs/clang-tidy/checks/cert-err09-cpp.rst index 1494bcc07e33..8f5220b425ad 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/cert-err09-cpp.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/cert-err09-cpp.rst @@ -8,3 +8,8 @@ cert-err09-cpp The cert-err09-cpp check is an alias, please see `misc-throw-by-value-catch-by-reference `_ for more information. + +This check corresponds to the CERT C++ Coding Standard recommendation +ERR09-CPP. Throw anonymous temporaries. However, all of the CERT recommendations +have been removed from public view, and so their justification for the behavior +of this check requires an account on their wiki to view. \ No newline at end of file diff --git a/clang-tools-extra/docs/clang-tidy/checks/cert-oop11-cpp.rst b/clang-tools-extra/docs/clang-tidy/checks/cert-oop11-cpp.rst index dcd0fee8b2d9..df06f75000fa 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/cert-oop11-cpp.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/cert-oop11-cpp.rst @@ -8,3 +8,9 @@ cert-oop11-cpp The cert-oop11-cpp check is an alias, please see `performance-move-constructor-init `_ for more information. + +This check corresponds to the CERT C++ Coding Standard recommendation +OOP11-CPP. Do not copy-initialize members or base classes from a move +constructor. However, all of the CERT recommendations have been removed from +public view, and so their justification for the behavior of this check requires +an account on their wiki to view. \ No newline at end of file diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc-throw-by-value-catch-by-reference.rst b/clang-tools-extra/docs/clang-tidy/checks/misc-throw-by-value-catch-by-reference.rst index bbe681a4fbf1..cc970fe014cc 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/misc-throw-by-value-catch-by-reference.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/misc-throw-by-value-catch-by-reference.rst @@ -7,7 +7,10 @@ misc-throw-by-value-catch-by-reference `cert-err61-cpp` redirects here as an alias for this check. Finds violations of the rule "Throw by value, catch by reference" presented for -example in "C++ Coding Standards" by H. Sutter and A. Alexandrescu. +example in "C++ Coding Standards" by H. Sutter and A. Alexandrescu, as well as +the CERT C++ Coding Standard rule `ERR61-CPP. Catch exceptions by lvalue reference +`_. + Exceptions: * Throwing string literals will not be flagged despite being a pointer. They @@ -28,8 +31,8 @@ Options .. option:: CheckThrowTemporaries - Triggers detection of violations of the rule `Throw anonymous temporaries - `_. + Triggers detection of violations of the CERT recommendation ERR09-CPP. Throw + anonymous temporaries. Default is `1`. .. option:: WarnOnLargeObject diff --git a/clang/CMakeLists.txt b/clang/CMakeLists.txt index 6cf28d8cbbb4..60937aa9db38 100644 --- a/clang/CMakeLists.txt +++ b/clang/CMakeLists.txt @@ -129,7 +129,6 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR ) set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX} ) if(LLVM_INCLUDE_TESTS) - set(Python_ADDITIONAL_VERSIONS 2.7) include(FindPythonInterp) if(NOT PYTHONINTERP_FOUND) message(FATAL_ERROR diff --git a/clang/docs/AttributeReference.rst b/clang/docs/AttributeReference.rst index a763ddeaeb10..8163b47185b3 100644 --- a/clang/docs/AttributeReference.rst +++ b/clang/docs/AttributeReference.rst @@ -1,13 +1,5546 @@ .. ------------------------------------------------------------------- NOTE: This file is automatically generated by running clang-tblgen - -gen-attr-docs. Do not edit this file by hand!! The contents for - this file are automatically generated by a server-side process. - - Please do not commit this file. The file exists for local testing - purposes only. + -gen-attr-docs. Do not edit this file by hand!! ------------------------------------------------------------------- =================== Attributes in Clang -=================== \ No newline at end of file +=================== +.. contents:: + :local: + +.. |br| raw:: html + +
+ +Introduction +============ + +This page lists the attributes currently supported by Clang. + +Function Attributes +=================== + + +#pragma omp declare simd +------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","","``omp declare simd``","" + +The `declare simd` construct can be applied to a function to enable the creation +of one or more versions that can process multiple arguments using SIMD +instructions from a single invocation in a SIMD loop. The `declare simd` +directive is a declarative directive. There may be multiple `declare simd` +directives for a function. The use of a `declare simd` construct on a function +enables the creation of SIMD versions of the associated function that can be +used to process multiple arguments from a single invocation from a SIMD loop +concurrently. +The syntax of the `declare simd` construct is as follows: + + .. code-block:: none + + #pragma omp declare simd [clause[[,] clause] ...] new-line + [#pragma omp declare simd [clause[[,] clause] ...] new-line] + [...] + function definition or declaration + +where clause is one of the following: + + .. code-block:: none + + simdlen(length) + linear(argument-list[:constant-linear-step]) + aligned(argument-list[:alignment]) + uniform(argument-list) + inbranch + notinbranch + + +#pragma omp declare target +-------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","","``omp declare target``","" + +The `declare target` directive specifies that variables and functions are mapped +to a device for OpenMP offload mechanism. + +The syntax of the declare target directive is as follows: + + .. code-block:: c + + #pragma omp declare target new-line + declarations-definition-seq + #pragma omp end declare target new-line + + +_Noreturn +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``_Noreturn``","","" + +A function declared as ``_Noreturn`` shall not return to its caller. The +compiler will generate a diagnostic for a function declared as ``_Noreturn`` +that appears to be capable of returning to its caller. + + +abi_tag +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``abi_tag``","``gnu::abi_tag``","","","","","Yes" + +The ``abi_tag`` attribute can be applied to a function, variable, class or +inline namespace declaration to modify the mangled name of the entity. It gives +the ability to distinguish between different versions of the same entity but +with different ABI versions supported. For example, a newer version of a class +could have a different set of data members and thus have a different size. Using +the ``abi_tag`` attribute, it is possible to have different mangled names for +a global variable of the class type. Therefore, the old code could keep using +the old manged name and the new code will use the new mangled name with tags. + + +acquire_capability, acquire_shared_capability +--------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``acquire_capability`` |br| ``acquire_shared_capability`` |br| ``exclusive_lock_function`` |br| ``shared_lock_function``","``clang::acquire_capability`` |br| ``clang::acquire_shared_capability``","","","","","" + +Marks a function as acquiring a capability. + + +alloc_align +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``alloc_align``","``gnu::alloc_align``","","","","","" + +Use ``__attribute__((alloc_align())`` on a function +declaration to specify that the return value of the function (which must be a +pointer type) is at least as aligned as the value of the indicated parameter. The +parameter is given by its index in the list of formal parameters; the first +parameter has index 1 unless the function is a C++ non-static member function, +in which case the first parameter has index 2 to account for the implicit ``this`` +parameter. + +.. code-block:: c++ + + // The returned pointer has the alignment specified by the first parameter. + void *a(size_t align) __attribute__((alloc_align(1))); + + // The returned pointer has the alignment specified by the second parameter. + void *b(void *v, size_t align) __attribute__((alloc_align(2))); + + // The returned pointer has the alignment specified by the second visible + // parameter, however it must be adjusted for the implicit 'this' parameter. + void *Foo::b(void *v, size_t align) __attribute__((alloc_align(3))); + +Note that this attribute merely informs the compiler that a function always +returns a sufficiently aligned pointer. It does not cause the compiler to +emit code to enforce that alignment. The behavior is undefined if the returned +poitner is not sufficiently aligned. + + +alloc_size +---------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``alloc_size``","``gnu::alloc_size``","","","","","Yes" + +The ``alloc_size`` attribute can be placed on functions that return pointers in +order to hint to the compiler how many bytes of memory will be available at the +returned pointer. ``alloc_size`` takes one or two arguments. + +- ``alloc_size(N)`` implies that argument number N equals the number of + available bytes at the returned pointer. +- ``alloc_size(N, M)`` implies that the product of argument number N and + argument number M equals the number of available bytes at the returned + pointer. + +Argument numbers are 1-based. + +An example of how to use ``alloc_size`` + +.. code-block:: c + + void *my_malloc(int a) __attribute__((alloc_size(1))); + void *my_calloc(int a, int b) __attribute__((alloc_size(1, 2))); + + int main() { + void *const p = my_malloc(100); + assert(__builtin_object_size(p, 0) == 100); + void *const a = my_calloc(20, 5); + assert(__builtin_object_size(a, 0) == 100); + } + +.. Note:: This attribute works differently in clang than it does in GCC. + Specifically, clang will only trace ``const`` pointers (as above); we give up + on pointers that are not marked as ``const``. In the vast majority of cases, + this is unimportant, because LLVM has support for the ``alloc_size`` + attribute. However, this may cause mildly unintuitive behavior when used with + other attributes, such as ``enable_if``. + + +allocator +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","``allocator``","","","" + +The ``__declspec(allocator)`` attribute is applied to functions that allocate +memory, such as operator new in C++. When CodeView debug information is emitted +(enabled by ``clang -gcodeview`` or ``clang-cl /Z7``), Clang will attempt to +record the code offset of heap allocation call sites in the debug info. It will +also record the type being allocated using some local heuristics. The Visual +Studio debugger uses this information to `profile memory usage`_. + +.. _profile memory usage: https://docs.microsoft.com/en-us/visualstudio/profiling/memory-usage + +This attribute does not affect optimizations in any way, unlike GCC's +``__attribute__((malloc))``. + + +artificial +---------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``artificial``","``gnu::artificial``","","","","","" + +The ``artificial`` attribute can be applied to an inline function. If such a +function is inlined, the attribute indicates that debuggers should associate +the resulting instructions with the call site, rather than with the +corresponding line within the inlined callee. + + +assert_capability, assert_shared_capability +------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``assert_capability`` |br| ``assert_shared_capability``","``clang::assert_capability`` |br| ``clang::assert_shared_capability``","","","","","" + +Marks a function that dynamically tests whether a capability is held, and halts +the program if it is not held. + + +assume_aligned +-------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``assume_aligned``","``gnu::assume_aligned``","","","","","Yes" + +Use ``__attribute__((assume_aligned([,]))`` on a function +declaration to specify that the return value of the function (which must be a +pointer type) has the specified offset, in bytes, from an address with the +specified alignment. The offset is taken to be zero if omitted. + +.. code-block:: c++ + + // The returned pointer value has 32-byte alignment. + void *a() __attribute__((assume_aligned (32))); + + // The returned pointer value is 4 bytes greater than an address having + // 32-byte alignment. + void *b() __attribute__((assume_aligned (32, 4))); + +Note that this attribute provides information to the compiler regarding a +condition that the code already ensures is true. It does not cause the compiler +to enforce the provided alignment assumption. + + +availability +------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``availability``","``clang::availability``","``clang::availability``","","","","Yes" + +The ``availability`` attribute can be placed on declarations to describe the +lifecycle of that declaration relative to operating system versions. Consider +the function declaration for a hypothetical function ``f``: + +.. code-block:: c++ + + void f(void) __attribute__((availability(macos,introduced=10.4,deprecated=10.6,obsoleted=10.7))); + +The availability attribute states that ``f`` was introduced in macOS 10.4, +deprecated in macOS 10.6, and obsoleted in macOS 10.7. This information +is used by Clang to determine when it is safe to use ``f``: for example, if +Clang is instructed to compile code for macOS 10.5, a call to ``f()`` +succeeds. If Clang is instructed to compile code for macOS 10.6, the call +succeeds but Clang emits a warning specifying that the function is deprecated. +Finally, if Clang is instructed to compile code for macOS 10.7, the call +fails because ``f()`` is no longer available. + +The availability attribute is a comma-separated list starting with the +platform name and then including clauses specifying important milestones in the +declaration's lifetime (in any order) along with additional information. Those +clauses can be: + +introduced=\ *version* + The first version in which this declaration was introduced. + +deprecated=\ *version* + The first version in which this declaration was deprecated, meaning that + users should migrate away from this API. + +obsoleted=\ *version* + The first version in which this declaration was obsoleted, meaning that it + was removed completely and can no longer be used. + +unavailable + This declaration is never available on this platform. + +message=\ *string-literal* + Additional message text that Clang will provide when emitting a warning or + error about use of a deprecated or obsoleted declaration. Useful to direct + users to replacement APIs. + +replacement=\ *string-literal* + Additional message text that Clang will use to provide Fix-It when emitting + a warning about use of a deprecated declaration. The Fix-It will replace + the deprecated declaration with the new declaration specified. + +Multiple availability attributes can be placed on a declaration, which may +correspond to different platforms. For most platforms, the availability +attribute with the platform corresponding to the target platform will be used; +any others will be ignored. However, the availability for ``watchOS`` and +``tvOS`` can be implicitly inferred from an ``iOS`` availability attribute. +Any explicit availability attributes for those platforms are still prefered over +the implicitly inferred availability attributes. If no availability attribute +specifies availability for the current target platform, the availability +attributes are ignored. Supported platforms are: + +``ios`` + Apple's iOS operating system. The minimum deployment target is specified by + the ``-mios-version-min=*version*`` or ``-miphoneos-version-min=*version*`` + command-line arguments. + +``macos`` + Apple's macOS operating system. The minimum deployment target is + specified by the ``-mmacosx-version-min=*version*`` command-line argument. + ``macosx`` is supported for backward-compatibility reasons, but it is + deprecated. + +``tvos`` + Apple's tvOS operating system. The minimum deployment target is specified by + the ``-mtvos-version-min=*version*`` command-line argument. + +``watchos`` + Apple's watchOS operating system. The minimum deployment target is specified by + the ``-mwatchos-version-min=*version*`` command-line argument. + +A declaration can typically be used even when deploying back to a platform +version prior to when the declaration was introduced. When this happens, the +declaration is `weakly linked +`_, +as if the ``weak_import`` attribute were added to the declaration. A +weakly-linked declaration may or may not be present a run-time, and a program +can determine whether the declaration is present by checking whether the +address of that declaration is non-NULL. + +The flag ``strict`` disallows using API when deploying back to a +platform version prior to when the declaration was introduced. An +attempt to use such API before its introduction causes a hard error. +Weakly-linking is almost always a better API choice, since it allows +users to query availability at runtime. + +If there are multiple declarations of the same entity, the availability +attributes must either match on a per-platform basis or later +declarations must not have availability attributes for that +platform. For example: + +.. code-block:: c + + void g(void) __attribute__((availability(macos,introduced=10.4))); + void g(void) __attribute__((availability(macos,introduced=10.4))); // okay, matches + void g(void) __attribute__((availability(ios,introduced=4.0))); // okay, adds a new platform + void g(void); // okay, inherits both macos and ios availability from above. + void g(void) __attribute__((availability(macos,introduced=10.5))); // error: mismatch + +When one method overrides another, the overriding method can be more widely available than the overridden method, e.g.,: + +.. code-block:: objc + + @interface A + - (id)method __attribute__((availability(macos,introduced=10.4))); + - (id)method2 __attribute__((availability(macos,introduced=10.4))); + @end + + @interface B : A + - (id)method __attribute__((availability(macos,introduced=10.3))); // okay: method moved into base class later + - (id)method __attribute__((availability(macos,introduced=10.5))); // error: this method was available via the base class in 10.4 + @end + +Starting with the macOS 10.12 SDK, the ``API_AVAILABLE`` macro from +```` can simplify the spelling: + +.. code-block:: objc + + @interface A + - (id)method API_AVAILABLE(macos(10.11))); + - (id)otherMethod API_AVAILABLE(macos(10.11), ios(11.0)); + @end + +Availability attributes can also be applied using a ``#pragma clang attribute``. +Any explicit availability attribute whose platform corresponds to the target +platform is applied to a declaration regardless of the availability attributes +specified in the pragma. For example, in the code below, +``hasExplicitAvailabilityAttribute`` will use the ``macOS`` availability +attribute that is specified with the declaration, whereas +``getsThePragmaAvailabilityAttribute`` will use the ``macOS`` availability +attribute that is applied by the pragma. + +.. code-block:: c + + #pragma clang attribute push (__attribute__((availability(macOS, introduced=10.12))), apply_to=function) + void getsThePragmaAvailabilityAttribute(void); + void hasExplicitAvailabilityAttribute(void) __attribute__((availability(macos,introduced=10.4))); + #pragma clang attribute pop + +For platforms like ``watchOS`` and ``tvOS``, whose availability attributes can +be implicitly inferred from an ``iOS`` availability attribute, the logic is +slightly more complex. The explicit and the pragma-applied availability +attributes whose platform corresponds to the target platform are applied as +described in the previous paragraph. However, the implicitly inferred attributes +are applied to a declaration only when there is no explicit or pragma-applied +availability attribute whose platform corresponds to the target platform. For +example, the function below will receive the ``tvOS`` availability from the +pragma rather than using the inferred ``iOS`` availability from the declaration: + +.. code-block:: c + + #pragma clang attribute push (__attribute__((availability(tvOS, introduced=12.0))), apply_to=function) + void getsThePragmaTVOSAvailabilityAttribute(void) __attribute__((availability(iOS,introduced=11.0))); + #pragma clang attribute pop + +The compiler is also able to apply implicly inferred attributes from a pragma +as well. For example, when targeting ``tvOS``, the function below will receive +a ``tvOS`` availability attribute that is implicitly inferred from the ``iOS`` +availability attribute applied by the pragma: + +.. code-block:: c + + #pragma clang attribute push (__attribute__((availability(iOS, introduced=12.0))), apply_to=function) + void infersTVOSAvailabilityFromPragma(void); + #pragma clang attribute pop + +The implicit attributes that are inferred from explicitly specified attributes +whose platform corresponds to the target platform are applied to the declaration +even if there is an availability attribute that can be inferred from a pragma. +For example, the function below will receive the ``tvOS, introduced=11.0`` +availability that is inferred from the attribute on the declaration rather than +inferring availability from the pragma: + +.. code-block:: c + + #pragma clang attribute push (__attribute__((availability(iOS, unavailable))), apply_to=function) + void infersTVOSAvailabilityFromAttributeNextToDeclaration(void) + __attribute__((availability(iOS,introduced=11.0))); + #pragma clang attribute pop + +Also see the documentation for `@available +`_ + + +callback +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``callback``","``clang::callback``","``clang::callback``","","","","Yes" + +The ``callback`` attribute specifies that the annotated function may invoke the +specified callback zero or more times. The callback, as well as the passed +arguments, are identified by their parameter name or position (starting with +1!) in the annotated function. The first position in the attribute identifies +the callback callee, the following positions declare describe its arguments. +The callback callee is required to be callable with the number, and order, of +the specified arguments. The index `0`, or the identifier `this`, is used to +represent an implicit "this" pointer in class methods. If there is no implicit +"this" pointer it shall not be referenced. The index '-1', or the name "__", +represents an unknown callback callee argument. This can be a value which is +not present in the declared parameter list, or one that is, but is potentially +inspected, captured, or modified. Parameter names and indices can be mixed in +the callback attribute. + +The ``callback`` attribute, which is directly translated to ``callback`` +metadata , make the +connection between the call to the annotated function and the callback callee. +This can enable interprocedural optimizations which were otherwise impossible. +If a function parameter is mentioned in the ``callback`` attribute, through its +position, it is undefined if that parameter is used for anything other than the +actual callback. Inspected, captured, or modified parameters shall not be +listed in the ``callback`` metadata. + +Example encodings for the callback performed by `pthread_create` are shown +below. The explicit attribute annotation indicates that the third parameter +(`start_routine`) is called zero or more times by the `pthread_create` function, +and that the fourth parameter (`arg`) is passed along. Note that the callback +behavior of `pthread_create` is automatically recognized by Clang. In addition, +the declarations of `__kmpc_fork_teams` and `__kmpc_fork_call`, generated for +`#pragma omp target teams` and `#pragma omp parallel`, respectively, are also +automatically recognized as broker functions. Further functions might be added +in the future. + + .. code-block:: c + + __attribute__((callback (start_routine, arg))) + int pthread_create(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine) (void *), void *arg); + + __attribute__((callback (3, 4))) + int pthread_create(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine) (void *), void *arg); + + +carries_dependency +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``carries_dependency``","``carries_dependency``","","","","","Yes" + +The ``carries_dependency`` attribute specifies dependency propagation into and +out of functions. + +When specified on a function or Objective-C method, the ``carries_dependency`` +attribute means that the return value carries a dependency out of the function, +so that the implementation need not constrain ordering upon return from that +function. Implementations of the function and its caller may choose to preserve +dependencies instead of emitting memory ordering instructions such as fences. + +Note, this attribute does not change the meaning of the program, but may result +in generation of more efficient code. + + +cf_consumed +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``cf_consumed``","``clang::cf_consumed``","``clang::cf_consumed``","","","","Yes" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +cf_returns_not_retained +----------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``cf_returns_not_retained``","``clang::cf_returns_not_retained``","``clang::cf_returns_not_retained``","","","","" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +cf_returns_retained +------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``cf_returns_retained``","``clang::cf_returns_retained``","``clang::cf_returns_retained``","","","","" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +code_seg +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","``code_seg``","","","" + +The ``__declspec(code_seg)`` attribute enables the placement of code into separate +named segments that can be paged or locked in memory individually. This attribute +is used to control the placement of instantiated templates and compiler-generated +code. See the documentation for `__declspec(code_seg)`_ on MSDN. + +.. _`__declspec(code_seg)`: http://msdn.microsoft.com/en-us/library/dn636922.aspx + + +convergent +---------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``convergent``","``clang::convergent``","``clang::convergent``","","","","Yes" + +The ``convergent`` attribute can be placed on a function declaration. It is +translated into the LLVM ``convergent`` attribute, which indicates that the call +instructions of a function with this attribute cannot be made control-dependent +on any additional values. + +In languages designed for SPMD/SIMT programming model, e.g. OpenCL or CUDA, +the call instructions of a function with this attribute must be executed by +all work items or threads in a work group or sub group. + +This attribute is different from ``noduplicate`` because it allows duplicating +function calls if it can be proved that the duplicated function calls are +not made control-dependent on any additional values, e.g., unrolling a loop +executed by all work items. + +Sample usage: +.. code-block:: c + + void convfunc(void) __attribute__((convergent)); + // Setting it as a C++11 attribute is also valid in a C++ program. + // void convfunc(void) [[clang::convergent]]; + + +cpu_dispatch +------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``cpu_dispatch``","``clang::cpu_dispatch``","``clang::cpu_dispatch``","``cpu_dispatch``","","","Yes" + +The ``cpu_specific`` and ``cpu_dispatch`` attributes are used to define and +resolve multiversioned functions. This form of multiversioning provides a +mechanism for declaring versions across translation units and manually +specifying the resolved function list. A specified CPU defines a set of minimum +features that are required for the function to be called. The result of this is +that future processors execute the most restrictive version of the function the +new processor can execute. + +Function versions are defined with ``cpu_specific``, which takes one or more CPU +names as a parameter. For example: + +.. code-block:: c + + // Declares and defines the ivybridge version of single_cpu. + __attribute__((cpu_specific(ivybridge))) + void single_cpu(void){} + + // Declares and defines the atom version of single_cpu. + __attribute__((cpu_specific(atom))) + void single_cpu(void){} + + // Declares and defines both the ivybridge and atom version of multi_cpu. + __attribute__((cpu_specific(ivybridge, atom))) + void multi_cpu(void){} + +A dispatching (or resolving) function can be declared anywhere in a project's +source code with ``cpu_dispatch``. This attribute takes one or more CPU names +as a parameter (like ``cpu_specific``). Functions marked with ``cpu_dispatch`` +are not expected to be defined, only declared. If such a marked function has a +definition, any side effects of the function are ignored; trivial function +bodies are permissible for ICC compatibility. + +.. code-block:: c + + // Creates a resolver for single_cpu above. + __attribute__((cpu_dispatch(ivybridge, atom))) + void single_cpu(void){} + + // Creates a resolver for multi_cpu, but adds a 3rd version defined in another + // translation unit. + __attribute__((cpu_dispatch(ivybridge, atom, sandybridge))) + void multi_cpu(void){} + +Note that it is possible to have a resolving function that dispatches based on +more or fewer options than are present in the program. Specifying fewer will +result in the omitted options not being considered during resolution. Specifying +a version for resolution that isn't defined in the program will result in a +linking failure. + +It is also possible to specify a CPU name of ``generic`` which will be resolved +if the executing processor doesn't satisfy the features required in the CPU +name. The behavior of a program executing on a processor that doesn't satisfy +any option of a multiversioned function is undefined. + + +cpu_specific +------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``cpu_specific``","``clang::cpu_specific``","``clang::cpu_specific``","``cpu_specific``","","","Yes" + +The ``cpu_specific`` and ``cpu_dispatch`` attributes are used to define and +resolve multiversioned functions. This form of multiversioning provides a +mechanism for declaring versions across translation units and manually +specifying the resolved function list. A specified CPU defines a set of minimum +features that are required for the function to be called. The result of this is +that future processors execute the most restrictive version of the function the +new processor can execute. + +Function versions are defined with ``cpu_specific``, which takes one or more CPU +names as a parameter. For example: + +.. code-block:: c + + // Declares and defines the ivybridge version of single_cpu. + __attribute__((cpu_specific(ivybridge))) + void single_cpu(void){} + + // Declares and defines the atom version of single_cpu. + __attribute__((cpu_specific(atom))) + void single_cpu(void){} + + // Declares and defines both the ivybridge and atom version of multi_cpu. + __attribute__((cpu_specific(ivybridge, atom))) + void multi_cpu(void){} + +A dispatching (or resolving) function can be declared anywhere in a project's +source code with ``cpu_dispatch``. This attribute takes one or more CPU names +as a parameter (like ``cpu_specific``). Functions marked with ``cpu_dispatch`` +are not expected to be defined, only declared. If such a marked function has a +definition, any side effects of the function are ignored; trivial function +bodies are permissible for ICC compatibility. + +.. code-block:: c + + // Creates a resolver for single_cpu above. + __attribute__((cpu_dispatch(ivybridge, atom))) + void single_cpu(void){} + + // Creates a resolver for multi_cpu, but adds a 3rd version defined in another + // translation unit. + __attribute__((cpu_dispatch(ivybridge, atom, sandybridge))) + void multi_cpu(void){} + +Note that it is possible to have a resolving function that dispatches based on +more or fewer options than are present in the program. Specifying fewer will +result in the omitted options not being considered during resolution. Specifying +a version for resolution that isn't defined in the program will result in a +linking failure. + +It is also possible to specify a CPU name of ``generic`` which will be resolved +if the executing processor doesn't satisfy the features required in the CPU +name. The behavior of a program executing on a processor that doesn't satisfy +any option of a multiversioned function is undefined. + + +diagnose_if +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``diagnose_if``","","","","","","" + +The ``diagnose_if`` attribute can be placed on function declarations to emit +warnings or errors at compile-time if calls to the attributed function meet +certain user-defined criteria. For example: + +.. code-block:: c + + int abs(int a) + __attribute__((diagnose_if(a >= 0, "Redundant abs call", "warning"))); + int must_abs(int a) + __attribute__((diagnose_if(a >= 0, "Redundant abs call", "error"))); + + int val = abs(1); // warning: Redundant abs call + int val2 = must_abs(1); // error: Redundant abs call + int val3 = abs(val); + int val4 = must_abs(val); // Because run-time checks are not emitted for + // diagnose_if attributes, this executes without + // issue. + + +``diagnose_if`` is closely related to ``enable_if``, with a few key differences: + +* Overload resolution is not aware of ``diagnose_if`` attributes: they're + considered only after we select the best candidate from a given candidate set. +* Function declarations that differ only in their ``diagnose_if`` attributes are + considered to be redeclarations of the same function (not overloads). +* If the condition provided to ``diagnose_if`` cannot be evaluated, no + diagnostic will be emitted. + +Otherwise, ``diagnose_if`` is essentially the logical negation of ``enable_if``. + +As a result of bullet number two, ``diagnose_if`` attributes will stack on the +same function. For example: + +.. code-block:: c + + int foo() __attribute__((diagnose_if(1, "diag1", "warning"))); + int foo() __attribute__((diagnose_if(1, "diag2", "warning"))); + + int bar = foo(); // warning: diag1 + // warning: diag2 + int (*fooptr)(void) = foo; // warning: diag1 + // warning: diag2 + + constexpr int supportsAPILevel(int N) { return N < 5; } + int baz(int a) + __attribute__((diagnose_if(!supportsAPILevel(10), + "Upgrade to API level 10 to use baz", "error"))); + int baz(int a) + __attribute__((diagnose_if(!a, "0 is not recommended.", "warning"))); + + int (*bazptr)(int) = baz; // error: Upgrade to API level 10 to use baz + int v = baz(0); // error: Upgrade to API level 10 to use baz + +Query for this feature with ``__has_attribute(diagnose_if)``. + + +disable_tail_calls +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``disable_tail_calls``","``clang::disable_tail_calls``","``clang::disable_tail_calls``","","","","Yes" + +The ``disable_tail_calls`` attribute instructs the backend to not perform tail call optimization inside the marked function. + +For example: + + .. code-block:: c + + int callee(int); + + int foo(int a) __attribute__((disable_tail_calls)) { + return callee(a); // This call is not tail-call optimized. + } + +Marking virtual functions as ``disable_tail_calls`` is legal. + + .. code-block:: c++ + + int callee(int); + + class Base { + public: + [[clang::disable_tail_calls]] virtual int foo1() { + return callee(); // This call is not tail-call optimized. + } + }; + + class Derived1 : public Base { + public: + int foo1() override { + return callee(); // This call is tail-call optimized. + } + }; + + +enable_if +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``enable_if``","","","","","","Yes" + +.. Note:: Some features of this attribute are experimental. The meaning of + multiple enable_if attributes on a single declaration is subject to change in + a future version of clang. Also, the ABI is not standardized and the name + mangling may change in future versions. To avoid that, use asm labels. + +The ``enable_if`` attribute can be placed on function declarations to control +which overload is selected based on the values of the function's arguments. +When combined with the ``overloadable`` attribute, this feature is also +available in C. + +.. code-block:: c++ + + int isdigit(int c); + int isdigit(int c) __attribute__((enable_if(c <= -1 || c > 255, "chosen when 'c' is out of range"))) __attribute__((unavailable("'c' must have the value of an unsigned char or EOF"))); + + void foo(char c) { + isdigit(c); + isdigit(10); + isdigit(-10); // results in a compile-time error. + } + +The enable_if attribute takes two arguments, the first is an expression written +in terms of the function parameters, the second is a string explaining why this +overload candidate could not be selected to be displayed in diagnostics. The +expression is part of the function signature for the purposes of determining +whether it is a redeclaration (following the rules used when determining +whether a C++ template specialization is ODR-equivalent), but is not part of +the type. + +The enable_if expression is evaluated as if it were the body of a +bool-returning constexpr function declared with the arguments of the function +it is being applied to, then called with the parameters at the call site. If the +result is false or could not be determined through constant expression +evaluation, then this overload will not be chosen and the provided string may +be used in a diagnostic if the compile fails as a result. + +Because the enable_if expression is an unevaluated context, there are no global +state changes, nor the ability to pass information from the enable_if +expression to the function body. For example, suppose we want calls to +strnlen(strbuf, maxlen) to resolve to strnlen_chk(strbuf, maxlen, size of +strbuf) only if the size of strbuf can be determined: + +.. code-block:: c++ + + __attribute__((always_inline)) + static inline size_t strnlen(const char *s, size_t maxlen) + __attribute__((overloadable)) + __attribute__((enable_if(__builtin_object_size(s, 0) != -1))), + "chosen when the buffer size is known but 'maxlen' is not"))) + { + return strnlen_chk(s, maxlen, __builtin_object_size(s, 0)); + } + +Multiple enable_if attributes may be applied to a single declaration. In this +case, the enable_if expressions are evaluated from left to right in the +following manner. First, the candidates whose enable_if expressions evaluate to +false or cannot be evaluated are discarded. If the remaining candidates do not +share ODR-equivalent enable_if expressions, the overload resolution is +ambiguous. Otherwise, enable_if overload resolution continues with the next +enable_if attribute on the candidates that have not been discarded and have +remaining enable_if attributes. In this way, we pick the most specific +overload out of a number of viable overloads using enable_if. + +.. code-block:: c++ + + void f() __attribute__((enable_if(true, ""))); // #1 + void f() __attribute__((enable_if(true, ""))) __attribute__((enable_if(true, ""))); // #2 + + void g(int i, int j) __attribute__((enable_if(i, ""))); // #1 + void g(int i, int j) __attribute__((enable_if(j, ""))) __attribute__((enable_if(true))); // #2 + +In this example, a call to f() is always resolved to #2, as the first enable_if +expression is ODR-equivalent for both declarations, but #1 does not have another +enable_if expression to continue evaluating, so the next round of evaluation has +only a single candidate. In a call to g(1, 1), the call is ambiguous even though +#2 has more enable_if attributes, because the first enable_if expressions are +not ODR-equivalent. + +Query for this feature with ``__has_attribute(enable_if)``. + +Note that functions with one or more ``enable_if`` attributes may not have +their address taken, unless all of the conditions specified by said +``enable_if`` are constants that evaluate to ``true``. For example: + +.. code-block:: c + + const int TrueConstant = 1; + const int FalseConstant = 0; + int f(int a) __attribute__((enable_if(a > 0, ""))); + int g(int a) __attribute__((enable_if(a == 0 || a != 0, ""))); + int h(int a) __attribute__((enable_if(1, ""))); + int i(int a) __attribute__((enable_if(TrueConstant, ""))); + int j(int a) __attribute__((enable_if(FalseConstant, ""))); + + void fn() { + int (*ptr)(int); + ptr = &f; // error: 'a > 0' is not always true + ptr = &g; // error: 'a == 0 || a != 0' is not a truthy constant + ptr = &h; // OK: 1 is a truthy constant + ptr = &i; // OK: 'TrueConstant' is a truthy constant + ptr = &j; // error: 'FalseConstant' is a constant, but not truthy + } + +Because ``enable_if`` evaluation happens during overload resolution, +``enable_if`` may give unintuitive results when used with templates, depending +on when overloads are resolved. In the example below, clang will emit a +diagnostic about no viable overloads for ``foo`` in ``bar``, but not in ``baz``: + +.. code-block:: c++ + + double foo(int i) __attribute__((enable_if(i > 0, ""))); + void *foo(int i) __attribute__((enable_if(i <= 0, ""))); + template + auto bar() { return foo(I); } + + template + auto baz() { return foo(T::number); } + + struct WithNumber { constexpr static int number = 1; }; + void callThem() { + bar(); + baz(); + } + +This is because, in ``bar``, ``foo`` is resolved prior to template +instantiation, so the value for ``I`` isn't known (thus, both ``enable_if`` +conditions for ``foo`` fail). However, in ``baz``, ``foo`` is resolved during +template instantiation, so the value for ``T::number`` is known. + + +exclude_from_explicit_instantiation +----------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``exclude_from_explicit_instantiation``","``clang::exclude_from_explicit_instantiation``","``clang::exclude_from_explicit_instantiation``","","","","Yes" + +The ``exclude_from_explicit_instantiation`` attribute opts-out a member of a +class template from being part of explicit template instantiations of that +class template. This means that an explicit instantiation will not instantiate +members of the class template marked with the attribute, but also that code +where an extern template declaration of the enclosing class template is visible +will not take for granted that an external instantiation of the class template +would provide those members (which would otherwise be a link error, since the +explicit instantiation won't provide those members). For example, let's say we +don't want the ``data()`` method to be part of libc++'s ABI. To make sure it +is not exported from the dylib, we give it hidden visibility: + + .. code-block:: c++ + + // in + template + class basic_string { + public: + __attribute__((__visibility__("hidden"))) + const value_type* data() const noexcept { ... } + }; + + template class basic_string; + +Since an explicit template instantiation declaration for ``basic_string`` +is provided, the compiler is free to assume that ``basic_string::data()`` +will be provided by another translation unit, and it is free to produce an +external call to this function. However, since ``data()`` has hidden visibility +and the explicit template instantiation is provided in a shared library (as +opposed to simply another translation unit), ``basic_string::data()`` +won't be found and a link error will ensue. This happens because the compiler +assumes that ``basic_string::data()`` is part of the explicit template +instantiation declaration, when it really isn't. To tell the compiler that +``data()`` is not part of the explicit template instantiation declaration, the +``exclude_from_explicit_instantiation`` attribute can be used: + + .. code-block:: c++ + + // in + template + class basic_string { + public: + __attribute__((__visibility__("hidden"))) + __attribute__((exclude_from_explicit_instantiation)) + const value_type* data() const noexcept { ... } + }; + + template class basic_string; + +Now, the compiler won't assume that ``basic_string::data()`` is provided +externally despite there being an explicit template instantiation declaration: +the compiler will implicitly instantiate ``basic_string::data()`` in the +TUs where it is used. + +This attribute can be used on static and non-static member functions of class +templates, static data members of class templates and member classes of class +templates. + + +flatten +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``flatten``","``gnu::flatten``","","","","","Yes" + +The ``flatten`` attribute causes calls within the attributed function to +be inlined unless it is impossible to do so, for example if the body of the +callee is unavailable or if the callee has the ``noinline`` attribute. + + +force_align_arg_pointer +----------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``force_align_arg_pointer``","``gnu::force_align_arg_pointer``","","","","","" + +Use this attribute to force stack alignment. + +Legacy x86 code uses 4-byte stack alignment. Newer aligned SSE instructions +(like 'movaps') that work with the stack require operands to be 16-byte aligned. +This attribute realigns the stack in the function prologue to make sure the +stack can be used with SSE instructions. + +Note that the x86_64 ABI forces 16-byte stack alignment at the call site. +Because of this, 'force_align_arg_pointer' is not needed on x86_64, except in +rare cases where the caller does not align the stack properly (e.g. flow +jumps from i386 arch code). + + .. code-block:: c + + __attribute__ ((force_align_arg_pointer)) + void f () { + ... + } + + +format +------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``format``","``gnu::format``","","","","","" + +Clang supports the ``format`` attribute, which indicates that the function +accepts a ``printf`` or ``scanf``-like format string and corresponding +arguments or a ``va_list`` that contains these arguments. + +Please see `GCC documentation about format attribute +`_ to find details +about attribute syntax. + +Clang implements two kinds of checks with this attribute. + +#. Clang checks that the function with the ``format`` attribute is called with + a format string that uses format specifiers that are allowed, and that + arguments match the format string. This is the ``-Wformat`` warning, it is + on by default. + +#. Clang checks that the format string argument is a literal string. This is + the ``-Wformat-nonliteral`` warning, it is off by default. + + Clang implements this mostly the same way as GCC, but there is a difference + for functions that accept a ``va_list`` argument (for example, ``vprintf``). + GCC does not emit ``-Wformat-nonliteral`` warning for calls to such + functions. Clang does not warn if the format string comes from a function + parameter, where the function is annotated with a compatible attribute, + otherwise it warns. For example: + + .. code-block:: c + + __attribute__((__format__ (__scanf__, 1, 3))) + void foo(const char* s, char *buf, ...) { + va_list ap; + va_start(ap, buf); + + vprintf(s, ap); // warning: format string is not a string literal + } + + In this case we warn because ``s`` contains a format string for a + ``scanf``-like function, but it is passed to a ``printf``-like function. + + If the attribute is removed, clang still warns, because the format string is + not a string literal. + + Another example: + + .. code-block:: c + + __attribute__((__format__ (__printf__, 1, 3))) + void foo(const char* s, char *buf, ...) { + va_list ap; + va_start(ap, buf); + + vprintf(s, ap); // warning + } + + In this case Clang does not warn because the format string ``s`` and + the corresponding arguments are annotated. If the arguments are + incorrect, the caller of ``foo`` will receive a warning. + + +gnu_inline +---------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``gnu_inline``","``gnu::gnu_inline``","","","","","Yes" + +The ``gnu_inline`` changes the meaning of ``extern inline`` to use GNU inline +semantics, meaning: + +* If any declaration that is declared ``inline`` is not declared ``extern``, + then the ``inline`` keyword is just a hint. In particular, an out-of-line + definition is still emitted for a function with external linkage, even if all + call sites are inlined, unlike in C99 and C++ inline semantics. + +* If all declarations that are declared ``inline`` are also declared + ``extern``, then the function body is present only for inlining and no + out-of-line version is emitted. + +Some important consequences: ``static inline`` emits an out-of-line +version if needed, a plain ``inline`` definition emits an out-of-line version +always, and an ``extern inline`` definition (in a header) followed by a +(non-``extern``) ``inline`` declaration in a source file emits an out-of-line +version of the function in that source file but provides the function body for +inlining to all includers of the header. + +Either ``__GNUC_GNU_INLINE__`` (GNU inline semantics) or +``__GNUC_STDC_INLINE__`` (C99 semantics) will be defined (they are mutually +exclusive). If ``__GNUC_STDC_INLINE__`` is defined, then the ``gnu_inline`` +function attribute can be used to get GNU inline semantics on a per function +basis. If ``__GNUC_GNU_INLINE__`` is defined, then the translation unit is +already being compiled with GNU inline semantics as the implied default. It is +unspecified which macro is defined in a C++ compilation. + +GNU inline semantics are the default behavior with ``-std=gnu89``, +``-std=c89``, ``-std=c94``, or ``-fgnu89-inline``. + + +ifunc +----- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``ifunc``","``gnu::ifunc``","","","","","Yes" + +``__attribute__((ifunc("resolver")))`` is used to mark that the address of a declaration should be resolved at runtime by calling a resolver function. + +The symbol name of the resolver function is given in quotes. A function with this name (after mangling) must be defined in the current translation unit; it may be ``static``. The resolver function should return a pointer. + +The ``ifunc`` attribute may only be used on a function declaration. A function declaration with an ``ifunc`` attribute is considered to be a definition of the declared entity. The entity must not have weak linkage; for example, in C++, it cannot be applied to a declaration if a definition at that location would be considered inline. + +Not all targets support this attribute. ELF target support depends on both the linker and runtime linker, and is available in at least lld 4.0 and later, binutils 2.20.1 and later, glibc v2.11.1 and later, and FreeBSD 9.1 and later. Non-ELF targets currently do not support this attribute. + + +import_module +------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``import_module``","``clang::import_module``","``clang::import_module``","","","","Yes" + +Clang supports the ``__attribute__((import_module()))`` +attribute for the WebAssembly target. This attribute may be attached to a +function declaration, where it modifies how the symbol is to be imported +within the WebAssembly linking environment. + +WebAssembly imports use a two-level namespace scheme, consisting of a module +name, which typically identifies a module from which to import, and a field +name, which typically identifies a field from that module to import. By +default, module names for C/C++ symbols are assigned automatically by the +linker. This attribute can be used to override the default behavior, and +reuqest a specific module name be used instead. + + +import_name +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``import_name``","``clang::import_name``","``clang::import_name``","","","","Yes" + +Clang supports the ``__attribute__((import_name()))`` +attribute for the WebAssembly target. This attribute may be attached to a +function declaration, where it modifies how the symbol is to be imported +within the WebAssembly linking environment. + +WebAssembly imports use a two-level namespace scheme, consisting of a module +name, which typically identifies a module from which to import, and a field +name, which typically identifies a field from that module to import. By +default, field names for C/C++ symbols are the same as their C/C++ symbol +names. This attribute can be used to override the default behavior, and +reuqest a specific field name be used instead. + + +internal_linkage +---------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``internal_linkage``","``clang::internal_linkage``","``clang::internal_linkage``","","","","Yes" + +The ``internal_linkage`` attribute changes the linkage type of the declaration to internal. +This is similar to C-style ``static``, but can be used on classes and class methods. When applied to a class definition, +this attribute affects all methods and static data members of that class. +This can be used to contain the ABI of a C++ library by excluding unwanted class methods from the export tables. + + +interrupt (ARM) +--------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``interrupt``","``gnu::interrupt``","","","","","" + +Clang supports the GNU style ``__attribute__((interrupt("TYPE")))`` attribute on +ARM targets. This attribute may be attached to a function definition and +instructs the backend to generate appropriate function entry/exit code so that +it can be used directly as an interrupt service routine. + +The parameter passed to the interrupt attribute is optional, but if +provided it must be a string literal with one of the following values: "IRQ", +"FIQ", "SWI", "ABORT", "UNDEF". + +The semantics are as follows: + +- If the function is AAPCS, Clang instructs the backend to realign the stack to + 8 bytes on entry. This is a general requirement of the AAPCS at public + interfaces, but may not hold when an exception is taken. Doing this allows + other AAPCS functions to be called. +- If the CPU is M-class this is all that needs to be done since the architecture + itself is designed in such a way that functions obeying the normal AAPCS ABI + constraints are valid exception handlers. +- If the CPU is not M-class, the prologue and epilogue are modified to save all + non-banked registers that are used, so that upon return the user-mode state + will not be corrupted. Note that to avoid unnecessary overhead, only + general-purpose (integer) registers are saved in this way. If VFP operations + are needed, that state must be saved manually. + + Specifically, interrupt kinds other than "FIQ" will save all core registers + except "lr" and "sp". "FIQ" interrupts will save r0-r7. +- If the CPU is not M-class, the return instruction is changed to one of the + canonical sequences permitted by the architecture for exception return. Where + possible the function itself will make the necessary "lr" adjustments so that + the "preferred return address" is selected. + + Unfortunately the compiler is unable to make this guarantee for an "UNDEF" + handler, where the offset from "lr" to the preferred return address depends on + the execution state of the code which generated the exception. In this case + a sequence equivalent to "movs pc, lr" will be used. + + +interrupt (AVR) +--------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``interrupt``","``gnu::interrupt``","","","","","Yes" + +Clang supports the GNU style ``__attribute__((interrupt))`` attribute on +AVR targets. This attribute may be attached to a function definition and instructs +the backend to generate appropriate function entry/exit code so that it can be used +directly as an interrupt service routine. + +On the AVR, the hardware globally disables interrupts when an interrupt is executed. +The first instruction of an interrupt handler declared with this attribute is a SEI +instruction to re-enable interrupts. See also the signal attribute that +does not insert a SEI instruction. + + +interrupt (MIPS) +---------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``interrupt``","``gnu::interrupt``","","","","","Yes" + +Clang supports the GNU style ``__attribute__((interrupt("ARGUMENT")))`` attribute on +MIPS targets. This attribute may be attached to a function definition and instructs +the backend to generate appropriate function entry/exit code so that it can be used +directly as an interrupt service routine. + +By default, the compiler will produce a function prologue and epilogue suitable for +an interrupt service routine that handles an External Interrupt Controller (eic) +generated interrupt. This behaviour can be explicitly requested with the "eic" +argument. + +Otherwise, for use with vectored interrupt mode, the argument passed should be +of the form "vector=LEVEL" where LEVEL is one of the following values: +"sw0", "sw1", "hw0", "hw1", "hw2", "hw3", "hw4", "hw5". The compiler will +then set the interrupt mask to the corresponding level which will mask all +interrupts up to and including the argument. + +The semantics are as follows: + +- The prologue is modified so that the Exception Program Counter (EPC) and + Status coprocessor registers are saved to the stack. The interrupt mask is + set so that the function can only be interrupted by a higher priority + interrupt. The epilogue will restore the previous values of EPC and Status. + +- The prologue and epilogue are modified to save and restore all non-kernel + registers as necessary. + +- The FPU is disabled in the prologue, as the floating pointer registers are not + spilled to the stack. + +- The function return sequence is changed to use an exception return instruction. + +- The parameter sets the interrupt mask for the function corresponding to the + interrupt level specified. If no mask is specified the interrupt mask + defaults to "eic". + + +interrupt (RISCV) +----------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``interrupt``","``gnu::interrupt``","","","","","Yes" + +Clang supports the GNU style ``__attribute__((interrupt))`` attribute on RISCV +targets. This attribute may be attached to a function definition and instructs +the backend to generate appropriate function entry/exit code so that it can be +used directly as an interrupt service routine. + +Permissible values for this parameter are ``user``, ``supervisor``, +and ``machine``. If there is no parameter, then it defaults to machine. + +Repeated interrupt attribute on the same declaration will cause a warning +to be emitted. In case of repeated declarations, the last one prevails. + +Refer to: +https://gcc.gnu.org/onlinedocs/gcc/RISC-V-Function-Attributes.html +https://riscv.org/specifications/privileged-isa/ +The RISC-V Instruction Set Manual Volume II: Privileged Architecture +Version 1.10. + + +kernel +------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``kernel``","","","","","","Yes" + +``__attribute__((kernel))`` is used to mark a ``kernel`` function in +RenderScript. + +In RenderScript, ``kernel`` functions are used to express data-parallel +computations. The RenderScript runtime efficiently parallelizes ``kernel`` +functions to run on computational resources such as multi-core CPUs and GPUs. +See the RenderScript_ documentation for more information. + +.. _RenderScript: https://developer.android.com/guide/topics/renderscript/compute.html + + +lifetimebound +------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``lifetimebound``","``clang::lifetimebound``","","","","","" + +The ``lifetimebound`` attribute indicates that a resource owned by +a function parameter or implicit object parameter +is retained by the return value of the annotated function +(or, for a parameter of a constructor, in the value of the constructed object). +It is only supported in C++. + +This attribute provides an experimental implementation of the facility +described in the C++ committee paper [http://wg21.link/p0936r0](P0936R0), +and is subject to change as the design of the corresponding functionality +changes. + + +long_call, far +-------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``long_call`` |br| ``far``","``gnu::long_call`` |br| ``gnu::far``","","","","","Yes" + +Clang supports the ``__attribute__((long_call))``, ``__attribute__((far))``, +and ``__attribute__((near))`` attributes on MIPS targets. These attributes may +only be added to function declarations and change the code generated +by the compiler when directly calling the function. The ``near`` attribute +allows calls to the function to be made using the ``jal`` instruction, which +requires the function to be located in the same naturally aligned 256MB +segment as the caller. The ``long_call`` and ``far`` attributes are synonyms +and require the use of a different call sequence that works regardless +of the distance between the functions. + +These attributes have no effect for position-independent code. + +These attributes take priority over command line switches such +as ``-mlong-calls`` and ``-mno-long-calls``. + + +micromips +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``micromips``","``gnu::micromips``","","","","","Yes" + +Clang supports the GNU style ``__attribute__((micromips))`` and +``__attribute__((nomicromips))`` attributes on MIPS targets. These attributes +may be attached to a function definition and instructs the backend to generate +or not to generate microMIPS code for that function. + +These attributes override the `-mmicromips` and `-mno-micromips` options +on the command line. + + +mig_server_routine +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``mig_server_routine``","``clang::mig_server_routine``","``clang::mig_server_routine``","","","","Yes" + +The Mach Interface Generator release-on-success convention dictates +functions that follow it to only release arguments passed to them when they +return "success" (a ``kern_return_t`` error code that indicates that +no errors have occured). Otherwise the release is performed by the MIG client +that called the function. The annotation ``__attribute__((mig_server_routine))`` +is applied in order to specify which functions are expected to follow the +convention. This allows the Static Analyzer to find bugs caused by violations of +that convention. The attribute would normally appear on the forward declaration +of the actual server routine in the MIG server header, but it may also be +added to arbitrary functions that need to follow the same convention - for +example, a user can add them to auxiliary functions called by the server routine +that have their return value of type ``kern_return_t`` unconditionally returned +from the routine. The attribute can be applied to C++ methods, and in this case +it will be automatically applied to overrides if the method is virtual. The +attribute can also be written using C++11 syntax: ``[[mig::server_routine]]``. + + +min_vector_width +---------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``min_vector_width``","``clang::min_vector_width``","``clang::min_vector_width``","","","","Yes" + +Clang supports the ``__attribute__((min_vector_width(width)))`` attribute. This +attribute may be attached to a function and informs the backend that this +function desires vectors of at least this width to be generated. Target-specific +maximum vector widths still apply. This means even if you ask for something +larger than the target supports, you will only get what the target supports. +This attribute is meant to be a hint to control target heuristics that may +generate narrower vectors than what the target hardware supports. + +This is currently used by the X86 target to allow some CPUs that support 512-bit +vectors to be limited to using 256-bit vectors to avoid frequency penalties. +This is currently enabled with the ``-prefer-vector-width=256`` command line +option. The ``min_vector_width`` attribute can be used to prevent the backend +from trying to split vector operations to match the ``prefer-vector-width``. All +X86 vector intrinsics from x86intrin.h already set this attribute. Additionally, +use of any of the X86-specific vector builtins will implicitly set this +attribute on the calling function. The intent is that explicitly writing vector +code using the X86 intrinsics will prevent ``prefer-vector-width`` from +affecting the code. + + +no_caller_saved_registers +------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``no_caller_saved_registers``","``gnu::no_caller_saved_registers``","","","","","" + +Use this attribute to indicate that the specified function has no +caller-saved registers. That is, all registers are callee-saved except for +registers used for passing parameters to the function or returning parameters +from the function. +The compiler saves and restores any modified registers that were not used for +passing or returning arguments to the function. + +The user can call functions specified with the 'no_caller_saved_registers' +attribute from an interrupt handler without saving and restoring all +call-clobbered registers. + +Note that 'no_caller_saved_registers' attribute is not a calling convention. +In fact, it only overrides the decision of which registers should be saved by +the caller, but not how the parameters are passed from the caller to the callee. + +For example: + + .. code-block:: c + + __attribute__ ((no_caller_saved_registers, fastcall)) + void f (int arg1, int arg2) { + ... + } + + In this case parameters 'arg1' and 'arg2' will be passed in registers. + In this case, on 32-bit x86 targets, the function 'f' will use ECX and EDX as + register parameters. However, it will not assume any scratch registers and + should save and restore any modified registers except for ECX and EDX. + + +no_sanitize +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``no_sanitize``","``clang::no_sanitize``","``clang::no_sanitize``","","","","Yes" + +Use the ``no_sanitize`` attribute on a function or a global variable +declaration to specify that a particular instrumentation or set of +instrumentations should not be applied. The attribute takes a list of +string literals, which have the same meaning as values accepted by the +``-fno-sanitize=`` flag. For example, +``__attribute__((no_sanitize("address", "thread")))`` specifies that +AddressSanitizer and ThreadSanitizer should not be applied to the +function or variable. + +See :ref:`Controlling Code Generation ` for a +full list of supported sanitizer flags. + + +no_sanitize_address, no_address_safety_analysis +----------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``no_address_safety_analysis`` |br| ``no_sanitize_address`` |br| ``no_sanitize_thread`` |br| ``no_sanitize_memory``","``gnu::no_address_safety_analysis`` |br| ``gnu::no_sanitize_address`` |br| ``gnu::no_sanitize_thread`` |br| ``clang::no_sanitize_memory``","``clang::no_sanitize_memory``","","","","Yes" + +.. _langext-address_sanitizer: + +Use ``__attribute__((no_sanitize_address))`` on a function or a global +variable declaration to specify that address safety instrumentation +(e.g. AddressSanitizer) should not be applied. + + +no_sanitize_memory +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``no_address_safety_analysis`` |br| ``no_sanitize_address`` |br| ``no_sanitize_thread`` |br| ``no_sanitize_memory``","``gnu::no_address_safety_analysis`` |br| ``gnu::no_sanitize_address`` |br| ``gnu::no_sanitize_thread`` |br| ``clang::no_sanitize_memory``","``clang::no_sanitize_memory``","","","","Yes" + +.. _langext-memory_sanitizer: + +Use ``__attribute__((no_sanitize_memory))`` on a function declaration to +specify that checks for uninitialized memory should not be inserted +(e.g. by MemorySanitizer). The function may still be instrumented by the tool +to avoid false positives in other places. + + +no_sanitize_thread +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``no_address_safety_analysis`` |br| ``no_sanitize_address`` |br| ``no_sanitize_thread`` |br| ``no_sanitize_memory``","``gnu::no_address_safety_analysis`` |br| ``gnu::no_sanitize_address`` |br| ``gnu::no_sanitize_thread`` |br| ``clang::no_sanitize_memory``","``clang::no_sanitize_memory``","","","","Yes" + +.. _langext-thread_sanitizer: + +Use ``__attribute__((no_sanitize_thread))`` on a function declaration to +specify that checks for data races on plain (non-atomic) memory accesses should +not be inserted by ThreadSanitizer. The function is still instrumented by the +tool to avoid false positives and provide meaningful stack traces. + + +no_speculative_load_hardening +----------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``no_speculative_load_hardening``","``clang::no_speculative_load_hardening``","``clang::no_speculative_load_hardening``","","","","Yes" + +This attribute can be applied to a function declaration in order to indicate + that `Speculative Load Hardening `_ + is *not* needed for the function body. This can also be applied to a method + in Objective C. This attribute will take precedence over the command line flag in + the case where `-mspeculative-load-hardening `_ is specified. + + Warning: This attribute may not prevent Speculative Load Hardening from being + enabled for a function which inlines a function that has the + 'speculative_load_hardening' attribute. This is intended to provide a + maximally conservative model where the code that is marked with the + 'speculative_load_hardening' attribute will always (even when inlined) + be hardened. A user of this attribute may want to mark functions called by + a function they do not want to be hardened with the 'noinline' attribute. + + For example: + + .. code-block:: c + + __attribute__((speculative_load_hardening)) + int foo(int i) { + return i; + } + + // Note: bar() may still have speculative load hardening enabled if + // foo() is inlined into bar(). Mark foo() with __attribute__((noinline)) + // to avoid this situation. + __attribute__((no_speculative_load_hardening)) + int bar(int i) { + return foo(i); + } + + +no_split_stack +-------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``no_split_stack``","``gnu::no_split_stack``","","","","","Yes" + +The ``no_split_stack`` attribute disables the emission of the split stack +preamble for a particular function. It has no effect if ``-fsplit-stack`` +is not specified. + + +no_stack_protector +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``no_stack_protector``","``clang::no_stack_protector``","``clang::no_stack_protector``","","","","Yes" + +Clang supports the ``__attribute__((no_stack_protector))`` attribute which disables +the stack protector on the specified function. This attribute is useful for +selectively disabling the stack protector on some functions when building with +``-fstack-protector`` compiler option. + +For example, it disables the stack protector for the function ``foo`` but function +``bar`` will still be built with the stack protector with the ``-fstack-protector`` +option. + +.. code-block:: c + + int __attribute__((no_stack_protector)) + foo (int x); // stack protection will be disabled for foo. + + int bar(int y); // bar can be built with the stack protector. + + +noalias +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","``noalias``","","","" + +The ``noalias`` attribute indicates that the only memory accesses inside +function are loads and stores from objects pointed to by its pointer-typed +arguments, with arbitrary offsets. + + +nocf_check +---------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``nocf_check``","``gnu::nocf_check``","","","","","Yes" + +Jump Oriented Programming attacks rely on tampering with addresses used by +indirect call / jmp, e.g. redirect control-flow to non-programmer +intended bytes in the binary. +X86 Supports Indirect Branch Tracking (IBT) as part of Control-Flow +Enforcement Technology (CET). IBT instruments ENDBR instructions used to +specify valid targets of indirect call / jmp. +The ``nocf_check`` attribute has two roles: +1. Appertains to a function - do not add ENDBR instruction at the beginning of +the function. +2. Appertains to a function pointer - do not track the target function of this +pointer (by adding nocf_check prefix to the indirect-call instruction). + + +nodiscard, warn_unused_result +----------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``warn_unused_result``","``nodiscard`` |br| ``clang::warn_unused_result`` |br| ``gnu::warn_unused_result``","``nodiscard``","","","","Yes" + +Clang supports the ability to diagnose when the results of a function call +expression are discarded under suspicious circumstances. A diagnostic is +generated when a function or its return type is marked with ``[[nodiscard]]`` +(or ``__attribute__((warn_unused_result))``) and the function call appears as a +potentially-evaluated discarded-value expression that is not explicitly cast to +`void`. + +.. code-block: c++ + struct [[nodiscard]] error_info { /*...*/ }; + error_info enable_missile_safety_mode(); + + void launch_missiles(); + void test_missiles() { + enable_missile_safety_mode(); // diagnoses + launch_missiles(); + } + error_info &foo(); + void f() { foo(); } // Does not diagnose, error_info is a reference. + + +noduplicate +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``noduplicate``","``clang::noduplicate``","``clang::noduplicate``","","","","Yes" + +The ``noduplicate`` attribute can be placed on function declarations to control +whether function calls to this function can be duplicated or not as a result of +optimizations. This is required for the implementation of functions with +certain special requirements, like the OpenCL "barrier" function, that might +need to be run concurrently by all the threads that are executing in lockstep +on the hardware. For example this attribute applied on the function +"nodupfunc" in the code below avoids that: + +.. code-block:: c + + void nodupfunc() __attribute__((noduplicate)); + // Setting it as a C++11 attribute is also valid + // void nodupfunc() [[clang::noduplicate]]; + void foo(); + void bar(); + + nodupfunc(); + if (a > n) { + foo(); + } else { + bar(); + } + +gets possibly modified by some optimizations into code similar to this: + +.. code-block:: c + + if (a > n) { + nodupfunc(); + foo(); + } else { + nodupfunc(); + bar(); + } + +where the call to "nodupfunc" is duplicated and sunk into the two branches +of the condition. + + +nomicromips +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``nomicromips``","``gnu::nomicromips``","","","","","Yes" + +Clang supports the GNU style ``__attribute__((micromips))`` and +``__attribute__((nomicromips))`` attributes on MIPS targets. These attributes +may be attached to a function definition and instructs the backend to generate +or not to generate microMIPS code for that function. + +These attributes override the `-mmicromips` and `-mno-micromips` options +on the command line. + + +noreturn +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","``noreturn``","","","","","Yes" + +A function declared as ``[[noreturn]]`` shall not return to its caller. The +compiler will generate a diagnostic for a function declared as ``[[noreturn]]`` +that appears to be capable of returning to its caller. + + +not_tail_called +--------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``not_tail_called``","``clang::not_tail_called``","``clang::not_tail_called``","","","","Yes" + +The ``not_tail_called`` attribute prevents tail-call optimization on statically bound calls. It has no effect on indirect calls. Virtual functions, objective-c methods, and functions marked as ``always_inline`` cannot be marked as ``not_tail_called``. + +For example, it prevents tail-call optimization in the following case: + + .. code-block:: c + + int __attribute__((not_tail_called)) foo1(int); + + int foo2(int a) { + return foo1(a); // No tail-call optimization on direct calls. + } + +However, it doesn't prevent tail-call optimization in this case: + + .. code-block:: c + + int __attribute__((not_tail_called)) foo1(int); + + int foo2(int a) { + int (*fn)(int) = &foo1; + + // not_tail_called has no effect on an indirect call even if the call can be + // resolved at compile time. + return (*fn)(a); + } + +Marking virtual functions as ``not_tail_called`` is an error: + + .. code-block:: c++ + + class Base { + public: + // not_tail_called on a virtual function is an error. + [[clang::not_tail_called]] virtual int foo1(); + + virtual int foo2(); + + // Non-virtual functions can be marked ``not_tail_called``. + [[clang::not_tail_called]] int foo3(); + }; + + class Derived1 : public Base { + public: + int foo1() override; + + // not_tail_called on a virtual function is an error. + [[clang::not_tail_called]] int foo2() override; + }; + + +nothrow +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``nothrow``","``gnu::nothrow``","","``nothrow``","","","Yes" + +Clang supports the GNU style ``__attribute__((nothrow))`` and Microsoft style +``__declspec(nothrow)`` attribute as an equivalent of `noexcept` on function +declarations. This attribute informs the compiler that the annotated function +does not throw an exception. This prevents exception-unwinding. This attribute +is particularly useful on functions in the C Standard Library that are +guaranteed to not throw an exception. + + +ns_consumed +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``ns_consumed``","``clang::ns_consumed``","``clang::ns_consumed``","","","","Yes" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +ns_consumes_self +---------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``ns_consumes_self``","``clang::ns_consumes_self``","``clang::ns_consumes_self``","","","","Yes" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +ns_returns_autoreleased +----------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``ns_returns_autoreleased``","``clang::ns_returns_autoreleased``","``clang::ns_returns_autoreleased``","","","","" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +ns_returns_not_retained +----------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``ns_returns_not_retained``","``clang::ns_returns_not_retained``","``clang::ns_returns_not_retained``","","","","" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +ns_returns_retained +------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``ns_returns_retained``","``clang::ns_returns_retained``","``clang::ns_returns_retained``","","","","" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +objc_method_family +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``objc_method_family``","``clang::objc_method_family``","``clang::objc_method_family``","","","","Yes" + +Many methods in Objective-C have conventional meanings determined by their +selectors. It is sometimes useful to be able to mark a method as having a +particular conventional meaning despite not having the right selector, or as +not having the conventional meaning that its selector would suggest. For these +use cases, we provide an attribute to specifically describe the "method family" +that a method belongs to. + +**Usage**: ``__attribute__((objc_method_family(X)))``, where ``X`` is one of +``none``, ``alloc``, ``copy``, ``init``, ``mutableCopy``, or ``new``. This +attribute can only be placed at the end of a method declaration: + +.. code-block:: objc + + - (NSString *)initMyStringValue __attribute__((objc_method_family(none))); + +Users who do not wish to change the conventional meaning of a method, and who +merely want to document its non-standard retain and release semantics, should +use the retaining behavior attributes (``ns_returns_retained``, +``ns_returns_not_retained``, etc). + +Query for this feature with ``__has_attribute(objc_method_family)``. + + +objc_requires_super +------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``objc_requires_super``","``clang::objc_requires_super``","``clang::objc_requires_super``","","","","Yes" + +Some Objective-C classes allow a subclass to override a particular method in a +parent class but expect that the overriding method also calls the overridden +method in the parent class. For these cases, we provide an attribute to +designate that a method requires a "call to ``super``" in the overriding +method in the subclass. + +**Usage**: ``__attribute__((objc_requires_super))``. This attribute can only +be placed at the end of a method declaration: + +.. code-block:: objc + + - (void)foo __attribute__((objc_requires_super)); + +This attribute can only be applied the method declarations within a class, and +not a protocol. Currently this attribute does not enforce any placement of +where the call occurs in the overriding method (such as in the case of +``-dealloc`` where the call must appear at the end). It checks only that it +exists. + +Note that on both OS X and iOS that the Foundation framework provides a +convenience macro ``NS_REQUIRES_SUPER`` that provides syntactic sugar for this +attribute: + +.. code-block:: objc + + - (void)foo NS_REQUIRES_SUPER; + +This macro is conditionally defined depending on the compiler's support for +this attribute. If the compiler does not support the attribute the macro +expands to nothing. + +Operationally, when a method has this annotation the compiler will warn if the +implementation of an override in a subclass does not call super. For example: + +.. code-block:: objc + + warning: method possibly missing a [super AnnotMeth] call + - (void) AnnotMeth{}; + ^ + + +optnone +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``optnone``","``clang::optnone``","``clang::optnone``","","","","Yes" + +The ``optnone`` attribute suppresses essentially all optimizations +on a function or method, regardless of the optimization level applied to +the compilation unit as a whole. This is particularly useful when you +need to debug a particular function, but it is infeasible to build the +entire application without optimization. Avoiding optimization on the +specified function can improve the quality of the debugging information +for that function. + +This attribute is incompatible with the ``always_inline`` and ``minsize`` +attributes. + + +os_consumed +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``os_consumed``","``clang::os_consumed``","``clang::os_consumed``","","","","Yes" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +os_consumes_this +---------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``os_consumes_this``","``clang::os_consumes_this``","``clang::os_consumes_this``","","","","" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +os_returns_not_retained +----------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``os_returns_not_retained``","``clang::os_returns_not_retained``","``clang::os_returns_not_retained``","","","","Yes" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +os_returns_retained +------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``os_returns_retained``","``clang::os_returns_retained``","``clang::os_returns_retained``","","","","Yes" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +os_returns_retained_on_non_zero +------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``os_returns_retained_on_non_zero``","``clang::os_returns_retained_on_non_zero``","``clang::os_returns_retained_on_non_zero``","","","","Yes" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +os_returns_retained_on_zero +--------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``os_returns_retained_on_zero``","``clang::os_returns_retained_on_zero``","``clang::os_returns_retained_on_zero``","","","","Yes" + +The behavior of a function with respect to reference counting for Foundation +(Objective-C), CoreFoundation (C) and OSObject (C++) is determined by a naming +convention (e.g. functions starting with "get" are assumed to return at +``+0``). + +It can be overriden using a family of the following attributes. In +Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to +a function communicates that the object is returned at ``+1``, and the caller +is responsible for freeing it. +Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +specifies that the object is returned at ``+0`` and the ownership remains with +the callee. +The annotation ``__attribute__((ns_consumes_self))`` specifies that +the Objective-C method call consumes the reference to ``self``, e.g. by +attaching it to a supplied parameter. +Additionally, parameters can have an annotation +``__attribute__((ns_consumed))``, which specifies that passing an owned object +as that parameter effectively transfers the ownership, and the caller is no +longer responsible for it. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +In C programs using CoreFoundation, a similar set of attributes: +``__attribute__((cf_returns_not_retained))``, +``__attribute__((cf_returns_retained))`` and ``__attribute__((cf_consumed))`` +have the same respective semantics when applied to CoreFoundation objects. +These attributes affect code generation when interacting with ARC code, and +they are used by the Clang Static Analyzer. + +Finally, in C++ interacting with XNU kernel (objects inheriting from OSObject), +the same attribute family is present: +``__attribute__((os_returns_not_retained))``, +``__attribute__((os_returns_retained))`` and ``__attribute__((os_consumed))``, +with the same respective semantics. +Similar to ``__attribute__((ns_consumes_self))``, +``__attribute__((os_consumes_this))`` specifies that the method call consumes +the reference to "this" (e.g., when attaching it to a different object supplied +as a parameter). +Out parameters (parameters the function is meant to write into, +either via pointers-to-pointers or references-to-pointers) +may be annotated with ``__attribute__((os_returns_retained))`` +or ``__attribute__((os_returns_not_retained))`` which specifies that the object +written into the out parameter should (or respectively should not) be released +after use. +Since often out parameters may or may not be written depending on the exit +code of the function, +annotations ``__attribute__((os_returns_retained_on_zero))`` +and ``__attribute__((os_returns_retained_on_non_zero))`` specify that +an out parameter at ``+1`` is written if and only if the function returns a zero +(respectively non-zero) error code. +Observe that return-code-dependent out parameter annotations are only +available for retained out parameters, as non-retained object do not have to be +released by the callee. +These attributes are only used by the Clang Static Analyzer. + +The family of attributes ``X_returns_X_retained`` can be added to functions, +C++ methods, and Objective-C methods and properties. +Attributes ``X_consumed`` can be added to parameters of methods, functions, +and Objective-C methods. + + +overloadable +------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``overloadable``","``clang::overloadable``","``clang::overloadable``","","","","Yes" + +Clang provides support for C++ function overloading in C. Function overloading +in C is introduced using the ``overloadable`` attribute. For example, one +might provide several overloaded versions of a ``tgsin`` function that invokes +the appropriate standard function computing the sine of a value with ``float``, +``double``, or ``long double`` precision: + +.. code-block:: c + + #include + float __attribute__((overloadable)) tgsin(float x) { return sinf(x); } + double __attribute__((overloadable)) tgsin(double x) { return sin(x); } + long double __attribute__((overloadable)) tgsin(long double x) { return sinl(x); } + +Given these declarations, one can call ``tgsin`` with a ``float`` value to +receive a ``float`` result, with a ``double`` to receive a ``double`` result, +etc. Function overloading in C follows the rules of C++ function overloading +to pick the best overload given the call arguments, with a few C-specific +semantics: + +* Conversion from ``float`` or ``double`` to ``long double`` is ranked as a + floating-point promotion (per C99) rather than as a floating-point conversion + (as in C++). + +* A conversion from a pointer of type ``T*`` to a pointer of type ``U*`` is + considered a pointer conversion (with conversion rank) if ``T`` and ``U`` are + compatible types. + +* A conversion from type ``T`` to a value of type ``U`` is permitted if ``T`` + and ``U`` are compatible types. This conversion is given "conversion" rank. + +* If no viable candidates are otherwise available, we allow a conversion from a + pointer of type ``T*`` to a pointer of type ``U*``, where ``T`` and ``U`` are + incompatible. This conversion is ranked below all other types of conversions. + Please note: ``U`` lacking qualifiers that are present on ``T`` is sufficient + for ``T`` and ``U`` to be incompatible. + +The declaration of ``overloadable`` functions is restricted to function +declarations and definitions. If a function is marked with the ``overloadable`` +attribute, then all declarations and definitions of functions with that name, +except for at most one (see the note below about unmarked overloads), must have +the ``overloadable`` attribute. In addition, redeclarations of a function with +the ``overloadable`` attribute must have the ``overloadable`` attribute, and +redeclarations of a function without the ``overloadable`` attribute must *not* +have the ``overloadable`` attribute. e.g., + +.. code-block:: c + + int f(int) __attribute__((overloadable)); + float f(float); // error: declaration of "f" must have the "overloadable" attribute + int f(int); // error: redeclaration of "f" must have the "overloadable" attribute + + int g(int) __attribute__((overloadable)); + int g(int) { } // error: redeclaration of "g" must also have the "overloadable" attribute + + int h(int); + int h(int) __attribute__((overloadable)); // error: declaration of "h" must not + // have the "overloadable" attribute + +Functions marked ``overloadable`` must have prototypes. Therefore, the +following code is ill-formed: + +.. code-block:: c + + int h() __attribute__((overloadable)); // error: h does not have a prototype + +However, ``overloadable`` functions are allowed to use a ellipsis even if there +are no named parameters (as is permitted in C++). This feature is particularly +useful when combined with the ``unavailable`` attribute: + +.. code-block:: c++ + + void honeypot(...) __attribute__((overloadable, unavailable)); // calling me is an error + +Functions declared with the ``overloadable`` attribute have their names mangled +according to the same rules as C++ function names. For example, the three +``tgsin`` functions in our motivating example get the mangled names +``_Z5tgsinf``, ``_Z5tgsind``, and ``_Z5tgsine``, respectively. There are two +caveats to this use of name mangling: + +* Future versions of Clang may change the name mangling of functions overloaded + in C, so you should not depend on an specific mangling. To be completely + safe, we strongly urge the use of ``static inline`` with ``overloadable`` + functions. + +* The ``overloadable`` attribute has almost no meaning when used in C++, + because names will already be mangled and functions are already overloadable. + However, when an ``overloadable`` function occurs within an ``extern "C"`` + linkage specification, it's name *will* be mangled in the same way as it + would in C. + +For the purpose of backwards compatibility, at most one function with the same +name as other ``overloadable`` functions may omit the ``overloadable`` +attribute. In this case, the function without the ``overloadable`` attribute +will not have its name mangled. + +For example: + +.. code-block:: c + + // Notes with mangled names assume Itanium mangling. + int f(int); + int f(double) __attribute__((overloadable)); + void foo() { + f(5); // Emits a call to f (not _Z1fi, as it would with an overload that + // was marked with overloadable). + f(1.0); // Emits a call to _Z1fd. + } + +Support for unmarked overloads is not present in some versions of clang. You may +query for it using ``__has_extension(overloadable_unmarked)``. + +Query for this attribute with ``__has_attribute(overloadable)``. + + +reinitializes +------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``reinitializes``","``clang::reinitializes``","","","","","" + +The ``reinitializes`` attribute can be applied to a non-static, non-const C++ +member function to indicate that this member function reinitializes the entire +object to a known state, independent of the previous state of the object. + +This attribute can be interpreted by static analyzers that warn about uses of an +object that has been left in an indeterminate state by a move operation. If a +member function marked with the ``reinitializes`` attribute is called on a +moved-from object, the analyzer can conclude that the object is no longer in an +indeterminate state. + +A typical example where this attribute would be used is on functions that clear +a container class: + +.. code-block:: c++ + + template + class Container { + public: + ... + [[clang::reinitializes]] void Clear(); + ... + }; + + +release_capability, release_shared_capability +--------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``release_capability`` |br| ``release_shared_capability`` |br| ``release_generic_capability`` |br| ``unlock_function``","``clang::release_capability`` |br| ``clang::release_shared_capability`` |br| ``clang::release_generic_capability`` |br| ``clang::unlock_function``","","","","","" + +Marks a function as releasing a capability. + + +short_call, near +---------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``short_call`` |br| ``near``","``gnu::short_call`` |br| ``gnu::near``","","","","","Yes" + +Clang supports the ``__attribute__((long_call))``, ``__attribute__((far))``, +``__attribute__((short__call))``, and ``__attribute__((near))`` attributes +on MIPS targets. These attributes may only be added to function declarations +and change the code generated by the compiler when directly calling +the function. The ``short_call`` and ``near`` attributes are synonyms and +allow calls to the function to be made using the ``jal`` instruction, which +requires the function to be located in the same naturally aligned 256MB segment +as the caller. The ``long_call`` and ``far`` attributes are synonyms and +require the use of a different call sequence that works regardless +of the distance between the functions. + +These attributes have no effect for position-independent code. + +These attributes take priority over command line switches such +as ``-mlong-calls`` and ``-mno-long-calls``. + + +signal +------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``signal``","``gnu::signal``","","","","","Yes" + +Clang supports the GNU style ``__attribute__((signal))`` attribute on +AVR targets. This attribute may be attached to a function definition and instructs +the backend to generate appropriate function entry/exit code so that it can be used +directly as an interrupt service routine. + +Interrupt handler functions defined with the signal attribute do not re-enable interrupts. + + +speculative_load_hardening +-------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``speculative_load_hardening``","``clang::speculative_load_hardening``","``clang::speculative_load_hardening``","","","","Yes" + +This attribute can be applied to a function declaration in order to indicate + that `Speculative Load Hardening `_ + should be enabled for the function body. This can also be applied to a method + in Objective C. This attribute will take precedence over the command line flag in + the case where `-mno-speculative-load-hardening `_ is specified. + + Speculative Load Hardening is a best-effort mitigation against + information leak attacks that make use of control flow + miss-speculation - specifically miss-speculation of whether a branch + is taken or not. Typically vulnerabilities enabling such attacks are + classified as "Spectre variant #1". Notably, this does not attempt to + mitigate against miss-speculation of branch target, classified as + "Spectre variant #2" vulnerabilities. + + When inlining, the attribute is sticky. Inlining a function that + carries this attribute will cause the caller to gain the + attribute. This is intended to provide a maximally conservative model + where the code in a function annotated with this attribute will always + (even after inlining) end up hardened. + + +target +------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``target``","``gnu::target``","","","","","Yes" + +Clang supports the GNU style ``__attribute__((target("OPTIONS")))`` attribute. +This attribute may be attached to a function definition and instructs +the backend to use different code generation options than were passed on the +command line. + +The current set of options correspond to the existing "subtarget features" for +the target with or without a "-mno-" in front corresponding to the absence +of the feature, as well as ``arch="CPU"`` which will change the default "CPU" +for the function. + +Example "subtarget features" from the x86 backend include: "mmx", "sse", "sse4.2", +"avx", "xop" and largely correspond to the machine specific options handled by +the front end. + +Additionally, this attribute supports function multiversioning for ELF based +x86/x86-64 targets, which can be used to create multiple implementations of the +same function that will be resolved at runtime based on the priority of their +``target`` attribute strings. A function is considered a multiversioned function +if either two declarations of the function have different ``target`` attribute +strings, or if it has a ``target`` attribute string of ``default``. For +example: + + .. code-block:: c++ + + __attribute__((target("arch=atom"))) + void foo() {} // will be called on 'atom' processors. + __attribute__((target("default"))) + void foo() {} // will be called on any other processors. + +All multiversioned functions must contain a ``default`` (fallback) +implementation, otherwise usages of the function are considered invalid. +Additionally, a function may not become multiversioned after its first use. + + +try_acquire_capability, try_acquire_shared_capability +----------------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``try_acquire_capability`` |br| ``try_acquire_shared_capability``","``clang::try_acquire_capability`` |br| ``clang::try_acquire_shared_capability``","","","","","" + +Marks a function that attempts to acquire a capability. This function may fail to +actually acquire the capability; they accept a Boolean value determining +whether acquiring the capability means success (true), or failing to acquire +the capability means success (false). + + +xray_always_instrument, xray_never_instrument, xray_log_args +------------------------------------------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``xray_always_instrument`` |br| ``xray_never_instrument``","``clang::xray_always_instrument`` |br| ``clang::xray_never_instrument``","``clang::xray_always_instrument`` |br| ``clang::xray_never_instrument``","","","","Yes" + +``__attribute__((xray_always_instrument))`` or ``[[clang::xray_always_instrument]]`` is used to mark member functions (in C++), methods (in Objective C), and free functions (in C, C++, and Objective C) to be instrumented with XRay. This will cause the function to always have space at the beginning and exit points to allow for runtime patching. + +Conversely, ``__attribute__((xray_never_instrument))`` or ``[[clang::xray_never_instrument]]`` will inhibit the insertion of these instrumentation points. + +If a function has neither of these attributes, they become subject to the XRay heuristics used to determine whether a function should be instrumented or otherwise. + +``__attribute__((xray_log_args(N)))`` or ``[[clang::xray_log_args(N)]]`` is used to preserve N function arguments for the logging function. Currently, only N==1 is supported. + + +xray_always_instrument, xray_never_instrument, xray_log_args +------------------------------------------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``xray_log_args``","``clang::xray_log_args``","``clang::xray_log_args``","","","","Yes" + +``__attribute__((xray_always_instrument))`` or ``[[clang::xray_always_instrument]]`` is used to mark member functions (in C++), methods (in Objective C), and free functions (in C, C++, and Objective C) to be instrumented with XRay. This will cause the function to always have space at the beginning and exit points to allow for runtime patching. + +Conversely, ``__attribute__((xray_never_instrument))`` or ``[[clang::xray_never_instrument]]`` will inhibit the insertion of these instrumentation points. + +If a function has neither of these attributes, they become subject to the XRay heuristics used to determine whether a function should be instrumented or otherwise. + +``__attribute__((xray_log_args(N)))`` or ``[[clang::xray_log_args(N)]]`` is used to preserve N function arguments for the logging function. Currently, only N==1 is supported. + + +Variable Attributes +=================== + + +always_destroy +-------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``always_destroy``","``clang::always_destroy``","","","","","Yes" + +The ``always_destroy`` attribute specifies that a variable with static or thread +storage duration should have its exit-time destructor run. This attribute is the +default unless clang was invoked with -fno-c++-static-destructors. + + +dllexport +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``dllexport``","``gnu::dllexport``","","``dllexport``","","","Yes" + +The ``__declspec(dllexport)`` attribute declares a variable, function, or +Objective-C interface to be exported from the module. It is available under the +``-fdeclspec`` flag for compatibility with various compilers. The primary use +is for COFF object files which explicitly specify what interfaces are available +for external use. See the dllexport_ documentation on MSDN for more +information. + +.. _dllexport: https://msdn.microsoft.com/en-us/library/3y1sfaz2.aspx + + +dllimport +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``dllimport``","``gnu::dllimport``","","``dllimport``","","","Yes" + +The ``__declspec(dllimport)`` attribute declares a variable, function, or +Objective-C interface to be imported from an external module. It is available +under the ``-fdeclspec`` flag for compatibility with various compilers. The +primary use is for COFF object files which explicitly specify what interfaces +are imported from external modules. See the dllimport_ documentation on MSDN +for more information. + +.. _dllimport: https://msdn.microsoft.com/en-us/library/3y1sfaz2.aspx + + +init_seg +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","","``init_seg``","" + +The attribute applied by ``pragma init_seg()`` controls the section into +which global initialization function pointers are emitted. It is only +available with ``-fms-extensions``. Typically, this function pointer is +emitted into ``.CRT$XCU`` on Windows. The user can change the order of +initialization by using a different section name with the same +``.CRT$XC`` prefix and a suffix that sorts lexicographically before or +after the standard ``.CRT$XCU`` sections. See the init_seg_ +documentation on MSDN for more information. + +.. _init_seg: http://msdn.microsoft.com/en-us/library/7977wcck(v=vs.110).aspx + + +maybe_unused, unused +-------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``unused``","``maybe_unused`` |br| ``gnu::unused``","``maybe_unused``","","","","" + +When passing the ``-Wunused`` flag to Clang, entities that are unused by the +program may be diagnosed. The ``[[maybe_unused]]`` (or +``__attribute__((unused))``) attribute can be used to silence such diagnostics +when the entity cannot be removed. For instance, a local variable may exist +solely for use in an ``assert()`` statement, which makes the local variable +unused when ``NDEBUG`` is defined. + +The attribute may be applied to the declaration of a class, a typedef, a +variable, a function or method, a function parameter, an enumeration, an +enumerator, a non-static data member, or a label. + +.. code-block: c++ + #include + + [[maybe_unused]] void f([[maybe_unused]] bool thing1, + [[maybe_unused]] bool thing2) { + [[maybe_unused]] bool b = thing1 && thing2; + assert(b); + } + + +no_destroy +---------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``no_destroy``","``clang::no_destroy``","","","","","Yes" + +The ``no_destroy`` attribute specifies that a variable with static or thread +storage duration shouldn't have its exit-time destructor run. Annotating every +static and thread duration variable with this attribute is equivalent to +invoking clang with -fno-c++-static-destructors. + +If a variable is declared with this attribute, clang doesn't access check or +generate the type's destructor. If you have a type that you only want to be +annotated with ``no_destroy``, you can therefore declare the destructor private: + +.. code-block:: c++ + + struct only_no_destroy { + only_no_destroy(); + private: + ~only_no_destroy(); + }; + + [[clang::no_destroy]] only_no_destroy global; // fine! + +Note that destructors are still required for subobjects of aggregates annotated +with this attribute. This is because previously constructed subobjects need to +be destroyed if an exception gets thrown before the initialization of the +complete object is complete. For instance: + +.. code-block::c++ + + void f() { + try { + [[clang::no_destroy]] + static only_no_destroy array[10]; // error, only_no_destroy has a private destructor. + } catch (...) { + // Handle the error + } + } + +Here, if the construction of `array[9]` fails with an exception, `array[0..8]` +will be destroyed, so the element's destructor needs to be accessible. + + +nodebug +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``nodebug``","``gnu::nodebug``","","","","","Yes" + +The ``nodebug`` attribute allows you to suppress debugging information for a +function or method, or for a variable that is not a parameter or a non-static +data member. + + +noescape +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``noescape``","``clang::noescape``","``clang::noescape``","","","","Yes" + +``noescape`` placed on a function parameter of a pointer type is used to inform +the compiler that the pointer cannot escape: that is, no reference to the object +the pointer points to that is derived from the parameter value will survive +after the function returns. Users are responsible for making sure parameters +annotated with ``noescape`` do not actuallly escape. + +For example: + +.. code-block:: c + + int *gp; + + void nonescapingFunc(__attribute__((noescape)) int *p) { + *p += 100; // OK. + } + + void escapingFunc(__attribute__((noescape)) int *p) { + gp = p; // Not OK. + } + +Additionally, when the parameter is a `block pointer +`, the same restriction +applies to copies of the block. For example: + +.. code-block:: c + + typedef void (^BlockTy)(); + BlockTy g0, g1; + + void nonescapingFunc(__attribute__((noescape)) BlockTy block) { + block(); // OK. + } + + void escapingFunc(__attribute__((noescape)) BlockTy block) { + g0 = block; // Not OK. + g1 = Block_copy(block); // Not OK either. + } + + +nosvm +----- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``nosvm``","","","","","","Yes" + +OpenCL 2.0 supports the optional ``__attribute__((nosvm))`` qualifier for +pointer variable. It informs the compiler that the pointer does not refer +to a shared virtual memory region. See OpenCL v2.0 s6.7.2 for details. + +Since it is not widely used and has been removed from OpenCL 2.1, it is ignored +by Clang. + + +objc_externally_retained +------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``objc_externally_retained``","``clang::objc_externally_retained``","``clang::objc_externally_retained``","","","","Yes" + +The ``objc_externally_retained`` attribute can be applied to strong local +variables, functions, methods, or blocks to opt into +`externally-retained semantics +`_. + +When applied to the definition of a function, method, or block, every parameter +of the function with implicit strong retainable object pointer type is +considered externally-retained, and becomes ``const``. By explicitly annotating +a parameter with ``__strong``, you can opt back into the default +non-externally-retained behaviour for that parameter. For instance, +``first_param`` is externally-retained below, but not ``second_param``: + +.. code-block:: objc + + __attribute__((objc_externally_retained)) + void f(NSArray *first_param, __strong NSArray *second_param) { + // ... + } + +Likewise, when applied to a strong local variable, that variable becomes +``const`` and is considered externally-retained. + +When compiled without ``-fobjc-arc``, this attribute is ignored. + + +pass_object_size, pass_dynamic_object_size +------------------------------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``pass_object_size`` |br| ``pass_dynamic_object_size``","``clang::pass_object_size`` |br| ``clang::pass_dynamic_object_size``","``clang::pass_object_size`` |br| ``clang::pass_dynamic_object_size``","","","","Yes" + +.. Note:: The mangling of functions with parameters that are annotated with + ``pass_object_size`` is subject to change. You can get around this by + using ``__asm__("foo")`` to explicitly name your functions, thus preserving + your ABI; also, non-overloadable C functions with ``pass_object_size`` are + not mangled. + +The ``pass_object_size(Type)`` attribute can be placed on function parameters to +instruct clang to call ``__builtin_object_size(param, Type)`` at each callsite +of said function, and implicitly pass the result of this call in as an invisible +argument of type ``size_t`` directly after the parameter annotated with +``pass_object_size``. Clang will also replace any calls to +``__builtin_object_size(param, Type)`` in the function by said implicit +parameter. + +Example usage: + +.. code-block:: c + + int bzero1(char *const p __attribute__((pass_object_size(0)))) + __attribute__((noinline)) { + int i = 0; + for (/**/; i < (int)__builtin_object_size(p, 0); ++i) { + p[i] = 0; + } + return i; + } + + int main() { + char chars[100]; + int n = bzero1(&chars[0]); + assert(n == sizeof(chars)); + return 0; + } + +If successfully evaluating ``__builtin_object_size(param, Type)`` at the +callsite is not possible, then the "failed" value is passed in. So, using the +definition of ``bzero1`` from above, the following code would exit cleanly: + +.. code-block:: c + + int main2(int argc, char *argv[]) { + int n = bzero1(argv); + assert(n == -1); + return 0; + } + +``pass_object_size`` plays a part in overload resolution. If two overload +candidates are otherwise equally good, then the overload with one or more +parameters with ``pass_object_size`` is preferred. This implies that the choice +between two identical overloads both with ``pass_object_size`` on one or more +parameters will always be ambiguous; for this reason, having two such overloads +is illegal. For example: + +.. code-block:: c++ + + #define PS(N) __attribute__((pass_object_size(N))) + // OK + void Foo(char *a, char *b); // Overload A + // OK -- overload A has no parameters with pass_object_size. + void Foo(char *a PS(0), char *b PS(0)); // Overload B + // Error -- Same signature (sans pass_object_size) as overload B, and both + // overloads have one or more parameters with the pass_object_size attribute. + void Foo(void *a PS(0), void *b); + + // OK + void Bar(void *a PS(0)); // Overload C + // OK + void Bar(char *c PS(1)); // Overload D + + void main() { + char known[10], *unknown; + Foo(unknown, unknown); // Calls overload B + Foo(known, unknown); // Calls overload B + Foo(unknown, known); // Calls overload B + Foo(known, known); // Calls overload B + + Bar(known); // Calls overload D + Bar(unknown); // Calls overload D + } + +Currently, ``pass_object_size`` is a bit restricted in terms of its usage: + +* Only one use of ``pass_object_size`` is allowed per parameter. + +* It is an error to take the address of a function with ``pass_object_size`` on + any of its parameters. If you wish to do this, you can create an overload + without ``pass_object_size`` on any parameters. + +* It is an error to apply the ``pass_object_size`` attribute to parameters that + are not pointers. Additionally, any parameter that ``pass_object_size`` is + applied to must be marked ``const`` at its function's definition. + +Clang also supports the ``pass_dynamic_object_size`` attribute, which behaves +identically to ``pass_object_size``, but evaluates a call to +``__builtin_dynamic_object_size`` at the callee instead of +``__builtin_object_size``. ``__builtin_dynamic_object_size`` provides some extra +runtime checks when the object size can't be determined at compile-time. You can +read more about ``__builtin_dynamic_object_size`` `here +`_. + + +require_constant_initialization +------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``require_constant_initialization``","``clang::require_constant_initialization``","","","","","Yes" + +This attribute specifies that the variable to which it is attached is intended +to have a `constant initializer `_ +according to the rules of [basic.start.static]. The variable is required to +have static or thread storage duration. If the initialization of the variable +is not a constant initializer an error will be produced. This attribute may +only be used in C++. + +Note that in C++03 strict constant expression checking is not done. Instead +the attribute reports if Clang can emit the variable as a constant, even if it's +not technically a 'constant initializer'. This behavior is non-portable. + +Static storage duration variables with constant initializers avoid hard-to-find +bugs caused by the indeterminate order of dynamic initialization. They can also +be safely used during dynamic initialization across translation units. + +This attribute acts as a compile time assertion that the requirements +for constant initialization have been met. Since these requirements change +between dialects and have subtle pitfalls it's important to fail fast instead +of silently falling back on dynamic initialization. + +.. code-block:: c++ + + // -std=c++14 + #define SAFE_STATIC [[clang::require_constant_initialization]] + struct T { + constexpr T(int) {} + ~T(); // non-trivial + }; + SAFE_STATIC T x = {42}; // Initialization OK. Doesn't check destructor. + SAFE_STATIC T y = 42; // error: variable does not have a constant initializer + // copy initialization is not a constant expression on a non-literal type. + + +section, __declspec(allocate) +----------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``section``","``gnu::section``","","``allocate``","","","Yes" + +The ``section`` attribute allows you to specify a specific section a +global variable or function should be in after translation. + + +swift_context +------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``swift_context``","``clang::swift_context``","``clang::swift_context``","","","","Yes" + +The ``swift_context`` attribute marks a parameter of a ``swiftcall`` +function as having the special context-parameter ABI treatment. + +This treatment generally passes the context value in a special register +which is normally callee-preserved. + +A ``swift_context`` parameter must either be the last parameter or must be +followed by a ``swift_error_result`` parameter (which itself must always be +the last parameter). + +A context parameter must have pointer or reference type. + + +swift_error_result +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``swift_error_result``","``clang::swift_error_result``","``clang::swift_error_result``","","","","Yes" + +The ``swift_error_result`` attribute marks a parameter of a ``swiftcall`` +function as having the special error-result ABI treatment. + +This treatment generally passes the underlying error value in and out of +the function through a special register which is normally callee-preserved. +This is modeled in C by pretending that the register is addressable memory: + +- The caller appears to pass the address of a variable of pointer type. + The current value of this variable is copied into the register before + the call; if the call returns normally, the value is copied back into the + variable. + +- The callee appears to receive the address of a variable. This address + is actually a hidden location in its own stack, initialized with the + value of the register upon entry. When the function returns normally, + the value in that hidden location is written back to the register. + +A ``swift_error_result`` parameter must be the last parameter, and it must be +preceded by a ``swift_context`` parameter. + +A ``swift_error_result`` parameter must have type ``T**`` or ``T*&`` for some +type T. Note that no qualifiers are permitted on the intermediate level. + +It is undefined behavior if the caller does not pass a pointer or +reference to a valid object. + +The standard convention is that the error value itself (that is, the +value stored in the apparent argument) will be null upon function entry, +but this is not enforced by the ABI. + + +swift_indirect_result +--------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``swift_indirect_result``","``clang::swift_indirect_result``","``clang::swift_indirect_result``","","","","Yes" + +The ``swift_indirect_result`` attribute marks a parameter of a ``swiftcall`` +function as having the special indirect-result ABI treatment. + +This treatment gives the parameter the target's normal indirect-result +ABI treatment, which may involve passing it differently from an ordinary +parameter. However, only the first indirect result will receive this +treatment. Furthermore, low-level lowering may decide that a direct result +must be returned indirectly; if so, this will take priority over the +``swift_indirect_result`` parameters. + +A ``swift_indirect_result`` parameter must either be the first parameter or +follow another ``swift_indirect_result`` parameter. + +A ``swift_indirect_result`` parameter must have type ``T*`` or ``T&`` for +some object type ``T``. If ``T`` is a complete type at the point of +definition of a function, it is undefined behavior if the argument +value does not point to storage of adequate size and alignment for a +value of type ``T``. + +Making indirect results explicit in the signature allows C functions to +directly construct objects into them without relying on language +optimizations like C++'s named return value optimization (NRVO). + + +swiftcall +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``swiftcall``","``clang::swiftcall``","``clang::swiftcall``","","","","" + +The ``swiftcall`` attribute indicates that a function should be called +using the Swift calling convention for a function or function pointer. + +The lowering for the Swift calling convention, as described by the Swift +ABI documentation, occurs in multiple phases. The first, "high-level" +phase breaks down the formal parameters and results into innately direct +and indirect components, adds implicit paraameters for the generic +signature, and assigns the context and error ABI treatments to parameters +where applicable. The second phase breaks down the direct parameters +and results from the first phase and assigns them to registers or the +stack. The ``swiftcall`` convention only handles this second phase of +lowering; the C function type must accurately reflect the results +of the first phase, as follows: + +- Results classified as indirect by high-level lowering should be + represented as parameters with the ``swift_indirect_result`` attribute. + +- Results classified as direct by high-level lowering should be represented + as follows: + + - First, remove any empty direct results. + + - If there are no direct results, the C result type should be ``void``. + + - If there is one direct result, the C result type should be a type with + the exact layout of that result type. + + - If there are a multiple direct results, the C result type should be + a struct type with the exact layout of a tuple of those results. + +- Parameters classified as indirect by high-level lowering should be + represented as parameters of pointer type. + +- Parameters classified as direct by high-level lowering should be + omitted if they are empty types; otherwise, they should be represented + as a parameter type with a layout exactly matching the layout of the + Swift parameter type. + +- The context parameter, if present, should be represented as a trailing + parameter with the ``swift_context`` attribute. + +- The error result parameter, if present, should be represented as a + trailing parameter (always following a context parameter) with the + ``swift_error_result`` attribute. + +``swiftcall`` does not support variadic arguments or unprototyped functions. + +The parameter ABI treatment attributes are aspects of the function type. +A function type which which applies an ABI treatment attribute to a +parameter is a different type from an otherwise-identical function type +that does not. A single parameter may not have multiple ABI treatment +attributes. + +Support for this feature is target-dependent, although it should be +supported on every target that Swift supports. Query for this support +with ``__has_attribute(swiftcall)``. This implies support for the +``swift_context``, ``swift_error_result``, and ``swift_indirect_result`` +attributes. + + +thread +------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","``thread``","","","" + +The ``__declspec(thread)`` attribute declares a variable with thread local +storage. It is available under the ``-fms-extensions`` flag for MSVC +compatibility. See the documentation for `__declspec(thread)`_ on MSDN. + +.. _`__declspec(thread)`: http://msdn.microsoft.com/en-us/library/9w1sdazb.aspx + +In Clang, ``__declspec(thread)`` is generally equivalent in functionality to the +GNU ``__thread`` keyword. The variable must not have a destructor and must have +a constant initializer, if any. The attribute only applies to variables +declared with static storage duration, such as globals, class static data +members, and static locals. + + +tls_model +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``tls_model``","``gnu::tls_model``","","","","","Yes" + +The ``tls_model`` attribute allows you to specify which thread-local storage +model to use. It accepts the following strings: + +* global-dynamic +* local-dynamic +* initial-exec +* local-exec + +TLS models are mutually exclusive. + + +uninitialized +------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``uninitialized``","``clang::uninitialized``","","","","","" + +The command-line parameter ``-ftrivial-auto-var-init=*`` can be used to +initialize trivial automatic stack variables. By default, trivial automatic +stack variables are uninitialized. This attribute is used to override the +command-line parameter, forcing variables to remain uninitialized. It has no +semantic meaning in that using uninitialized values is undefined behavior, +it rather documents the programmer's intent. + + +Field Attributes +================ + + +no_unique_address +----------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","``no_unique_address``","","","","","" + +The ``no_unique_address`` attribute allows tail padding in a non-static data +member to overlap other members of the enclosing class (and in the special +case when the type is empty, permits it to fully overlap other members). +The field is laid out as if a base class were encountered at the corresponding +point within the class (except that it does not share a vptr with the enclosing +object). + +Example usage: + +.. code-block:: c++ + + template struct my_vector { + T *p; + [[no_unique_address]] Alloc alloc; + // ... + }; + static_assert(sizeof(my_vector>) == sizeof(int*)); + +``[[no_unique_address]]`` is a standard C++20 attribute. Clang supports its use +in C++11 onwards. + + +Type Attributes +=============== + + +align_value +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``align_value``","","","","","","Yes" + +The align_value attribute can be added to the typedef of a pointer type or the +declaration of a variable of pointer or reference type. It specifies that the +pointer will point to, or the reference will bind to, only objects with at +least the provided alignment. This alignment value must be some positive power +of 2. + + .. code-block:: c + + typedef double * aligned_double_ptr __attribute__((align_value(64))); + void foo(double & x __attribute__((align_value(128)), + aligned_double_ptr y) { ... } + +If the pointer value does not have the specified alignment at runtime, the +behavior of the program is undefined. + + +hip_pinned_shadow +----------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``hip_pinned_shadow``","","","``__hip_pinned_shadow__``","","","Yes" + +The GNU style attribute __attribute__((hip_pinned_shadow)) or MSVC style attribute +__declspec(hip_pinned_shadow) can be added to the definition of a global variable +to indicate it is a HIP pinned shadow variable. A HIP pinned shadow variable can +be accessed on both device side and host side. It has external linkage and is +not initialized on device side. It has internal linkage and is initialized by +the initializer on host side. + + +noderef +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``noderef``","``clang::noderef``","``clang::noderef``","","","","" + +The ``noderef`` attribute causes clang to diagnose dereferences of annotated pointer types. +This is ideally used with pointers that point to special memory which cannot be read +from or written to, but allowing for the pointer to be used in pointer arithmetic. +The following are examples of valid expressions where dereferences are diagnosed: + +.. code-block:: c + + int __attribute__((noderef)) *p; + int x = *p; // warning + + int __attribute__((noderef)) **p2; + x = **p2; // warning + + int * __attribute__((noderef)) *p3; + p = *p3; // warning + + struct S { + int a; + }; + struct S __attribute__((noderef)) *s; + x = s->a; // warning + x = (*s).a; // warning + +Not all dereferences may diagnose a warning if the value directed by the pointer may not be +accessed. The following are examples of valid expressions where may not be diagnosed: + +.. code-block:: c + + int *q; + int __attribute__((noderef)) *p; + q = &*p; + q = *&p; + + struct S { + int a; + }; + struct S __attribute__((noderef)) *s; + p = &s->a; + p = &(*s).a; + +``noderef`` is currently only supported for pointers and arrays and not usable for +references or Objective-C object pointers. + +.. code-block: c++ + + int x = 2; + int __attribute__((noderef)) &y = x; // warning: 'noderef' can only be used on an array or pointer type + +.. code-block: objc + + id __attribute__((noderef)) obj = [NSObject new]; // warning: 'noderef' can only be used on an array or pointer type + + +objc_class_stub +--------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``objc_class_stub``","``clang::objc_class_stub``","``clang::objc_class_stub``","","","","Yes" + +This attribute specifies that the Objective-C class to which it applies is +instantiated at runtime. + +Unlike ``__attribute__((objc_runtime_visible))``, a class having this attribute +still has a "class stub" that is visible to the linker. This allows categories +to be defined. Static message sends with the class as a receiver use a special +access pattern to ensure the class is lazily instantiated from the class stub. + +Classes annotated with this attribute cannot be subclassed and cannot have +implementations defined for them. This attribute is intended for use in +Swift-generated headers for classes defined in Swift. + +Adding or removing this attribute to a class is an ABI-breaking change. + + +Statement Attributes +==================== + + +#pragma clang loop +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","","``clang loop`` |br| ``unroll`` |br| ``nounroll`` |br| ``unroll_and_jam`` |br| ``nounroll_and_jam``","" + +The ``#pragma clang loop`` directive allows loop optimization hints to be +specified for the subsequent loop. The directive allows pipelining to be +disabled, or vectorization, interleaving, and unrolling to be enabled or disabled. +Vector width, interleave count, unrolling count, and the initiation interval +for pipelining can be explicitly specified. See `language extensions +`_ +for details. + + +#pragma unroll, #pragma nounroll +-------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","","``clang loop`` |br| ``unroll`` |br| ``nounroll`` |br| ``unroll_and_jam`` |br| ``nounroll_and_jam``","" + +Loop unrolling optimization hints can be specified with ``#pragma unroll`` and +``#pragma nounroll``. The pragma is placed immediately before a for, while, +do-while, or c++11 range-based for loop. + +Specifying ``#pragma unroll`` without a parameter directs the loop unroller to +attempt to fully unroll the loop if the trip count is known at compile time and +attempt to partially unroll the loop if the trip count is not known at compile +time: + +.. code-block:: c++ + + #pragma unroll + for (...) { + ... + } + +Specifying the optional parameter, ``#pragma unroll _value_``, directs the +unroller to unroll the loop ``_value_`` times. The parameter may optionally be +enclosed in parentheses: + +.. code-block:: c++ + + #pragma unroll 16 + for (...) { + ... + } + + #pragma unroll(16) + for (...) { + ... + } + +Specifying ``#pragma nounroll`` indicates that the loop should not be unrolled: + +.. code-block:: c++ + + #pragma nounroll + for (...) { + ... + } + +``#pragma unroll`` and ``#pragma unroll _value_`` have identical semantics to +``#pragma clang loop unroll(full)`` and +``#pragma clang loop unroll_count(_value_)`` respectively. ``#pragma nounroll`` +is equivalent to ``#pragma clang loop unroll(disable)``. See +`language extensions +`_ +for further details including limitations of the unroll hints. + + +__read_only, __write_only, __read_write (read_only, write_only, read_write) +--------------------------------------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``__read_only`` |br| ``read_only`` |br| ``__write_only`` |br| ``write_only`` |br| ``__read_write`` |br| ``read_write``","","" + +The access qualifiers must be used with image object arguments or pipe arguments +to declare if they are being read or written by a kernel or function. + +The read_only/__read_only, write_only/__write_only and read_write/__read_write +names are reserved for use as access qualifiers and shall not be used otherwise. + +.. code-block:: c + + kernel void + foo (read_only image2d_t imageA, + write_only image2d_t imageB) { + ... + } + +In the above example imageA is a read-only 2D image object, and imageB is a +write-only 2D image object. + +The read_write (or __read_write) qualifier can not be used with pipe. + +More details can be found in the OpenCL C language Spec v2.0, Section 6.6. + + +fallthrough +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","``fallthrough`` |br| ``clang::fallthrough``","``fallthrough``","","","","" + +The ``fallthrough`` (or ``clang::fallthrough``) attribute is used +to annotate intentional fall-through +between switch labels. It can only be applied to a null statement placed at a +point of execution between any statement and the next switch label. It is +common to mark these places with a specific comment, but this attribute is +meant to replace comments with a more strict annotation, which can be checked +by the compiler. This attribute doesn't change semantics of the code and can +be used wherever an intended fall-through occurs. It is designed to mimic +control-flow statements like ``break;``, so it can be placed in most places +where ``break;`` can, but only if there are no statements on the execution path +between it and the next switch label. + +By default, Clang does not warn on unannotated fallthrough from one ``switch`` +case to another. Diagnostics on fallthrough without a corresponding annotation +can be enabled with the ``-Wimplicit-fallthrough`` argument. + +Here is an example: + +.. code-block:: c++ + + // compile with -Wimplicit-fallthrough + switch (n) { + case 22: + case 33: // no warning: no statements between case labels + f(); + case 44: // warning: unannotated fall-through + g(); + [[clang::fallthrough]]; + case 55: // no warning + if (x) { + h(); + break; + } + else { + i(); + [[clang::fallthrough]]; + } + case 66: // no warning + p(); + [[clang::fallthrough]]; // warning: fallthrough annotation does not + // directly precede case label + q(); + case 77: // warning: unannotated fall-through + r(); + } + + +intel_reqd_sub_group_size +------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``intel_reqd_sub_group_size``","","","","","","Yes" + +The optional attribute intel_reqd_sub_group_size can be used to indicate that +the kernel must be compiled and executed with the specified subgroup size. When +this attribute is present, get_max_sub_group_size() is guaranteed to return the +specified integer value. This is important for the correctness of many subgroup +algorithms, and in some cases may be used by the compiler to generate more optimal +code. See `cl_intel_required_subgroup_size +` +for details. + + +opencl_unroll_hint +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``opencl_unroll_hint``","","","","","","" + +The opencl_unroll_hint attribute qualifier can be used to specify that a loop +(for, while and do loops) can be unrolled. This attribute qualifier can be +used to specify full unrolling or partial unrolling by a specified amount. +This is a compiler hint and the compiler may ignore this directive. See +`OpenCL v2.0 `_ +s6.11.5 for details. + + +suppress +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","``gsl::suppress``","","","","","" + +The ``[[gsl::suppress]]`` attribute suppresses specific +clang-tidy diagnostics for rules of the `C++ Core Guidelines`_ in a portable +way. The attribute can be attached to declarations, statements, and at +namespace scope. + +.. code-block:: c++ + + [[gsl::suppress("Rh-public")]] + void f_() { + int *p; + [[gsl::suppress("type")]] { + p = reinterpret_cast(7); + } + } + namespace N { + [[clang::suppress("type", "bounds")]]; + ... + } + +.. _`C++ Core Guidelines`: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#inforce-enforcement + + +Declaration Attributes +====================== + + +__single_inhertiance, __multiple_inheritance, __virtual_inheritance +------------------------------------------------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``__single_inheritance`` |br| ``__multiple_inheritance`` |br| ``__virtual_inheritance`` |br| ``__unspecified_inheritance``","","" + +This collection of keywords is enabled under ``-fms-extensions`` and controls +the pointer-to-member representation used on ``*-*-win32`` targets. + +The ``*-*-win32`` targets utilize a pointer-to-member representation which +varies in size and alignment depending on the definition of the underlying +class. + +However, this is problematic when a forward declaration is only available and +no definition has been made yet. In such cases, Clang is forced to utilize the +most general representation that is available to it. + +These keywords make it possible to use a pointer-to-member representation other +than the most general one regardless of whether or not the definition will ever +be present in the current translation unit. + +This family of keywords belong between the ``class-key`` and ``class-name``: + +.. code-block:: c++ + + struct __single_inheritance S; + int S::*i; + struct S {}; + +This keyword can be applied to class templates but only has an effect when used +on full specializations: + +.. code-block:: c++ + + template struct __single_inheritance A; // warning: inheritance model ignored on primary template + template struct __multiple_inheritance A; // warning: inheritance model ignored on partial specialization + template <> struct __single_inheritance A; + +Note that choosing an inheritance model less general than strictly necessary is +an error: + +.. code-block:: c++ + + struct __multiple_inheritance S; // error: inheritance model does not match definition + int S::*i; + struct S {}; + + +deprecated +---------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``deprecated``","``gnu::deprecated`` |br| ``deprecated``","``deprecated``","``deprecated``","","","" + +The ``deprecated`` attribute can be applied to a function, a variable, or a +type. This is useful when identifying functions, variables, or types that are +expected to be removed in a future version of a program. + +Consider the function declaration for a hypothetical function ``f``: + +.. code-block:: c++ + + void f(void) __attribute__((deprecated("message", "replacement"))); + +When spelled as `__attribute__((deprecated))`, the deprecated attribute can have +two optional string arguments. The first one is the message to display when +emitting the warning; the second one enables the compiler to provide a Fix-It +to replace the deprecated name with a new name. Otherwise, when spelled as +`[[gnu::deprecated]] or [[deprecated]]`, the attribute can have one optional +string argument which is the message to display when emitting the warning. + + +empty_bases +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","``empty_bases``","","","" + +The empty_bases attribute permits the compiler to utilize the +empty-base-optimization more frequently. +This attribute only applies to struct, class, and union types. +It is only supported when using the Microsoft C++ ABI. + + +enum_extensibility +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``enum_extensibility``","``clang::enum_extensibility``","``clang::enum_extensibility``","","","","Yes" + +Attribute ``enum_extensibility`` is used to distinguish between enum definitions +that are extensible and those that are not. The attribute can take either +``closed`` or ``open`` as an argument. ``closed`` indicates a variable of the +enum type takes a value that corresponds to one of the enumerators listed in the +enum definition or, when the enum is annotated with ``flag_enum``, a value that +can be constructed using values corresponding to the enumerators. ``open`` +indicates a variable of the enum type can take any values allowed by the +standard and instructs clang to be more lenient when issuing warnings. + +.. code-block:: c + + enum __attribute__((enum_extensibility(closed))) ClosedEnum { + A0, A1 + }; + + enum __attribute__((enum_extensibility(open))) OpenEnum { + B0, B1 + }; + + enum __attribute__((enum_extensibility(closed),flag_enum)) ClosedFlagEnum { + C0 = 1 << 0, C1 = 1 << 1 + }; + + enum __attribute__((enum_extensibility(open),flag_enum)) OpenFlagEnum { + D0 = 1 << 0, D1 = 1 << 1 + }; + + void foo1() { + enum ClosedEnum ce; + enum OpenEnum oe; + enum ClosedFlagEnum cfe; + enum OpenFlagEnum ofe; + + ce = A1; // no warnings + ce = 100; // warning issued + oe = B1; // no warnings + oe = 100; // no warnings + cfe = C0 | C1; // no warnings + cfe = C0 | C1 | 4; // warning issued + ofe = D0 | D1; // no warnings + ofe = D0 | D1 | 4; // no warnings + } + + +external_source_symbol +---------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``external_source_symbol``","``clang::external_source_symbol``","``clang::external_source_symbol``","","","","Yes" + +The ``external_source_symbol`` attribute specifies that a declaration originates +from an external source and describes the nature of that source. + +The fact that Clang is capable of recognizing declarations that were defined +externally can be used to provide better tooling support for mixed-language +projects or projects that rely on auto-generated code. For instance, an IDE that +uses Clang and that supports mixed-language projects can use this attribute to +provide a correct 'jump-to-definition' feature. For a concrete example, +consider a protocol that's defined in a Swift file: + +.. code-block:: swift + + @objc public protocol SwiftProtocol { + func method() + } + +This protocol can be used from Objective-C code by including a header file that +was generated by the Swift compiler. The declarations in that header can use +the ``external_source_symbol`` attribute to make Clang aware of the fact +that ``SwiftProtocol`` actually originates from a Swift module: + +.. code-block:: objc + + __attribute__((external_source_symbol(language="Swift",defined_in="module"))) + @protocol SwiftProtocol + @required + - (void) method; + @end + +Consequently, when 'jump-to-definition' is performed at a location that +references ``SwiftProtocol``, the IDE can jump to the original definition in +the Swift source file rather than jumping to the Objective-C declaration in the +auto-generated header file. + +The ``external_source_symbol`` attribute is a comma-separated list that includes +clauses that describe the origin and the nature of the particular declaration. +Those clauses can be: + +language=\ *string-literal* + The name of the source language in which this declaration was defined. + +defined_in=\ *string-literal* + The name of the source container in which the declaration was defined. The + exact definition of source container is language-specific, e.g. Swift's + source containers are modules, so ``defined_in`` should specify the Swift + module name. + +generated_declaration + This declaration was automatically generated by some tool. + +The clauses can be specified in any order. The clauses that are listed above are +all optional, but the attribute has to have at least one clause. + + +flag_enum +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``flag_enum``","``clang::flag_enum``","``clang::flag_enum``","","","","Yes" + +This attribute can be added to an enumerator to signal to the compiler that it +is intended to be used as a flag type. This will cause the compiler to assume +that the range of the type includes all of the values that you can get by +manipulating bits of the enumerator when issuing warnings. + + +layout_version +-------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","``layout_version``","","","" + +The layout_version attribute requests that the compiler utilize the class +layout rules of a particular compiler version. +This attribute only applies to struct, class, and union types. +It is only supported when using the Microsoft C++ ABI. + + +lto_visibility_public +--------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``lto_visibility_public``","``clang::lto_visibility_public``","``clang::lto_visibility_public``","","","","Yes" + +See :doc:`LTOVisibility`. + + +novtable +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","``novtable``","","","" + +This attribute can be added to a class declaration or definition to signal to +the compiler that constructors and destructors will not reference the virtual +function table. It is only supported when using the Microsoft C++ ABI. + + +objc_boxable +------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``objc_boxable``","``clang::objc_boxable``","``clang::objc_boxable``","","","","Yes" + +Structs and unions marked with the ``objc_boxable`` attribute can be used +with the Objective-C boxed expression syntax, ``@(...)``. + +**Usage**: ``__attribute__((objc_boxable))``. This attribute +can only be placed on a declaration of a trivially-copyable struct or union: + +.. code-block:: objc + + struct __attribute__((objc_boxable)) some_struct { + int i; + }; + union __attribute__((objc_boxable)) some_union { + int i; + float f; + }; + typedef struct __attribute__((objc_boxable)) _some_struct some_struct; + + // ... + + some_struct ss; + NSValue *boxed = @(ss); + + +objc_nonlazy_class +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``objc_nonlazy_class``","``clang::objc_nonlazy_class``","``clang::objc_nonlazy_class``","","","","Yes" + +This attribute can be added to an Objective-C ``@interface`` or +``@implementation`` declaration to add the class to the list of non-lazily +initialized classes. A non-lazy class will be initialized eagerly when the +Objective-C runtime is loaded. This is required for certain system classes which +have instances allocated in non-standard ways, such as the classes for blocks +and constant strings. Adding this attribute is essentially equivalent to +providing a trivial `+load` method but avoids the (fairly small) load-time +overheads associated with defining and calling such a method. + + +objc_runtime_name +----------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``objc_runtime_name``","``clang::objc_runtime_name``","``clang::objc_runtime_name``","","","","Yes" + +By default, the Objective-C interface or protocol identifier is used +in the metadata name for that object. The `objc_runtime_name` +attribute allows annotated interfaces or protocols to use the +specified string argument in the object's metadata name instead of the +default name. + +**Usage**: ``__attribute__((objc_runtime_name("MyLocalName")))``. This attribute +can only be placed before an @protocol or @interface declaration: + +.. code-block:: objc + + __attribute__((objc_runtime_name("MyLocalName"))) + @interface Message + @end + + +objc_runtime_visible +-------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``objc_runtime_visible``","``clang::objc_runtime_visible``","``clang::objc_runtime_visible``","","","","Yes" + +This attribute specifies that the Objective-C class to which it applies is +visible to the Objective-C runtime but not to the linker. Classes annotated +with this attribute cannot be subclassed and cannot have categories defined for +them. + + +objc_subclassing_restricted +--------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``objc_subclassing_restricted``","``clang::objc_subclassing_restricted``","``clang::objc_subclassing_restricted``","","","","Yes" + +This attribute can be added to an Objective-C ``@interface`` declaration to +ensure that this class cannot be subclassed. + + +selectany +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``selectany``","``gnu::selectany``","","``selectany``","","","" + +This attribute appertains to a global symbol, causing it to have a weak +definition ( +`linkonce `_ +), allowing the linker to select any definition. + +For more information see +`gcc documentation `_ +or `msvc documentation `_. + + +transparent_union +----------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``transparent_union``","``gnu::transparent_union``","","","","","" + +This attribute can be applied to a union to change the behaviour of calls to +functions that have an argument with a transparent union type. The compiler +behaviour is changed in the following manner: + +- A value whose type is any member of the transparent union can be passed as an + argument without the need to cast that value. + +- The argument is passed to the function using the calling convention of the + first member of the transparent union. Consequently, all the members of the + transparent union should have the same calling convention as its first member. + +Transparent unions are not supported in C++. + + +trivial_abi +----------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``trivial_abi``","``clang::trivial_abi``","","","","","Yes" + +The ``trivial_abi`` attribute can be applied to a C++ class, struct, or union. +It instructs the compiler to pass and return the type using the C ABI for the +underlying type when the type would otherwise be considered non-trivial for the +purpose of calls. +A class annotated with `trivial_abi` can have non-trivial destructors or copy/move constructors without automatically becoming non-trivial for the purposes of calls. For example: + + .. code-block:: c++ + + // A is trivial for the purposes of calls because `trivial_abi` makes the + // user-provided special functions trivial. + struct __attribute__((trivial_abi)) A { + ~A(); + A(const A &); + A(A &&); + int x; + }; + + // B's destructor and copy/move constructor are considered trivial for the + // purpose of calls because A is trivial. + struct B { + A a; + }; + +If a type is trivial for the purposes of calls, has a non-trivial destructor, +and is passed as an argument by value, the convention is that the callee will +destroy the object before returning. + +Attribute ``trivial_abi`` has no effect in the following cases: + +- The class directly declares a virtual base or virtual methods. +- The class has a base class that is non-trivial for the purposes of calls. +- The class has a non-static data member whose type is non-trivial for the purposes of calls, which includes: + + - classes that are non-trivial for the purposes of calls + - __weak-qualified types in Objective-C++ + - arrays of any of the above + + +OpenCL Address Spaces +===================== +The address space qualifier may be used to specify the region of memory that is +used to allocate the object. OpenCL supports the following address spaces: +__generic(generic), __global(global), __local(local), __private(private), +__constant(constant). + + .. code-block:: c + + __constant int c = ...; + + __generic int* foo(global int* g) { + __local int* l; + private int p; + ... + return l; + } + +More details can be found in the OpenCL C language Spec v2.0, Section 6.5. + +constant +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``__constant`` |br| ``constant``","","" + +The constant address space attribute signals that an object is located in +a constant (non-modifiable) memory region. It is available to all work items. +Any type can be annotated with the constant address space attribute. Objects +with the constant address space qualifier can be declared in any scope and must +have an initializer. + + +generic +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``__generic`` |br| ``generic``","","" + +The generic address space attribute is only available with OpenCL v2.0 and later. +It can be used with pointer types. Variables in global and local scope and +function parameters in non-kernel functions can have the generic address space +type attribute. It is intended to be a placeholder for any other address space +except for '__constant' in OpenCL code which can be used with multiple address +spaces. + + +global +------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``__global`` |br| ``global``","","" + +The global address space attribute specifies that an object is allocated in +global memory, which is accessible by all work items. The content stored in this +memory area persists between kernel executions. Pointer types to the global +address space are allowed as function parameters or local variables. Starting +with OpenCL v2.0, the global address space can be used with global (program +scope) variables and static local variable as well. + + +local +----- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``__local`` |br| ``local``","","" + +The local address space specifies that an object is allocated in the local (work +group) memory area, which is accessible to all work items in the same work +group. The content stored in this memory region is not accessible after +the kernel execution ends. In a kernel function scope, any variable can be in +the local address space. In other scopes, only pointer types to the local address +space are allowed. Local address space variables cannot have an initializer. + + +private +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``__private`` |br| ``private``","","" + +The private address space specifies that an object is allocated in the private +(work item) memory. Other work items cannot access the same memory area and its +content is destroyed after work item execution ends. Local variables can be +declared in the private address space. Function arguments are always in the +private address space. Kernel function arguments of a pointer or an array type +cannot point to the private address space. + + +AMD GPU Attributes +================== + + +amdgpu_flat_work_group_size +--------------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``amdgpu_flat_work_group_size``","``clang::amdgpu_flat_work_group_size``","","","","","Yes" + +The flat work-group size is the number of work-items in the work-group size +specified when the kernel is dispatched. It is the product of the sizes of the +x, y, and z dimension of the work-group. + +Clang supports the +``__attribute__((amdgpu_flat_work_group_size(, )))`` attribute for the +AMDGPU target. This attribute may be attached to a kernel function definition +and is an optimization hint. + +```` parameter specifies the minimum flat work-group size, and ```` +parameter specifies the maximum flat work-group size (must be greater than +````) to which all dispatches of the kernel will conform. Passing ``0, 0`` +as ``, `` implies the default behavior (``128, 256``). + +If specified, the AMDGPU target backend might be able to produce better machine +code for barriers and perform scratch promotion by estimating available group +segment size. + +An error will be given if: + - Specified values violate subtarget specifications; + - Specified values are not compatible with values provided through other + attributes. + + +amdgpu_num_sgpr +--------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``amdgpu_num_sgpr``","``clang::amdgpu_num_sgpr``","","","","","Yes" + +Clang supports the ``__attribute__((amdgpu_num_sgpr()))`` and +``__attribute__((amdgpu_num_vgpr()))`` attributes for the AMDGPU +target. These attributes may be attached to a kernel function definition and are +an optimization hint. + +If these attributes are specified, then the AMDGPU target backend will attempt +to limit the number of SGPRs and/or VGPRs used to the specified value(s). The +number of used SGPRs and/or VGPRs may further be rounded up to satisfy the +allocation requirements or constraints of the subtarget. Passing ``0`` as +``num_sgpr`` and/or ``num_vgpr`` implies the default behavior (no limits). + +These attributes can be used to test the AMDGPU target backend. It is +recommended that the ``amdgpu_waves_per_eu`` attribute be used to control +resources such as SGPRs and VGPRs since it is aware of the limits for different +subtargets. + +An error will be given if: + - Specified values violate subtarget specifications; + - Specified values are not compatible with values provided through other + attributes; + - The AMDGPU target backend is unable to create machine code that can meet the + request. + + +amdgpu_num_vgpr +--------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``amdgpu_num_vgpr``","``clang::amdgpu_num_vgpr``","","","","","Yes" + +Clang supports the ``__attribute__((amdgpu_num_sgpr()))`` and +``__attribute__((amdgpu_num_vgpr()))`` attributes for the AMDGPU +target. These attributes may be attached to a kernel function definition and are +an optimization hint. + +If these attributes are specified, then the AMDGPU target backend will attempt +to limit the number of SGPRs and/or VGPRs used to the specified value(s). The +number of used SGPRs and/or VGPRs may further be rounded up to satisfy the +allocation requirements or constraints of the subtarget. Passing ``0`` as +``num_sgpr`` and/or ``num_vgpr`` implies the default behavior (no limits). + +These attributes can be used to test the AMDGPU target backend. It is +recommended that the ``amdgpu_waves_per_eu`` attribute be used to control +resources such as SGPRs and VGPRs since it is aware of the limits for different +subtargets. + +An error will be given if: + - Specified values violate subtarget specifications; + - Specified values are not compatible with values provided through other + attributes; + - The AMDGPU target backend is unable to create machine code that can meet the + request. + + +amdgpu_waves_per_eu +------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``amdgpu_waves_per_eu``","``clang::amdgpu_waves_per_eu``","","","","","Yes" + +A compute unit (CU) is responsible for executing the wavefronts of a work-group. +It is composed of one or more execution units (EU), which are responsible for +executing the wavefronts. An EU can have enough resources to maintain the state +of more than one executing wavefront. This allows an EU to hide latency by +switching between wavefronts in a similar way to symmetric multithreading on a +CPU. In order to allow the state for multiple wavefronts to fit on an EU, the +resources used by a single wavefront have to be limited. For example, the number +of SGPRs and VGPRs. Limiting such resources can allow greater latency hiding, +but can result in having to spill some register state to memory. + +Clang supports the ``__attribute__((amdgpu_waves_per_eu([, ])))`` +attribute for the AMDGPU target. This attribute may be attached to a kernel +function definition and is an optimization hint. + +```` parameter specifies the requested minimum number of waves per EU, and +*optional* ```` parameter specifies the requested maximum number of waves +per EU (must be greater than ```` if specified). If ```` is omitted, +then there is no restriction on the maximum number of waves per EU other than +the one dictated by the hardware for which the kernel is compiled. Passing +``0, 0`` as ``, `` implies the default behavior (no limits). + +If specified, this attribute allows an advanced developer to tune the number of +wavefronts that are capable of fitting within the resources of an EU. The AMDGPU +target backend can use this information to limit resources, such as number of +SGPRs, number of VGPRs, size of available group and private memory segments, in +such a way that guarantees that at least ```` wavefronts and at most +```` wavefronts are able to fit within the resources of an EU. Requesting +more wavefronts can hide memory latency but limits available registers which +can result in spilling. Requesting fewer wavefronts can help reduce cache +thrashing, but can reduce memory latency hiding. + +This attribute controls the machine code generated by the AMDGPU target backend +to ensure it is capable of meeting the requested values. However, when the +kernel is executed, there may be other reasons that prevent meeting the request, +for example, there may be wavefronts from other kernels executing on the EU. + +An error will be given if: + - Specified values violate subtarget specifications; + - Specified values are not compatible with values provided through other + attributes; + - The AMDGPU target backend is unable to create machine code that can meet the + request. + + +Calling Conventions +=================== +Clang supports several different calling conventions, depending on the target +platform and architecture. The calling convention used for a function determines +how parameters are passed, how results are returned to the caller, and other +low-level details of calling a function. + +aarch64_vector_pcs +------------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``aarch64_vector_pcs``","``clang::aarch64_vector_pcs``","``clang::aarch64_vector_pcs``","","","","" + +On AArch64 targets, this attribute changes the calling convention of a +function to preserve additional floating-point and Advanced SIMD registers +relative to the default calling convention used for AArch64. + +This means it is more efficient to call such functions from code that performs +extensive floating-point and vector calculations, because fewer live SIMD and FP +registers need to be saved. This property makes it well-suited for e.g. +floating-point or vector math library functions, which are typically leaf +functions that require a small number of registers. + +However, using this attribute also means that it is more expensive to call +a function that adheres to the default calling convention from within such +a function. Therefore, it is recommended that this attribute is only used +for leaf functions. + +For more information, see the documentation for `aarch64_vector_pcs`_ on +the Arm Developer website. + +.. _`aarch64_vector_pcs`: https://developer.arm.com/products/software-development-tools/hpc/arm-compiler-for-hpc/vector-function-abi + + +fastcall +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``fastcall``","``gnu::fastcall``","","","``__fastcall`` |br| ``_fastcall``","","" + +On 32-bit x86 targets, this attribute changes the calling convention of a +function to use ECX and EDX as register parameters and clear parameters off of +the stack on return. This convention does not support variadic calls or +unprototyped functions in C, and has no effect on x86_64 targets. This calling +convention is supported primarily for compatibility with existing code. Users +seeking register parameters should use the ``regparm`` attribute, which does +not require callee-cleanup. See the documentation for `__fastcall`_ on MSDN. + +.. _`__fastcall`: http://msdn.microsoft.com/en-us/library/6xa169sk.aspx + + +ms_abi +------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``ms_abi``","``gnu::ms_abi``","","","","","" + +On non-Windows x86_64 targets, this attribute changes the calling convention of +a function to match the default convention used on Windows x86_64. This +attribute has no effect on Windows targets or non-x86_64 targets. + + +pcs +--- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``pcs``","``gnu::pcs``","","","","","" + +On ARM targets, this attribute can be used to select calling conventions +similar to ``stdcall`` on x86. Valid parameter values are "aapcs" and +"aapcs-vfp". + + +preserve_all +------------ +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``preserve_all``","``clang::preserve_all``","``clang::preserve_all``","","","","" + +On X86-64 and AArch64 targets, this attribute changes the calling convention of +a function. The ``preserve_all`` calling convention attempts to make the code +in the caller even less intrusive than the ``preserve_most`` calling convention. +This calling convention also behaves identical to the ``C`` calling convention +on how arguments and return values are passed, but it uses a different set of +caller/callee-saved registers. This removes the burden of saving and +recovering a large register set before and after the call in the caller. If +the arguments are passed in callee-saved registers, then they will be +preserved by the callee across the call. This doesn't apply for values +returned in callee-saved registers. + +- On X86-64 the callee preserves all general purpose registers, except for + R11. R11 can be used as a scratch register. Furthermore it also preserves + all floating-point registers (XMMs/YMMs). + +The idea behind this convention is to support calls to runtime functions +that don't need to call out to any other functions. + +This calling convention, like the ``preserve_most`` calling convention, will be +used by a future version of the Objective-C runtime and should be considered +experimental at this time. + + +preserve_most +------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``preserve_most``","``clang::preserve_most``","``clang::preserve_most``","","","","" + +On X86-64 and AArch64 targets, this attribute changes the calling convention of +a function. The ``preserve_most`` calling convention attempts to make the code +in the caller as unintrusive as possible. This convention behaves identically +to the ``C`` calling convention on how arguments and return values are passed, +but it uses a different set of caller/callee-saved registers. This alleviates +the burden of saving and recovering a large register set before and after the +call in the caller. If the arguments are passed in callee-saved registers, +then they will be preserved by the callee across the call. This doesn't +apply for values returned in callee-saved registers. + +- On X86-64 the callee preserves all general purpose registers, except for + R11. R11 can be used as a scratch register. Floating-point registers + (XMMs/YMMs) are not preserved and need to be saved by the caller. + +The idea behind this convention is to support calls to runtime functions +that have a hot path and a cold path. The hot path is usually a small piece +of code that doesn't use many registers. The cold path might need to call out to +another function and therefore only needs to preserve the caller-saved +registers, which haven't already been saved by the caller. The +`preserve_most` calling convention is very similar to the ``cold`` calling +convention in terms of caller/callee-saved registers, but they are used for +different types of function calls. ``coldcc`` is for function calls that are +rarely executed, whereas `preserve_most` function calls are intended to be +on the hot path and definitely executed a lot. Furthermore ``preserve_most`` +doesn't prevent the inliner from inlining the function call. + +This calling convention will be used by a future version of the Objective-C +runtime and should therefore still be considered experimental at this time. +Although this convention was created to optimize certain runtime calls to +the Objective-C runtime, it is not limited to this runtime and might be used +by other runtimes in the future too. The current implementation only +supports X86-64 and AArch64, but the intention is to support more architectures +in the future. + + +regcall +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``regcall``","``gnu::regcall``","","","``__regcall``","","" + +On x86 targets, this attribute changes the calling convention to +`__regcall`_ convention. This convention aims to pass as many arguments +as possible in registers. It also tries to utilize registers for the +return value whenever it is possible. + +.. _`__regcall`: https://software.intel.com/en-us/node/693069 + + +regparm +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``regparm``","``gnu::regparm``","","","","","" + +On 32-bit x86 targets, the regparm attribute causes the compiler to pass +the first three integer parameters in EAX, EDX, and ECX instead of on the +stack. This attribute has no effect on variadic functions, and all parameters +are passed via the stack as normal. + + +stdcall +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``stdcall``","``gnu::stdcall``","","","``__stdcall`` |br| ``_stdcall``","","" + +On 32-bit x86 targets, this attribute changes the calling convention of a +function to clear parameters off of the stack on return. This convention does +not support variadic calls or unprototyped functions in C, and has no effect on +x86_64 targets. This calling convention is used widely by the Windows API and +COM applications. See the documentation for `__stdcall`_ on MSDN. + +.. _`__stdcall`: http://msdn.microsoft.com/en-us/library/zxk0tw93.aspx + + +thiscall +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``thiscall``","``gnu::thiscall``","","","``__thiscall`` |br| ``_thiscall``","","" + +On 32-bit x86 targets, this attribute changes the calling convention of a +function to use ECX for the first parameter (typically the implicit ``this`` +parameter of C++ methods) and clear parameters off of the stack on return. This +convention does not support variadic calls or unprototyped functions in C, and +has no effect on x86_64 targets. See the documentation for `__thiscall`_ on +MSDN. + +.. _`__thiscall`: http://msdn.microsoft.com/en-us/library/ek8tkfbw.aspx + + +vectorcall +---------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``vectorcall``","``clang::vectorcall``","``clang::vectorcall``","","``__vectorcall`` |br| ``_vectorcall``","","" + +On 32-bit x86 *and* x86_64 targets, this attribute changes the calling +convention of a function to pass vector parameters in SSE registers. + +On 32-bit x86 targets, this calling convention is similar to ``__fastcall``. +The first two integer parameters are passed in ECX and EDX. Subsequent integer +parameters are passed in memory, and callee clears the stack. On x86_64 +targets, the callee does *not* clear the stack, and integer parameters are +passed in RCX, RDX, R8, and R9 as is done for the default Windows x64 calling +convention. + +On both 32-bit x86 and x86_64 targets, vector and floating point arguments are +passed in XMM0-XMM5. Homogeneous vector aggregates of up to four elements are +passed in sequential SSE registers if enough are available. If AVX is enabled, +256 bit vectors are passed in YMM0-YMM5. Any vector or aggregate type that +cannot be passed in registers for any reason is passed by reference, which +allows the caller to align the parameter memory. + +See the documentation for `__vectorcall`_ on MSDN for more details. + +.. _`__vectorcall`: http://msdn.microsoft.com/en-us/library/dn375768.aspx + + +Consumed Annotation Checking +============================ +Clang supports additional attributes for checking basic resource management +properties, specifically for unique objects that have a single owning reference. +The following attributes are currently supported, although **the implementation +for these annotations is currently in development and are subject to change.** + +callable_when +------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``callable_when``","``clang::callable_when``","","","","","Yes" + +Use ``__attribute__((callable_when(...)))`` to indicate what states a method +may be called in. Valid states are unconsumed, consumed, or unknown. Each +argument to this attribute must be a quoted string. E.g.: + +``__attribute__((callable_when("unconsumed", "unknown")))`` + + +consumable +---------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``consumable``","``clang::consumable``","","","","","Yes" + +Each ``class`` that uses any of the typestate annotations must first be marked +using the ``consumable`` attribute. Failure to do so will result in a warning. + +This attribute accepts a single parameter that must be one of the following: +``unknown``, ``consumed``, or ``unconsumed``. + + +param_typestate +--------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``param_typestate``","``clang::param_typestate``","","","","","Yes" + +This attribute specifies expectations about function parameters. Calls to an +function with annotated parameters will issue a warning if the corresponding +argument isn't in the expected state. The attribute is also used to set the +initial state of the parameter when analyzing the function's body. + + +return_typestate +---------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``return_typestate``","``clang::return_typestate``","","","","","Yes" + +The ``return_typestate`` attribute can be applied to functions or parameters. +When applied to a function the attribute specifies the state of the returned +value. The function's body is checked to ensure that it always returns a value +in the specified state. On the caller side, values returned by the annotated +function are initialized to the given state. + +When applied to a function parameter it modifies the state of an argument after +a call to the function returns. The function's body is checked to ensure that +the parameter is in the expected state before returning. + + +set_typestate +------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``set_typestate``","``clang::set_typestate``","","","","","Yes" + +Annotate methods that transition an object into a new state with +``__attribute__((set_typestate(new_state)))``. The new state must be +unconsumed, consumed, or unknown. + + +test_typestate +-------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``test_typestate``","``clang::test_typestate``","","","","","Yes" + +Use ``__attribute__((test_typestate(tested_state)))`` to indicate that a method +returns true if the object is in the specified state.. + + +Type Safety Checking +==================== +Clang supports additional attributes to enable checking type safety properties +that can't be enforced by the C type system. To see warnings produced by these +checks, ensure that -Wtype-safety is enabled. Use cases include: + +* MPI library implementations, where these attributes enable checking that + the buffer type matches the passed ``MPI_Datatype``; +* for HDF5 library there is a similar use case to MPI; +* checking types of variadic functions' arguments for functions like + ``fcntl()`` and ``ioctl()``. + +You can detect support for these attributes with ``__has_attribute()``. For +example: + +.. code-block:: c++ + + #if defined(__has_attribute) + # if __has_attribute(argument_with_type_tag) && \ + __has_attribute(pointer_with_type_tag) && \ + __has_attribute(type_tag_for_datatype) + # define ATTR_MPI_PWT(buffer_idx, type_idx) __attribute__((pointer_with_type_tag(mpi,buffer_idx,type_idx))) + /* ... other macros ... */ + # endif + #endif + + #if !defined(ATTR_MPI_PWT) + # define ATTR_MPI_PWT(buffer_idx, type_idx) + #endif + + int MPI_Send(void *buf, int count, MPI_Datatype datatype /*, other args omitted */) + ATTR_MPI_PWT(1,3); + +argument_with_type_tag +---------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``argument_with_type_tag`` |br| ``pointer_with_type_tag``","``clang::argument_with_type_tag`` |br| ``clang::pointer_with_type_tag``","``clang::argument_with_type_tag`` |br| ``clang::pointer_with_type_tag``","","","","" + +Use ``__attribute__((argument_with_type_tag(arg_kind, arg_idx, +type_tag_idx)))`` on a function declaration to specify that the function +accepts a type tag that determines the type of some other argument. + +This attribute is primarily useful for checking arguments of variadic functions +(``pointer_with_type_tag`` can be used in most non-variadic cases). + +In the attribute prototype above: + * ``arg_kind`` is an identifier that should be used when annotating all + applicable type tags. + * ``arg_idx`` provides the position of a function argument. The expected type of + this function argument will be determined by the function argument specified + by ``type_tag_idx``. In the code example below, "3" means that the type of the + function's third argument will be determined by ``type_tag_idx``. + * ``type_tag_idx`` provides the position of a function argument. This function + argument will be a type tag. The type tag will determine the expected type of + the argument specified by ``arg_idx``. In the code example below, "2" means + that the type tag associated with the function's second argument should agree + with the type of the argument specified by ``arg_idx``. + +For example: + +.. code-block:: c++ + + int fcntl(int fd, int cmd, ...) + __attribute__(( argument_with_type_tag(fcntl,3,2) )); + // The function's second argument will be a type tag; this type tag will + // determine the expected type of the function's third argument. + + +pointer_with_type_tag +--------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``argument_with_type_tag`` |br| ``pointer_with_type_tag``","``clang::argument_with_type_tag`` |br| ``clang::pointer_with_type_tag``","``clang::argument_with_type_tag`` |br| ``clang::pointer_with_type_tag``","","","","" + +Use ``__attribute__((pointer_with_type_tag(ptr_kind, ptr_idx, type_tag_idx)))`` +on a function declaration to specify that the function accepts a type tag that +determines the pointee type of some other pointer argument. + +In the attribute prototype above: + * ``ptr_kind`` is an identifier that should be used when annotating all + applicable type tags. + * ``ptr_idx`` provides the position of a function argument; this function + argument will have a pointer type. The expected pointee type of this pointer + type will be determined by the function argument specified by + ``type_tag_idx``. In the code example below, "1" means that the pointee type + of the function's first argument will be determined by ``type_tag_idx``. + * ``type_tag_idx`` provides the position of a function argument; this function + argument will be a type tag. The type tag will determine the expected pointee + type of the pointer argument specified by ``ptr_idx``. In the code example + below, "3" means that the type tag associated with the function's third + argument should agree with the pointee type of the pointer argument specified + by ``ptr_idx``. + +For example: + +.. code-block:: c++ + + typedef int MPI_Datatype; + int MPI_Send(void *buf, int count, MPI_Datatype datatype /*, other args omitted */) + __attribute__(( pointer_with_type_tag(mpi,1,3) )); + // The function's 3rd argument will be a type tag; this type tag will + // determine the expected pointee type of the function's 1st argument. + + +type_tag_for_datatype +--------------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``type_tag_for_datatype``","``clang::type_tag_for_datatype``","``clang::type_tag_for_datatype``","","","","" + +When declaring a variable, use +``__attribute__((type_tag_for_datatype(kind, type)))`` to create a type tag that +is tied to the ``type`` argument given to the attribute. + +In the attribute prototype above: + * ``kind`` is an identifier that should be used when annotating all applicable + type tags. + * ``type`` indicates the name of the type. + +Clang supports annotating type tags of two forms. + + * **Type tag that is a reference to a declared identifier.** + Use ``__attribute__((type_tag_for_datatype(kind, type)))`` when declaring that + identifier: + + .. code-block:: c++ + + typedef int MPI_Datatype; + extern struct mpi_datatype mpi_datatype_int + __attribute__(( type_tag_for_datatype(mpi,int) )); + #define MPI_INT ((MPI_Datatype) &mpi_datatype_int) + // &mpi_datatype_int is a type tag. It is tied to type "int". + + * **Type tag that is an integral literal.** + Declare a ``static const`` variable with an initializer value and attach + ``__attribute__((type_tag_for_datatype(kind, type)))`` on that declaration: + + .. code-block:: c++ + + typedef int MPI_Datatype; + static const MPI_Datatype mpi_datatype_int + __attribute__(( type_tag_for_datatype(mpi,int) )) = 42; + #define MPI_INT ((MPI_Datatype) 42) + // The number 42 is a type tag. It is tied to type "int". + + +The ``type_tag_for_datatype`` attribute also accepts an optional third argument +that determines how the type of the function argument specified by either +``arg_idx`` or ``ptr_idx`` is compared against the type associated with the type +tag. (Recall that for the ``argument_with_type_tag`` attribute, the type of the +function argument specified by ``arg_idx`` is compared against the type +associated with the type tag. Also recall that for the ``pointer_with_type_tag`` +attribute, the pointee type of the function argument specified by ``ptr_idx`` is +compared against the type associated with the type tag.) There are two supported +values for this optional third argument: + + * ``layout_compatible`` will cause types to be compared according to + layout-compatibility rules (In C++11 [class.mem] p 17, 18, see the + layout-compatibility rules for two standard-layout struct types and for two + standard-layout union types). This is useful when creating a type tag + associated with a struct or union type. For example: + + .. code-block:: c++ + + /* In mpi.h */ + typedef int MPI_Datatype; + struct internal_mpi_double_int { double d; int i; }; + extern struct mpi_datatype mpi_datatype_double_int + __attribute__(( type_tag_for_datatype(mpi, + struct internal_mpi_double_int, layout_compatible) )); + + #define MPI_DOUBLE_INT ((MPI_Datatype) &mpi_datatype_double_int) + + int MPI_Send(void *buf, int count, MPI_Datatype datatype, ...) + __attribute__(( pointer_with_type_tag(mpi,1,3) )); + + /* In user code */ + struct my_pair { double a; int b; }; + struct my_pair *buffer; + MPI_Send(buffer, 1, MPI_DOUBLE_INT /*, ... */); // no warning because the + // layout of my_pair is + // compatible with that of + // internal_mpi_double_int + + struct my_int_pair { int a; int b; } + struct my_int_pair *buffer2; + MPI_Send(buffer2, 1, MPI_DOUBLE_INT /*, ... */); // warning because the + // layout of my_int_pair + // does not match that of + // internal_mpi_double_int + + * ``must_be_null`` specifies that the function argument specified by either + ``arg_idx`` (for the ``argument_with_type_tag`` attribute) or ``ptr_idx`` (for + the ``pointer_with_type_tag`` attribute) should be a null pointer constant. + The second argument to the ``type_tag_for_datatype`` attribute is ignored. For + example: + + .. code-block:: c++ + + /* In mpi.h */ + typedef int MPI_Datatype; + extern struct mpi_datatype mpi_datatype_null + __attribute__(( type_tag_for_datatype(mpi, void, must_be_null) )); + + #define MPI_DATATYPE_NULL ((MPI_Datatype) &mpi_datatype_null) + int MPI_Send(void *buf, int count, MPI_Datatype datatype, ...) + __attribute__(( pointer_with_type_tag(mpi,1,3) )); + + /* In user code */ + struct my_pair { double a; int b; }; + struct my_pair *buffer; + MPI_Send(buffer, 1, MPI_DATATYPE_NULL /*, ... */); // warning: MPI_DATATYPE_NULL + // was specified but buffer + // is not a null pointer + + +Nullability Attributes +====================== +Whether a particular pointer may be "null" is an important concern when working with pointers in the C family of languages. The various nullability attributes indicate whether a particular pointer can be null or not, which makes APIs more expressive and can help static analysis tools identify bugs involving null pointers. Clang supports several kinds of nullability attributes: the ``nonnull`` and ``returns_nonnull`` attributes indicate which function or method parameters and result types can never be null, while nullability type qualifiers indicate which pointer types can be null (``_Nullable``) or cannot be null (``_Nonnull``). + +The nullability (type) qualifiers express whether a value of a given pointer type can be null (the ``_Nullable`` qualifier), doesn't have a defined meaning for null (the ``_Nonnull`` qualifier), or for which the purpose of null is unclear (the ``_Null_unspecified`` qualifier). Because nullability qualifiers are expressed within the type system, they are more general than the ``nonnull`` and ``returns_nonnull`` attributes, allowing one to express (for example) a nullable pointer to an array of nonnull pointers. Nullability qualifiers are written to the right of the pointer to which they apply. For example: + + .. code-block:: c + + // No meaningful result when 'ptr' is null (here, it happens to be undefined behavior). + int fetch(int * _Nonnull ptr) { return *ptr; } + + // 'ptr' may be null. + int fetch_or_zero(int * _Nullable ptr) { + return ptr ? *ptr : 0; + } + + // A nullable pointer to non-null pointers to const characters. + const char *join_strings(const char * _Nonnull * _Nullable strings, unsigned n); + +In Objective-C, there is an alternate spelling for the nullability qualifiers that can be used in Objective-C methods and properties using context-sensitive, non-underscored keywords. For example: + + .. code-block:: objective-c + + @interface NSView : NSResponder + - (nullable NSView *)ancestorSharedWithView:(nonnull NSView *)aView; + @property (assign, nullable) NSView *superview; + @property (readonly, nonnull) NSArray *subviews; + @end + +_Nonnull +-------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``_Nonnull``","","" + +The ``_Nonnull`` nullability qualifier indicates that null is not a meaningful value for a value of the ``_Nonnull`` pointer type. For example, given a declaration such as: + + .. code-block:: c + + int fetch(int * _Nonnull ptr); + +a caller of ``fetch`` should not provide a null value, and the compiler will produce a warning if it sees a literal null value passed to ``fetch``. Note that, unlike the declaration attribute ``nonnull``, the presence of ``_Nonnull`` does not imply that passing null is undefined behavior: ``fetch`` is free to consider null undefined behavior or (perhaps for backward-compatibility reasons) defensively handle null. + + +_Null_unspecified +----------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``_Null_unspecified``","","" + +The ``_Null_unspecified`` nullability qualifier indicates that neither the ``_Nonnull`` nor ``_Nullable`` qualifiers make sense for a particular pointer type. It is used primarily to indicate that the role of null with specific pointers in a nullability-annotated header is unclear, e.g., due to overly-complex implementations or historical factors with a long-lived API. + + +_Nullable +--------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "","","","","``_Nullable``","","" + +The ``_Nullable`` nullability qualifier indicates that a value of the ``_Nullable`` pointer type can be null. For example, given: + + .. code-block:: c + + int fetch_or_zero(int * _Nullable ptr); + +a caller of ``fetch_or_zero`` can provide null. + + +nonnull +------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``nonnull``","``gnu::nonnull``","","","","","" + +The ``nonnull`` attribute indicates that some function parameters must not be null, and can be used in several different ways. It's original usage (`from GCC `_) is as a function (or Objective-C method) attribute that specifies which parameters of the function are nonnull in a comma-separated list. For example: + + .. code-block:: c + + extern void * my_memcpy (void *dest, const void *src, size_t len) + __attribute__((nonnull (1, 2))); + +Here, the ``nonnull`` attribute indicates that parameters 1 and 2 +cannot have a null value. Omitting the parenthesized list of parameter indices means that all parameters of pointer type cannot be null: + + .. code-block:: c + + extern void * my_memcpy (void *dest, const void *src, size_t len) + __attribute__((nonnull)); + +Clang also allows the ``nonnull`` attribute to be placed directly on a function (or Objective-C method) parameter, eliminating the need to specify the parameter index ahead of type. For example: + + .. code-block:: c + + extern void * my_memcpy (void *dest __attribute__((nonnull)), + const void *src __attribute__((nonnull)), size_t len); + +Note that the ``nonnull`` attribute indicates that passing null to a non-null parameter is undefined behavior, which the optimizer may take advantage of to, e.g., remove null checks. The ``_Nonnull`` type qualifier indicates that a pointer cannot be null in a more general manner (because it is part of the type system) and does not imply undefined behavior, making it more widely applicable. + + +returns_nonnull +--------------- +.. csv-table:: Supported Syntaxes + :header: "GNU", "C++11", "C2x", "``__declspec``", "Keyword", "``#pragma``", "``#pragma clang attribute``" + + "``returns_nonnull``","``gnu::returns_nonnull``","","","","","Yes" + +The ``returns_nonnull`` attribute indicates that a particular function (or Objective-C method) always returns a non-null pointer. For example, a particular system ``malloc`` might be defined to terminate a process when memory is not available rather than returning a null pointer: + + .. code-block:: c + + extern void * malloc (size_t size) __attribute__((returns_nonnull)); + +The ``returns_nonnull`` attribute implies that returning a null pointer is undefined behavior, which the optimizer may take advantage of. The ``_Nonnull`` type qualifier indicates that a pointer cannot be null in a more general manner (because it is part of the type system) and does not imply undefined behavior, making it more widely applicable + + diff --git a/clang/docs/ClangCommandLineReference.rst b/clang/docs/ClangCommandLineReference.rst index 4c1fe07be3a6..5f8264762c85 100644 --- a/clang/docs/ClangCommandLineReference.rst +++ b/clang/docs/ClangCommandLineReference.rst @@ -198,6 +198,10 @@ Filename (or -) to write dependency output to Emit Clang AST files for source inputs +.. option:: -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang + +Trivial automatic variable initialization to zero is only here for benchmarks, it'll eventually be removed, and I'm OK with that because I'm only using it to benchmark + .. option:: -exported\_symbols\_list .. option:: -faligned-new= @@ -210,10 +214,6 @@ Use approximate transcendental functions Flush denormal floating point values to zero in CUDA device mode. -.. option:: -fcuda-rdc, -fno-cuda-rdc - -Generate relocatable device code, also known as separate compilation mode. - .. option:: -fcuda-short-ptr, -fno-cuda-short-ptr Use 32-bit pointers for accessing const/local/shared address spaces. @@ -222,6 +222,10 @@ Use 32-bit pointers for accessing const/local/shared address spaces. Reserve register r19 (Hexagon only) +.. option:: -fgpu-rdc, -fcuda-rdc, -fno-gpu-rdc + +Generate relocatable device code, also known as separate compilation mode. + .. option:: -fheinous-gnu-extensions .. option:: -flat\_namespace @@ -254,6 +258,10 @@ Use the gcc toolchain at the given directory Generate CodeView debug information +.. option:: -gcodeview-ghash, -gno-codeview-ghash + +Emit type record hashes in a .debug$H section + .. option:: -headerpad\_max\_install\_names .. option:: -help, --help @@ -278,6 +286,8 @@ Make the next included directory (-I or -F) an indexer header map .. option:: -install\_name +.. option:: -interface-stub-version= + .. option:: -keep\_private\_externs .. option:: -lazy\_framework @@ -288,6 +298,10 @@ Make the next included directory (-I or -F) an indexer header map .. option:: -mbig-endian, -EB +.. option:: -mbranch-protection= + +Enforce targets of indirect branches and function returns + .. option:: --migrate Run the migrator @@ -592,6 +606,8 @@ Statically link the sanitizer runtime .. option:: -static-libstdc++ +.. option:: -static-pie + .. option:: -std-default= .. option:: -stdlib=, --stdlib=, --stdlib @@ -612,10 +628,6 @@ C++ standard library to use Generate code for the given target -.. option:: --print-supported-cpus - -Print supported cpu models for the given target - .. option:: -time Time individual commands @@ -636,6 +648,10 @@ Enable some traditional CPP emulation .. option:: -unexported\_symbols\_list +.. option:: -unwindlib=, --unwindlib= + +Unwind library to use + .. option:: -v, --verbose Show commands to run and use verbose output @@ -694,6 +710,10 @@ Only run preprocess and compilation steps Only run preprocess, compile, and assemble steps +.. option:: -emit-interface-stubs + +Generate Inteface Stub Files. + .. option:: -emit-llvm Use the LLVM representation for assembler and object files @@ -798,15 +818,7 @@ Don't use blacklist file for sanitizers .. option:: -fparse-all-comments -.. option:: -frecord-command-line, -frecord-gcc-switches, -fno-record-command-line, -fno-record-gcc-switches - -Generate a section named ".GCC.command.line" containing the clang driver -command-line. After linking, the section may contain multiple command lines, -which will be individually terminated by null bytes. Separate arguments within -a command line are combined with spaces; spaces and backslashes within an -argument are escaped with backslashes. This format differs from the format of -the equivalent section produced by GCC with the -frecord-gcc-switches flag. -This option is currently only supported on ELF targets. +.. option:: -frecord-command-line, -fno-record-command-line, -frecord-gcc-switches .. option:: -fsanitize-address-field-padding= @@ -816,20 +828,18 @@ Level of field padding for AddressSanitizer Enable linker dead stripping of globals in AddressSanitizer -.. option:: -fsanitize-address-use-odr-indicator, -fno-sanitize-address-use-odr-indicator - -Enable ODR indicator globals to avoid false ODR violation reports in partially sanitized programs at the cost of an increase in binary size - .. option:: -fsanitize-address-poison-custom-array-cookie, -fno-sanitize-address-poison-custom-array-cookie -Enable "poisoning" array cookies when allocating arrays with a custom operator new\[\] in Address Sanitizer, preventing accesses to the cookies from user code. An array cookie is a small implementation-defined header added to certain array allocations to record metadata such as the length of the array. Accesses to array cookies from user code are technically allowed by the standard but are more likely to be the result of an out-of-bounds array access. - -An operator new\[\] is "custom" if it is not one of the allocation functions provided by the C++ standard library. Array cookies from non-custom allocation functions are always poisoned. +Enable poisoning array cookies when using custom operator new\[\] in AddressSanitizer .. option:: -fsanitize-address-use-after-scope, -fno-sanitize-address-use-after-scope Enable use-after-scope detection in AddressSanitizer +.. option:: -fsanitize-address-use-odr-indicator, -fno-sanitize-address-use-odr-indicator + +Enable ODR indicator globals to avoid false ODR violation reports in partially sanitized programs at the cost of an increase in binary size + .. option:: -fsanitize-blacklist= Path to blacklist file for sanitizers @@ -846,6 +856,10 @@ Generalize pointers in CFI indirect call type signature checks Specify the type of coverage instrumentation for Sanitizers +.. option:: -fsanitize-hwaddress-abi= + +Select the HWAddressSanitizer ABI to target (interceptor or platform, default interceptor) + .. option:: -fsanitize-link-c++-runtime .. option:: -fsanitize-memory-track-origins, -fno-sanitize-memory-track-origins @@ -908,6 +922,10 @@ Enable function outlining (AArch64 only) .. option:: --param , --param= +.. option:: -print-supported-cpus, --print-supported-cpus, -mcpu=?, -mtune=? + +Print supported cpu models for the given target (if target is not specified, it will print the supported cpus for the default target) + .. option:: -std=, --std=, --std Language standard to compile for @@ -1078,6 +1096,10 @@ Set directory to include search path with prefix Add directory to SYSTEM include search path, absolute paths are relative to -isysroot +.. option:: --libomptarget-nvptx-path= + +Path to libomptarget-nvptx libraries + .. option:: --ptxas-path= Path to ptxas (used for compiling CUDA code) @@ -1235,6 +1257,10 @@ Use ANSI escape codes for diagnostics Use Apple's kernel extensions ABI +.. option:: -fapple-link-rtlib + +Force linking the clang builtins runtime library + .. option:: -fapple-pragma-pack, -fno-apple-pragma-pack Enable Apple gcc-compatible #pragma pack handling @@ -1289,6 +1315,8 @@ Enable C++ static destructor registration (the default) Instrument control-flow architecture protection. Options: return, branch, full, none. +.. option:: -fcf-runtime-abi= + .. option:: -fchar8\_t, -fno-char8\_t Enable C++ builtin type char8\_t @@ -1323,6 +1351,16 @@ Generate coverage mapping to enable code coverage analysis .. option:: -fcreate-profile +.. option:: -fcs-profile-generate + +Generate instrumented code to collect context sensitive execution counts into default.profraw (overridden by LLVM\_PROFILE\_FILE env var) + +.. program:: clang1 +.. option:: -fcs-profile-generate= +.. program:: clang + +Generate instrumented code to collect context sensitive execution counts into /default.profraw (overridden by LLVM\_PROFILE\_FILE env var) + .. option:: -fcxx-exceptions, -fno-cxx-exceptions Enable C++ exceptions @@ -1333,6 +1371,10 @@ Enable C++ exceptions Place each data in its own section (ELF Only) +.. option:: -fdebug-compilation-dir + +The compilation directory to embed in the debug info. + .. option:: -fdebug-info-for-profiling, -fno-debug-info-for-profiling Emit extra debug info to make sample profile more accurate. @@ -1349,6 +1391,10 @@ Emit macro debug information remap file source paths in debug info +.. option:: -fdebug-ranges-base-address, -fno-debug-ranges-base-address + +Use DWARF base address selection entries in debug\_ranges + .. option:: -fdebug-types-section, -fno-debug-types-section Place debug types in their own section (ELF Only) @@ -1657,6 +1703,8 @@ Synthesize retain and release calls for Objective-C pointers Use EH-safe code when synthesizing retains and releases in -fobjc-arc +.. option:: -fobjc-convert-messages-to-runtime-calls, -fno-objc-convert-messages-to-runtime-calls + .. option:: -fobjc-exceptions, -fno-objc-exceptions Enable Objective-C exceptions @@ -1703,8 +1751,16 @@ Emit OpenMP code only for SIMD-based constructs. Specify the file name of any generated YAML optimization record +.. option:: -foptimization-record-passes= + +Only include passes which match a specified regular expression in the generated optimization record (by default, include all passes) + .. option:: -foptimize-sibling-calls, -fno-optimize-sibling-calls +.. option:: -forder-file-instrumentation + +Generate instrumented code to collect order file into default.profraw file (overridden by '=' form of option or LLVM\_PROFILE\_FILE env var) + .. option:: -foutput-class-dir=, --output-class-directory , --output-class-directory= .. option:: -fpack-struct, -fno-pack-struct @@ -1719,6 +1775,10 @@ Specify the default maximum struct packing alignment Recognize and construct Pascal-style string literals +.. option:: -fpass-plugin= + +Load pass plugin from a dynamic shared object file (only with new pass manager). + .. option:: -fpcc-struct-return Override the default ABI to return all structs on the stack @@ -1743,6 +1803,14 @@ Load the named plugin (dynamic shared object) .. option:: -fprofile-dir= +.. option:: -fprofile-exclude-files= + +Instrument only functions from files where names don't match all the regexes separated by a semi-colon + +.. option:: -fprofile-filter-files= + +Instrument only functions from files where names match any regex separated by a semi-colon + .. option:: -fprofile-generate, -fno-profile-generate Generate instrumented code to collect execution counts into default.profraw (overridden by LLVM\_PROFILE\_FILE env var) @@ -1771,6 +1839,10 @@ Generate instrumented code to collect execution counts into (overridden b Use instrumentation data for profile-guided optimization +.. option:: -fprofile-remapping-file=, -fprofile-remapping-file + +Use the remappings described in to match the profile data against names in the program + .. option:: -fprofile-sample-accurate, -fauto-profile-accurate, -fno-profile-sample-accurate Specifies that the sample profile is accurate. If the sample @@ -1834,6 +1906,12 @@ Turn on loop reroller Generate a YAML optimization record file +.. program:: clang1 +.. option:: -fsave-optimization-record= +.. program:: clang + +Generate an optimization record file in a specific format (default: YAML) + .. option:: -fseh-exceptions Use SEH style exceptions @@ -1882,19 +1960,23 @@ Enable the superword-level parallelism vectorization passes Provide minimal debug info in the object/executable to facilitate online symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF +.. option:: -fsplit-lto-unit, -fno-split-lto-unit + +Enables splitting of the LTO unit. + .. option:: -fsplit-stack .. option:: -fstack-protector, -fno-stack-protector -Enable stack protectors for functions potentially vulnerable to stack smashing +Enable stack protectors for some functions vulnerable to stack smashing. This uses a loose heuristic which considers functions vulnerable if they contain a char (or 8bit integer) array or constant sized calls to alloca, which are of greater size than ssp-buffer-size (default: 8 bytes). All variable sized calls to alloca are considered vulnerable .. option:: -fstack-protector-all -Force the usage of stack protectors for all functions +Enable stack protectors for all functions .. option:: -fstack-protector-strong -Use a strong heuristic to apply stack protectors to functions +Enable stack protectors for some functions vulnerable to stack smashing. Compared to -fstack-protector, this uses a stronger heuristic that includes functions containing arrays of any size (and any type), as well as any calls to alloca or the taking of an address from a local variable .. option:: -fstack-size-section, -fno-stack-size-section @@ -1926,6 +2008,8 @@ Enable optimizations based on the strict rules for overwriting polymorphic C++ o .. option:: -fstruct-path-tbaa, -fno-struct-path-tbaa +.. option:: -fsymbol-partition= + .. option:: -ftabstop= .. option:: -ftemplate-backtrace-limit= @@ -1944,6 +2028,8 @@ Perform ThinLTO importing using provided function summary index .. option:: -ftime-report +.. option:: -ftime-trace + .. option:: -ftls-model= .. option:: -ftrap-function= @@ -1968,6 +2054,10 @@ Specify the function to be called on overflow Process trigraph sequences +.. option:: -ftrivial-auto-var-init= + +Initialize trivial automatic stack variables: uninitialized (default) \| pattern + .. option:: -funique-section-names, -fno-unique-section-names Use unique names for text and data sections (ELF Only) @@ -2006,6 +2096,10 @@ Enable the loop vectorization passes .. option:: -fverbose-asm, -fno-verbose-asm +.. option:: -fvisibility-global-new-delete-hidden + +Give global C++ operator new and delete declarations hidden visibility + .. option:: -fvisibility-inlines-hidden Give inline C++ member functions hidden visibility by default @@ -2080,6 +2174,14 @@ DEPRECATED: Filename defining the whitelist for imbuing the 'never instrument' X Enable System z vector language extension +.. option:: -mlong-double-128 + +Force long double to be 128 bits + +.. option:: -mlong-double-64 + +Force long double to be 64 bits + .. option:: -pedantic, --pedantic, -no-pedantic, --no-pedantic .. option:: -pedantic-errors, --pedantic-errors @@ -2168,9 +2270,9 @@ Link stack frames through backchain on System Z .. option:: -mconsole -.. option:: -mcpu=, -mv5 (equivalent to -mcpu=hexagonv5), -mv55 (equivalent to -mcpu=hexagonv55), -mv60 (equivalent to -mcpu=hexagonv60), -mv62 (equivalent to -mcpu=hexagonv62), -mv65 (equivalent to -mcpu=hexagonv65) - -Use -mcpu=? to see a list of supported cpu models. +.. program:: clang1 +.. option:: -mcpu=, -mv5 (equivalent to -mcpu=hexagonv5), -mv55 (equivalent to -mcpu=hexagonv55), -mv60 (equivalent to -mcpu=hexagonv60), -mv62 (equivalent to -mcpu=hexagonv62), -mv65 (equivalent to -mcpu=hexagonv65), -mv66 (equivalent to -mcpu=hexagonv66) +.. program:: clang .. option:: -mcrc, -mno-crc @@ -2204,6 +2306,8 @@ Enable merging of globals .. option:: -mhwdiv=, --mhwdiv , --mhwdiv= +.. option:: -mhwmult= + .. option:: -miamcu, -mno-iamcu Use Intel MCU ABI @@ -2226,7 +2330,7 @@ Generate branches with extended addressability, usually via indirect jumps. .. option:: -mmacosx-version-min=, -mmacos-version-min= -Set macOS deployment target +Set Mac OS X deployment target .. option:: -mmcu= @@ -2280,6 +2384,8 @@ Select return address signing scope Use software floating point +.. option:: -mspeculative-load-hardening, -mno-speculative-load-hardening + .. option:: -mstack-alignment= Set the stack alignment @@ -2304,9 +2410,13 @@ The thread model to use, e.g. posix, single (posix by default) .. option:: -mthumb, -mno-thumb -.. option:: -mtune= +.. option:: -mtls-direct-seg-refs, -mno-tls-direct-seg-refs -Use -mtune=? to see a list of supported cpu models. +Enable direct TLS access through segment registers (default) + +.. program:: clang1 +.. option:: -mtune= +.. program:: clang .. option:: -mtvos-version-min=, -mappletvos-version-min= @@ -2318,83 +2428,147 @@ Use -mtune=? to see a list of supported cpu models. .. option:: -mwatchos-version-min= +.. option:: -mwavefrontsize64, -mno-wavefrontsize64 + +Wavefront size 64 is used + .. option:: -mwindows .. option:: -mx32 AARCH64 ------- +.. option:: -fcall-saved-x10 + +Make the x10 register call-saved (AArch64 only) + +.. option:: -fcall-saved-x11 + +Make the x11 register call-saved (AArch64 only) + +.. option:: -fcall-saved-x12 + +Make the x12 register call-saved (AArch64 only) + +.. option:: -fcall-saved-x13 + +Make the x13 register call-saved (AArch64 only) + +.. option:: -fcall-saved-x14 + +Make the x14 register call-saved (AArch64 only) + +.. option:: -fcall-saved-x15 + +Make the x15 register call-saved (AArch64 only) + +.. option:: -fcall-saved-x18 + +Make the x18 register call-saved (AArch64 only) + +.. option:: -fcall-saved-x8 + +Make the x8 register call-saved (AArch64 only) + +.. option:: -fcall-saved-x9 + +Make the x9 register call-saved (AArch64 only) + .. option:: -ffixed-x1 -Reserve the x1 register (AArch64 only) +Reserve the 1 register (AArch64 only) -.. option:: -ffixed-x2 +.. option:: -ffixed-x10 -Reserve the x2 register (AArch64 only) +Reserve the 10 register (AArch64 only) -.. option:: -ffixed-x3 +.. option:: -ffixed-x11 -Reserve the x3 register (AArch64 only) +Reserve the 11 register (AArch64 only) -.. option:: -ffixed-x4 +.. option:: -ffixed-x12 -Reserve the x4 register (AArch64 only) +Reserve the 12 register (AArch64 only) -.. option:: -ffixed-x5 +.. option:: -ffixed-x13 -Reserve the x5 register (AArch64 only) +Reserve the 13 register (AArch64 only) -.. option:: -ffixed-x6 +.. option:: -ffixed-x14 -Reserve the x6 register (AArch64 only) +Reserve the 14 register (AArch64 only) -.. option:: -ffixed-x7 +.. option:: -ffixed-x15 -Reserve the x7 register (AArch64 only) +Reserve the 15 register (AArch64 only) .. option:: -ffixed-x18 -Reserve the x18 register (AArch64 only) +Reserve the 18 register (AArch64 only) + +.. option:: -ffixed-x2 + +Reserve the 2 register (AArch64 only) .. option:: -ffixed-x20 -Reserve the x20 register (AArch64 only) +Reserve the 20 register (AArch64 only) -.. option:: -fcall-saved-x8 +.. option:: -ffixed-x21 -Make the x8 register call-saved (AArch64 only) +Reserve the 21 register (AArch64 only) -.. option:: -fcall-saved-x9 +.. option:: -ffixed-x22 -Make the x9 register call-saved (AArch64 only) +Reserve the 22 register (AArch64 only) -.. option:: -fcall-saved-x10 +.. option:: -ffixed-x23 -Make the x10 register call-saved (AArch64 only) +Reserve the 23 register (AArch64 only) -.. option:: -fcall-saved-x11 +.. option:: -ffixed-x24 -Make the x11 register call-saved (AArch64 only) +Reserve the 24 register (AArch64 only) -.. option:: -fcall-saved-x12 +.. option:: -ffixed-x25 -Make the x12 register call-saved (AArch64 only) +Reserve the 25 register (AArch64 only) -.. option:: -fcall-saved-x13 +.. option:: -ffixed-x26 -Make the x13 register call-saved (AArch64 only) +Reserve the 26 register (AArch64 only) -.. option:: -fcall-saved-x14 +.. option:: -ffixed-x27 -Make the x14 register call-saved (AArch64 only) +Reserve the 27 register (AArch64 only) -.. option:: -fcall-saved-x15 +.. option:: -ffixed-x28 -Make the x15 register call-saved (AArch64 only) +Reserve the 28 register (AArch64 only) -.. option:: -fcall-saved-x18 +.. option:: -ffixed-x3 -Make the x18 register call-saved (AArch64 only) +Reserve the 3 register (AArch64 only) + +.. option:: -ffixed-x4 + +Reserve the 4 register (AArch64 only) + +.. option:: -ffixed-x5 + +Reserve the 5 register (AArch64 only) + +.. option:: -ffixed-x6 + +Reserve the 6 register (AArch64 only) + +.. option:: -ffixed-x7 + +Reserve the 7 register (AArch64 only) + +.. option:: -ffixed-x9 + +Reserve the 9 register (AArch64 only) .. option:: -mfix-cortex-a53-835769, -mno-fix-cortex-a53-835769 @@ -2406,14 +2580,17 @@ Generate code which only uses the general purpose registers (AArch64 only) AMDGPU ------ +.. option:: -mcode-object-v3, -mno-code-object-v3 + +Enable code object v3 (AMDGPU only) + .. option:: -mcumode, -mno-cumode -CU wavefront execution mode is used if enabled and WGP wavefront execution mode -is used if disabled (AMDGPU only) +CU wavefront execution mode is used (AMDGPU only) -.. option:: -mwavefrontsize64, -mno-wavefrontsize64 +.. option:: -msram-ecc, -mno-sram-ecc -Wavefront size 64 is used if enabled and wavefront size 32 if disabled (AMDGPU only) +Enable SRAM ECC (AMDGPU only) .. option:: -mxnack, -mno-xnack @@ -2425,6 +2602,10 @@ ARM Reserve the r9 register (ARM only) +.. option:: -mcmse + +Allow use of CMSE (Armv8-M Security Extensions) + .. option:: -mexecute-only, -mno-execute-only, -mpure-code Disallow generation of data access to code sections (ARM only) @@ -2447,7 +2628,7 @@ Disallow generation of deprecated IT blocks for ARMv8. It is on by default for A .. option:: -mtp= -Read thread pointer from coprocessor register (ARM only) +Thread pointer access method (AArch32/AArch64 only) .. option:: -munaligned-access, -mno-unaligned-access @@ -2605,14 +2786,26 @@ PowerPC WebAssembly ----------- +.. option:: -matomics, -mno-atomics + +.. option:: -mbulk-memory, -mno-bulk-memory + .. option:: -mexception-handling, -mno-exception-handling +.. option:: -mmultivalue, -mno-multivalue + +.. option:: -mmutable-globals, -mno-mutable-globals + .. option:: -mnontrapping-fptoint, -mno-nontrapping-fptoint .. option:: -msign-ext, -mno-sign-ext .. option:: -msimd128, -mno-simd128 +.. option:: -mtail-call, -mno-tail-call + +.. option:: -munimplemented-simd128, -mno-unimplemented-simd128 + X86 --- .. option:: -m3dnow, -mno-3dnow @@ -2627,10 +2820,10 @@ X86 .. option:: -mavx2, -mno-avx2 -.. option:: -mavx512bitalg, -mno-avx512bitalg - .. option:: -mavx512bf16, -mno-avx512bf16 +.. option:: -mavx512bitalg, -mno-avx512bitalg + .. option:: -mavx512bw, -mno-avx512bw .. option:: -mavx512cd, -mno-avx512cd @@ -2779,6 +2972,10 @@ RISCV Enable linker relaxation +.. option:: -msave-restore, -mno-save-restore + +Enable using library calls for save and restore + Optimization level ~~~~~~~~~~~~~~~~~~ @@ -2836,6 +3033,10 @@ ___________ .. option:: -ggdb3 +.. option:: -gline-directives-only + +Emit debug line info directives only + .. option:: -gline-tables-only, -g1, -gmlt Emit debug line number tables only @@ -2866,10 +3067,16 @@ Embed source text in DWARF debug sections .. option:: -gpubnames, -gno-pubnames -.. option:: -grecord-command-line, -grecord-gcc-switches, -gno-record-command-line, -gno-record-gcc-switches +.. option:: -grecord-command-line, -gno-record-command-line, -grecord-gcc-switches .. option:: -gsplit-dwarf +.. program:: clang1 +.. option:: -gsplit-dwarf= +.. program:: clang + +Set DWARF fission mode to either 'split' or 'single' + .. option:: -gstrict-dwarf, -gno-strict-dwarf .. option:: -gz diff --git a/clang/docs/ClangStaticAnalyzer.rst b/clang/docs/ClangStaticAnalyzer.rst index 7a309dc4acd9..3a4f332e5789 100644 --- a/clang/docs/ClangStaticAnalyzer.rst +++ b/clang/docs/ClangStaticAnalyzer.rst @@ -2,6 +2,8 @@ Clang Static Analyzer ===================== +.. _clang-static-analyzer-docs: + The Clang Static Analyzer is a source code analysis tool that finds bugs in C, C++, and Objective-C programs. It implements *path-sensitive*, *inter-procedural analysis* based on *symbolic execution* technique. diff --git a/clang/docs/DiagnosticsReference.rst b/clang/docs/DiagnosticsReference.rst index 7d9b1e8359a8..fe0325bed2a7 100644 --- a/clang/docs/DiagnosticsReference.rst +++ b/clang/docs/DiagnosticsReference.rst @@ -207,17 +207,6 @@ This diagnostic is enabled by default. Controls `-Wpointer-bool-conversion`_, `-Wstring-compare`_, `-Wtautological-pointer-compare`_. --Waddress-of-array-temporary ----------------------------- -This diagnostic is enabled by default. - -**Diagnostic text:** - -+---------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`pointer is initialized by a temporary array, which will be destroyed at the end of the full-expression`| -+---------------------------------------------------------------------------------------------------------------------------------------------+ - - -Waddress-of-packed-member -------------------------- This diagnostic is enabled by default. @@ -244,21 +233,6 @@ This diagnostic is an error by default, but the flag ``-Wno-address-of-temporary ------------------ This diagnostic flag exists for GCC compatibility, and has no effect in Clang. --Waligned-allocation-unavailable --------------------------------- -This diagnostic is an error by default, but the flag ``-Wno-aligned-allocation-unavailable`` can be used to disable the error. - -**Diagnostic text:** - -+--------------------------------------------------+--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:error:`error:` |nbsp| :diagtext:`aligned` |nbsp| |+------------------------+| |nbsp| :diagtext:`function of type '`:placeholder:`B`:diagtext:`' is only available on` |nbsp| :placeholder:`C` |nbsp| :placeholder:`D` |nbsp| :diagtext:`or newer`| -| ||:diagtext:`allocation` || | -| |+------------------------+| | -| ||:diagtext:`deallocation`|| | -| |+------------------------+| | -+--------------------------------------------------+--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -Wall ----- Some of the diagnostics controlled by this flag are enabled by default. @@ -473,6 +447,17 @@ This diagnostic is enabled by default. +-----------------------------------------------------------------------------------------------------------------------------+ +-Wargument-outside-range +------------------------ +This diagnostic is an error by default, but the flag ``-Wno-argument-outside-range`` can be used to disable the error. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:error:`error:` |nbsp| :diagtext:`argument value` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is outside the valid range \[`:placeholder:`B`:diagtext:`,` |nbsp| :placeholder:`C`:diagtext:`\]`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Warray-bounds -------------- This diagnostic is enabled by default. @@ -491,9 +476,17 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`array index` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is before the beginning of the array`| +----------------------------------------------------------------------------------------------------------------------------------+ -+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`array argument is too small; contains` |nbsp| :placeholder:`A` |nbsp| :diagtext:`elements, callee requires at least` |nbsp| :placeholder:`B`| -+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++---------------------------------------------------------------------------+----------------------------------------------------------------------------+--------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`array argument is too small;` |nbsp| |+--------------------------------------------------------------------------+|:diagtext:`, callee requires at least` |nbsp| :placeholder:`B`| +| ||+------------------------------------------------------------------------+|| | +| |||:diagtext:`contains` |nbsp| :placeholder:`A` |nbsp| :diagtext:`elements`||| | +| ||+------------------------------------------------------------------------+|| | +| |+--------------------------------------------------------------------------+| | +| ||+----------------------------------------------+ || | +| |||:diagtext:`is of size` |nbsp| :placeholder:`A`| || | +| ||+----------------------------------------------+ || | +| |+--------------------------------------------------------------------------+| | ++---------------------------------------------------------------------------+----------------------------------------------------------------------------+--------------------------------------------------------------+ +-----------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`'static' has no effect on zero-length arrays`| @@ -572,13 +565,41 @@ This diagnostic is enabled by default. -Wat-protocol ------------- +This diagnostic flag exists for GCC compatibility, and has no effect in Clang. + +-Watimport-in-framework-header +------------------------------ This diagnostic is enabled by default. **Diagnostic text:** -+-------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`@protocol is using a forward protocol declaration of` |nbsp| :placeholder:`A`| -+-------------------------------------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`use of '@import' in framework header is discouraged, including this header requires -fmodules`| ++------------------------------------------------------------------------------------------------------------------------------------+ + + +-Watomic-alignment +------------------ +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------+------------------------+------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+----------------------+| |nbsp| :diagtext:`atomic operation may incur significant performance penalty`| +| ||:diagtext:`large` || | +| |+----------------------+| | +| ||:diagtext:`misaligned`|| | +| |+----------------------+| | ++---------------------------+------------------------+------------------------------------------------------------------------------+ + + +-Watomic-implicit-seq-cst +------------------------- +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit use of sequentially-consistent atomic may incur stronger memory barriers than necessary`| ++---------------------------------------------------------------------------------------------------------------------------------------+ -Watomic-memory-ordering @@ -690,6 +711,20 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`'unavailable' availability overrides all other availability information`| +--------------------------------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------------+----------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ignoring availability attribute` |nbsp| |+--------------------------------------+| +| ||:diagtext:`on '+load' method` || +| |+--------------------------------------+| +| ||:diagtext:`with constructor attribute`|| +| |+--------------------------------------+| +| ||:diagtext:`with destructor attribute` || +| |+--------------------------------------+| ++------------------------------------------------------------------------------+----------------------------------------+ + ++---------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`only 'unavailable' and 'deprecated' are supported for Swift availability`| ++---------------------------------------------------------------------------------------------------------------+ + +------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`unknown platform` |nbsp| :placeholder:`A` |nbsp| :diagtext:`in availability macro`| +------------------------------------------------------------------------------------------------------------------------+ @@ -731,6 +766,33 @@ This diagnostic is enabled by default. +---------------------------+--------------------------------+---------------------------------------------------------------------------------------------------+-----------------------------------------------+--------------------------------+ +-Wavr-rtlib-linking-quirks +-------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`support for linking stdlibs for microcontroller '`:placeholder:`A`:diagtext:`' is not implemented`| ++----------------------------------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`no avr-gcc installation can be found on the system, cannot link standard libraries`| ++-------------------------------------------------------------------------------------------------------------------------+ + ++--------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`no avr-libc installation can be found on the system, cannot link standard libraries`| ++--------------------------------------------------------------------------------------------------------------------------+ + ++--------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`no target microcontroller specified on command line, cannot link standard libraries, please pass -mmcu=`| ++--------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++-----------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`standard library not linked and so no interrupt vector table or compiler runtime routines will be linked`| ++-----------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wbackend-plugin ---------------- This diagnostic is enabled by default. @@ -779,31 +841,44 @@ Also controls `-Wc++98-compat-bind-to-temporary-copy`_. | |+---------------------+| +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------+ -+--------------------------------------------------------------------+-----------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`no viable constructor` |nbsp| |+---------------------------------------+| |nbsp| :diagtext:`of type` |nbsp| :placeholder:`B`:diagtext:`; C++98 requires a copy constructor when binding a reference to a temporary`| -| ||:diagtext:`copying variable` || | -| |+---------------------------------------+| | -| ||:diagtext:`copying parameter` || | -| |+---------------------------------------+| | -| ||:diagtext:`returning object` || | -| |+---------------------------------------+| | -| ||:diagtext:`throwing object` || | -| |+---------------------------------------+| | -| ||:diagtext:`copying member subobject` || | -| |+---------------------------------------+| | -| ||:diagtext:`copying array element` || | -| |+---------------------------------------+| | -| ||:diagtext:`allocating object` || | -| |+---------------------------------------+| | -| ||:diagtext:`copying temporary` || | -| |+---------------------------------------+| | -| ||:diagtext:`initializing base subobject`|| | -| |+---------------------------------------+| | -| ||:diagtext:`initializing vector element`|| | -| |+---------------------------------------+| | -| ||:diagtext:`capturing value` || | -| |+---------------------------------------+| | -+--------------------------------------------------------------------+-----------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ ++--------------------------------------------------------------------+------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`no viable constructor` |nbsp| |+----------------------------------------------------+| |nbsp| :diagtext:`of type` |nbsp| :placeholder:`B`:diagtext:`; C++98 requires a copy constructor when binding a reference to a temporary`| +| ||:diagtext:`copying variable` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`copying parameter` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`returning object` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`initializing statement expression result`|| | +| |+----------------------------------------------------+| | +| ||:diagtext:`throwing object` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`copying member subobject` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`copying array element` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`allocating object` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`copying temporary` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`initializing base subobject` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`initializing vector element` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`capturing value` || | +| |+----------------------------------------------------+| | ++--------------------------------------------------------------------+------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ + + +-Wbinding-in-condition +---------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++--------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ISO C++17 does not permit structured binding declaration in a condition`| ++--------------------------------------------------------------------------------------------------------------+ -Wbitfield-constant-conversion @@ -944,9 +1019,9 @@ This diagnostic is enabled by default. **Diagnostic text:** -+------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`will always overflow destination buffer`| -+------------------------------------------------------------------------------------------------------+ ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' will always overflow; destination buffer has size` |nbsp| :placeholder:`B`:diagtext:`, but size argument is` |nbsp| :placeholder:`C`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -Wbuiltin-requires-header @@ -1180,28 +1255,6 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-inline-namespace`_, `-Wc++11-long- |:warning:`warning:` |nbsp| :diagtext:`default template arguments for a function template are a C++11 extension`| +---------------------------------------------------------------------------------------------------------------+ -+-------------------------------------------------------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`first declaration of` |nbsp| |+-------------------------------------+| |nbsp| :diagtext:`specialization of` |nbsp| :placeholder:`B` |nbsp| :diagtext:`outside namespace` |nbsp| :placeholder:`C` |nbsp| :diagtext:`is a C++11 extension`| -| ||:diagtext:`class template` || | -| |+-------------------------------------+| | -| ||:diagtext:`class template partial` || | -| |+-------------------------------------+| | -| ||:diagtext:`variable template` || | -| |+-------------------------------------+| | -| ||:diagtext:`variable template partial`|| | -| |+-------------------------------------+| | -| ||:diagtext:`function template` || | -| |+-------------------------------------+| | -| ||:diagtext:`member function` || | -| |+-------------------------------------+| | -| ||:diagtext:`static data member` || | -| |+-------------------------------------+| | -| ||:diagtext:`member class` || | -| |+-------------------------------------+| | -| ||:diagtext:`member enumeration` || | -| |+-------------------------------------+| | -+-------------------------------------------------------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - +------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`'typename' occurs outside of a template`| +------------------------------------------------------------------------------+ @@ -1260,19 +1313,21 @@ Some of the diagnostics controlled by this flag are enabled by default. **Diagnostic text:** -+-----------------------+----------------------------------------+--------+--------------------------------------------------------------------------------------------------------------------------+ -|:error:`error:` |nbsp| |+--------------------------------------+| |nbsp| |+------------------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`case value` || ||+--------------------------------------------------------------------------------------------------------------+ || -| |+--------------------------------------+| |||:diagtext:`cannot be narrowed from type` |nbsp| :placeholder:`C` |nbsp| :diagtext:`to` |nbsp| :placeholder:`D`| || -| ||:diagtext:`enumerator value` || ||+--------------------------------------------------------------------------------------------------------------+ || -| |+--------------------------------------+| |+------------------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`non-type template argument`|| ||+----------------------------------------------------------------------------------------------------------------------+|| -| |+--------------------------------------+| |||:diagtext:`evaluates to` |nbsp| :placeholder:`C`:diagtext:`, which cannot be narrowed to type` |nbsp| :placeholder:`D`||| -| ||:diagtext:`array size` || ||+----------------------------------------------------------------------------------------------------------------------+|| -| |+--------------------------------------+| |+------------------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`constexpr if condition` || | | -| |+--------------------------------------+| | | -+-----------------------+----------------------------------------+--------+--------------------------------------------------------------------------------------------------------------------------+ ++-----------------------+-----------------------------------------+--------+--------------------------------------------------------------------------------------------------------------------------+ +|:error:`error:` |nbsp| |+---------------------------------------+| |nbsp| |+------------------------------------------------------------------------------------------------------------------------+| +| ||:diagtext:`case value` || ||+--------------------------------------------------------------------------------------------------------------+ || +| |+---------------------------------------+| |||:diagtext:`cannot be narrowed from type` |nbsp| :placeholder:`C` |nbsp| :diagtext:`to` |nbsp| :placeholder:`D`| || +| ||:diagtext:`enumerator value` || ||+--------------------------------------------------------------------------------------------------------------+ || +| |+---------------------------------------+| |+------------------------------------------------------------------------------------------------------------------------+| +| ||:diagtext:`non-type template argument` || ||+----------------------------------------------------------------------------------------------------------------------+|| +| |+---------------------------------------+| |||:diagtext:`evaluates to` |nbsp| :placeholder:`C`:diagtext:`, which cannot be narrowed to type` |nbsp| :placeholder:`D`||| +| ||:diagtext:`array size` || ||+----------------------------------------------------------------------------------------------------------------------+|| +| |+---------------------------------------+| |+------------------------------------------------------------------------------------------------------------------------+| +| ||:diagtext:`constexpr if condition` || | | +| |+---------------------------------------+| | | +| ||:diagtext:`explicit specifier argument`|| | | +| |+---------------------------------------+| | | ++-----------------------+-----------------------------------------+--------+--------------------------------------------------------------------------------------------------------------------------+ +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |:error:`error:` |nbsp| :diagtext:`constant expression evaluates to` |nbsp| :placeholder:`A` |nbsp| :diagtext:`which cannot be narrowed to type` |nbsp| :placeholder:`B`| @@ -1402,6 +1457,10 @@ Some of the diagnostics controlled by this flag are enabled by default. **Diagnostic text:** ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ISO C++ standards before C++17 do not allow new expression for type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to use list-initialization`| ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`constexpr if is a C++17 extension`| +------------------------------------------------------------------------+ @@ -1501,8 +1560,30 @@ Synonym for `-Wc++17-extensions`_. -Wc++2a-compat -------------- +Some of the diagnostics controlled by this flag are enabled by default. + **Diagnostic text:** ++------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`consteval is incompatible with C++ standards before C++20`| ++------------------------------------------------------------------------------------------------+ + ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`aggregate initialization of type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`with user-declared constructors is incompatible with C++2a`| ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`this expression will be parsed as explicit(bool) in C++2a`| ++------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'<=>' is a single token in C++2a; add a space to avoid a change in behavior`| ++------------------------------------------------------------------------------------------------------------------+ + ++--------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`type of UTF-8 string literal will change from array of const char to array of const char8\_t in C++2a`| ++--------------------------------------------------------------------------------------------------------------------------------------------+ + +-------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' is a keyword in C++2a`| +-------------------------------------------------------------------------------------------+ @@ -1519,14 +1600,62 @@ Some of the diagnostics controlled by this flag are enabled by default. **Diagnostic text:** ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`use of function template name with no prior declaration in function call with explicit template arguments is a C++2a extension`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +----------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`default member initializer for bit-field is a C++2a extension`| +----------------------------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------+-------------------------+----------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`use of this statement in a constexpr` |nbsp| |+-----------------------+| |nbsp| :diagtext:`is a C++2a extension`| +| ||:diagtext:`function` || | +| |+-----------------------+| | +| ||:diagtext:`constructor`|| | +| |+-----------------------+| | ++-----------------------------------------------------------------------------------+-------------------------+----------------------------------------+ + ++------------------------------------------------------------------------------+-------------------------+----------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`function try block in constexpr` |nbsp| |+-----------------------+| |nbsp| :diagtext:`is a C++2a extension`| +| ||:diagtext:`function` || | +| |+-----------------------+| | +| ||:diagtext:`constructor`|| | +| |+-----------------------+| | ++------------------------------------------------------------------------------+-------------------------+----------------------------------------+ + ++---------------------------------------------------------------------------------+--------------------------------------------------------------+----------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`decomposition declaration declared` |nbsp| |+------------------------------------------------------------+| |nbsp| :diagtext:`is a C++2a extension`| +| ||+------------------------------------------+ || | +| |||:diagtext:`'`:placeholder:`B`:diagtext:`'`| || | +| ||+------------------------------------------+ || | +| |+------------------------------------------------------------+| | +| ||+----------------------------------------------------------+|| | +| |||:diagtext:`with '`:placeholder:`B`:diagtext:`' specifiers`||| | +| ||+----------------------------------------------------------+|| | +| |+------------------------------------------------------------+| | ++---------------------------------------------------------------------------------+--------------------------------------------------------------+----------------------------------------+ + +--------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`explicit capture of 'this' with a capture default of '=' is a C++2a extension`| +--------------------------------------------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`range-based for loop initialization statements are a C++2a extension`| ++-----------------------------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`initialized lambda pack captures are a C++2a extension`| ++---------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`inline nested namespace definition is a C++2a extension`| ++----------------------------------------------------------------------------------------------+ + ++--------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`explicit template parameter list for lambdas is a C++2a extension`| ++--------------------------------------------------------------------------------------------------------+ + +--------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`invoking a pointer to a 'const &' member function on an rvalue is a C++2a extension`| +--------------------------------------------------------------------------------------------------------------------------+ @@ -1536,14 +1665,98 @@ Some of the diagnostics controlled by this flag are enabled by default. -------------------------------- **Diagnostic text:** ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`use of function template name with no prior function template declaration in function call with explicit template arguments is incompatible with C++ standards before C++2a`| ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +-------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`default member initializer for bit-field is incompatible with C++ standards before C++2a`| +-------------------------------------------------------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------+-------------------------+-------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`use of this statement in a constexpr` |nbsp| |+-----------------------+| |nbsp| :diagtext:`is incompatible with C++ standards before C++2a`| +| ||:diagtext:`function` || | +| |+-----------------------+| | +| ||:diagtext:`constructor`|| | +| |+-----------------------+| | ++-----------------------------------------------------------------------------------+-------------------------+-------------------------------------------------------------------+ + ++------------------------------------------------------------------------------+-------------------------+-------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`function try block in constexpr` |nbsp| |+-----------------------+| |nbsp| :diagtext:`is incompatible with C++ standards before C++2a`| +| ||:diagtext:`function` || | +| |+-----------------------+| | +| ||:diagtext:`constructor`|| | +| |+-----------------------+| | ++------------------------------------------------------------------------------+-------------------------+-------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`virtual constexpr functions are incompatible with C++ standards before C++2a`| ++-------------------------------------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------+--------------------------------------------------------------+-------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`decomposition declaration declared` |nbsp| |+------------------------------------------------------------+| |nbsp| :diagtext:`is incompatible with C++ standards before C++2a`| +| ||+------------------------------------------+ || | +| |||:diagtext:`'`:placeholder:`B`:diagtext:`'`| || | +| ||+------------------------------------------+ || | +| |+------------------------------------------------------------+| | +| ||+----------------------------------------------------------+|| | +| |||:diagtext:`with '`:placeholder:`B`:diagtext:`' specifiers`||| | +| ||+----------------------------------------------------------+|| | +| |+------------------------------------------------------------+| | ++---------------------------------------------------------------------------------+--------------------------------------------------------------+-------------------------------------------------------------------+ + ++-------------------------------------------------------------------------+--------------------------------------+----------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`explicitly defaulting this` |nbsp| |+------------------------------------+| |nbsp| :diagtext:`with a type different from the implicit type is incompatible with C++ standards before C++2a`| +| ||:diagtext:`default constructor` || | +| |+------------------------------------+| | +| ||:diagtext:`copy constructor` || | +| |+------------------------------------+| | +| ||:diagtext:`move constructor` || | +| |+------------------------------------+| | +| ||:diagtext:`copy assignment operator`|| | +| |+------------------------------------+| | +| ||:diagtext:`move assignment operator`|| | +| |+------------------------------------+| | +| ||:diagtext:`destructor` || | +| |+------------------------------------+| | ++-------------------------------------------------------------------------+--------------------------------------+----------------------------------------------------------------------------------------------------------------+ + +-----------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`explicit capture of 'this' with a capture default of '=' is incompatible with C++ standards before C++2a`| +-----------------------------------------------------------------------------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`range-based for loop initialization statements are incompatible with C++ standards before C++2a`| ++--------------------------------------------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`initialized lambda capture packs are incompatible with C++ standards before C++2a`| ++------------------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`inline nested namespace definition is incompatible with C++ standards before C++2a`| ++-------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------+----------------------------------+-----------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+--------------------------------+| |nbsp| :diagtext:`of lambda is incompatible with C++ standards before C++2a`| +| ||:diagtext:`default construction`|| | +| |+--------------------------------+| | +| ||:diagtext:`assignment` || | +| |+--------------------------------+| | ++---------------------------+----------------------------------+-----------------------------------------------------------------------------+ + ++-----------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`explicit template parameter list for lambdas is incompatible with C++ standards before C++2a`| ++-----------------------------------------------------------------------------------------------------------------------------------+ + ++-----------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'<=>' operator is incompatible with C++ standards before C++2a`| ++-----------------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'char8\_t' type specifier is incompatible with C++ standards before C++20`| ++----------------------------------------------------------------------------------------------------------------+ + -Wc++98-c++11-c++14-c++17-compat-pedantic ----------------------------------------- @@ -1560,6 +1773,16 @@ Also controls `-Wc++98-c++11-c++14-c++17-compat`_. -------------------------- **Diagnostic text:** ++------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`class template argument deduction is incompatible with C++ standards before C++17`|+---------------------------------------------------------------------------------+| +| || || +| |+---------------------------------------------------------------------------------+| +| ||+-------------------------------------------------------------------------------+|| +| |||:diagtext:`; for compatibility, use explicit type name` |nbsp| :placeholder:`B`||| +| ||+-------------------------------------------------------------------------------+|| +| |+---------------------------------------------------------------------------------+| ++------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------+ + +---------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`constexpr if is incompatible with C++ standards before C++17`| +---------------------------------------------------------------------------------------------------+ @@ -1688,10 +1911,18 @@ Also controls `-Wc++98-c++11-c++14-compat`_. |:warning:`warning:` |nbsp| :diagtext:`'decltype(auto)' type specifier is incompatible with C++ standards before C++14`| +----------------------------------------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`return type deduction is incompatible with C++ standards before C++14`| ++------------------------------------------------------------------------------------------------------------+ + +--------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`digit separators are incompatible with C++ standards before C++14`| +--------------------------------------------------------------------------------------------------------+ ++----------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`generic lambdas are incompatible with C++11`| ++----------------------------------------------------------------------------------+ + +-------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`initialized lambda captures are incompatible with C++ standards before C++14`| +-------------------------------------------------------------------------------------------------------------------+ @@ -1801,9 +2032,13 @@ Also controls `-Wc++98-c++11-c++14-c++17-compat`_, `-Wc++98-c++11-c++14-compat`_ |:warning:`warning:` |nbsp| :diagtext:`jump from this goto statement to its label is incompatible with C++98`| +------------------------------------------------------------------------------------------------------------+ -+---------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`jump from this indirect goto statement to one of its possible targets is incompatible with C++98`| -+---------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------+----------------------+--------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`jump from this` |nbsp| |+--------------------+| |nbsp| :diagtext:`goto statement to one of its possible targets is incompatible with C++98`| +| ||:diagtext:`indirect`|| | +| |+--------------------+| | +| ||:diagtext:`asm` || | +| |+--------------------+| | ++-------------------------------------------------------------+----------------------+--------------------------------------------------------------------------------------------+ +------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`initialization of initializer\_list object is incompatible with C++98`| @@ -1855,7 +2090,7 @@ Also controls `-Wc++98-c++11-c++14-c++17-compat`_, `-Wc++98-c++11-c++14-compat`_ +---------------------------+------------------------------+------------------------------------------------------------------------------------------------+--------------------------------------+----------------------------------------------+ |:warning:`warning:` |nbsp| |+----------------------------+| |nbsp| :diagtext:`member` |nbsp| :placeholder:`B` |nbsp| :diagtext:`with a non-trivial` |nbsp| |+------------------------------------+| |nbsp| :diagtext:`is incompatible with C++98`| -| ||:diagtext:`anonymous struct`|| ||:diagtext:`constructor` || | +| ||:diagtext:`anonymous struct`|| ||:diagtext:`default constructor` || | | |+----------------------------+| |+------------------------------------+| | | ||:diagtext:`union` || ||:diagtext:`copy constructor` || | | |+----------------------------+| |+------------------------------------+| | @@ -1949,28 +2184,6 @@ Also controls `-Wc++98-c++11-c++14-c++17-compat`_, `-Wc++98-c++11-c++14-compat`_ |:warning:`warning:` |nbsp| :diagtext:`default template arguments for a function template are incompatible with C++98`| +---------------------------------------------------------------------------------------------------------------------+ -+---------------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| |+-------------------------------------+| |nbsp| :diagtext:`specialization of` |nbsp| :placeholder:`B` |nbsp| :diagtext:`outside namespace` |nbsp| :placeholder:`C` |nbsp| :diagtext:`is incompatible with C++98`| -| ||:diagtext:`class template` || | -| |+-------------------------------------+| | -| ||:diagtext:`class template partial` || | -| |+-------------------------------------+| | -| ||:diagtext:`variable template` || | -| |+-------------------------------------+| | -| ||:diagtext:`variable template partial`|| | -| |+-------------------------------------+| | -| ||:diagtext:`function template` || | -| |+-------------------------------------+| | -| ||:diagtext:`member function` || | -| |+-------------------------------------+| | -| ||:diagtext:`static data member` || | -| |+-------------------------------------+| | -| ||:diagtext:`member class` || | -| |+-------------------------------------+| | -| ||:diagtext:`member enumeration` || | -| |+-------------------------------------+| | -+---------------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - +----------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`trailing return types are incompatible with C++98`| +----------------------------------------------------------------------------------------+ @@ -2022,29 +2235,42 @@ Also controls `-Wc++98-c++11-c++14-c++17-compat`_, `-Wc++98-c++11-c++14-compat`_ ------------------------------------- **Diagnostic text:** -+---------------------------+-----------------------------------------+----------------------------------------------------------------------------------------------------------------------------+------------------------------------------------+----------------------------+ -|:warning:`warning:` |nbsp| |+---------------------------------------+| |nbsp| :diagtext:`of type` |nbsp| :placeholder:`C` |nbsp| :diagtext:`when binding a reference to a temporary would` |nbsp| |+----------------------------------------------+| |nbsp| :diagtext:`in C++98`| -| ||:diagtext:`copying variable` || ||:diagtext:`invoke an inaccessible constructor`|| | -| |+---------------------------------------+| |+----------------------------------------------+| | -| ||:diagtext:`copying parameter` || ||:diagtext:`find no viable constructor` || | -| |+---------------------------------------+| |+----------------------------------------------+| | -| ||:diagtext:`returning object` || ||:diagtext:`find ambiguous constructors` || | -| |+---------------------------------------+| |+----------------------------------------------+| | -| ||:diagtext:`throwing object` || ||:diagtext:`invoke a deleted constructor` || | -| |+---------------------------------------+| |+----------------------------------------------+| | -| ||:diagtext:`copying member subobject` || | | | -| |+---------------------------------------+| | | | -| ||:diagtext:`copying array element` || | | | -| |+---------------------------------------+| | | | -| ||:diagtext:`allocating object` || | | | -| |+---------------------------------------+| | | | -| ||:diagtext:`copying temporary` || | | | -| |+---------------------------------------+| | | | -| ||:diagtext:`initializing base subobject`|| | | | -| |+---------------------------------------+| | | | -| ||:diagtext:`initializing vector element`|| | | | -| |+---------------------------------------+| | | | -+---------------------------+-----------------------------------------+----------------------------------------------------------------------------------------------------------------------------+------------------------------------------------+----------------------------+ ++---------------------------+------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+------------------------------------------------+----------------------------+ +|:warning:`warning:` |nbsp| |+----------------------------------------------------+| |nbsp| :diagtext:`of type` |nbsp| :placeholder:`C` |nbsp| :diagtext:`when binding a reference to a temporary would` |nbsp| |+----------------------------------------------+| |nbsp| :diagtext:`in C++98`| +| ||:diagtext:`copying variable` || ||:diagtext:`invoke an inaccessible constructor`|| | +| |+----------------------------------------------------+| |+----------------------------------------------+| | +| ||:diagtext:`copying parameter` || ||:diagtext:`find no viable constructor` || | +| |+----------------------------------------------------+| |+----------------------------------------------+| | +| ||:diagtext:`returning object` || ||:diagtext:`find ambiguous constructors` || | +| |+----------------------------------------------------+| |+----------------------------------------------+| | +| ||:diagtext:`initializing statement expression result`|| ||:diagtext:`invoke a deleted constructor` || | +| |+----------------------------------------------------+| |+----------------------------------------------+| | +| ||:diagtext:`throwing object` || | | | +| |+----------------------------------------------------+| | | | +| ||:diagtext:`copying member subobject` || | | | +| |+----------------------------------------------------+| | | | +| ||:diagtext:`copying array element` || | | | +| |+----------------------------------------------------+| | | | +| ||:diagtext:`allocating object` || | | | +| |+----------------------------------------------------+| | | | +| ||:diagtext:`copying temporary` || | | | +| |+----------------------------------------------------+| | | | +| ||:diagtext:`initializing base subobject` || | | | +| |+----------------------------------------------------+| | | | +| ||:diagtext:`initializing vector element` || | | | +| |+----------------------------------------------------+| | | | +| ||:diagtext:`capturing value` || | | | +| |+----------------------------------------------------+| | | | ++---------------------------+------------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------+------------------------------------------------+----------------------------+ + + +-Wc++98-compat-extra-semi +------------------------- +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`extra ';' outside of a function is incompatible with C++98`| ++-------------------------------------------------------------------------------------------------+ -Wc++98-compat-local-type-template-args @@ -2058,7 +2284,7 @@ Also controls `-Wc++98-c++11-c++14-c++17-compat`_, `-Wc++98-c++11-c++14-compat`_ -Wc++98-compat-pedantic ----------------------- -Also controls `-Wc++98-c++11-c++14-c++17-compat-pedantic`_, `-Wc++98-c++11-c++14-compat-pedantic`_, `-Wc++98-c++11-compat-pedantic`_, `-Wc++98-compat`_, `-Wc++98-compat-bind-to-temporary-copy`_. +Also controls `-Wc++98-c++11-c++14-c++17-compat-pedantic`_, `-Wc++98-c++11-c++14-compat-pedantic`_, `-Wc++98-c++11-compat-pedantic`_, `-Wc++98-compat`_, `-Wc++98-compat-bind-to-temporary-copy`_, `-Wc++98-compat-extra-semi`_. **Diagnostic text:** @@ -2098,10 +2324,6 @@ Also controls `-Wc++98-c++11-c++14-c++17-compat-pedantic`_, `-Wc++98-c++11-c++14 |:warning:`warning:` |nbsp| :diagtext:`#line number greater than 32767 is incompatible with C++98`| +-------------------------------------------------------------------------------------------------+ -+-------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`extra ';' outside of a function is incompatible with C++98`| -+-------------------------------------------------------------------------------------------------+ - +----------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`variadic macros are incompatible with C++98`| +----------------------------------------------------------------------------------+ @@ -2225,6 +2447,21 @@ Some of the diagnostics controlled by this flag are enabled by default. +---------------------------------------------------------------------------------------+ +-Wcall-to-pure-virtual-from-ctor-dtor +------------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------+----------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`call to pure virtual member function` |nbsp| :placeholder:`A` |nbsp| :diagtext:`has undefined behavior; overrides of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`in subclasses are not available in the` |nbsp| |+-----------------------+| |nbsp| :diagtext:`of` |nbsp| :placeholder:`C`| +| ||:diagtext:`constructor`|| | +| |+-----------------------+| | +| ||:diagtext:`destructor` || | +| |+-----------------------+| | ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------------+----------------------------------------------+ + + -Wcast-align ------------ **Diagnostic text:** @@ -2275,6 +2512,29 @@ This diagnostic is enabled by default. +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +-Wcast-qual-unrelated +--------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------+-----------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ISO C++ does not allow` |nbsp| |+---------------------------------+| |nbsp| :diagtext:`from` |nbsp| :placeholder:`B` |nbsp| :diagtext:`to` |nbsp| :placeholder:`C` |nbsp| :diagtext:`because it casts away qualifiers, even though the source and destination types are unrelated`| +| ||:diagtext:`const\_cast` || | +| |+---------------------------------+| | +| ||:diagtext:`static\_cast` || | +| |+---------------------------------+| | +| ||:diagtext:`reinterpret\_cast` || | +| |+---------------------------------+| | +| ||:diagtext:`dynamic\_cast` || | +| |+---------------------------------+| | +| ||:diagtext:`C-style cast` || | +| |+---------------------------------+| | +| ||:diagtext:`functional-style cast`|| | +| |+---------------------------------+| | ++---------------------------------------------------------------------+-----------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wchar-align ------------ This diagnostic flag exists for GCC compatibility, and has no effect in Clang. @@ -2310,14 +2570,18 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`support for '/Yc' and '/Yu' with different filenames not implemented yet; flags ignored`| +------------------------------------------------------------------------------------------------------------------------------+ -+--------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`support for '`:placeholder:`A`:diagtext:`' without a filename not implemented yet; flag ignored`| -+--------------------------------------------------------------------------------------------------------------------------------------+ - +----------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`support for '`:placeholder:`A`:diagtext:`' without a corresponding /FI flag not implemented yet; flag ignored`| +----------------------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`#pragma hdrstop filename not supported, /Fp can be used to specify precompiled header filename`| ++-------------------------------------------------------------------------------------------------------------------------------------+ + ++-----------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`definition of macro` |nbsp| :placeholder:`A` |nbsp| :diagtext:`does not match definition in precompiled header`| ++-----------------------------------------------------------------------------------------------------------------------------------------------------+ + -Wclass-varargs --------------- @@ -2397,6 +2661,17 @@ This diagnostic is enabled by default. +----------------------------------------------------------------------------------------------------------------------+ +-Wconcepts-ts-compat +-------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ISO C++2a does not permit the 'bool' keyword after 'concept'`| ++---------------------------------------------------------------------------------------------------+ + + -Wconditional-type-mismatch --------------------------- This diagnostic is enabled by default. @@ -2444,7 +2719,7 @@ This diagnostic is enabled by default. --------------------- This diagnostic is enabled by default. -Also controls `-Wbitfield-constant-conversion`_. +Also controls `-Wbitfield-constant-conversion`_, `-Wobjc-bool-constant-conversion`_. **Diagnostic text:** @@ -2516,7 +2791,7 @@ This diagnostic is enabled by default. ------------ Some of the diagnostics controlled by this flag are enabled by default. -Also controls `-Wbitfield-enum-conversion`_, `-Wbool-conversion`_, `-Wconstant-conversion`_, `-Wenum-conversion`_, `-Wfloat-conversion`_, `-Wint-conversion`_, `-Wliteral-conversion`_, `-Wnon-literal-null-conversion`_, `-Wnull-conversion`_, `-Wobjc-literal-conversion`_, `-Wshorten-64-to-32`_, `-Wsign-conversion`_, `-Wstring-conversion`_. +Also controls `-Wbitfield-enum-conversion`_, `-Wbool-conversion`_, `-Wconstant-conversion`_, `-Wenum-conversion`_, `-Wfloat-conversion`_, `-Wimplicit-float-conversion`_, `-Wimplicit-int-conversion`_, `-Wint-conversion`_, `-Wliteral-conversion`_, `-Wnon-literal-null-conversion`_, `-Wnull-conversion`_, `-Wobjc-literal-conversion`_, `-Wshorten-64-to-32`_, `-Wsign-conversion`_, `-Wstring-conversion`_. **Diagnostic text:** @@ -2524,18 +2799,14 @@ Also controls `-Wbitfield-enum-conversion`_, `-Wbool-conversion`_, `-Wconstant-c |:warning:`warning:` |nbsp| :diagtext:`implicit conversion discards imaginary component:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B`| +--------------------------------------------------------------------------------------------------------------------------------------------------------------+ -+----------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`implicit conversion loses floating-point precision:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B`| -+----------------------------------------------------------------------------------------------------------------------------------------------------------------+ - -+---------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`implicit conversion loses integer precision:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B`| -+---------------------------------------------------------------------------------------------------------------------------------------------------------+ - +--------------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`implicit conversion turns vector to scalar:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B`| +--------------------------------------------------------------------------------------------------------------------------------------------------------+ ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`passing non-generic address space pointer to` |nbsp| :placeholder:`A` |nbsp| :diagtext:`may cause dynamic conversion affecting performance`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`non-type template argument with value '`:placeholder:`A`:diagtext:`' converted to '`:placeholder:`B`:diagtext:`' for unsigned template parameter of type` |nbsp| :placeholder:`C`| +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -2593,10 +2864,30 @@ Synonym for `-W#warnings`_. +------------------------------------------------------------------------------------------------------------+----------------------+--------------------------------------------------------------------------------------------+------------------------+ +-Wctad-maybe-unsupported +------------------------ +**Diagnostic text:** + ++--------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`may not intend to support class template argument deduction`| ++--------------------------------------------------------------------------------------------------------------------------+ + + -Wctor-dtor-privacy ------------------- This diagnostic flag exists for GCC compatibility, and has no effect in Clang. +-Wctu +----- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`imported AST from '`:placeholder:`A`:diagtext:`' had been generated for a different target, current:` |nbsp| :placeholder:`B`:diagtext:`, imported:` |nbsp| :placeholder:`C`| ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wcuda-compat ------------- Some of the diagnostics controlled by this flag are enabled by default. @@ -2637,6 +2928,55 @@ Some of the diagnostics controlled by this flag are enabled by default. +---------------------------------------------------------------------------------------------------------------------------------------+--------------------+----------------------------------------------------------------------------+ +-Wdangling +---------- +This diagnostic is enabled by default. + +Also controls `-Wdangling-field`_, `-Wdangling-initializer-list`_, `-Wreturn-stack-address`_. + +**Diagnostic text:** + ++---------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+----------------------------+---------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| |nbsp| |+--------------------------+|:diagtext:`will be destroyed at the end of the full-expression`| +| ||+-----------------------------+---------------------------------------------------------+--------+------------------------------------------------------------------------+|| ||+------------------------+|| | +| |||:diagtext:`temporary` |nbsp| |+-------------------------------------------------------+| |nbsp| |+----------------------------------------------------------------------+||| |||:placeholder:`D` |nbsp| ||| | +| ||| ||:diagtext:`whose address is used as value of` || ||+-------------------------------+------------------------------------+|||| ||+------------------------+|| | +| ||| |+-------------------------------------------------------+| |||+-----------------------------+|:diagtext:`member of local variable`||||| |+--------------------------+| | +| ||| ||+--------------------------------+--------------------+|| |||| || ||||| || || | +| ||| |||+------------------------------+|:diagtext:`bound to`||| |||+-----------------------------+| ||||| |+--------------------------+| | +| ||| |||| || ||| ||||:diagtext:`reference` |nbsp| || ||||| | | | +| ||| |||+------------------------------+| ||| |||+-----------------------------+| ||||| | | | +| ||| ||||:diagtext:`implicitly` |nbsp| || ||| ||+-------------------------------+------------------------------------+|||| | | | +| ||| |||+------------------------------+| ||| |+----------------------------------------------------------------------+||| | | | +| ||| ||+--------------------------------+--------------------+|| ||+-------------------------+-----------------------+ |||| | | | +| ||| |+-------------------------------------------------------+| |||:diagtext:`local` |nbsp| |+---------------------+| |||| | | | +| ||| | | ||| ||:diagtext:`variable` || |||| | | | +| ||| | | ||| |+---------------------+| |||| | | | +| ||| | | ||| ||:diagtext:`reference`|| |||| | | | +| ||| | | ||| |+---------------------+| |||| | | | +| ||| | | ||+-------------------------+-----------------------+ |||| | | | +| ||| | | |+----------------------------------------------------------------------+||| | | | +| ||+-----------------------------+---------------------------------------------------------+--------+------------------------------------------------------------------------+|| | | | +| |+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| | | | +| ||+---------------------------------+----------------------------------------------------------+ || | | | +| |||:diagtext:`array backing` |nbsp| |+--------------------------------------------------------+| || | | | +| ||| ||:diagtext:`initializer list subobject of local variable`|| || | | | +| ||| |+--------------------------------------------------------+| || | | | +| ||| ||:diagtext:`local initializer list` || || | | | +| ||| |+--------------------------------------------------------+| || | | | +| ||+---------------------------------+----------------------------------------------------------+ || | | | +| |+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| | | | ++---------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+----------------------------+---------------------------------------------------------------+ + ++---------------------------------------------------------------------------+-----------------------------------------------+------------------------------------------------------------------------------------------------------------------------------+---------------------------+--------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`sorry, lifetime extension of` |nbsp| |+---------------------------------------------+| |nbsp| :diagtext:`created by aggregate initialization using default member initializer is not supported; lifetime of` |nbsp| |+-------------------------+| |nbsp| :diagtext:`will end at the end of the full-expression`| +| ||:diagtext:`temporary` || ||:diagtext:`temporary` || | +| |+---------------------------------------------+| |+-------------------------+| | +| ||:diagtext:`backing array of initializer list`|| ||:diagtext:`backing array`|| | +| |+---------------------------------------------+| |+-------------------------+| | ++---------------------------------------------------------------------------+-----------------------------------------------+------------------------------------------------------------------------------------------------------------------------------+---------------------------+--------------------------------------------------------------+ + + -Wdangling-else --------------- This diagnostic is enabled by default. @@ -2654,21 +2994,33 @@ This diagnostic is enabled by default. **Diagnostic text:** -+---------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`binding reference member` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to stack allocated parameter` |nbsp| :placeholder:`B`| -+---------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------------------------------------------------------------------------------+-----------------------+------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`binding reference member` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to stack allocated` |nbsp| |+---------------------+| |nbsp| :placeholder:`B`| +| ||:diagtext:`variable` || | +| |+---------------------+| | +| ||:diagtext:`parameter`|| | +| |+---------------------+| | ++-------------------------------------------------------------------------------------------------------------------------------------+-----------------------+------------------------+ -+----------------------------------------------------------------+----------------------------------+----------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`binding reference` |nbsp| |+--------------------------------+|:diagtext:`member` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to a temporary value`| -| || || | -| |+--------------------------------+| | -| ||:diagtext:`subobject of` |nbsp| || | -| |+--------------------------------+| | -+----------------------------------------------------------------+----------------------------------+----------------------------------------------------------------------------------+ ++---------------------------+--------------------------------------------------------+--------+----------------------------------+--------------------------------------------------+----------------------+------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+------------------------------------------------------+| |nbsp| |+--------------------------------+|:diagtext:`member` |nbsp| :placeholder:`A` |nbsp| |+--------------------+| |nbsp| :diagtext:`a temporary object whose lifetime is shorter than the lifetime of the constructed object`| +| ||:diagtext:`reference` || || || ||:diagtext:`binds to`|| | +| |+------------------------------------------------------+| |+--------------------------------+| |+--------------------+| | +| ||:diagtext:`backing array for 'std::initializer\_list'`|| ||:diagtext:`subobject of` |nbsp| || ||:diagtext:`is` || | +| |+------------------------------------------------------+| |+--------------------------------+| |+--------------------+| | ++---------------------------+--------------------------------------------------------+--------+----------------------------------+--------------------------------------------------+----------------------+------------------------------------------------------------------------------------------------------------+ -+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`initializing pointer member` |nbsp| :placeholder:`A` |nbsp| :diagtext:`with the stack address of parameter` |nbsp| :placeholder:`B`| -+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------------------------------------------------------------------+-----------------------+------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`initializing pointer member` |nbsp| :placeholder:`A` |nbsp| :diagtext:`with the stack address of` |nbsp| |+---------------------+| |nbsp| :placeholder:`B`| +| ||:diagtext:`variable` || | +| |+---------------------+| | +| ||:diagtext:`parameter`|| | +| |+---------------------+| | ++-----------------------------------------------------------------------------------------------------------------------------------------------+-----------------------+------------------------+ + ++--------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`temporary bound to reference member of allocated object will be destroyed at the end of the full-expression`| ++--------------------------------------------------------------------------------------------------------------------------------------------------+ -Wdangling-initializer-list @@ -2677,13 +3029,24 @@ This diagnostic is enabled by default. **Diagnostic text:** -+-----------------------------------------------------------------------------------------------------------------+---------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`array backing the initializer list will be destroyed at the end of` |nbsp| |+-------------------------------+| -| ||:diagtext:`the full-expression`|| -| |+-------------------------------+| -| ||:diagtext:`the constructor` || -| |+-------------------------------+| -+-----------------------------------------------------------------------------------------------------------------+---------------------------------+ ++------------------------------------------------------------+----------------------------------------------------------------+-----------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`array backing` |nbsp| |+--------------------------------------------------------------+| |nbsp| :diagtext:`will be destroyed at the end of the full-expression`| +| ||:diagtext:`initializer list subobject of the allocated object`|| | +| |+--------------------------------------------------------------+| | +| ||:diagtext:`the allocated initializer list` || | +| |+--------------------------------------------------------------+| | ++------------------------------------------------------------+----------------------------------------------------------------+-----------------------------------------------------------------------+ + + +-Wdarwin-sdk-settings +--------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`SDK settings were ignored as 'SDKSettings.json' could not be parsed`| ++----------------------------------------------------------------------------------------------------------+ -Wdate-time @@ -2726,6 +3089,29 @@ This diagnostic is enabled by default. +-----------------------------------------------------------------------------------+ +-Wdefaulted-function-deleted +---------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-------------------------------------------------------------------+--------------------------------------+-----------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`explicitly defaulted` |nbsp| |+------------------------------------+| |nbsp| :diagtext:`is implicitly deleted`| +| ||:diagtext:`default constructor` || | +| |+------------------------------------+| | +| ||:diagtext:`copy constructor` || | +| |+------------------------------------+| | +| ||:diagtext:`move constructor` || | +| |+------------------------------------+| | +| ||:diagtext:`copy assignment operator`|| | +| |+------------------------------------+| | +| ||:diagtext:`move assignment operator`|| | +| |+------------------------------------+| | +| ||:diagtext:`destructor` || | +| |+------------------------------------+| | ++-------------------------------------------------------------------+--------------------------------------+-----------------------------------------+ + + -Wdelegating-ctor-cycles ------------------------ This diagnostic is an error by default, but the flag ``-Wno-delegating-ctor-cycles`` can be used to disable the error. @@ -2737,6 +3123,21 @@ This diagnostic is an error by default, but the flag ``-Wno-delegating-ctor-cycl +------------------------------------------------------------------------------------------------------------------------+ +-Wdelete-abstract-non-virtual-dtor +---------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------+------------------------+------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+----------------------+| |nbsp| :diagtext:`called on` |nbsp| :placeholder:`B` |nbsp| :diagtext:`that is abstract but has non-virtual destructor`| +| ||:diagtext:`delete` || | +| |+----------------------+| | +| ||:diagtext:`destructor`|| | +| |+----------------------+| | ++---------------------------+------------------------+------------------------------------------------------------------------------------------------------------------------+ + + -Wdelete-incomplete ------------------- This diagnostic is enabled by default. @@ -2752,20 +3153,10 @@ This diagnostic is enabled by default. +--------------------------------------------------------------------------------------------------------------------------------------------------+ --Wdelete-non-virtual-dtor -------------------------- -Some of the diagnostics controlled by this flag are enabled by default. - +-Wdelete-non-abstract-non-virtual-dtor +-------------------------------------- **Diagnostic text:** -+---------------------------+------------------------+------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| |+----------------------+| |nbsp| :diagtext:`called on` |nbsp| :placeholder:`B` |nbsp| :diagtext:`that is abstract but has non-virtual destructor`| -| ||:diagtext:`delete` || | -| |+----------------------+| | -| ||:diagtext:`destructor`|| | -| |+----------------------+| | -+---------------------------+------------------------+------------------------------------------------------------------------------------------------------------------------+ - +---------------------------+------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| |+----------------------+| |nbsp| :diagtext:`called on non-final` |nbsp| :placeholder:`B` |nbsp| :diagtext:`that has virtual functions but non-virtual destructor`| | ||:diagtext:`delete` || | @@ -2775,11 +3166,18 @@ Some of the diagnostics controlled by this flag are enabled by default. +---------------------------+------------------------+----------------------------------------------------------------------------------------------------------------------------------------+ +-Wdelete-non-virtual-dtor +------------------------- +Some of the diagnostics controlled by this flag are enabled by default. + +Controls `-Wdelete-abstract-non-virtual-dtor`_, `-Wdelete-non-abstract-non-virtual-dtor`_. + + -Wdeprecated ------------ Some of the diagnostics controlled by this flag are enabled by default. -Also controls `-Wdeprecated-attributes`_, `-Wdeprecated-declarations`_, `-Wdeprecated-dynamic-exception-spec`_, `-Wdeprecated-increment-bool`_, `-Wdeprecated-register`_, `-Wdeprecated-writable-strings`_. +Also controls `-Wdeprecated-attributes`_, `-Wdeprecated-declarations`_, `-Wdeprecated-dynamic-exception-spec`_, `-Wdeprecated-increment-bool`_, `-Wdeprecated-register`_, `-Wdeprecated-this-capture`_, `-Wdeprecated-writable-strings`_. **Diagnostic text:** @@ -2957,6 +3355,15 @@ This diagnostic is enabled by default. +-------------------------------------------------------------------------------------------------------------------+ +-Wdeprecated-this-capture +------------------------- +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit capture of 'this' with a capture default of '=' is deprecated`| ++-------------------------------------------------------------------------------------------------------------+ + + -Wdeprecated-writable-strings ----------------------------- Synonym for `-Wc++11-compat-deprecated-writable-strings`_. @@ -3283,7 +3690,7 @@ Also controls `-Wdocumentation-unknown-command`_. -Wduplicate-decl-specifier -------------------------- -This diagnostic is enabled by default. +Some of the diagnostics controlled by this flag are enabled by default. **Diagnostic text:** @@ -3295,6 +3702,14 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`duplicate '`:placeholder:`A`:diagtext:`' declaration specifier`| +-----------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`multiple identical address spaces specified for type`| ++-------------------------------------------------------------------------------------------+ + ++-----------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`duplicate '`:placeholder:`A`:diagtext:`' declaration specifier`| ++-----------------------------------------------------------------------------------------------------+ + -Wduplicate-enum ---------------- @@ -3418,6 +3833,21 @@ This diagnostic is enabled by default. +-------------------------------------------------------------------------------------------------+ +-Wempty-init-stmt +----------------- +**Diagnostic text:** + ++--------------------------------------------------------------------------+-----------------------------+---------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`empty initialization statement of '`|+---------------------------+|:diagtext:`' has no effect`| +| ||:diagtext:`if` || | +| |+---------------------------+| | +| ||:diagtext:`switch` || | +| |+---------------------------+| | +| ||:diagtext:`range-based for`|| | +| |+---------------------------+| | ++--------------------------------------------------------------------------+-----------------------------+---------------------------+ + + -Wempty-translation-unit ------------------------ **Diagnostic text:** @@ -3540,6 +3970,21 @@ Some of the diagnostics controlled by this flag are enabled by default. +-------------------------------------------------------------------------------------------------+ +-Wexperimental-isel +------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`-fexperimental-isel support for the '`:placeholder:`A`:diagtext:`' architecture is incomplete`| ++------------------------------------------------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`-fexperimental-isel support is incomplete for this architecture at the current optimization level`| ++----------------------------------------------------------------------------------------------------------------------------------------+ + + -Wexplicit-initialize-call -------------------------- This diagnostic is enabled by default. @@ -3564,13 +4009,34 @@ This diagnostic is enabled by default. +-------------------------------------------------------------------------------------------------------------------------------------+ --Wextended-offsetof -------------------- +-Wexport-unnamed +---------------- +This diagnostic is enabled by default. + **Diagnostic text:** -+--------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`using extended field designator is an extension`| -+--------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------+------------------------------+------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ISO C++20 does not permit` |nbsp| |+----------------------------+| |nbsp| :diagtext:`declaration to appear in an export block`| +| ||:diagtext:`an empty` || | +| |+----------------------------+| | +| ||:diagtext:`a static\_assert`|| | +| |+----------------------------+| | ++------------------------------------------------------------------------+------------------------------+------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ISO C++20 does not permit a declaration that does not introduce any names to be exported`| ++-------------------------------------------------------------------------------------------------------------------------------+ + + +-Wexport-using-directive +------------------------ +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-----------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ISO C++20 does not permit using directive to be exported`| ++-----------------------------------------------------------------------------------------------+ -Wextern-c-compat @@ -3603,7 +4069,7 @@ This diagnostic is enabled by default. ------- Some of the diagnostics controlled by this flag are enabled by default. -Also controls `-Wignored-qualifiers`_, `-Winitializer-overrides`_, `-Wmissing-field-initializers`_, `-Wmissing-method-return-type`_, `-Wnull-pointer-arithmetic`_, `-Wsemicolon-before-method-body`_, `-Wsign-compare`_, `-Wunused-parameter`_. +Also controls `-Wempty-init-stmt`_, `-Wignored-qualifiers`_, `-Winitializer-overrides`_, `-Wmissing-field-initializers`_, `-Wmissing-method-return-type`_, `-Wnull-pointer-arithmetic`_, `-Wsemicolon-before-method-body`_, `-Wsign-compare`_, `-Wunused-parameter`_. **Diagnostic text:** @@ -3625,7 +4091,7 @@ This diagnostic is enabled by default. -Wextra-semi ------------ -Also controls `-Wc++11-extra-semi`_. +Also controls `-Wc++11-extra-semi`_, `-Wc++98-compat-extra-semi`_. **Diagnostic text:** @@ -3648,6 +4114,17 @@ Also controls `-Wc++11-extra-semi`_. +---------------------------------------------------------------------------------+ +-Wextra-semi-stmt +----------------- +Also controls `-Wempty-init-stmt`_. + +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`empty expression statement has no effect; remove unnecessary ';' to silence this warning`| ++-------------------------------------------------------------------------------------------------------------------------------+ + + -Wextra-tokens -------------- This diagnostic is enabled by default. @@ -3674,6 +4151,15 @@ This diagnostic is enabled by default. +------------------------------------------------------------------------------+ +-Wfixed-enum-extension +---------------------- +**Diagnostic text:** + ++-----------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`enumeration types with a fixed underlying type are a Clang extension`| ++-----------------------------------------------------------------------------------------------------------+ + + -Wflag-enum ----------- This diagnostic is enabled by default. @@ -3722,9 +4208,13 @@ Also controls `-Wfloat-overflow-conversion`_, `-Wfloat-zero-conversion`_. --------------------------- **Diagnostic text:** -+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`implicit conversion of out of range value from` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B` |nbsp| :diagtext:`changes value from` |nbsp| :placeholder:`C` |nbsp| :diagtext:`to` |nbsp| :placeholder:`D`| -+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit conversion from` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B` |nbsp| :diagtext:`changes value from` |nbsp| :placeholder:`C` |nbsp| :diagtext:`to` |nbsp| :placeholder:`D`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit conversion of out of range value from` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B` |nbsp| :diagtext:`is undefined`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -Wfloat-zero-conversion @@ -3960,6 +4450,14 @@ This diagnostic is enabled by default. ----------------- **Diagnostic text:** ++---------------------------+----------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+--------------------------------------------+| |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' should not be used as format arguments; add an explicit cast to` |nbsp| :placeholder:`B` |nbsp| :diagtext:`instead`| +| ||:diagtext:`values of type` || | +| |+--------------------------------------------+| | +| ||:diagtext:`enum values with underlying type`|| | +| |+--------------------------------------------+| | ++---------------------------+----------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+------------------------+ |:warning:`warning:` |nbsp| :diagtext:`format specifies type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`but the argument has` |nbsp| |+---------------------------+| |nbsp| :placeholder:`B`| | ||:diagtext:`type` || | @@ -4002,6 +4500,21 @@ Some of the diagnostics controlled by this flag are enabled by default. Controls `-Wformat-nonliteral`_, `-Wformat-security`_, `-Wformat-y2k`_. +-Wfortify-source +---------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' will always overflow; destination buffer has size` |nbsp| :placeholder:`B`:diagtext:`, but size argument is` |nbsp| :placeholder:`C`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' size argument is too large; destination buffer has size` |nbsp| :placeholder:`B`:diagtext:`, but size argument is` |nbsp| :placeholder:`C`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wfour-char-constants --------------------- **Diagnostic text:** @@ -4024,6 +4537,17 @@ The text of this diagnostic is not controlled by Clang. +--------------------------------------------------------------------------------------------------------------------------------------+ +-Wframework-include-private-from-public +--------------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`public framework header includes private framework header '`:placeholder:`A`:diagtext:`'`| ++-------------------------------------------------------------------------------------------------------------------------------+ + + -Wfunction-def-in-objc-container -------------------------------- This diagnostic is enabled by default. @@ -4035,6 +4559,21 @@ This diagnostic is enabled by default. +--------------------------------------------------------------------------------------------------------+ +-Wfunction-multiversion +----------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`body of cpu\_dispatch function will be ignored`| ++-------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`CPU list contains duplicate entries; attribute ignored`| ++---------------------------------------------------------------------------------------------+ + + -Wfuture-compat --------------- This diagnostic flag exists for GCC compatibility, and has no effect in Clang. @@ -4073,6 +4612,14 @@ Some of the diagnostics controlled by this flag are enabled by default. |:warning:`warning:` |nbsp| :diagtext:`GCC does not allow an attribute in this position on a function declaration`| +-----------------------------------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`GCC does not allow the` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute to be written on a type`| ++------------------------------------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`GCC does not allow variable declarations in for loop initializers before C99`| ++-------------------------------------------------------------------------------------------------------------------+ + +----------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' is bound to current loop, GCC binds it to the enclosing loop`| +----------------------------------------------------------------------------------------------------------------------------------+ @@ -4433,6 +4980,10 @@ This diagnostic is enabled by default. **Diagnostic text:** ++--------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'trivial\_abi' cannot be applied to` |nbsp| :placeholder:`A`| ++--------------------------------------------------------------------------------------------------+ + +---------------------------+-------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| |+-----------------+| |nbsp| :diagtext:`will always resolve to` |nbsp| :placeholder:`A` |nbsp| :diagtext:`even if weak definition of` |nbsp| :placeholder:`B` |nbsp| :diagtext:`is overridden`| | ||:diagtext:`alias`|| | @@ -4461,6 +5012,10 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`attribute` |nbsp| :placeholder:`A` |nbsp| :diagtext:`after definition is ignored`| +-----------------------------------------------------------------------------------------------------------------------+ ++---------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'dllexport' attribute ignored on explicit instantiation definition`| ++---------------------------------------------------------------------------------------------------------+ + +--------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute can only be applied to instance variables or properties`| +--------------------------------------------------------------------------------------------------------------------------------+ @@ -4557,124 +5112,64 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`\_\_weak attribute cannot be specified on an automatic variable when ARC is not enabled`| +------------------------------------------------------------------------------------------------------------------------------+ -+------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute only applies to` |nbsp| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`unions` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`variables and functions` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions and global variables` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions, variables, and Objective-C interfaces` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions and methods` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`parameters` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions, methods and blocks` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions, methods, and classes` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions, methods, and parameters` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions, methods, and global variables` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`classes` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`enums` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`variables` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`methods` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`fields and global variables` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`structs` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`parameters and typedefs` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`variables and typedefs` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`thread-local variables` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`variables and fields` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`variables, data members and tag types` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`types and namespaces` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`Objective-C interfaces` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`methods and properties` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions, methods, and properties` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`struct or union` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`struct, union or class` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`types` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`Objective-C instance methods` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`init methods of interface or class extension declarations` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`variables, functions and classes` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions, variables, classes, and Objective-C interfaces` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`Objective-C protocols` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`variables with static or thread storage duration` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions, methods, properties, and global variables` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`structs, unions, and typedefs` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`structs and typedefs` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`interface or protocol declarations` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`kernel functions` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`non-K&R-style functions` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`variables, enums, fields and typedefs` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`functions, methods, enums, and classes` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`structs, classes, variables, functions, and inline namespaces` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`variables, functions, methods, types, enumerations, enumerators, labels, and non-static data members`|| -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`classes and enumerations` || -| |+----------------------------------------------------------------------------------------------------------------+| -| ||:diagtext:`named declarations` || -| |+----------------------------------------------------------------------------------------------------------------+| -+------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------------------------------+---------------------------------------------------+ +|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute only applies to` |nbsp| |+-------------------------------------------------+| +| ||:diagtext:`functions` || +| |+-------------------------------------------------+| +| ||:diagtext:`unions` || +| |+-------------------------------------------------+| +| ||:diagtext:`variables and functions` || +| |+-------------------------------------------------+| +| ||:diagtext:`functions and methods` || +| |+-------------------------------------------------+| +| ||:diagtext:`functions, methods and blocks` || +| |+-------------------------------------------------+| +| ||:diagtext:`functions, methods, and parameters` || +| |+-------------------------------------------------+| +| ||:diagtext:`variables` || +| |+-------------------------------------------------+| +| ||:diagtext:`variables and fields` || +| |+-------------------------------------------------+| +| ||:diagtext:`variables, data members and tag types`|| +| |+-------------------------------------------------+| +| ||:diagtext:`types and namespaces` || +| |+-------------------------------------------------+| +| ||:diagtext:`variables, functions and classes` || +| |+-------------------------------------------------+| +| ||:diagtext:`kernel functions` || +| |+-------------------------------------------------+| +| ||:diagtext:`non-K&R-style functions` || +| |+-------------------------------------------------+| ++------------------------------------------------------------------------------------------------+---------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute only applies to` |nbsp| :placeholder:`B`| ++----------------------------------------------------------------------------------------------------------------+ +--------------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`attribute` |nbsp| :placeholder:`A` |nbsp| :diagtext:`ignored, because it cannot be applied to omitted return type`| +--------------------------------------------------------------------------------------------------------------------------------------------------------+ -+----------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`calling convention` |nbsp| :placeholder:`A` |nbsp| :diagtext:`ignored for this target`| -+----------------------------------------------------------------------------------------------------------------------------+ - -+-------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`calling convention ignored on constructor/destructor`| -+-------------------------------------------------------------------------------------------------------------------+ - -+--------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`calling convention ignored on variadic function`| -+--------------------------------------------------------------------------------------------------------------+ ++----------------------------------------------------------------------------------------------------------+---------------------------------------+ +|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`calling convention is not supported` |nbsp| |+-------------------------------------+| +| ||:diagtext:`for this target` || +| |+-------------------------------------+| +| ||:diagtext:`on variadic function` || +| |+-------------------------------------+| +| ||:diagtext:`on constructor/destructor`|| +| |+-------------------------------------+| +| ||:diagtext:`on builtin function` || +| |+-------------------------------------+| ++----------------------------------------------------------------------------------------------------------+---------------------------------------+ +-------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`attribute` |nbsp| :placeholder:`A` |nbsp| :diagtext:`ignored, because it cannot be applied to a type`| +-------------------------------------------------------------------------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ignoring \_\_declspec(allocator) because the function return type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is not a pointer or reference type`| ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +------------------------------------------------------------------------------------------------------------------------+-----------------------+----------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`attribute` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is ignored, place it after "`|+---------------------+|:diagtext:`" to apply attribute to type declaration`| | ||:diagtext:`class` || | @@ -4721,35 +5216,63 @@ This diagnostic is enabled by default. | |+----------------------------------+| +---------------------------------------------------------------------------+------------------------------------+ ++------------------------------------------------------------------------------------------------------------------+-----------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'objc\_externally\_retained' can only be applied to local variables` |nbsp| |+---------------------------------+| +| ||:diagtext:`of retainable type` || +| |+---------------------------------+| +| ||:diagtext:`with strong ownership`|| +| |+---------------------------------+| ++------------------------------------------------------------------------------------------------------------------+-----------------------------------+ + +--------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`'internal\_linkage' attribute on a non-static local variable is ignored`| +--------------------------------------------------------------------------------------------------------------+ ++---------------------------+--------------------+-------------------------------------------------------------------------------------+----------------------------------+ +|:warning:`warning:` |nbsp| |+------------------+| |nbsp| :diagtext:`'interrupt' attribute only applies to functions that have` |nbsp| |+--------------------------------+| +| ||:diagtext:`MIPS` || ||:diagtext:`no parameters` || +| |+------------------+| |+--------------------------------+| +| ||:diagtext:`MSP430`|| ||:diagtext:`a 'void' return type`|| +| |+------------------+| |+--------------------------------+| +| ||:diagtext:`RISC-V`|| | | +| |+------------------+| | | ++---------------------------+--------------------+-------------------------------------------------------------------------------------+----------------------------------+ + +--------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`qualifiers after comma in declarator list are ignored`| +--------------------------------------------------------------------------------------------+ -+-------------------------------------------------------------------------------------------------------------+----------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`MIPS 'interrupt' attribute only applies to functions that have` |nbsp| |+--------------------------------+| -| ||:diagtext:`no parameters` || -| |+--------------------------------+| -| ||:diagtext:`a 'void' return type`|| -| |+--------------------------------+| -+-------------------------------------------------------------------------------------------------------------+----------------------------------+ ++------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'mig\_server\_routine' attribute only applies to routines that return a kern\_return\_t`| ++------------------------------------------------------------------------------------------------------------------------------+ +---------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`unknown attribute '`:placeholder:`A`:diagtext:`'`| +---------------------------------------------------------------------------------------+ -+------------------------------------------------------------------------------------------------+-----------------------------------+------------------------------+ -|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute only applies to` |nbsp| |+---------------------------------+| |nbsp| :diagtext:`parameters`| -| ||:diagtext:`Objective-C object` || | -| |+---------------------------------+| | -| ||:diagtext:`pointer` || | -| |+---------------------------------+| | -| ||:diagtext:`pointer-to-CF-pointer`|| | -| |+---------------------------------+| | -+------------------------------------------------------------------------------------------------+-----------------------------------+------------------------------+ ++-------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'nocf\_check' attribute ignored; use -fcf-protection to enable the attribute`| ++-------------------------------------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'noderef' can only be used on an array or pointer type`| ++---------------------------------------------------------------------------------------------+ + ++--------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'nothrow' attribute conflicts with exception specification; attribute ignored`| ++--------------------------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------------------+---------------------------------------------------+------------------------------+ +|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute only applies to` |nbsp| |+-------------------------------------------------+| |nbsp| :diagtext:`parameters`| +| ||:diagtext:`Objective-C object` || | +| |+-------------------------------------------------+| | +| ||:diagtext:`pointer` || | +| |+-------------------------------------------------+| | +| ||:diagtext:`pointer-to-CF-pointer` || | +| |+-------------------------------------------------+| | +| ||:diagtext:`pointer/reference-to-OSObject-pointer`|| | +| |+-------------------------------------------------+| | ++------------------------------------------------------------------------------------------------+---------------------------------------------------+------------------------------+ +------------------------------------------------------------------------------------------------+------------------------+---------------------------------------+--------------------------------------+ |:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute only applies to` |nbsp| |+----------------------+| |nbsp| :diagtext:`that return` |nbsp| |+------------------------------------+| @@ -4765,6 +5288,10 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute is deprecated and ignored in OpenCL version` |nbsp| :placeholder:`B`| +--------------------------------------------------------------------------------------------------------------------------------------------+ ++----------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`repeated RISC-V 'interrupt' attribute`| ++----------------------------------------------------------------------------+ + +---------------------------+-----------------------+---------------------------------------------------------------------------------------------------------------------------------------------+-----------------------+-------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| |+---------------------+| |nbsp| :diagtext:`of field` |nbsp| :placeholder:`B` |nbsp| :diagtext:`(`:placeholder:`C` |nbsp| :diagtext:`bits) does not match the` |nbsp| |+---------------------+| |nbsp| :diagtext:`of the first field in transparent union; transparent\_union attribute ignored`| | ||:diagtext:`alignment`|| ||:diagtext:`alignment`|| | @@ -4803,13 +5330,17 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`\_\_declspec attribute` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is not supported`| +-------------------------------------------------------------------------------------------------------------------------+ -+-------------------------------------------------------+-------------------------+----------------------------------+---------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`ignoring` |nbsp| |+-----------------------+|+--------------------------------+| |nbsp| :diagtext:`'`:placeholder:`C`:diagtext:`' in the target attribute string`| -| ||:diagtext:`unsupported`||| || | -| |+-----------------------+|+--------------------------------+| | -| ||:diagtext:`duplicate` ||| |nbsp| :diagtext:`architecture`|| | -| |+-----------------------+|+--------------------------------+| | -+-------------------------------------------------------+-------------------------+----------------------------------+---------------------------------------------------------------------------------+ ++---------------------------+-------------------------+----------------------------------+---------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+-----------------------+|+--------------------------------+| |nbsp| :diagtext:`'`:placeholder:`C`:diagtext:`' in the 'target' attribute string; 'target' attribute ignored`| +| ||:diagtext:`unsupported`||| || | +| |+-----------------------+|+--------------------------------+| | +| ||:diagtext:`duplicate` ||| |nbsp| :diagtext:`architecture`|| | +| |+-----------------------+|+--------------------------------+| | ++---------------------------+-------------------------+----------------------------------+---------------------------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'\_\_clang\_\_' is a predefined macro name, not an attribute scope specifier; did you mean '\_Clang' instead?`| ++----------------------------------------------------------------------------------------------------------------------------------------------------+ -Wignored-optimization-argument @@ -4842,11 +5373,22 @@ This diagnostic is enabled by default. +------------------------------------------------------------------------------------------+------------------------------------------------------------------------------+ +-Wignored-pragma-optimize +------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++--------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'#pragma optimize' is not supported`| ++--------------------------------------------------------------------------+ + + -Wignored-pragmas ----------------- This diagnostic is enabled by default. -Also controls `-Wignored-pragma-intrinsic`_. +Also controls `-Wignored-pragma-intrinsic`_, `-Wignored-pragma-optimize`_. **Diagnostic text:** @@ -4882,6 +5424,10 @@ Also controls `-Wignored-pragma-intrinsic`_. |:warning:`warning:` |nbsp| :diagtext:`unexpected debug command '`:placeholder:`A`:diagtext:`'`| +----------------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`unknown module '`:placeholder:`A`:diagtext:`'`| ++------------------------------------------------------------------------------------+ + +------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`expected action or ')' in '#pragma` |nbsp| :placeholder:`A`:diagtext:`' - ignored`| +------------------------------------------------------------------------------------------------------------------------+ @@ -4894,6 +5440,10 @@ Also controls `-Wignored-pragma-intrinsic`_. |:warning:`warning:` |nbsp| :diagtext:`missing ':' or ')' after` |nbsp| :placeholder:`A` |nbsp| :diagtext:`- ignoring`| +---------------------------------------------------------------------------------------------------------------------+ ++----------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`expected ',' in '#pragma` |nbsp| :placeholder:`A`:diagtext:`'`| ++----------------------------------------------------------------------------------------------------+ + +---------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`expected identifier in '#pragma` |nbsp| :placeholder:`A`:diagtext:`' - ignored`| +---------------------------------------------------------------------------------------------------------------------+ @@ -4942,6 +5492,10 @@ Also controls `-Wignored-pragma-intrinsic`_. |:warning:`warning:` |nbsp| :diagtext:`expected push, pop or a string literal for the section name in '#pragma` |nbsp| :placeholder:`A`:diagtext:`' - ignored`| +-------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`expected string literal in '#pragma` |nbsp| :placeholder:`A`:diagtext:`' - ignoring`| ++--------------------------------------------------------------------------------------------------------------------------+ + +---------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`extra tokens at end of '#pragma` |nbsp| :placeholder:`A`:diagtext:`' - ignored`| +---------------------------------------------------------------------------------------------------------------------+ @@ -4958,10 +5512,30 @@ Also controls `-Wignored-pragma-intrinsic`_. |:warning:`warning:` |nbsp| :diagtext:`unknown action for '#pragma` |nbsp| :placeholder:`A`:diagtext:`' - ignored`| +-----------------------------------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`unexpected argument '`:placeholder:`A`:diagtext:`' to '#pragma` |nbsp| :placeholder:`B`:diagtext:`'`|+------------------------------------------------+| +| || || +| |+------------------------------------------------+| +| ||+----------------------------------------------+|| +| |||:diagtext:`; expected` |nbsp| :placeholder:`D`||| +| ||+----------------------------------------------+|| +| |+------------------------------------------------+| ++------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------+ + +------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`unknown action '`:placeholder:`B`:diagtext:`' for '#pragma` |nbsp| :placeholder:`A`:diagtext:`' - ignored`| +------------------------------------------------------------------------------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------------------------+--------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`missing argument to '#pragma` |nbsp| :placeholder:`A`:diagtext:`'`|+------------------------------------------------+| +| || || +| |+------------------------------------------------+| +| ||+----------------------------------------------+|| +| |||:diagtext:`; expected` |nbsp| :placeholder:`C`||| +| ||+----------------------------------------------+|| +| |+------------------------------------------------+| ++--------------------------------------------------------------------------------------------------------+--------------------------------------------------+ + +----------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`incorrect use of '#pragma ms\_struct on\|off' - ignored`| +----------------------------------------------------------------------------------------------+ @@ -5039,13 +5613,13 @@ Some of the diagnostics controlled by this flag are enabled by default. |:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' qualifier on omitted return type` |nbsp| :placeholder:`B` |nbsp| :diagtext:`has no effect`| +---------------------------------------------------------------------------------------------------------------------------------------------------------------+ -+------------------------------------------------------------------------------------+---------------+------------------------------------------+-------------------+-----------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' type qualifier`|+-------------+| |nbsp| :diagtext:`on return type` |nbsp| |+-----------------+| |nbsp| :diagtext:`no effect`| -| || || ||:diagtext:`:has` || | -| |+-------------+| |+-----------------+| | -| ||:diagtext:`s`|| ||:diagtext:`:have`|| | -| |+-------------+| |+-----------------+| | -+------------------------------------------------------------------------------------+---------------+------------------------------------------+-------------------+-----------------------------+ ++------------------------------------------------------------------------------------+---------------+------------------------------------------+------------------+-----------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' type qualifier`|+-------------+| |nbsp| :diagtext:`on return type` |nbsp| |+----------------+| |nbsp| :diagtext:`no effect`| +| || || ||:diagtext:`has` || | +| |+-------------+| |+----------------+| | +| ||:diagtext:`s`|| ||:diagtext:`have`|| | +| |+-------------+| |+----------------+| | ++------------------------------------------------------------------------------------+---------------+------------------------------------------+------------------+-----------------------------+ +---------------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' qualifier on function type` |nbsp| :placeholder:`B` |nbsp| :diagtext:`has no effect`| @@ -5126,19 +5700,39 @@ Also controls `-Wimplicit-fallthrough-per-function`_. +------------------------------------------------------------------------------------------------------------------+ +-Wimplicit-fixed-point-conversion +--------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit conversion from` |nbsp| :placeholder:`A` |nbsp| :diagtext:`cannot fit within the range of values for` |nbsp| :placeholder:`B`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +-Wimplicit-float-conversion +--------------------------- +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit conversion loses floating-point precision:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit conversion when assigning computation result loses floating-point precision:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B`| ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wimplicit-function-declaration ------------------------------- Some of the diagnostics controlled by this flag are enabled by default. **Diagnostic text:** -+----------------------------------------------------------------------------------------------------------------------------------------+--------------------+ -|:warning:`warning:` |nbsp| :diagtext:`implicit declaration of function` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is invalid in` |nbsp| |+------------------+| -| ||:diagtext:`C99` || -| |+------------------+| -| ||:diagtext:`OpenCL`|| -| |+------------------+| -+----------------------------------------------------------------------------------------------------------------------------------------+--------------------+ ++------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit declaration of function` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is invalid in C99`| ++------------------------------------------------------------------------------------------------------------------------------------+ +---------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`implicitly declaring library function '`:placeholder:`A`:diagtext:`' with type` |nbsp| :placeholder:`B`| @@ -5164,6 +5758,19 @@ This diagnostic is enabled by default. +--------------------------------------------------------------------------------+ +-Wimplicit-int-conversion +------------------------- +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`higher order bits are zeroes after implicit conversion`| ++---------------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit conversion loses integer precision:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wimplicit-retain-self ---------------------- **Diagnostic text:** @@ -5214,9 +5821,9 @@ This diagnostic is enabled by default. **Diagnostic text:** -+------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`#include\_next with absolute path`| -+------------------------------------------------------------------------+ ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`#include\_next in file found relative to primary source file or found by absolute path; will search from start of include path`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -Winclude-next-outside-header @@ -5225,9 +5832,9 @@ This diagnostic is enabled by default. **Diagnostic text:** -+----------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`#include\_next in primary source file`| -+----------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`#include\_next in primary source file; will search from start of include path`| ++--------------------------------------------------------------------------------------------------------------------+ -Wincompatible-exception-spec @@ -5295,6 +5902,10 @@ This diagnostic is an error by default, but the flag ``-Wno-incompatible-ms-stru |:error:`error:` |nbsp| :diagtext:`ms\_struct may not produce Microsoft-compatible layouts for classes with base classes or virtual functions`| +---------------------------------------------------------------------------------------------------------------------------------------------+ ++------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:error:`error:` |nbsp| :diagtext:`ms\_struct may not produce Microsoft-compatible layouts with fundamental data types with sizes that aren't a power of two`| ++------------------------------------------------------------------------------------------------------------------------------------------------------------+ + -Wincompatible-pointer-types ---------------------------- @@ -5388,6 +5999,17 @@ This diagnostic is enabled by default. +------------------------------------------------------------------------------------------------------------------------------------+ +-Wincomplete-framework-module-declaration +----------------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`skipping '`:placeholder:`A`:diagtext:`' because module declaration of '`:placeholder:`B`:diagtext:`' lacks the 'framework' qualifier`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wincomplete-implementation --------------------------- This diagnostic is enabled by default. @@ -5406,6 +6028,17 @@ Some of the diagnostics controlled by this flag are enabled by default. Controls `-Wincomplete-umbrella`_, `-Wnon-modular-include-in-module`_. +-Wincomplete-setjmp-declaration +------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`declaration of built-in function '`:placeholder:`A`:diagtext:`' requires the declaration of the 'jmp\_buf' type, commonly provided in the header .`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wincomplete-umbrella --------------------- This diagnostic is enabled by default. @@ -5642,6 +6275,18 @@ Also controls `-Wignored-optimization-argument`_. **Diagnostic text:** ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`the given MCU supports` |nbsp| :placeholder:`A` |nbsp| :diagtext:`hardware multiply, but -mhwmult is set to` |nbsp| :placeholder:`B`:diagtext:`.`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`no MCU device specified, but '-mhwmult' is set to 'auto', assuming no hardware multiply. Use -mmcu to specify a MSP430 device, or -mhwmult to set hardware multiply type explicitly.`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`the given MCU does not support hardware multiply, but -mhwmult is set to` |nbsp| :placeholder:`A`:diagtext:`.`| ++----------------------------------------------------------------------------------------------------------------------------------------------------+ + +-----------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`the object size sanitizer has no effect at -O0, but is explicitly enabled:` |nbsp| :placeholder:`A`| +-----------------------------------------------------------------------------------------------------------------------------------------+ @@ -5900,6 +6545,10 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`implicit conversion from` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B` |nbsp| :diagtext:`changes value from` |nbsp| :placeholder:`C` |nbsp| :diagtext:`to` |nbsp| :placeholder:`D`| +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit conversion of out of range value from` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B` |nbsp| :diagtext:`is undefined`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + -Wliteral-range --------------- @@ -6065,6 +6714,21 @@ This diagnostic is enabled by default. +----------------------------------------------------------------+---------------------------------------+------------------------------------------------------+ +-Wmemset-transposed-args +------------------------ +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------+-----------------------------------------------------+---------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+---------------------------------------------------+|:diagtext:`; did you mean to transpose the last two arguments?`| +| ||:diagtext:`'size' argument to memset is '0'` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`setting buffer to a 'sizeof' expression`|| | +| |+---------------------------------------------------+| | ++---------------------------+-----------------------------------------------------+---------------------------------------------------------------+ + + -Wmemsize-comparison -------------------- This diagnostic is enabled by default. @@ -6093,7 +6757,7 @@ This diagnostic is enabled by default. ----------- Some of the diagnostics controlled by this flag are enabled by default. -Controls `-Winconsistent-dllimport`_, `-Wmicrosoft-anon-tag`_, `-Wmicrosoft-cast`_, `-Wmicrosoft-charize`_, `-Wmicrosoft-comment-paste`_, `-Wmicrosoft-const-init`_, `-Wmicrosoft-cpp-macro`_, `-Wmicrosoft-default-arg-redefinition`_, `-Wmicrosoft-end-of-file`_, `-Wmicrosoft-enum-forward-reference`_, `-Wmicrosoft-enum-value`_, `-Wmicrosoft-exception-spec`_, `-Wmicrosoft-explicit-constructor-call`_, `-Wmicrosoft-extra-qualification`_, `-Wmicrosoft-fixed-enum`_, `-Wmicrosoft-flexible-array`_, `-Wmicrosoft-goto`_, `-Wmicrosoft-include`_, `-Wmicrosoft-mutable-reference`_, `-Wmicrosoft-pure-definition`_, `-Wmicrosoft-redeclare-static`_, `-Wmicrosoft-sealed`_, `-Wmicrosoft-template`_, `-Wmicrosoft-union-member-reference`_, `-Wmicrosoft-unqualified-friend`_, `-Wmicrosoft-using-decl`_, `-Wmicrosoft-void-pseudo-dtor`_. +Controls `-Winconsistent-dllimport`_, `-Wmicrosoft-anon-tag`_, `-Wmicrosoft-cast`_, `-Wmicrosoft-charize`_, `-Wmicrosoft-comment-paste`_, `-Wmicrosoft-const-init`_, `-Wmicrosoft-cpp-macro`_, `-Wmicrosoft-default-arg-redefinition`_, `-Wmicrosoft-drectve-section`_, `-Wmicrosoft-end-of-file`_, `-Wmicrosoft-enum-forward-reference`_, `-Wmicrosoft-enum-value`_, `-Wmicrosoft-exception-spec`_, `-Wmicrosoft-explicit-constructor-call`_, `-Wmicrosoft-extra-qualification`_, `-Wmicrosoft-fixed-enum`_, `-Wmicrosoft-flexible-array`_, `-Wmicrosoft-goto`_, `-Wmicrosoft-include`_, `-Wmicrosoft-mutable-reference`_, `-Wmicrosoft-pure-definition`_, `-Wmicrosoft-redeclare-static`_, `-Wmicrosoft-sealed`_, `-Wmicrosoft-template`_, `-Wmicrosoft-union-member-reference`_, `-Wmicrosoft-unqualified-friend`_, `-Wmicrosoft-using-decl`_, `-Wmicrosoft-void-pseudo-dtor`_. -Wmicrosoft-anon-tag @@ -6187,6 +6851,17 @@ This diagnostic is enabled by default. +-----------------------------------------------------------------------+ +-Wmicrosoft-drectve-section +--------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`#pragma` |nbsp| :placeholder:`A`:diagtext:`(".drectve") has undefined behavior, use #pragma comment(linker, ...) instead`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wmicrosoft-end-of-file ----------------------- **Diagnostic text:** @@ -6333,6 +7008,17 @@ This diagnostic is enabled by default. +----------------------------------------------------------------------------------------------------------+ +-Wmicrosoft-inaccessible-base +----------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`accessing inaccessible direct base` |nbsp| :placeholder:`A` |nbsp| :diagtext:`of` |nbsp| :placeholder:`B` |nbsp| :diagtext:`is a Microsoft extension`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wmicrosoft-include ------------------- This diagnostic is enabled by default. @@ -6400,10 +7086,6 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`use of identifier` |nbsp| :placeholder:`A` |nbsp| :diagtext:`found via unqualified lookup into dependent bases of class templates is a Microsoft extension`| +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -+--------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`explicit specialization of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`within class scope is a Microsoft extension`| -+--------------------------------------------------------------------------------------------------------------------------------------------------------+ - +-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`using the undeclared type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`as a default template argument is a Microsoft extension`| +-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -6412,32 +7094,36 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`non-type template argument containing a dereference operation is a Microsoft extension`| +-----------------------------------------------------------------------------------------------------------------------------+ -+---------------------------+---------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| |+-------------------------------------+| |nbsp| :diagtext:`specialization of` |nbsp| :placeholder:`B` |nbsp| :diagtext:`outside namespace enclosing` |nbsp| :placeholder:`C` |nbsp| :diagtext:`is a Microsoft extension`| -| ||:diagtext:`class template` || | -| |+-------------------------------------+| | -| ||:diagtext:`class template partial` || | -| |+-------------------------------------+| | -| ||:diagtext:`variable template` || | -| |+-------------------------------------+| | -| ||:diagtext:`variable template partial`|| | -| |+-------------------------------------+| | -| ||:diagtext:`function template` || | -| |+-------------------------------------+| | -| ||:diagtext:`member function` || | -| |+-------------------------------------+| | -| ||:diagtext:`static data member` || | -| |+-------------------------------------+| | -| ||:diagtext:`member class` || | -| |+-------------------------------------+| | -| ||:diagtext:`member enumeration` || | -| |+-------------------------------------+| | -+---------------------------+---------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++---------------------------+---------------------------------------+-----------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------+--------------------------------------------+ +|:warning:`warning:` |nbsp| |+-------------------------------------+| |nbsp| :diagtext:`specialization of` |nbsp| :placeholder:`B` |nbsp| :diagtext:`not in` |nbsp| |+----------------------------------------------------------------------------------------+| |nbsp| :diagtext:`is a Microsoft extension`| +| ||:diagtext:`class template` || ||+---------------------------------------------------------+ || | +| |+-------------------------------------+| |||:diagtext:`a namespace enclosing` |nbsp| :placeholder:`C`| || | +| ||:diagtext:`class template partial` || ||+---------------------------------------------------------+ || | +| |+-------------------------------------+| |+----------------------------------------------------------------------------------------+| | +| ||:diagtext:`variable template` || ||+--------------------------------------------------------------------------------------+|| | +| |+-------------------------------------+| |||:diagtext:`class` |nbsp| :placeholder:`C` |nbsp| :diagtext:`or an enclosing namespace`||| | +| ||:diagtext:`variable template partial`|| ||+--------------------------------------------------------------------------------------+|| | +| |+-------------------------------------+| |+----------------------------------------------------------------------------------------+| | +| ||:diagtext:`function template` || | | | +| |+-------------------------------------+| | | | +| ||:diagtext:`member function` || | | | +| |+-------------------------------------+| | | | +| ||:diagtext:`static data member` || | | | +| |+-------------------------------------+| | | | +| ||:diagtext:`member class` || | | | +| |+-------------------------------------+| | | | +| ||:diagtext:`member enumeration` || | | | +| |+-------------------------------------+| | | | ++---------------------------+---------------------------------------+-----------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------+--------------------------------------------+ +------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`template argument for template type parameter must be a type; omitted 'typename' is a Microsoft extension`| +------------------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'static' can only be specified inside the class definition`| ++-------------------------------------------------------------------------------------------------+ + +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`use of undeclared identifier` |nbsp| :placeholder:`A`:diagtext:`; unqualified lookup into dependent bases of class template` |nbsp| :placeholder:`B` |nbsp| :diagtext:`is a Microsoft extension`| +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -6528,25 +7214,25 @@ This diagnostic is enabled by default. ----------------- **Diagnostic text:** -+---------------------------------------------------------------------------------+--------------------------+------------------------------+-----------------------------------------------------------+--------------------------+------------------------------+ -|:warning:`warning:` |nbsp| :placeholder:`C` |nbsp| :diagtext:`defined as` |nbsp| |+------------------------+|+----------------------------+| |nbsp| :diagtext:`here but previously declared as` |nbsp| |+------------------------+|+----------------------------+| -| ||:diagtext:`a struct` ||| || ||:diagtext:`a struct` ||| || -| |+------------------------+|+----------------------------+| |+------------------------+|+----------------------------+| -| ||:diagtext:`an interface`||| |nbsp| :diagtext:`template`|| ||:diagtext:`an interface`||| |nbsp| :diagtext:`template`|| -| |+------------------------+|+----------------------------+| |+------------------------+|+----------------------------+| -| ||:diagtext:`a class` || | ||:diagtext:`a class` || | -| |+------------------------+| | |+------------------------+| | -+---------------------------------------------------------------------------------+--------------------------+------------------------------+-----------------------------------------------------------+--------------------------+------------------------------+ ++---------------------------------------------------------------------------------+--------------------------+------------------------------+-----------------------------------------------------------+--------------------------+------------------------------+----------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :placeholder:`C` |nbsp| :diagtext:`defined as` |nbsp| |+------------------------+|+----------------------------+| |nbsp| :diagtext:`here but previously declared as` |nbsp| |+------------------------+|+----------------------------+|:diagtext:`; this is valid, but may result in linker errors under the Microsoft C++ ABI`| +| ||:diagtext:`a struct` ||| || ||:diagtext:`a struct` ||| || | +| |+------------------------+|+----------------------------+| |+------------------------+|+----------------------------+| | +| ||:diagtext:`an interface`||| |nbsp| :diagtext:`template`|| ||:diagtext:`an interface`||| |nbsp| :diagtext:`template`|| | +| |+------------------------+|+----------------------------+| |+------------------------+|+----------------------------+| | +| ||:diagtext:`a class` || | ||:diagtext:`a class` || | | +| |+------------------------+| | |+------------------------+| | | ++---------------------------------------------------------------------------------+--------------------------+------------------------------+-----------------------------------------------------------+--------------------------+------------------------------+----------------------------------------------------------------------------------------+ -+---------------------------+-----------------------+------------------------------+--------------------------------------------------------------------------------+-----------------------+------------------------------+ -|:warning:`warning:` |nbsp| |+---------------------+|+----------------------------+| |nbsp| :placeholder:`C` |nbsp| :diagtext:`was previously declared as a` |nbsp| |+---------------------+|+----------------------------+| -| ||:diagtext:`struct` ||| || ||:diagtext:`struct` ||| || -| |+---------------------+|+----------------------------+| |+---------------------+|+----------------------------+| -| ||:diagtext:`interface`||| |nbsp| :diagtext:`template`|| ||:diagtext:`interface`||| |nbsp| :diagtext:`template`|| -| |+---------------------+|+----------------------------+| |+---------------------+|+----------------------------+| -| ||:diagtext:`class` || | ||:diagtext:`class` || | -| |+---------------------+| | |+---------------------+| | -+---------------------------+-----------------------+------------------------------+--------------------------------------------------------------------------------+-----------------------+------------------------------+ ++---------------------------+-----------------------+------------------------------+--------------------------------------------------------------------------------+-----------------------+------------------------------+----------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+---------------------+|+----------------------------+| |nbsp| :placeholder:`C` |nbsp| :diagtext:`was previously declared as a` |nbsp| |+---------------------+|+----------------------------+|:diagtext:`; this is valid, but may result in linker errors under the Microsoft C++ ABI`| +| ||:diagtext:`struct` ||| || ||:diagtext:`struct` ||| || | +| |+---------------------+|+----------------------------+| |+---------------------+|+----------------------------+| | +| ||:diagtext:`interface`||| |nbsp| :diagtext:`template`|| ||:diagtext:`interface`||| |nbsp| :diagtext:`template`|| | +| |+---------------------+|+----------------------------+| |+---------------------+|+----------------------------+| | +| ||:diagtext:`class` || | ||:diagtext:`class` || | | +| |+---------------------+| | |+---------------------+| | | ++---------------------------+-----------------------+------------------------------+--------------------------------------------------------------------------------+-----------------------+------------------------------+----------------------------------------------------------------------------------------+ -Wmissing-braces @@ -6755,6 +7441,21 @@ This diagnostic is enabled by default. +----------------------------------------------------------------------------------------------------------------+ +-Rmodule-import +--------------- +**Diagnostic text:** + ++------------------------------------------------------------------------------------+-----------------------------------------------------------+-------------------------------------------------------+ +|:remark:`remark:` |nbsp| :diagtext:`importing module '`:placeholder:`A`:diagtext:`'`|+---------------------------------------------------------+| |nbsp| :diagtext:`from '`:placeholder:`B`:diagtext:`'`| +| || || | +| |+---------------------------------------------------------+| | +| ||+-------------------------------------------------------+|| | +| ||| |nbsp| :diagtext:`into '`:placeholder:`D`:diagtext:`'`||| | +| ||+-------------------------------------------------------+|| | +| |+---------------------------------------------------------+| | ++------------------------------------------------------------------------------------+-----------------------------------------------------------+-------------------------------------------------------+ + + -Wmodule-import-in-extern-c --------------------------- This diagnostic is an error by default, but the flag ``-Wno-module-import-in-extern-c`` can be used to disable the error. @@ -6797,7 +7498,7 @@ Controls `-Wcast-of-sel-type`_, `-Wchar-subscripts`_, `-Wcomment`_, `-Wdelete-no -Wmove ------ -Controls `-Wpessimizing-move`_, `-Wredundant-move`_, `-Wself-move`_. +Controls `-Wpessimizing-move`_, `-Wredundant-move`_, `-Wreturn-std-move`_, `-Wself-move`_. -Wmsvc-include @@ -6888,6 +7589,25 @@ This diagnostic is enabled by default. +----------------------------------------------------------------+ +-Wnoderef +--------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`dereferencing` |nbsp| :placeholder:`A`:diagtext:`; was declared with a 'noderef' type`| ++----------------------------------------------------------------------------------------------------------------------------+ + ++-----------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`dereferencing expression marked as 'noderef'`| ++-----------------------------------------------------------------------------------+ + ++-----------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`casting to dereferenceable pointer removes 'noderef' attribute`| ++-----------------------------------------------------------------------------------------------------+ + + -Wnoexcept-type --------------- Synonym for `-Wc++17-compat-mangling`_. @@ -7033,6 +7753,25 @@ This diagnostic is enabled by default. +---------------------------------------------------------------------------------------------------------------------+ +-Wnontrivial-memaccess +---------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------+ +|:warning:`warning:` |nbsp| |+-----------------------------+| |nbsp| :diagtext:`this` |nbsp| :placeholder:`B` |nbsp| :diagtext:`call is a pointer to record` |nbsp| :placeholder:`C` |nbsp| :diagtext:`that is not trivial to` |nbsp| |+----------------------------------------+| +| ||:diagtext:`destination for` || ||:diagtext:`primitive-default-initialize`|| +| |+-----------------------------+| |+----------------------------------------+| +| ||:diagtext:`source of` || ||:diagtext:`primitive-copy` || +| |+-----------------------------+| |+----------------------------------------+| +| ||:diagtext:`first operand of` || | | +| |+-----------------------------+| | | +| ||:diagtext:`second operand of`|| | | +| |+-----------------------------+| | | ++---------------------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------+ + + -Wnsconsumed-mismatch --------------------- This diagnostic is enabled by default. @@ -7274,16 +8013,38 @@ This diagnostic is enabled by default. +---------------------------------------------------------------------------------------------------------------------------+-------------------------+---------------------------------------------------------------------------------------------------------------------------------+ +-Wobjc-bool-constant-conversion +------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`implicit conversion from constant value` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to BOOL; the only well defined values for BOOL are YES and NO`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +-Wobjc-boxing +------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`string is ill-formed as UTF-8 and will become a null` |nbsp| :placeholder:`A` |nbsp| :diagtext:`when boxed`| ++-------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wobjc-circular-container ------------------------- This diagnostic is enabled by default. **Diagnostic text:** -+-----------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`adding '`:placeholder:`A`:diagtext:`' to '`:placeholder:`B`:diagtext:`' might cause circular dependency in container`| -+-----------------------------------------------------------------------------------------------------------------------------------------------------------+ - ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`adding` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B` |nbsp| :diagtext:`might cause circular dependency in container`| ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + -Wobjc-cocoa-api ---------------- @@ -7504,6 +8265,15 @@ This diagnostic is enabled by default. +-----------------------------------------------------------------------------------------------------------------------------+ +-Wobjc-property-assign-on-object-type +------------------------------------- +**Diagnostic text:** + ++--------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'assign' property of object type may become a dangling reference; consider using 'unsafe\_unretained'`| ++--------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wobjc-property-implementation ------------------------------ This diagnostic is enabled by default. @@ -7699,10 +8469,102 @@ This diagnostic is enabled by default. **Diagnostic text:** ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`template parameter lists have a different number of parameters (`:placeholder:`A` |nbsp| :diagtext:`vs` |nbsp| :placeholder:`B`:diagtext:`)`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`template parameter has different kinds in different translation units`| ++------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`field` |nbsp| :placeholder:`A` |nbsp| :diagtext:`declared with incompatible types in different translation units (`:placeholder:`B` |nbsp| :diagtext:`vs.` |nbsp| :placeholder:`C`:diagtext:`)`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`external function` |nbsp| :placeholder:`A` |nbsp| :diagtext:`declared with incompatible types in different translation units (`:placeholder:`B` |nbsp| :diagtext:`vs.` |nbsp| :placeholder:`C`:diagtext:`)`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`instance variable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`declared with incompatible types in different translation units (`:placeholder:`B` |nbsp| :diagtext:`vs.` |nbsp| :placeholder:`C`:diagtext:`)`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`non-type template parameter declared with incompatible types in different translation units (`:placeholder:`A` |nbsp| :diagtext:`vs.` |nbsp| :placeholder:`B`:diagtext:`)`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+--------------------+| |nbsp| :diagtext:`method` |nbsp| :placeholder:`B` |nbsp| :diagtext:`has a different number of parameters in different translation units (`:placeholder:`C` |nbsp| :diagtext:`vs.` |nbsp| :placeholder:`D`:diagtext:`)`| +| ||:diagtext:`class` || | +| |+--------------------+| | +| ||:diagtext:`instance`|| | +| |+--------------------+| | ++---------------------------+----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------+----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+--------------------+| |nbsp| :diagtext:`method` |nbsp| :placeholder:`B` |nbsp| :diagtext:`has a parameter with a different types in different translation units (`:placeholder:`C` |nbsp| :diagtext:`vs.` |nbsp| :placeholder:`D`:diagtext:`)`| +| ||:diagtext:`class` || | +| |+--------------------+| | +| ||:diagtext:`instance`|| | +| |+--------------------+| | ++---------------------------+----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+--------------------+| |nbsp| :diagtext:`method` |nbsp| :placeholder:`B` |nbsp| :diagtext:`has incompatible result types in different translation units (`:placeholder:`C` |nbsp| :diagtext:`vs.` |nbsp| :placeholder:`D`:diagtext:`)`| +| ||:diagtext:`class` || | +| |+--------------------+| | +| ||:diagtext:`instance`|| | +| |+--------------------+| | ++---------------------------+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------+----------------------+-------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+--------------------+| |nbsp| :diagtext:`method` |nbsp| :placeholder:`B` |nbsp| :diagtext:`is variadic in one translation unit and not variadic in another`| +| ||:diagtext:`class` || | +| |+--------------------+| | +| ||:diagtext:`instance`|| | +| |+--------------------+| | ++---------------------------+----------------------+-------------------------------------------------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------+-------------------------+--------------------------------------------------+-------------------------+-----------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`property` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is implemented with` |nbsp| |+-----------------------+| |nbsp| :diagtext:`in one translation but` |nbsp| |+-----------------------+| |nbsp| :diagtext:`in another translation unit`| +| ||:diagtext:`@synthesize`|| ||:diagtext:`@dynamic` || | +| |+-----------------------+| |+-----------------------+| | +| ||:diagtext:`@dynamic` || ||:diagtext:`@synthesize`|| | +| |+-----------------------+| |+-----------------------+| | ++----------------------------------------------------------------------------------------------------------------------+-------------------------+--------------------------------------------------+-------------------------+-----------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`property` |nbsp| :placeholder:`A` |nbsp| :diagtext:`declared with incompatible types in different translation units (`:placeholder:`B` |nbsp| :diagtext:`vs.` |nbsp| :placeholder:`C`:diagtext:`)`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++---------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`class` |nbsp| :placeholder:`A` |nbsp| :diagtext:`has incompatible superclasses`| ++---------------------------------------------------------------------------------------------------------------------+ + ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`property` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is synthesized to different ivars in different translation units (`:placeholder:`B` |nbsp| :diagtext:`vs.` |nbsp| :placeholder:`C`:diagtext:`)`| ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------+-------------------+----------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`parameter kind mismatch; parameter is` |nbsp| |+-----------------+| |nbsp| :diagtext:`parameter pack`| +| ||:diagtext:`not a`|| | +| |+-----------------+| | +| ||:diagtext:`a` || | +| |+-----------------+| | ++------------------------------------------------------------------------------------+-------------------+----------------------------------+ + +--------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`has incompatible definitions in different translation units`| +--------------------------------------------------------------------------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`external variable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`defined in multiple translation units`| ++-----------------------------------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`external variable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`declared with incompatible types in different translation units (`:placeholder:`B` |nbsp| :diagtext:`vs.` |nbsp| :placeholder:`C`:diagtext:`)`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + -Wold-style-cast ---------------- @@ -7738,6 +8600,10 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`aligned clause will be ignored because the requested alignment is not a power of 2`| +-------------------------------------------------------------------------------------------------------------------------+ ++----------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`allocator with the 'thread' trait access has unspecified behavior on '`:placeholder:`A`:diagtext:`' directive`| ++----------------------------------------------------------------------------------------------------------------------------------------------------+ + +---------------------------------------------------------------------------------+---------------------------------------------------+-------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`zero linear step (`:placeholder:`A` |nbsp| |+-------------------------------------------------+|:diagtext:`should probably be const)`| | || || | @@ -7746,6 +8612,16 @@ This diagnostic is enabled by default. | |+-------------------------------------------------+| | +---------------------------------------------------------------------------------+---------------------------------------------------+-------------------------------------+ ++---------------------------------------------------------------------------+----------------------------------------------+-----------------------------------------------------------+----------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`allocate directive specifies` |nbsp| |+--------------------------------------------+| |nbsp| :diagtext:`allocator while previously used` |nbsp| |+--------------------------------------------+| +| ||:diagtext:`default` || ||:diagtext:`default` || +| |+--------------------------------------------+| |+--------------------------------------------+| +| ||+------------------------------------------+|| ||+------------------------------------------+|| +| |||:diagtext:`'`:placeholder:`B`:diagtext:`'`||| |||:diagtext:`'`:placeholder:`D`:diagtext:`'`||| +| ||+------------------------------------------+|| ||+------------------------------------------+|| +| |+--------------------------------------------+| |+--------------------------------------------+| ++---------------------------------------------------------------------------+----------------------------------------------+-----------------------------------------------------------+----------------------------------------------+ + -Wopenmp-loop-form ------------------ @@ -7772,6 +8648,14 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`The OpenMP offloading target '`:placeholder:`A`:diagtext:`' is similar to target '`:placeholder:`B`:diagtext:`' already specified - will be ignored.`| +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`No library '`:placeholder:`A`:diagtext:`' found in the default clang lib directory or in LIBRARY\_PATH. Expect degraded performance due to no inlining of runtime functions on target devices.`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`Non-trivial type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is mapped, only trivial types are guaranteed to be mapped correctly`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +-----------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`declaration is not declared in any declare target region`| +-----------------------------------------------------------------------------------------------+ @@ -7787,14 +8671,14 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`option '-ffine-grained-bitfield-accesses' cannot be enabled together with a sanitizer; flag ignored`| +------------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`The '`:placeholder:`A`:diagtext:`' architecture does not support -moutline; flag ignored`| ++-------------------------------------------------------------------------------------------------------------------------------+ + +----------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`option '`:placeholder:`A`:diagtext:`' was ignored by the PS4 toolchain, using '-fPIC'`| +----------------------------------------------------------------------------------------------------------------------------+ -+-------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`ignoring '-mabicalls' option as it cannot be used with non position-independent code and the N64 ABI`| -+-------------------------------------------------------------------------------------------------------------------------------------------+ - +-------------------------------------------------------------------------------------------------------------------+-------------------------------------------+----------------------+ |:warning:`warning:` |nbsp| :diagtext:`ignoring '-mlong-calls' option as it is not currently supported with` |nbsp| |+-----------------------------------------+|:diagtext:`-mabicalls`| | || || | @@ -7803,6 +8687,29 @@ This diagnostic is enabled by default. | |+-----------------------------------------+| | +-------------------------------------------------------------------------------------------------------------------+-------------------------------------------+----------------------+ ++-----------------------------------------------------------------------------------------------------------------------+-------------------------------+----------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ignoring '`:placeholder:`A`:diagtext:`' option as it cannot be used with` |nbsp| |+-----------------------------+| |nbsp| :diagtext:`-mabicalls and the N64 ABI`| +| ||:diagtext:`implicit usage of`|| | +| |+-----------------------------+| | +| || || | +| |+-----------------------------+| | ++-----------------------------------------------------------------------------------------------------------------------+-------------------------------+----------------------------------------------+ + ++----------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`auto-vectorization requires HVX, use -mhvx to enable it`| ++----------------------------------------------------------------------------------------------+ + + +-Wordered-compare-function-pointers +----------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ordered comparison of function pointers (`:placeholder:`A` |nbsp| :diagtext:`and` |nbsp| :placeholder:`B`:diagtext:`)`| ++------------------------------------------------------------------------------------------------------------------------------------------------------------+ + -Wout-of-line-declaration ------------------------- @@ -7885,6 +8792,7 @@ This diagnostic is enabled by default. | |+---------------------+| +-----------------------------------------------------------------------------------------------+-----------------------+ + -Woverride-init --------------- Synonym for `-Winitializer-overrides`_. @@ -8079,10 +8987,14 @@ This diagnostic is enabled by default. -Wpedantic ---------- -Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-literal`_, `-Wc11-extensions`_, `-Wcomplex-component-init`_, `-Wdeclaration-after-statement`_, `-Wdollar-in-identifier-extension`_, `-Wembedded-directive`_, `-Wempty-translation-unit`_, `-Wextended-offsetof`_, `-Wflexible-array-extensions`_, `-Wformat-pedantic`_, `-Wfour-char-constants`_, `-Wgnu-anonymous-struct`_, `-Wgnu-auto-type`_, `-Wgnu-binary-literal`_, `-Wgnu-case-range`_, `-Wgnu-complex-integer`_, `-Wgnu-compound-literal-initializer`_, `-Wgnu-conditional-omitted-operand`_, `-Wgnu-empty-initializer`_, `-Wgnu-empty-struct`_, `-Wgnu-flexible-array-initializer`_, `-Wgnu-flexible-array-union-member`_, `-Wgnu-folding-constant`_, `-Wgnu-imaginary-constant`_, `-Wgnu-include-next`_, `-Wgnu-label-as-value`_, `-Wgnu-redeclared-enum`_, `-Wgnu-statement-expression`_, `-Wgnu-union-cast`_, `-Wgnu-zero-line-directive`_, `-Wgnu-zero-variadic-macro-arguments`_, `-Wimport-preprocessor-directive-pedantic`_, `-Wkeyword-macro`_, `-Wlanguage-extension-token`_, `-Wlong-long`_, `-Wmicrosoft-charize`_, `-Wmicrosoft-comment-paste`_, `-Wmicrosoft-cpp-macro`_, `-Wmicrosoft-end-of-file`_, `-Wmicrosoft-enum-value`_, `-Wmicrosoft-fixed-enum`_, `-Wmicrosoft-flexible-array`_, `-Wmicrosoft-redeclare-static`_, `-Wnested-anon-types`_, `-Wnullability-extension`_, `-Woverlength-strings`_, `-Wretained-language-linkage`_, `-Wundefined-internal-type`_, `-Wvla-extension`_, `-Wzero-length-array`_. +Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-literal`_, `-Wc11-extensions`_, `-Wcomplex-component-init`_, `-Wdeclaration-after-statement`_, `-Wdollar-in-identifier-extension`_, `-Wembedded-directive`_, `-Wempty-translation-unit`_, `-Wfixed-enum-extension`_, `-Wflexible-array-extensions`_, `-Wfour-char-constants`_, `-Wgnu-anonymous-struct`_, `-Wgnu-auto-type`_, `-Wgnu-binary-literal`_, `-Wgnu-case-range`_, `-Wgnu-complex-integer`_, `-Wgnu-compound-literal-initializer`_, `-Wgnu-conditional-omitted-operand`_, `-Wgnu-empty-initializer`_, `-Wgnu-empty-struct`_, `-Wgnu-flexible-array-initializer`_, `-Wgnu-flexible-array-union-member`_, `-Wgnu-folding-constant`_, `-Wgnu-imaginary-constant`_, `-Wgnu-include-next`_, `-Wgnu-label-as-value`_, `-Wgnu-redeclared-enum`_, `-Wgnu-statement-expression`_, `-Wgnu-union-cast`_, `-Wgnu-zero-line-directive`_, `-Wgnu-zero-variadic-macro-arguments`_, `-Wimport-preprocessor-directive-pedantic`_, `-Wkeyword-macro`_, `-Wlanguage-extension-token`_, `-Wlong-long`_, `-Wmicrosoft-charize`_, `-Wmicrosoft-comment-paste`_, `-Wmicrosoft-cpp-macro`_, `-Wmicrosoft-end-of-file`_, `-Wmicrosoft-enum-value`_, `-Wmicrosoft-fixed-enum`_, `-Wmicrosoft-flexible-array`_, `-Wmicrosoft-redeclare-static`_, `-Wnested-anon-types`_, `-Wnullability-extension`_, `-Woverlength-strings`_, `-Wretained-language-linkage`_, `-Wundefined-internal-type`_, `-Wvla-extension`_, `-Wzero-length-array`_. **Diagnostic text:** ++-----------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`duplicate '`:placeholder:`A`:diagtext:`' declaration specifier`| ++-----------------------------------------------------------------------------------------------------+ + +------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`'enable\_if' is a clang extension`| +------------------------------------------------------------------------+ @@ -8115,31 +9027,37 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter | |+------------------+| | +--------------------------------------------------------+--------------------+------------------------------------------------------------+ -+--------------------------------------------------------------------+-----------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`no viable constructor` |nbsp| |+---------------------------------------+| |nbsp| :diagtext:`of type` |nbsp| :placeholder:`B`:diagtext:`; C++98 requires a copy constructor when binding a reference to a temporary`| -| ||:diagtext:`copying variable` || | -| |+---------------------------------------+| | -| ||:diagtext:`copying parameter` || | -| |+---------------------------------------+| | -| ||:diagtext:`returning object` || | -| |+---------------------------------------+| | -| ||:diagtext:`throwing object` || | -| |+---------------------------------------+| | -| ||:diagtext:`copying member subobject` || | -| |+---------------------------------------+| | -| ||:diagtext:`copying array element` || | -| |+---------------------------------------+| | -| ||:diagtext:`allocating object` || | -| |+---------------------------------------+| | -| ||:diagtext:`copying temporary` || | -| |+---------------------------------------+| | -| ||:diagtext:`initializing base subobject`|| | -| |+---------------------------------------+| | -| ||:diagtext:`initializing vector element`|| | -| |+---------------------------------------+| | -| ||:diagtext:`capturing value` || | -| |+---------------------------------------+| | -+--------------------------------------------------------------------+-----------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ ++--------------------------------------------------------------------+------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`no viable constructor` |nbsp| |+----------------------------------------------------+| |nbsp| :diagtext:`of type` |nbsp| :placeholder:`B`:diagtext:`; C++98 requires a copy constructor when binding a reference to a temporary`| +| ||:diagtext:`copying variable` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`copying parameter` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`returning object` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`initializing statement expression result`|| | +| |+----------------------------------------------------+| | +| ||:diagtext:`throwing object` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`copying member subobject` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`copying array element` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`allocating object` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`copying temporary` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`initializing base subobject` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`initializing vector element` || | +| |+----------------------------------------------------+| | +| ||:diagtext:`capturing value` || | +| |+----------------------------------------------------+| | ++--------------------------------------------------------------------+------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------+ + ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`ISO C++ standards before C++17 do not allow new expression for type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to use list-initialization`| ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +--------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`parameter` |nbsp| :placeholder:`A` |nbsp| :diagtext:`was not declared, defaulting to type 'int'`| @@ -8185,25 +9103,33 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter |:warning:`warning:` |nbsp| :diagtext:`flexible array members are a C99 feature`| +-------------------------------------------------------------------------------+ -+---------------------------------------------------------------+-----------------------+--------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`invalid application of '`|+---------------------+|:diagtext:`' to a function type`| -| ||:diagtext:`sizeof` || | -| |+---------------------+| | -| ||:diagtext:`alignof` || | -| |+---------------------+| | -| ||:diagtext:`vec\_step`|| | -| |+---------------------+| | -+---------------------------------------------------------------+-----------------------+--------------------------------+ - -+---------------------------------------------------------------+-----------------------+----------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`invalid application of '`|+---------------------+|:diagtext:`' to a void type`| -| ||:diagtext:`sizeof` || | -| |+---------------------+| | -| ||:diagtext:`alignof` || | -| |+---------------------+| | -| ||:diagtext:`vec\_step`|| | -| |+---------------------+| | -+---------------------------------------------------------------+-----------------------+----------------------------+ ++---------------------------------------------------------------+-----------------------------------------------------+--------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`invalid application of '`|+---------------------------------------------------+|:diagtext:`' to a function type`| +| ||:diagtext:`sizeof` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`alignof` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`vec\_step` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`\_\_builtin\_omp\_required\_simd\_align`|| | +| |+---------------------------------------------------+| | +| ||:diagtext:`\_\_alignof` || | +| |+---------------------------------------------------+| | ++---------------------------------------------------------------+-----------------------------------------------------+--------------------------------+ + ++---------------------------------------------------------------+-----------------------------------------------------+----------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`invalid application of '`|+---------------------------------------------------+|:diagtext:`' to a void type`| +| ||:diagtext:`sizeof` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`alignof` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`vec\_step` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`\_\_builtin\_omp\_required\_simd\_align`|| | +| |+---------------------------------------------------+| | +| ||:diagtext:`\_\_alignof` || | +| |+---------------------------------------------------+| | ++---------------------------------------------------------------+-----------------------------------------------------+----------------------------+ +-------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`ISO C90 does not allow subscripting non-lvalue array`| @@ -8313,6 +9239,14 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter | |+------------------+| | +-----------------------------------------------------------------------------+--------------------+---------------------------------------------+ ++------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`format specifies type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`but the argument has` |nbsp| |+---------------------------+| |nbsp| :placeholder:`B`| +| ||:diagtext:`type` || | +| |+---------------------------+| | +| ||:diagtext:`underlying type`|| | +| |+---------------------------+| | ++------------------------------------------------------------------------------------------------------------------------------------+-----------------------------+------------------------+ + +---------------------------------------------------+----------------------+-----------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`void` |nbsp| |+--------------------+| |nbsp| :placeholder:`A` |nbsp| :diagtext:`should not return void expression`| | ||:diagtext:`function`|| | @@ -8451,6 +9385,10 @@ Also controls `-Wc++11-extra-semi`_, `-Wc++11-long-long`_, `-Wc++14-binary-liter |:warning:`warning:` |nbsp| :diagtext:`empty macro arguments are a C99 feature`| +------------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`variadic macros are a Clang extension in OpenCL`| ++--------------------------------------------------------------------------------------+ + +----------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`C requires #line number to be less than` |nbsp| :placeholder:`A`:diagtext:`, allowed as extension`| +----------------------------------------------------------------------------------------------------------------------------------------+ @@ -8510,25 +9448,33 @@ Some of the diagnostics controlled by this flag are enabled by default. | |+---------------------+| |+-------------+| | +----------------------------------------------------+-----------------------+---------------------------+---------------+----------------------------------------------+ -+---------------------------------------------------------------+-----------------------+--------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`invalid application of '`|+---------------------+|:diagtext:`' to a function type`| -| ||:diagtext:`sizeof` || | -| |+---------------------+| | -| ||:diagtext:`alignof` || | -| |+---------------------+| | -| ||:diagtext:`vec\_step`|| | -| |+---------------------+| | -+---------------------------------------------------------------+-----------------------+--------------------------------+ - -+---------------------------------------------------------------+-----------------------+----------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`invalid application of '`|+---------------------+|:diagtext:`' to a void type`| -| ||:diagtext:`sizeof` || | -| |+---------------------+| | -| ||:diagtext:`alignof` || | -| |+---------------------+| | -| ||:diagtext:`vec\_step`|| | -| |+---------------------+| | -+---------------------------------------------------------------+-----------------------+----------------------------+ ++---------------------------------------------------------------+-----------------------------------------------------+--------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`invalid application of '`|+---------------------------------------------------+|:diagtext:`' to a function type`| +| ||:diagtext:`sizeof` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`alignof` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`vec\_step` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`\_\_builtin\_omp\_required\_simd\_align`|| | +| |+---------------------------------------------------+| | +| ||:diagtext:`\_\_alignof` || | +| |+---------------------------------------------------+| | ++---------------------------------------------------------------+-----------------------------------------------------+--------------------------------+ + ++---------------------------------------------------------------+-----------------------------------------------------+----------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`invalid application of '`|+---------------------------------------------------+|:diagtext:`' to a void type`| +| ||:diagtext:`sizeof` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`alignof` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`vec\_step` || | +| |+---------------------------------------------------+| | +| ||:diagtext:`\_\_builtin\_omp\_required\_simd\_align`|| | +| |+---------------------------------------------------+| | +| ||:diagtext:`\_\_alignof` || | +| |+---------------------------------------------------+| | ++---------------------------------------------------------------+-----------------------------------------------------+----------------------------+ +-----------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`subtraction of pointers to type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`of zero size has undefined behavior`| @@ -8560,6 +9506,17 @@ This diagnostic is enabled by default. +-------------------------------------------------+------------------------------+---------------------------------------------------------------------------------+ +-Wpointer-integer-compare +------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-----------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`comparison between pointer and integer (`:placeholder:`A` |nbsp| :diagtext:`and` |nbsp| :placeholder:`B`:diagtext:`)`| ++-----------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wpointer-sign -------------- This diagnostic is enabled by default. @@ -8726,26 +9683,34 @@ This diagnostic is enabled by default. **Diagnostic text:** -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`top-level module '`:placeholder:`A`:diagtext:`' in private module map, expected a submodule of '`:placeholder:`B`:diagtext:`'`| -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++----------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`expected canonical name for private module '`:placeholder:`A`:diagtext:`'`| ++----------------------------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`private submodule '`:placeholder:`A`:diagtext:`' in private module map, expected top-level module`| ++----------------------------------------------------------------------------------------------------------------------------------------+ +----------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`module '`:placeholder:`A`:diagtext:`' already re-exported as '`:placeholder:`B`:diagtext:`'`| +----------------------------------------------------------------------------------------------------------------------------------+ ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`no submodule named` |nbsp| :placeholder:`A` |nbsp| :diagtext:`in module '`:placeholder:`B`:diagtext:`'; using top level '`:placeholder:`C`:diagtext:`'`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + -Wprofile-instr-missing ----------------------- **Diagnostic text:** -+-----------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+-------------------+---------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`profile data may be incomplete: of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`function`|+-------------+|:diagtext:`,` |nbsp| :placeholder:`B` |nbsp| |+-----------------+| |nbsp| :diagtext:`no data`| -| || || ||:diagtext:`:has` || | -| |+-------------+| |+-----------------+| | -| ||:diagtext:`s`|| ||:diagtext:`:have`|| | -| |+-------------+| |+-----------------+| | -+-----------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+-------------------+---------------------------+ ++-----------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+------------------+---------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`profile data may be incomplete: of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`function`|+-------------+|:diagtext:`,` |nbsp| :placeholder:`B` |nbsp| |+----------------+| |nbsp| :diagtext:`no data`| +| || || ||:diagtext:`has` || | +| |+-------------+| |+----------------+| | +| ||:diagtext:`s`|| ||:diagtext:`have`|| | +| |+-------------+| |+----------------+| | ++-----------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+------------------+---------------------------+ -Wprofile-instr-out-of-date @@ -8754,13 +9719,13 @@ This diagnostic is enabled by default. **Diagnostic text:** -+------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+-------------------+--------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`profile data may be out of date: of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`function`|+-------------+|:diagtext:`,` |nbsp| :placeholder:`B` |nbsp| |+-----------------+| |nbsp| :diagtext:`mismatched data that will be ignored`| -| || || ||:diagtext:`:has` || | -| |+-------------+| |+-----------------+| | -| ||:diagtext:`s`|| ||:diagtext:`:have`|| | -| |+-------------+| |+-----------------+| | -+------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+-------------------+--------------------------------------------------------+ ++------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+------------------+--------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`profile data may be out of date: of` |nbsp| :placeholder:`A` |nbsp| :diagtext:`function`|+-------------+|:diagtext:`,` |nbsp| :placeholder:`B` |nbsp| |+----------------+| |nbsp| :diagtext:`mismatched data that will be ignored`| +| || || ||:diagtext:`has` || | +| |+-------------+| |+----------------+| | +| ||:diagtext:`s`|| ||:diagtext:`have`|| | +| |+-------------+| |+----------------+| | ++------------------------------------------------------------------------------------------------------------------------------+---------------+---------------------------------------------+------------------+--------------------------------------------------------+ -Wprofile-instr-unprofiled @@ -8861,6 +9826,15 @@ This diagnostic is enabled by default. +---------------------------------------------------------------------------------------------------------+ +-Wquoted-include-in-framework-header +------------------------------------ +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`double-quoted include "`:placeholder:`A`:diagtext:`" in framework header, expected angle-bracketed instead`| ++-------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wrange-loop-analysis --------------------- **Diagnostic text:** @@ -9064,13 +10038,35 @@ This diagnostic is enabled by default. | |+------------------------+| | +--------------------------------------------------------+--------------------------+------------------------------------------+ -+---------------------------+--------------------------+-------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| |+------------------------+| |nbsp| :diagtext:`stack memory associated with local variable` |nbsp| :placeholder:`B` |nbsp| :diagtext:`returned`| -| ||:diagtext:`address of` || | -| |+------------------------+| | -| ||:diagtext:`reference to`|| | -| |+------------------------+| | -+---------------------------+--------------------------+-------------------------------------------------------------------------------------------------------------------+ ++---------------------------+--------------------------+--------------------------------------------------------+----------------------------+----------------------------------------------------+ +|:warning:`warning:` |nbsp| |+------------------------+| |nbsp| :diagtext:`stack memory associated with` |nbsp| |+--------------------------+| |nbsp| :placeholder:`B` |nbsp| :diagtext:`returned`| +| ||:diagtext:`address of` || ||:diagtext:`local variable`|| | +| |+------------------------+| |+--------------------------+| | +| ||:diagtext:`reference to`|| ||:diagtext:`parameter` || | +| |+------------------------+| |+--------------------------+| | ++---------------------------+--------------------------+--------------------------------------------------------+----------------------------+----------------------------------------------------+ + + +-Wreturn-std-move +----------------- +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------------------------------+----------------------+---------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`local variable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`will be copied despite being` |nbsp| |+--------------------+| |nbsp| :diagtext:`by name`| +| ||:diagtext:`returned`|| | +| |+--------------------+| | +| ||:diagtext:`thrown` || | +| |+--------------------+| | ++-------------------------------------------------------------------------------------------------------------------------------------+----------------------+---------------------------+ + + +-Wreturn-std-move-in-c++11 +-------------------------- +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`prior to the resolution of a defect report against ISO C++11, local variable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`would have been copied despite being returned by name, due to its not matching the function return type`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -Wreturn-type @@ -9149,17 +10145,6 @@ This diagnostic is enabled by default. +-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ --Wrtti-for-exceptions ---------------------- -This diagnostic is enabled by default. - -**Diagnostic text:** - -+--------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`implicitly enabling rtti for exception handling`| -+--------------------------------------------------------------------------------------+ - - -Rsanitize-address ------------------ **Diagnostic text:** @@ -9199,9 +10184,17 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`section attribute is specified on redeclared variable`| +--------------------------------------------------------------------------------------------+ -+----------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`section does not match previous declaration`| -+----------------------------------------------------------------------------------+ ++------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`duplicate code segment specifiers`| ++------------------------------------------------------------------------+ + ++---------------------------+---------------------+-------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`does not match previous declaration`| +| ||:diagtext:`codeseg`|| | +| |+-------------------+| | +| ||:diagtext:`section`|| | +| |+-------------------+| | ++---------------------------+---------------------+-------------------------------------------------------+ -Wselector @@ -9228,7 +10221,7 @@ Also controls `-Wselector-type-mismatch`_. ------------- Some of the diagnostics controlled by this flag are enabled by default. -Also controls `-Wself-assign-field`_. +Also controls `-Wself-assign-field`_, `-Wself-assign-overloaded`_. **Diagnostic text:** @@ -9252,6 +10245,15 @@ This diagnostic is enabled by default. +--------------------------------------------------------+-------------------------------+-----------------------------+ +-Wself-assign-overloaded +------------------------ +**Diagnostic text:** + ++------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`explicitly assigning value of variable of type` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to itself`| ++------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wself-move ----------- **Diagnostic text:** @@ -9357,9 +10359,15 @@ Controls `-Wshadow`_, `-Wshadow-field`_, `-Wshadow-field-in-constructor`_, `-Wsh -------------- **Diagnostic text:** -+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`non-static data member '`:placeholder:`A`:diagtext:`' of '`:placeholder:`B`:diagtext:`' shadows member inherited from type '`:placeholder:`C`:diagtext:`'`| -+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++---------------------------+------------------------------------+--------------------------------+--------------------------------------------------+----------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+----------------------------------+| |nbsp| :placeholder:`A` |nbsp| |+------------------------------------------------+|:diagtext:`shadows member inherited from type` |nbsp| :placeholder:`C`| +| ||:diagtext:`parameter` || || || | +| |+----------------------------------+| |+------------------------------------------------+| | +| ||:diagtext:`non-static data member`|| ||+----------------------------------------------+|| | +| |+----------------------------------+| |||:diagtext:`of` |nbsp| :placeholder:`B` |nbsp| ||| | +| | | ||+----------------------------------------------+|| | +| | | |+------------------------------------------------+| | ++---------------------------+------------------------------------+--------------------------------+--------------------------------------------------+----------------------------------------------------------------------+ -Wshadow-field-in-constructor @@ -9518,6 +10526,10 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`operand of ? changes signedness:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B`| +---------------------------------------------------------------------------------------------------------------------------------------------+ ++-----------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`the resulting value is always non-negative after implicit conversion`| ++-----------------------------------------------------------------------------------------------------------+ + -Wsign-promo ------------ @@ -9554,6 +10566,17 @@ This diagnostic is enabled by default. +--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +-Wsizeof-pointer-div +-------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'`:placeholder:`A`:diagtext:`' will return the size of the pointer, not the array itself`| ++-------------------------------------------------------------------------------------------------------------------------------+ + + -Wsizeof-pointer-memaccess -------------------------- This diagnostic is enabled by default. @@ -9728,6 +10751,17 @@ This diagnostic is enabled by default. +----------------------------------------------------------------------------------------------------------------------------------------------------+ +-Wstdlibcxx-not-found +--------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`include path for libstdc++ headers not found; pass '-stdlib=libc++' on the command line to use the libc++ standard library instead`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wstrict-aliasing ----------------- This diagnostic flag exists for GCC compatibility, and has no effect in Clang. @@ -9896,6 +10930,24 @@ This diagnostic is enabled by default. +--------------------------------------------------------------------------------------------------------------------------------+ +-Wsuspicious-bzero +------------------ +This diagnostic is enabled by default. + +**Diagnostic text:** + ++----------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`'size' argument to bzero is '0'`| ++----------------------------------------------------------------------+ + + +-Wsuspicious-memaccess +---------------------- +This diagnostic is enabled by default. + +Controls `-Wdynamic-class-memaccess`_, `-Wmemset-transposed-args`_, `-Wnontrivial-memaccess`_, `-Wsizeof-pointer-memaccess`_, `-Wsuspicious-bzero`_. + + -Wswitch -------- This diagnostic is enabled by default. @@ -9906,25 +10958,25 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`overflow converting case value to switch condition type (`:placeholder:`A` |nbsp| :diagtext:`to` |nbsp| :placeholder:`B`:diagtext:`)`| +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -+---------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| |+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -| ||+-----------------------------------------------------------------------------------------------+ || -| |||:diagtext:`:enumeration value` |nbsp| :placeholder:`B` |nbsp| :diagtext:`not handled in switch`| || -| ||+-----------------------------------------------------------------------------------------------+ || -| |+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -| ||+-----------------------------------------------------------------------------------------------------------------------------------------------+ || -| |||:diagtext:`:enumeration values` |nbsp| :placeholder:`B` |nbsp| :diagtext:`and` |nbsp| :placeholder:`C` |nbsp| :diagtext:`not handled in switch`| || -| ||+-----------------------------------------------------------------------------------------------------------------------------------------------+ || -| |+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -| ||+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ || -| |||:diagtext:`:enumeration values` |nbsp| :placeholder:`B`:diagtext:`,` |nbsp| :placeholder:`C`:diagtext:`, and` |nbsp| :placeholder:`D` |nbsp| :diagtext:`not handled in switch`| || -| ||+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ || -| |+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -| ||+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+|| -| |||:diagtext:`:`:placeholder:`A` |nbsp| :diagtext:`enumeration values not handled in switch:` |nbsp| :placeholder:`B`:diagtext:`,` |nbsp| :placeholder:`C`:diagtext:`,` |nbsp| :placeholder:`D`:diagtext:`...`||| -| ||+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+|| -| |+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -+---------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| +| ||+----------------------------------------------------------------------------------------------+ || +| |||:diagtext:`enumeration value` |nbsp| :placeholder:`B` |nbsp| :diagtext:`not handled in switch`| || +| ||+----------------------------------------------------------------------------------------------+ || +| |+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| +| ||+----------------------------------------------------------------------------------------------------------------------------------------------+ || +| |||:diagtext:`enumeration values` |nbsp| :placeholder:`B` |nbsp| :diagtext:`and` |nbsp| :placeholder:`C` |nbsp| :diagtext:`not handled in switch`| || +| ||+----------------------------------------------------------------------------------------------------------------------------------------------+ || +| |+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| +| ||+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ || +| |||:diagtext:`enumeration values` |nbsp| :placeholder:`B`:diagtext:`,` |nbsp| :placeholder:`C`:diagtext:`, and` |nbsp| :placeholder:`D` |nbsp| :diagtext:`not handled in switch`| || +| ||+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ || +| |+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| +| ||+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+|| +| |||:placeholder:`A` |nbsp| :diagtext:`enumeration values not handled in switch:` |nbsp| :placeholder:`B`:diagtext:`,` |nbsp| :placeholder:`C`:diagtext:`,` |nbsp| :placeholder:`D`:diagtext:`...`||| +| ||+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+|| +| |+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| ++---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`case value not in enumerated type` |nbsp| :placeholder:`A`| @@ -9950,25 +11002,25 @@ This diagnostic flag exists for GCC compatibility, and has no effect in Clang. ------------- **Diagnostic text:** -+---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| |+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -| ||+----------------------------------------------------------------------------------------------------------+ || -| |||:diagtext:`:enumeration value` |nbsp| :placeholder:`B` |nbsp| :diagtext:`not explicitly handled in switch`| || -| ||+----------------------------------------------------------------------------------------------------------+ || -| |+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -| ||+----------------------------------------------------------------------------------------------------------------------------------------------------------+ || -| |||:diagtext:`:enumeration values` |nbsp| :placeholder:`B` |nbsp| :diagtext:`and` |nbsp| :placeholder:`C` |nbsp| :diagtext:`not explicitly handled in switch`| || -| ||+----------------------------------------------------------------------------------------------------------------------------------------------------------+ || -| |+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -| ||+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ || -| |||:diagtext:`:enumeration values` |nbsp| :placeholder:`B`:diagtext:`,` |nbsp| :placeholder:`C`:diagtext:`, and` |nbsp| :placeholder:`D` |nbsp| :diagtext:`not explicitly handled in switch`| || -| ||+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ || -| |+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -| ||+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+|| -| |||:diagtext:`:`:placeholder:`A` |nbsp| :diagtext:`enumeration values not explicitly handled in switch:` |nbsp| :placeholder:`B`:diagtext:`,` |nbsp| :placeholder:`C`:diagtext:`,` |nbsp| :placeholder:`D`:diagtext:`...`||| -| ||+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+|| -| |+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| -+---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++---------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| +| ||+---------------------------------------------------------------------------------------------------------+ || +| |||:diagtext:`enumeration value` |nbsp| :placeholder:`B` |nbsp| :diagtext:`not explicitly handled in switch`| || +| ||+---------------------------------------------------------------------------------------------------------+ || +| |+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| +| ||+---------------------------------------------------------------------------------------------------------------------------------------------------------+ || +| |||:diagtext:`enumeration values` |nbsp| :placeholder:`B` |nbsp| :diagtext:`and` |nbsp| :placeholder:`C` |nbsp| :diagtext:`not explicitly handled in switch`| || +| ||+---------------------------------------------------------------------------------------------------------------------------------------------------------+ || +| |+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| +| ||+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ || +| |||:diagtext:`enumeration values` |nbsp| :placeholder:`B`:diagtext:`,` |nbsp| :placeholder:`C`:diagtext:`, and` |nbsp| :placeholder:`D` |nbsp| :diagtext:`not explicitly handled in switch`| || +| ||+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ || +| |+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| +| ||+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+|| +| |||:placeholder:`A` |nbsp| :diagtext:`enumeration values not explicitly handled in switch:` |nbsp| :placeholder:`B`:diagtext:`,` |nbsp| :placeholder:`C`:diagtext:`,` |nbsp| :placeholder:`D`:diagtext:`...`||| +| ||+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+|| +| |+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| ++---------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -Wsync-fetch-and-nand-semantics-changed @@ -9990,18 +11042,16 @@ This diagnostic flag exists for GCC compatibility, and has no effect in Clang. ---------------------- Some of the diagnostics controlled by this flag are enabled by default. -Also controls `-Wtautological-constant-compare`_, `-Wtautological-overlap-compare`_, `-Wtautological-pointer-compare`_, `-Wtautological-undefined-compare`_. +Also controls `-Wtautological-constant-compare`_, `-Wtautological-objc-bool-compare`_, `-Wtautological-overlap-compare`_, `-Wtautological-pointer-compare`_, `-Wtautological-undefined-compare`_. **Diagnostic text:** +---------------------------+---------------------------+--------------------------------------------------+------------------------+ |:warning:`warning:` |nbsp| |+-------------------------+|:diagtext:`comparison always evaluates to` |nbsp| |+----------------------+| -| ||:diagtext:`self-` || ||:diagtext:`false` || +| ||:diagtext:`self-` || ||:diagtext:`a constant`|| | |+-------------------------+| |+----------------------+| -| ||:diagtext:`array` |nbsp| || ||:diagtext:`true` || +| ||:diagtext:`array` |nbsp| || ||:placeholder:`C` || | |+-------------------------+| |+----------------------+| -| | | ||:diagtext:`a constant`|| -| | | |+----------------------+| +---------------------------+---------------------------+--------------------------------------------------+------------------------+ +-------------------------------------------------------------------------------------+-------------------+ @@ -10017,17 +11067,26 @@ Also controls `-Wtautological-constant-compare`_, `-Wtautological-overlap-compar ------------------------------- This diagnostic is enabled by default. -Also controls `-Wtautological-constant-out-of-range-compare`_, `-Wtautological-unsigned-enum-zero-compare`_, `-Wtautological-unsigned-zero-compare`_. +Also controls `-Wtautological-constant-out-of-range-compare`_. **Diagnostic text:** -+---------------------------------------------------------+------------------+--------------------------------+------------------+-------------------------------------+-------------------+ -|:warning:`warning:` |nbsp| :diagtext:`comparison` |nbsp| |+----------------+| |nbsp| :placeholder:`C` |nbsp| |+----------------+| |nbsp| :diagtext:`is always` |nbsp| |+-----------------+| -| ||:placeholder:`D`|| ||:placeholder:`B`|| ||:diagtext:`false`|| -| |+----------------+| |+----------------+| |+-----------------+| -| ||:placeholder:`B`|| ||:placeholder:`D`|| ||:diagtext:`true` || -| |+----------------+| |+----------------+| |+-----------------+| -+---------------------------------------------------------+------------------+--------------------------------+------------------+-------------------------------------+-------------------+ ++----------------------------------------------------------------------+------------------------------------------------+--------------------------------+----------------------------------------------------------+-----------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`result of comparison of` |nbsp| |+----------------------------------------------+| |nbsp| :diagtext:`with` |nbsp| |+--------------------------------------------------------+| |nbsp| :diagtext:`is always` |nbsp| :placeholder:`E`| +| ||+--------------------------------------------+|| ||+------------------------------------------------------+|| | +| |||:diagtext:`constant` |nbsp| :placeholder:`A`||| |||:diagtext:`expression of type` |nbsp| :placeholder:`C`||| | +| ||+--------------------------------------------+|| ||+------------------------------------------------------+|| | +| |+----------------------------------------------+| |+--------------------------------------------------------+| | +| ||:diagtext:`true` || ||:diagtext:`boolean expression` || | +| |+----------------------------------------------+| |+--------------------------------------------------------+| | +| ||:diagtext:`false` || | | | +| |+----------------------------------------------+| | | | ++----------------------------------------------------------------------+------------------------------------------------+--------------------------------+----------------------------------------------------------+-----------------------------------------------------+ + + +-Wtautological-constant-in-range-compare +---------------------------------------- +Controls `-Wtautological-type-limit-compare`_, `-Wtautological-unsigned-enum-zero-compare`_, `-Wtautological-unsigned-zero-compare`_. -Wtautological-constant-out-of-range-compare @@ -10036,17 +11095,28 @@ This diagnostic is enabled by default. **Diagnostic text:** -+------------------------------------------------------------+------------------------------------------------+--------------------------------+----------------------------------------------------------+-------------------------------------+-------------------+ -|:warning:`warning:` |nbsp| :diagtext:`comparison of` |nbsp| |+----------------------------------------------+| |nbsp| :diagtext:`with` |nbsp| |+--------------------------------------------------------+| |nbsp| :diagtext:`is always` |nbsp| |+-----------------+| -| ||+--------------------------------------------+|| ||+------------------------------------------------------+|| ||:diagtext:`false`|| -| |||:diagtext:`constant` |nbsp| :placeholder:`A`||| |||:diagtext:`expression of type` |nbsp| :placeholder:`C`||| |+-----------------+| -| ||+--------------------------------------------+|| ||+------------------------------------------------------+|| ||:diagtext:`true` || -| |+----------------------------------------------+| |+--------------------------------------------------------+| |+-----------------+| -| ||:diagtext:`true` || ||:diagtext:`boolean expression` || | | -| |+----------------------------------------------+| |+--------------------------------------------------------+| | | -| ||:diagtext:`false` || | | | | -| |+----------------------------------------------+| | | | | -+------------------------------------------------------------+------------------------------------------------+--------------------------------+----------------------------------------------------------+-------------------------------------+-------------------+ ++----------------------------------------------------------------------+------------------------------------------------+--------------------------------+----------------------------------------------------------+-----------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`result of comparison of` |nbsp| |+----------------------------------------------+| |nbsp| :diagtext:`with` |nbsp| |+--------------------------------------------------------+| |nbsp| :diagtext:`is always` |nbsp| :placeholder:`E`| +| ||+--------------------------------------------+|| ||+------------------------------------------------------+|| | +| |||:diagtext:`constant` |nbsp| :placeholder:`A`||| |||:diagtext:`expression of type` |nbsp| :placeholder:`C`||| | +| ||+--------------------------------------------+|| ||+------------------------------------------------------+|| | +| |+----------------------------------------------+| |+--------------------------------------------------------+| | +| ||:diagtext:`true` || ||:diagtext:`boolean expression` || | +| |+----------------------------------------------+| |+--------------------------------------------------------+| | +| ||:diagtext:`false` || | | | +| |+----------------------------------------------+| | | | ++----------------------------------------------------------------------+------------------------------------------------+--------------------------------+----------------------------------------------------------+-----------------------------------------------------+ + + +-Wtautological-objc-bool-compare +-------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`result of comparison of constant` |nbsp| :placeholder:`A` |nbsp| :diagtext:`with expression of type BOOL is always` |nbsp| :placeholder:`B`:diagtext:`, as the only well defined values for BOOL are YES and NO`| ++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -Wtautological-overlap-compare @@ -10087,6 +11157,19 @@ This diagnostic is enabled by default. +------------------------------------------------------------+------------------------+----------------------------------------------------------+-------------------------+-----------------------------------------------------+-------------------+ +-Wtautological-type-limit-compare +--------------------------------- +**Diagnostic text:** + ++-------------------------------------------------------------------+------------------+--------------------------------+------------------+-----------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`result of comparison` |nbsp| |+----------------+| |nbsp| :placeholder:`C` |nbsp| |+----------------+| |nbsp| :diagtext:`is always` |nbsp| :placeholder:`E`| +| ||:placeholder:`D`|| ||:placeholder:`B`|| | +| |+----------------+| |+----------------+| | +| ||:placeholder:`B`|| ||:placeholder:`D`|| | +| |+----------------+| |+----------------+| | ++-------------------------------------------------------------------+------------------+--------------------------------+------------------+-----------------------------------------------------+ + + -Wtautological-undefined-compare -------------------------------- This diagnostic is enabled by default. @@ -10112,32 +11195,28 @@ This diagnostic is enabled by default. -Wtautological-unsigned-enum-zero-compare ----------------------------------------- -This diagnostic is enabled by default. - **Diagnostic text:** -+------------------------------------------------------------+--------------------------------------+--------------------------------+--------------------------------------+-------------------------------------+-------------------+ -|:warning:`warning:` |nbsp| :diagtext:`comparison of` |nbsp| |+------------------------------------+| |nbsp| :placeholder:`C` |nbsp| |+------------------------------------+| |nbsp| :diagtext:`is always` |nbsp| |+-----------------+| -| ||:placeholder:`D` || ||:diagtext:`unsigned enum expression`|| ||:diagtext:`false`|| -| |+------------------------------------+| |+------------------------------------+| |+-----------------+| -| ||:diagtext:`unsigned enum expression`|| ||:placeholder:`D` || ||:diagtext:`true` || -| |+------------------------------------+| |+------------------------------------+| |+-----------------+| -+------------------------------------------------------------+--------------------------------------+--------------------------------+--------------------------------------+-------------------------------------+-------------------+ ++----------------------------------------------------------------------+--------------------------------------+--------------------------------+--------------------------------------+-----------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`result of comparison of` |nbsp| |+------------------------------------+| |nbsp| :placeholder:`C` |nbsp| |+------------------------------------+| |nbsp| :diagtext:`is always` |nbsp| :placeholder:`E`| +| ||:placeholder:`D` || ||:diagtext:`unsigned enum expression`|| | +| |+------------------------------------+| |+------------------------------------+| | +| ||:diagtext:`unsigned enum expression`|| ||:placeholder:`D` || | +| |+------------------------------------+| |+------------------------------------+| | ++----------------------------------------------------------------------+--------------------------------------+--------------------------------+--------------------------------------+-----------------------------------------------------+ -Wtautological-unsigned-zero-compare ------------------------------------ -This diagnostic is enabled by default. - **Diagnostic text:** -+------------------------------------------------------------+---------------------------------+--------------------------------+---------------------------------+-------------------------------------+-------------------+ -|:warning:`warning:` |nbsp| :diagtext:`comparison of` |nbsp| |+-------------------------------+| |nbsp| :placeholder:`C` |nbsp| |+-------------------------------+| |nbsp| :diagtext:`is always` |nbsp| |+-----------------+| -| ||:placeholder:`D` || ||:diagtext:`unsigned expression`|| ||:diagtext:`false`|| -| |+-------------------------------+| |+-------------------------------+| |+-----------------+| -| ||:diagtext:`unsigned expression`|| ||:placeholder:`D` || ||:diagtext:`true` || -| |+-------------------------------+| |+-------------------------------+| |+-----------------+| -+------------------------------------------------------------+---------------------------------+--------------------------------+---------------------------------+-------------------------------------+-------------------+ ++----------------------------------------------------------------------+---------------------------------+--------------------------------+---------------------------------+-----------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`result of comparison of` |nbsp| |+-------------------------------+| |nbsp| :placeholder:`C` |nbsp| |+-------------------------------+| |nbsp| :diagtext:`is always` |nbsp| :placeholder:`E`| +| ||:placeholder:`D` || ||:diagtext:`unsigned expression`|| | +| |+-------------------------------+| |+-------------------------------+| | +| ||:diagtext:`unsigned expression`|| ||:placeholder:`D` || | +| |+-------------------------------+| |+-------------------------------+| | ++----------------------------------------------------------------------+---------------------------------+--------------------------------+---------------------------------+-----------------------------------------------------+ -Wtentative-definition-incomplete-type @@ -10188,17 +11267,17 @@ Controls `-Wthread-safety-analysis`_, `-Wthread-safety-attributes`_, `-Wthread-s |:warning:`warning:` |nbsp| :diagtext:`cannot call function '`:placeholder:`B`:diagtext:`' while` |nbsp| :placeholder:`A` |nbsp| :diagtext:`'`:placeholder:`C`:diagtext:`' is held`| +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -+---------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`calling function '`:placeholder:`B`:diagtext:`' requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| -| ||+------------------------------------------+ || -| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || -| ||+------------------------------------------+ || -| |+--------------------------------------------------------+| -| ||+------------------------------------------------------+|| -| |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| -| ||+------------------------------------------------------+|| -| |+--------------------------------------------------------+| -+---------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ ++---------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`calling function` |nbsp| :placeholder:`B` |nbsp| :diagtext:`requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| +| ||+------------------------------------------+ || +| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || +| ||+------------------------------------------+ || +| |+--------------------------------------------------------+| +| ||+------------------------------------------------------+|| +| |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| +| ||+------------------------------------------------------+|| +| |+--------------------------------------------------------+| ++---------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ +--------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`'`:placeholder:`B`:diagtext:`' is acquired exclusively and shared in the same scope`| @@ -10224,45 +11303,45 @@ Controls `-Wthread-safety-analysis`_, `-Wthread-safety-attributes`_, `-Wthread-s | |+---------------------+| |+---------------------+| | +----------------------------------------------------------------------------------------------------------------------------------------+-----------------------+--------------------------------------------+-----------------------+--------------------------+ -+---------------------------+---------------------+---------------------------------------------------------------------------------------------------+-----------------------------------+ -|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`the value pointed to by '`:placeholder:`A`:diagtext:`' requires holding` |nbsp| |+---------------------------------+| -| ||:diagtext:`reading`|| ||:diagtext:`any mutex` || -| |+-------------------+| |+---------------------------------+| -| ||:diagtext:`writing`|| ||:diagtext:`any mutex exclusively`|| -| |+-------------------+| |+---------------------------------+| -+---------------------------+---------------------+---------------------------------------------------------------------------------------------------+-----------------------------------+ - -+---------------------------+---------------------+---------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`the value pointed to by '`:placeholder:`B`:diagtext:`' requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| -| ||:diagtext:`reading`|| ||+------------------------------------------+ || -| |+-------------------+| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || -| ||:diagtext:`writing`|| ||+------------------------------------------+ || -| |+-------------------+| |+--------------------------------------------------------+| -| | | ||+------------------------------------------------------+|| -| | | |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| -| | | ||+------------------------------------------------------+|| -| | | |+--------------------------------------------------------+| -+---------------------------+---------------------+---------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ - -+---------------------------+---------------------+------------------------------------------------------------------------------------+-----------------------------------+ -|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`variable '`:placeholder:`A`:diagtext:`' requires holding` |nbsp| |+---------------------------------+| -| ||:diagtext:`reading`|| ||:diagtext:`any mutex` || -| |+-------------------+| |+---------------------------------+| -| ||:diagtext:`writing`|| ||:diagtext:`any mutex exclusively`|| -| |+-------------------+| |+---------------------------------+| -+---------------------------+---------------------+------------------------------------------------------------------------------------+-----------------------------------+ - -+---------------------------+---------------------+------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`variable '`:placeholder:`B`:diagtext:`' requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| -| ||:diagtext:`reading`|| ||+------------------------------------------+ || -| |+-------------------+| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || -| ||:diagtext:`writing`|| ||+------------------------------------------+ || -| |+-------------------+| |+--------------------------------------------------------+| -| | | ||+------------------------------------------------------+|| -| | | |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| -| | | ||+------------------------------------------------------+|| -| | | |+--------------------------------------------------------+| -+---------------------------+---------------------+------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ ++---------------------------+---------------------+---------------------------------------------------------------------------------------------------------------+-----------------------------------+ +|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`the value pointed to by` |nbsp| :placeholder:`A` |nbsp| :diagtext:`requires holding` |nbsp| |+---------------------------------+| +| ||:diagtext:`reading`|| ||:diagtext:`any mutex` || +| |+-------------------+| |+---------------------------------+| +| ||:diagtext:`writing`|| ||:diagtext:`any mutex exclusively`|| +| |+-------------------+| |+---------------------------------+| ++---------------------------+---------------------+---------------------------------------------------------------------------------------------------------------+-----------------------------------+ + ++---------------------------+---------------------+---------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`the value pointed to by` |nbsp| :placeholder:`B` |nbsp| :diagtext:`requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| +| ||:diagtext:`reading`|| ||+------------------------------------------+ || +| |+-------------------+| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || +| ||:diagtext:`writing`|| ||+------------------------------------------+ || +| |+-------------------+| |+--------------------------------------------------------+| +| | | ||+------------------------------------------------------+|| +| | | |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| +| | | ||+------------------------------------------------------+|| +| | | |+--------------------------------------------------------+| ++---------------------------+---------------------+---------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ + ++---------------------------+---------------------+------------------------------------------------------------------------------------------------+-----------------------------------+ +|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`variable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`requires holding` |nbsp| |+---------------------------------+| +| ||:diagtext:`reading`|| ||:diagtext:`any mutex` || +| |+-------------------+| |+---------------------------------+| +| ||:diagtext:`writing`|| ||:diagtext:`any mutex exclusively`|| +| |+-------------------+| |+---------------------------------+| ++---------------------------+---------------------+------------------------------------------------------------------------------------------------+-----------------------------------+ + ++---------------------------+---------------------+------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`variable` |nbsp| :placeholder:`B` |nbsp| :diagtext:`requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| +| ||:diagtext:`reading`|| ||+------------------------------------------+ || +| |+-------------------+| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || +| ||:diagtext:`writing`|| ||+------------------------------------------+ || +| |+-------------------+| |+--------------------------------------------------------+| +| | | ||+------------------------------------------------------+|| +| | | |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| +| | | ||+------------------------------------------------------+|| +| | | |+--------------------------------------------------------+| ++---------------------------+---------------------+------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -Wthread-safety-attributes @@ -10289,6 +11368,14 @@ Controls `-Wthread-safety-analysis`_, `-Wthread-safety-attributes`_, `-Wthread-s |:warning:`warning:` |nbsp| :diagtext:`ignoring` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute because its argument is invalid`| +------------------------------------------------------------------------------------------------------------------------------------+ ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute without capability arguments refers to 'this', but` |nbsp| :placeholder:`B` |nbsp| :diagtext:`isn't annotated with 'capability' or 'scoped\_lockable' attribute`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + ++----------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :placeholder:`A` |nbsp| :diagtext:`attribute without capability arguments can only be applied to non-static methods of a class`| ++----------------------------------------------------------------------------------------------------------------------------------------------------------+ + -Wthread-safety-beta -------------------- @@ -10312,70 +11399,70 @@ Controls `-Wthread-safety-analysis`_, `-Wthread-safety-attributes`_, `-Wthread-s ----------------------- **Diagnostic text:** -+---------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`calling function '`:placeholder:`B`:diagtext:`' requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| -| ||+------------------------------------------+ || -| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || -| ||+------------------------------------------+ || -| |+--------------------------------------------------------+| -| ||+------------------------------------------------------+|| -| |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| -| ||+------------------------------------------------------+|| -| |+--------------------------------------------------------+| -+---------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ - -+---------------------------+---------------------+---------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`the value pointed to by '`:placeholder:`B`:diagtext:`' requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| -| ||:diagtext:`reading`|| ||+------------------------------------------+ || -| |+-------------------+| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || -| ||:diagtext:`writing`|| ||+------------------------------------------+ || -| |+-------------------+| |+--------------------------------------------------------+| -| | | ||+------------------------------------------------------+|| -| | | |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| -| | | ||+------------------------------------------------------+|| -| | | |+--------------------------------------------------------+| -+---------------------------+---------------------+---------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ - -+---------------------------+---------------------+------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`variable '`:placeholder:`B`:diagtext:`' requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| -| ||:diagtext:`reading`|| ||+------------------------------------------+ || -| |+-------------------+| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || -| ||:diagtext:`writing`|| ||+------------------------------------------+ || -| |+-------------------+| |+--------------------------------------------------------+| -| | | ||+------------------------------------------------------+|| -| | | |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| -| | | ||+------------------------------------------------------+|| -| | | |+--------------------------------------------------------+| -+---------------------------+---------------------+------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ ++---------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`calling function` |nbsp| :placeholder:`B` |nbsp| :diagtext:`requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| +| ||+------------------------------------------+ || +| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || +| ||+------------------------------------------+ || +| |+--------------------------------------------------------+| +| ||+------------------------------------------------------+|| +| |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| +| ||+------------------------------------------------------+|| +| |+--------------------------------------------------------+| ++---------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ + ++---------------------------+---------------------+---------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`the value pointed to by` |nbsp| :placeholder:`B` |nbsp| :diagtext:`requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| +| ||:diagtext:`reading`|| ||+------------------------------------------+ || +| |+-------------------+| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || +| ||:diagtext:`writing`|| ||+------------------------------------------+ || +| |+-------------------+| |+--------------------------------------------------------+| +| | | ||+------------------------------------------------------+|| +| | | |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| +| | | ||+------------------------------------------------------+|| +| | | |+--------------------------------------------------------+| ++---------------------------+---------------------+---------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ + ++---------------------------+---------------------+------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ +|:warning:`warning:` |nbsp| |+-------------------+| |nbsp| :diagtext:`variable` |nbsp| :placeholder:`B` |nbsp| :diagtext:`requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| +| ||:diagtext:`reading`|| ||+------------------------------------------+ || +| |+-------------------+| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || +| ||:diagtext:`writing`|| ||+------------------------------------------+ || +| |+-------------------+| |+--------------------------------------------------------+| +| | | ||+------------------------------------------------------+|| +| | | |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| +| | | ||+------------------------------------------------------+|| +| | | |+--------------------------------------------------------+| ++---------------------------+---------------------+------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -Wthread-safety-reference ------------------------- **Diagnostic text:** -+----------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`passing variable '`:placeholder:`B`:diagtext:`' by reference requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| -| ||+------------------------------------------+ || -| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || -| ||+------------------------------------------+ || -| |+--------------------------------------------------------+| -| ||+------------------------------------------------------+|| -| |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| -| ||+------------------------------------------------------+|| -| |+--------------------------------------------------------+| -+----------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ - -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`passing the value that '`:placeholder:`B`:diagtext:`' points to by reference requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| -| ||+------------------------------------------+ || -| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || -| ||+------------------------------------------+ || -| |+--------------------------------------------------------+| -| ||+------------------------------------------------------+|| -| |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| -| ||+------------------------------------------------------+|| -| |+--------------------------------------------------------+| -+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ ++----------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`passing variable` |nbsp| :placeholder:`B` |nbsp| :diagtext:`by reference requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| +| ||+------------------------------------------+ || +| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || +| ||+------------------------------------------+ || +| |+--------------------------------------------------------+| +| ||+------------------------------------------------------+|| +| |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| +| ||+------------------------------------------------------+|| +| |+--------------------------------------------------------+| ++----------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ + ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`passing the value that` |nbsp| :placeholder:`B` |nbsp| :diagtext:`points to by reference requires holding` |nbsp| :placeholder:`A` |nbsp| |+--------------------------------------------------------+| +| ||+------------------------------------------+ || +| |||:diagtext:`'`:placeholder:`C`:diagtext:`'`| || +| ||+------------------------------------------+ || +| |+--------------------------------------------------------+| +| ||+------------------------------------------------------+|| +| |||:diagtext:`'`:placeholder:`C`:diagtext:`' exclusively`||| +| ||+------------------------------------------------------+|| +| |+--------------------------------------------------------+| ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------------------+ -Wthread-safety-verbose @@ -10412,7 +11499,13 @@ This diagnostic is enabled by default. -Wtype-limits ------------- -This diagnostic flag exists for GCC compatibility, and has no effect in Clang. +Synonym for `-Wtautological-constant-in-range-compare`_. + + +-Wtype-limits +------------- +Synonym for `-Wtautological-constant-in-range-compare`_. + -Wtype-safety ------------- @@ -10592,6 +11685,17 @@ This diagnostic is enabled by default. +---------------------------------------------------------------------------------------------------------------------------------------------------------+ +-Wunderaligned-exception-object +------------------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`underaligned exception object thrown`| ++---------------------------------------------------------------------------+ + + -Wunevaluated-expression ------------------------ This diagnostic is enabled by default. @@ -10656,6 +11760,17 @@ This diagnostic is enabled by default. +---------------------------------------------------------------------------------------------+ +-Wunicode-homoglyph +------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`treating Unicode character as identifier character rather than as '`:placeholder:`B`:diagtext:`' symbol`| ++-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wunicode-whitespace -------------------- This diagnostic is enabled by default. @@ -10667,6 +11782,17 @@ This diagnostic is enabled by default. +-------------------------------------------------------------------------------+ +-Wunicode-zero-width +-------------------- +This diagnostic is enabled by default. + +**Diagnostic text:** + ++----------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`identifier contains Unicode character that is invisible in some environments`| ++----------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wuninitialized --------------- Some of the diagnostics controlled by this flag are enabled by default. @@ -10687,9 +11813,13 @@ Also controls `-Wsometimes-uninitialized`_, `-Wstatic-self-init`_. |:warning:`warning:` |nbsp| :diagtext:`reference` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is not yet bound to a value when used here`| +--------------------------------------------------------------------------------------------------------------------------------------+ -+------------------------------------------------------------------------------------------------------------------------------------------------+ -|:warning:`warning:` |nbsp| :diagtext:`block pointer variable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is uninitialized when captured by block`| -+------------------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------------------------------------------------------------------------------------------------------+---------------------------+------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`block pointer variable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is` |nbsp| |+-------------------------+| |nbsp| :diagtext:`when captured by block`| +| ||:diagtext:`uninitialized`|| | +| |+-------------------------+| | +| ||:diagtext:`null` || | +| |+-------------------------+| | ++-------------------------------------------------------------------------------------------------------------------+---------------------------+------------------------------------------+ +---------------------------------------------------------------------------------------------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`variable` |nbsp| :placeholder:`A` |nbsp| :diagtext:`is uninitialized when used within its own initialization`| @@ -10718,6 +11848,10 @@ This diagnostic is enabled by default. |:warning:`warning:` |nbsp| :diagtext:`unknown argument ignored in clang-cl: '`:placeholder:`A`:diagtext:`'`| +-----------------------------------------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`unknown argument ignored in clang-cl '`:placeholder:`A`:diagtext:`'; did you mean '`:placeholder:`B`:diagtext:`'?`| ++--------------------------------------------------------------------------------------------------------------------------------------------------------+ + -Wunknown-attributes -------------------- @@ -10775,6 +11909,18 @@ Some of the diagnostics controlled by this flag are enabled by default. |:warning:`warning:` |nbsp| :diagtext:`unexpected token in pragma diagnostic`| +----------------------------------------------------------------------------+ ++----------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`#pragma execution\_character\_set expected '`:placeholder:`A`:diagtext:`'`| ++----------------------------------------------------------------------------------------------------------------+ + ++------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`#pragma execution\_character\_set invalid value '`:placeholder:`A`:diagtext:`', only 'UTF-8' is supported`| ++------------------------------------------------------------------------------------------------------------------------------------------------+ + ++-------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`#pragma execution\_character\_set expected 'push' or 'pop'`| ++-------------------------------------------------------------------------------------------------+ + +-------------------------------------------------------------+ |:warning:`warning:` |nbsp| :diagtext:`unknown pragma ignored`| +-------------------------------------------------------------+ @@ -11048,6 +12194,17 @@ This diagnostic is enabled by default. +-------------------------------------------------------------------------------------------------------------------------------------------------+ +-Wunsupported-target-opt +------------------------ +This diagnostic is enabled by default. + +**Diagnostic text:** + ++---------------------------------------------------------------------------------------------------------------------------------------------------------+ +|:warning:`warning:` |nbsp| :diagtext:`debug information option '`:placeholder:`A`:diagtext:`' is not supported for target '`:placeholder:`B`:diagtext:`'`| ++---------------------------------------------------------------------------------------------------------------------------------------------------------+ + + -Wunsupported-visibility ------------------------ This diagnostic is enabled by default. @@ -11138,19 +12295,17 @@ This diagnostic is enabled by default. **Diagnostic text:** -+---------------------------+-----------------------------------------+--------------------------------------------+ -|:warning:`warning:` |nbsp| |+---------------------------------------+| |nbsp| :diagtext:`comparison result unused`| -| ||+----------------+--------------------+|| | -| |||+--------------+|:diagtext:`equality`||| | -| |||| || ||| | -| |||+--------------+| ||| | -| ||||:diagtext:`in`|| ||| | -| |||+--------------+| ||| | -| ||+----------------+--------------------+|| | -| |+---------------------------------------+| | -| ||:diagtext:`relational` || | -| |+---------------------------------------+| | -+---------------------------+-----------------------------------------+--------------------------------------------+ ++---------------------------+------------------------+--------------------------------------------+ +|:warning:`warning:` |nbsp| |+----------------------+| |nbsp| :diagtext:`comparison result unused`| +| ||:diagtext:`equality` || | +| |+----------------------+| | +| ||:diagtext:`inequality`|| | +| |+----------------------+| | +| ||:diagtext:`relational`|| | +| |+----------------------+| | +| ||:diagtext:`three-way` || | +| |+----------------------+| | ++---------------------------+------------------------+--------------------------------------------+ -Wunused-const-variable diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index cb72c459c1e5..0fec251c4bdc 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -1525,8 +1525,8 @@ OpenCL Features C++ for OpenCL -------------- -This functionality is built on top of OpenCL C v2.0 and C++17. Regular C++ -features can be used in OpenCL kernel code. All functionality from OpenCL C +This functionality is built on top of OpenCL C v2.0 and C++17 enabling most of +regular C++ features in OpenCL kernel code. Most functionality from OpenCL C is inherited. This section describes minor differences to OpenCL C and any limitations related to C++ support as well as interactions between OpenCL and C++ features that are not documented elsewhere. @@ -1537,6 +1537,7 @@ Restrictions to C++17 The following features are not supported: - Virtual functions +- Exceptions - ``dynamic_cast`` operator - Non-placement ``new``/``delete`` operators - Standard C++ libraries. Currently there is no solution for alternative C++ @@ -1552,20 +1553,24 @@ Address space behavior Address spaces are part of the type qualifiers; many rules are just inherited from the qualifier behavior documented in OpenCL C v2.0 s6.5 and Embedded C extension ISO/IEC JTC1 SC22 WG14 N1021 s3.1. Note that since the address space -behavior in C++ is not documented formally yet, Clang extends existing concept +behavior in C++ is not documented formally, Clang extends the existing concept from C and OpenCL. For example conversion rules are extended from qualification -conversion but the compatibility is determined using sets and overlapping from -Embedded C (ISO/IEC JTC1 SC22 WG14 N1021 s3.1.3). For OpenCL it means that -implicit conversions are allowed from named to ``__generic`` but not vice versa -(OpenCL C v2.0 s6.5.5) except for ``__constant`` address space. Most of the -rules are built on top of this behavior. +conversion but the compatibility is determined using notation of sets and +overlapping of address spaces from Embedded C (ISO/IEC JTC1 SC22 WG14 N1021 +s3.1.3). For OpenCL it means that implicit conversions are allowed from +a named address space (except for ``__constant``) to ``__generic`` (OpenCL C +v2.0 6.5.5). Reverse conversion is only allowed explicitly. The ``__constant`` +address space does not overlap with any other and therefore no valid conversion +between ``__constant`` and other address spaces exists. Most of the rules +follow this logic. **Casts** -C style cast will follow OpenCL C v2.0 rules (s6.5.5). All cast operators will -permit implicit conversion to ``__generic``. However converting from named -address spaces to ``__generic`` can only be done using ``addrspace_cast``. Note -that conversions between ``__constant`` and any other is still disallowed. +C-style casts follow OpenCL C v2.0 rules (s6.5.5). All cast operators +permit conversion to ``__generic`` implicitly. However converting from +``__generic`` to named address spaces can only be done using ``addrspace_cast``. +Note that conversions between ``__constant`` and any other address space +are disallowed. .. _opencl_cpp_addrsp_deduction: @@ -1578,7 +1583,7 @@ Address spaces are not deduced for: - non-pointer/non-reference class members except for static data members that are deduced to ``__global`` address space. - non-pointer/non-reference alias declarations. -- ``decltype`` expression. +- ``decltype`` expressions. .. code-block:: c++ @@ -1607,7 +1612,7 @@ TODO: Add example for type alias and decltype! **References** -References types can be qualified with an address space. +Reference types can be qualified with an address space. .. code-block:: c++ @@ -1622,29 +1627,29 @@ rules from address space pointer conversion (OpenCL v2.0 s6.5.5). **Default address space** All non-static member functions take an implicit object parameter ``this`` that -is a pointer type. By default this pointer parameter is in ``__generic`` address -space. All concrete objects passed as an argument to ``this`` parameter will be -converted to ``__generic`` address space first if the conversion is valid. -Therefore programs using objects in ``__constant`` address space won't be compiled -unless address space is explicitly specified using address space qualifiers on -member functions +is a pointer type. By default this pointer parameter is in the ``__generic`` +address space. All concrete objects passed as an argument to ``this`` parameter +will be converted to the ``__generic`` address space first if such conversion is +valid. Therefore programs using objects in the ``__constant`` address space will +not be compiled unless the address space is explicitly specified using address +space qualifiers on member functions (see :ref:`Member function qualifier `) as the conversion between ``__constant`` and ``__generic`` is disallowed. Member function -qualifiers can also be used in case conversion to ``__generic`` address space is -undesirable (even if it is legal), for example to take advantage of memory bank -accesses. Note this not only applies to regular member functions but to -constructors and destructors too. +qualifiers can also be used in case conversion to the ``__generic`` address space +is undesirable (even if it is legal). For example, a method can be implemented to +exploit memory access coalescing for segments with memory bank. This not only +applies to regular member functions but to constructors and destructors too. .. _opencl_cpp_addrspace_method_qual: **Member function qualifier** -Clang allows specifying address space qualifier on member functions to signal that -they are to be used with objects constructed in some specific address space. This -works just the same as qualifying member functions with ``const`` or any other -qualifiers. The overloading resolution will select overload with most specific -address space if multiple candidates are provided. If there is no conversion to -to an address space among existing overloads compilation will fail with a +Clang allows specifying an address space qualifier on member functions to signal +that they are to be used with objects constructed in some specific address space. +This works just the same as qualifying member functions with ``const`` or any +other qualifiers. The overloading resolution will select the candidate with the +most specific address space if multiple candidates are provided. If there is no +conversion to an address space among candidates, compilation will fail with a diagnostic. .. code-block:: c++ @@ -1667,7 +1672,7 @@ diagnostic. **Implicit special members** All implicit special members (default, copy, or move constructor, copy or move -assignment, destructor) will be generated with ``__generic`` address space. +assignment, destructor) will be generated with the ``__generic`` address space. .. code-block:: c++ @@ -1682,15 +1687,15 @@ assignment, destructor) will be generated with ``__generic`` address space. **Builtin operators** -All builtin operators are available in the specific address spaces, thus no conversion -to ``__generic`` is performed. +All builtin operators are available in the specific address spaces, thus no +conversion to ``__generic`` is performed. **Templates** -There is no deduction of address spaces in non-pointer/non-reference template parameters -and dependent types (see :ref:`Deduction `). The address -space of template parameter is deduced during the type deduction if it's not explicitly -provided in instantiation. +There is no deduction of address spaces in non-pointer/non-reference template +parameters and dependent types (see :ref:`Deduction `). +The address space of a template parameter is deduced during type deduction if +it is not explicitly provided in the instantiation. .. code-block:: c++ @@ -1701,13 +1706,14 @@ provided in instantiation. 5 6 __global int g; 7 void bar(){ - 8 foo(&g); // error: template instantiation failed as function scope variable appears to - 9 // be declared in __global address space (see line 3) + 8 foo(&g); // error: template instantiation failed as function scope variable + 9 // appears to be declared in __global address space (see line 3) 10 } -It is not legal to specify multiple different address spaces between template definition and -instantiation. If multiple different address spaces are specified in template definition and -instantiation compilation of such program will fail with a diagnostic. +It is not legal to specify multiple different address spaces between template +definition and instantiation. If multiple different address spaces are specified in +template definition and instantiation, compilation of such a program will fail with +a diagnostic. .. code-block:: c++ @@ -1717,11 +1723,12 @@ instantiation compilation of such program will fail with a diagnostic. } void bar() { - foo<__global int>(); // error: conflicting address space qualifiers are provided __global - // and __private + foo<__global int>(); // error: conflicting address space qualifiers are provided + // __global and __private } -Once template is instantiated regular restrictions for address spaces will apply. +Once a template has been instantiated, regular restrictions for address spaces will +apply. .. code-block:: c++ @@ -1731,15 +1738,15 @@ Once template is instantiated regular restrictions for address spaces will apply } void bar(){ - foo<__global int>(); // error: function scope variable cannot be declared in __global - // address space + foo<__global int>(); // error: function scope variable cannot be declared in + // __global address space } **Temporary materialization** -All temporaries are materialized in ``__private`` address space. If a reference with some -other address space is bound to them, the conversion will be generated in case it's valid -otherwise compilation will fail with a diagnostic. +All temporaries are materialized in the ``__private`` address space. If a +reference with another address space is bound to them, the conversion will be +generated in case it is valid, otherwise compilation will fail with a diagnostic. .. code-block:: c++ @@ -1763,26 +1770,29 @@ TODO Constructing and destroying global objects ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Global objects are constructed before the first kernel using the global +Global objects must be constructed before the first kernel using the global objects is executed and destroyed just after the last kernel using the program objects is executed. In OpenCL v2.0 drivers there is no specific API for invoking global constructors. However, an easy workaround would be -to enqueue constructor initialization kernel that has a name +to enqueue a constructor initialization kernel that has a name ``@_GLOBAL__sub_I_``. This kernel is only present if there are any global objects to be initialized in the compiled binary. One way to check this is by passing ``CL_PROGRAM_KERNEL_NAMES`` to ``clGetProgramInfo`` (OpenCL v2.0 s5.8.7). -Note that if multiple files are compiled and linked into libraries multiple +Note that if multiple files are compiled and linked into libraries, multiple kernels that initialize global objects for multiple modules would have to be invoked. +Applications are currently required to run initialization of global objects +manually before running any kernels in which the objects are used. + .. code-block:: console - clang -cl-std=c++ test.cl + clang -cl-std=clc++ test.cl -If there are any global objects to be initialized the final binary will -contain ``@_GLOBAL__sub_I_test.cl`` kernel to be enqueued. +If there are any global objects to be initialized, the final binary will +contain the ``@_GLOBAL__sub_I_test.cl`` kernel to be enqueued. Global destructors can not be invoked in OpenCL v2.0 drivers. However, all memory used for program scope objects is released on ``clReleaseProgram``. diff --git a/clang/docs/MemorySanitizer.rst b/clang/docs/MemorySanitizer.rst index f513b009a32f..8a88198d3e92 100644 --- a/clang/docs/MemorySanitizer.rst +++ b/clang/docs/MemorySanitizer.rst @@ -204,6 +204,9 @@ Limitations non-position-independent executables, and could fail on some Linux kernel versions with disabled ASLR. Refer to documentation for older versions for more details. +* MemorySanitizer might be incompatible with position-independent executables + from FreeBSD 13 but there is a check done at runtime and throws a warning + in this case. Current Status ============== diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index dadcc77f4803..dd2f146f088b 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -1,6 +1,6 @@ -======================================= -Clang 9.0.0 (In-Progress) Release Notes -======================================= +========================= +Clang 9.0.0 Release Notes +========================= .. contents:: :local: @@ -8,11 +8,6 @@ Clang 9.0.0 (In-Progress) Release Notes Written by the `LLVM Team `_ -.. warning:: - - These are in-progress notes for the upcoming Clang 9 release. - Release notes for previous releases can be found on - `the Download Page `_. Introduction ============ @@ -30,10 +25,6 @@ For more information about Clang or LLVM, including information about the latest release, please see the `Clang Web Site `_ or the `LLVM Web Site `_. -Note that if you are reading this file from a Subversion checkout or the -main Clang web page, this document applies to the *next* release, not -the current one. To see the release notes for a specific release, please -see the `releases page `_. What's New in Clang 9.0.0? ========================== @@ -46,12 +37,9 @@ sections with improvements to Clang's support for those languages. Major New Features ------------------ -- ... - -Improvements to Clang's diagnostics -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +- Experimental support for :ref:`C++ for OpenCL ` has been + added. -- ... Non-comprehensive list of changes in this release ------------------------------------------------- @@ -62,38 +50,23 @@ Non-comprehensive list of changes in this release However, to retrieve Clang's version, please favor the one of the macro defined in :ref:`clang namespaced version macros `. -- ... - New Compiler Flags ------------------ -- ... - -Deprecated Compiler Flags -------------------------- +- ``-ftime-trace`` and ``ftime-trace-granularity=N`` + Emits flame chart style compilation time report in chrome://tracing and + speedscope.app compatible format. A trace .json file is written next to the + compiled object file, containing hierarchical time information about frontend + activities (file parsing, template instantiation) and backend activities + (modules and functions being optimized, optimization passes). -The following options are deprecated and ignored. They will be removed in -future versions of Clang. - -- ... Modified Compiler Flags ----------------------- - ``clang -dumpversion`` now returns the version of Clang itself. -- ... - -New Pragmas in Clang --------------------- - -- ... - -Attribute Changes in Clang --------------------------- - -- ... Windows Support --------------- @@ -102,53 +75,137 @@ Windows Support ``clang-cl /diagnostic:caret /c test.cc`` for example now produces ``clang: error: no such file or directory: '/diagnostic:caret'; did you mean '/diagnostics:caret'?`` +- clang now parses the ``__declspec(allocator)`` specifier and generates debug + information, so that memory usage can be tracked in Visual Studio. + +- The ``-print-search-dirs`` option now separates elements with semicolons, + as is the norm for path lists on Windows + +- Improved handling of dllexport in conjunction with explicit template + instantiations for MinGW, to allow building a shared libc++ for MinGW + without ``--export-all-symbols`` to override the dllexport attributes C Language Changes in Clang --------------------------- -- ``__FILE_NAME__`` macro has been added as a Clang specific extension supported +- The ``__FILE_NAME__`` macro has been added as a Clang specific extension supported in all C-family languages. This macro is similar to ``__FILE__`` except it will always provide the last path component when possible. -- ... - -C11 Feature Support -^^^^^^^^^^^^^^^^^^^ +- Initial support for ``asm goto`` statements (a GNU C extension) has been + added for control flow from inline assembly to labels. The main consumers of + this construct are the Linux kernel (CONFIG_JUMP_LABEL=y) and glib. There are + still a few unsupported corner cases in Clang's integrated assembler and + IfConverter. Please file bugs for any issues you run into. -... C++ Language Changes in Clang ----------------------------- -- ... +- Support for the address space attribute in various C++ features was improved, + refer to :ref:`C++ for OpenCL ` for more details. The following + features deviated from OpenCL: + + (1) Address spaces as method qualifiers are not accepted yet; -C++1z Feature Support -^^^^^^^^^^^^^^^^^^^^^ + (2) There is no address space deduction. -... Objective-C Language Changes in Clang ------------------------------------- - Fixed encoding of ObjC pointer types that are pointers to typedefs. -.. code-block:: objc + .. code-block:: objc typedef NSArray MyArray; // clang used to encode this as "^{NSArray=#}" instead of "@". const char *s0 = @encode(MyArray *); -OpenCL C Language Changes in Clang ----------------------------------- +OpenCL Kernel Language Changes in Clang +--------------------------------------- -... +OpenCL C +^^^^^^^^ -ABI Changes in Clang --------------------- +- Enabled use of variadic macro as a Clang extension. + +- Added initial support for implicitly including OpenCL builtin + fuctions using efficient trie lookup generated by TableGen. + A corresponding frontend-only flag ``-fdeclare-opencl-builtins`` + has been added to enable trie during parsing. + +- Refactored header file to be used for common parts between + regular header added using ``-finclude-default-header`` and trie + based declarations added using ``-fdeclare-opencl-builtins``. + +- Improved string formatting diagnostics in printf for vector types. + +- Simplified the internal representation of blocks, including their + generation in IR. Furthermore, indirect calls to block function + has been changed to direct function calls. + +- Added diagnostics for conversions of nested pointers with + different address spaces. + +- Added ``cl_arm_integer_dot_product`` extension. + +- Fixed global samplers in OpenCL v2.0. + +- Improved math builtin functions with parameters of type ``long + long`` for x86. + +.. _openclcpp: + +C++ for OpenCL +^^^^^^^^^^^^^^ + +Experimental support for C++17 features in OpenCL has been added +and backwards compatibility with OpenCL C v2.0 was enabled. +The documentation has been added for supported language features +into :doc:`LanguageExtensions` and :doc:`UsersManual`. + +Implemented features are: + +- Address space behavior is improved in majority of C++ features: + + - Templates parameters and arguments; + + - Reference types; + + - Type deduction; + + - Objects and member functions, including special member + functions; + + - Builtin operators; + + - Method qualifiers now include address space; + + - Address space deduction has been extended for C++ use cases; + + - Improved overload ranking rules; + + - All standard cast operators now prevent converting address + spaces (except for conversions allowed implicitly). They + can still be cast using C-style cast. + +- Vector types as in OpenCL C, including compound vector + initialization. + +- OpenCL-specific types: images, samplers, events, pipes, are + accepted. Note that blocks are not supported yet. + +- OpenCL standard header in Clang can be compiled in C++ mode. + +- Global constructors can be invoked from the host side using + a specific, compiler-generated kernel. + +- Overloads with generic address space are added to all atomic + builtin functions, including the ones prior to OpenCL v2.0. -- ... OpenMP Support in Clang ----------------------- @@ -180,27 +237,29 @@ release of Clang. Users of the build system should adjust accordingly. install-clang-headers target now installs clang's API headers (corresponding to its libraries), which is consistent with the install-llvm-headers target. -- ... +- In 9.0.0 and later Clang added a new target on Linux/Unix systems, clang-cpp, + which generates a shared library comprised of all the clang component + libraries and exporting the clang C++ APIs. Additionally the build system + gained the new "CLANG_LINK_CLANG_DYLIB" option, which defaults Off, and when + set to On, will force clang (and clang-based tools) to link the clang-cpp + library instead of statically linking clang's components. This option will + reduce the size of binary distributions at the expense of compiler performance. -AST Matchers ------------- - -- ... clang-format ------------ - Add language support for clang-formatting C# files. - Add Microsoft coding style to encapsulate default C# formatting style. -- Added new option `PPDIS_BeforeHash` (in configuration: `BeforeHash`) to - `IndentPPDirectives` which indents preprocessor directives before the hash. -- Added new option `AlignConsecutiveMacros` to align the C/C++ preprocessor +- Added new option ``PPDIS_BeforeHash`` (in configuration: ``BeforeHash``) to + ``IndentPPDirectives`` which indents preprocessor directives before the hash. +- Added new option ``AlignConsecutiveMacros`` to align the C/C++ preprocessor macros of consecutive lines. libclang -------- -- When `CINDEXTEST_INCLUDE_ATTRIBUTED_TYPES` is not provided when making a +- When ``CINDEXTEST_INCLUDE_ATTRIBUTED_TYPES`` is not provided when making a CXType, the equivalent type of the AttributedType is returned instead of the modified type if the user does not want attribute sugar. The equivalent type represents the minimally-desugared type which the AttributedType is @@ -210,37 +269,85 @@ libclang Static Analyzer --------------- +- Fixed a bug where an incorrect checker name would be displayed for a bug + report. + +- New checker: ``security.insecureAPI.DeprecatedOrUnsafeBufferHandling`` to detect + uses of unsafe/deprecated buffer handling functions for C code using the C11 + standard or newer. + +- New checker: ``osx.MIGChecker`` to find violations of the Mach Interface + Generator calling convention + +- New checker: ``optin.osx.OSObjectCStyleCast`` to find C-style casts of of XNU + libkern OSObjects + +- New package: ``apiModeling.llvm`` contains modeling checkers to improve the + accuracy of reports on LLVM's own codebase. + +- The Static Analyzer received + :ref:`developer documentation `. + - The UninitializedObject checker is now considered as stable. - (moved from the 'alpha.cplusplus' to the 'optin.cplusplus' package) + (moved from the ``alpha.cplusplus`` to the ``optin.cplusplus`` package) -... +- New frontend flags: The list of available checkers are now split into 3 + different frontend flags: -.. _release-notes-ubsan: + - ``-analyzer-checker-help``: The list of user-facing, stable checkers. -Undefined Behavior Sanitizer (UBSan) ------------------------------------- + - ``-analyzer-checker-help-alpha``: The list of in-development + checkers not yet advised to be turned on. -- ... + - ``-analyzer-checker-help-developer``: Checkers never meant to be + enabled/disabled by hand + development checkers. -Core Analysis Improvements -========================== +- New frontend flags: While they have always been around, for the first time, + checker and package options are listable: -- ... + - ``-analyzer-checker-option-help``: The list of user-facing, stable checker + and package options. -New Issues Found -================ + - ``-analyzer-checker-option-help-alpha``: The list of in-development checker + options not yet advised to be used. -- ... + - ``-analyzer-checker-option-help-developer``: Options never meant to be + enabled/disabled by hand + development options. -Python Binding Changes ----------------------- +- New frontend flag: ``-analyzer-werror`` to turn analyzer warnings into errors. -The following methods have been added: +- Numerous fixes to increase the stability of the experimental cross translation + unit analysis (CTU). -- ... +- CTU now handles virtual functions as well. -Significant Known Problems -========================== + +Linux Kernel +============ + +With support for asm goto, the mainline Linux kernel for x86_64 is now buildable +(and bootable) with Clang 9. Other architectures that don't require +CONFIG_JUMP_LABEL=y such as arm, aarch64, ppc32, ppc64le, (and possibly mips) +have been supported with older releases of Clang (Clang 4 was first used with +aarch64). + +The Android and ChromeOS Linux distributions have moved to building their Linux +kernels with Clang, and Google is currently testing Clang built kernels for +their production Linux kernels. + +Further, LLD, llvm-objcopy, llvm-ar, llvm-nm, llvm-objdump can all be used to +build a working Linux kernel. + +More information about building Linux kernels with Clang can be found: + +- `ClangBuiltLinux web page `_. +- `Issue Tracker `_. +- `Wiki `_. +- `Mailing List `_. +- `Bi-weekly Meeting `_. +- #clangbuiltlinux on Freenode. +- `Clang Meta bug `_. +- `Continuous Integration `_. Additional Information ====================== diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index 2fbb414f6820..7b9a4e67177b 100644 --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -2397,8 +2397,8 @@ Compiling to bitcode can be done as follows: This will produce a generic test.bc file that can be used in vendor toolchains to perform machine code generation. -Clang currently supports OpenCL C language standards up to v2.0. Starting from Clang9 -C++ mode is available for OpenCL (see :ref:`C++ for OpenCL `). +Clang currently supports OpenCL C language standards up to v2.0. Starting from +clang 9 a C++ mode is available for OpenCL (see :ref:`C++ for OpenCL `). OpenCL Specific Options ----------------------- @@ -2762,21 +2762,22 @@ There are some standard OpenCL functions that are implemented as Clang builtins: C++ for OpenCL -------------- -Starting from Clang9 kernel code can contain C++17 features: classes, templates, +Starting from clang 9 kernel code can contain C++17 features: classes, templates, function overloading, type deduction, etc. Please note that this is not an implementation of `OpenCL C++ `_ and there is no plan to support it in clang in any new releases in the near future. -There are only a few restrictions on allowed C++ features. For detailed information -please refer to documentation on Extensions (:doc:`LanguageExtensions`). +For detailed information about restrictions to allowed C++ features please +refer to :doc:`LanguageExtensions`. Since C++ features are to be used on top of OpenCL C functionality, all existing restrictions from OpenCL C v2.0 will inherently apply. All OpenCL C builtin types -and function libraries are supported and can be used in the new mode. +and function libraries are supported and can be used in this mode. -To enable the new mode pass the following command line option when compiling ``.cl`` -file ``-cl-std=c++`` or ``-std=c++``. +To enable the C++ for OpenCL mode, pass one of following command line options when +compiling ``.cl`` file ``-cl-std=clc++``, ``-cl-std=CLC++``, ``-std=clc++`` or +``-std=CLC++``. .. code-block:: c++ @@ -2794,7 +2795,7 @@ file ``-cl-std=c++`` or ``-std=c++``. .. code-block:: console - clang -cl-std=c++ test.cl + clang -cl-std=clc++ test.cl .. _target_features: @@ -2998,42 +2999,42 @@ Execute ``clang-cl /?`` to see a list of supported options: CL.EXE COMPATIBILITY OPTIONS: /? Display available options /arch: Set architecture for code generation - /Brepro- Emit an object file which cannot be reproduced over time - /Brepro Emit an object file which can be reproduced over time + /Brepro- Write current time into COFF output (default) + /Brepro Do not write current time into COFF output (breaks link.exe /incremental) /clang: Pass to the clang driver - /C Don't discard comments when preprocessing + /C Do not discard comments when preprocessing /c Compile only /d1PP Retain macro definitions in /E mode /d1reportAllClassLayout Dump record layout information - /diagnostics:caret Enable caret and column diagnostics (on by default) + /diagnostics:caret Enable caret and column diagnostics (default) /diagnostics:classic Disable column and caret diagnostics /diagnostics:column Disable caret diagnostics but keep column info /D Define macro - /EH Exception handling model + /EH Set exception handling model /EP Disable linemarker output and preprocess to stdout /execution-charset: - Runtime encoding, supports only UTF-8 + Set runtime encoding, supports only UTF-8 /E Preprocess to stdout /fallback Fall back to cl.exe if clang-cl fails to compile /FA Output assembly code file during compilation - /Fa Output assembly code to this file during compilation (with /FA) - /Fe Set output executable file or directory (ends in / or \) + /Fa Set assembly output file name (with /FA) + /Fe Set output executable file name /FI Include file before parsing /Fi Set preprocess output file name (with /P) - /Fo Set output object file, or directory (ends in / or \) (with /c) + /Fo Set output object file (with /c) /fp:except- /fp:except /fp:fast /fp:precise /fp:strict - /Fp Set pch filename (with /Yc and /Yu) + /Fp Set pch file name (with /Yc and /Yu) /GA Assume thread-local variables are defined in the executable /Gd Set __cdecl as a default calling convention /GF- Disable string pooling /GF Enable string pooling (default) - /GR- Disable emission of RTTI data + /GR- Do not emit RTTI data /Gregcall Set __regcall as a default calling convention - /GR Enable emission of RTTI data + /GR Emit RTTI data (default) /Gr Set __fastcall as a default calling convention /GS- Disable buffer security check /GS Enable buffer security check (default) @@ -3042,15 +3043,15 @@ Execute ``clang-cl /?`` to see a list of supported options: /guard: Enable Control Flow Guard with /guard:cf, or only the table with /guard:cf,nochecks /Gv Set __vectorcall as a default calling convention - /Gw- Don't put each data item in its own section + /Gw- Do not put each data item in its own section (default) /Gw Put each data item in its own section - /GX- Disable exception handling - /GX Enable exception handling - /Gy- Don't put each function in its own section (default) + /GX- Deprecated (like not passing /EH) + /GX Deprecated; use /EHsc + /Gy- Do not put each function in its own section (default) /Gy Put each function in its own section /Gz Set __stdcall as a default calling convention /help Display available options - /imsvc Add directory to system include search path, as if part of %INCLUDE% + /imsvc Add to system include search path, as if in %INCLUDE% /I Add directory to include search path /J Make char type unsigned /LDd Create debug DLL @@ -3060,11 +3061,10 @@ Execute ``clang-cl /?`` to see a list of supported options: /MD Use DLL run-time /MTd Use static debug run-time /MT Use static run-time - /O0 Disable optimization - /O1 Optimize for size (same as /Og /Os /Oy /Ob2 /GF /Gy) - /O2 Optimize for speed (same as /Og /Oi /Ot /Oy /Ob2 /GF /Gy) + /O1 Optimize for size (like /Og /Os /Oy /Ob2 /GF /Gy) + /O2 Optimize for speed (like /Og /Oi /Ot /Oy /Ob2 /GF /Gy) /Ob0 Disable function inlining - /Ob1 Only inline functions which are (explicitly or implicitly) marked inline + /Ob1 Only inline functions explicitly or implicitly marked inline /Ob2 Inline functions as deemed beneficial by the compiler /Od Disable optimization /Og No effect @@ -3072,23 +3072,23 @@ Execute ``clang-cl /?`` to see a list of supported options: /Oi Enable use of builtin functions /Os Optimize for size /Ot Optimize for speed - /Ox Deprecated (same as /Og /Oi /Ot /Oy /Ob2); use /O2 instead + /Ox Deprecated (like /Og /Oi /Ot /Oy /Ob2); use /O2 /Oy- Disable frame pointer omission (x86 only, default) /Oy Enable frame pointer omission (x86 only) /O Set multiple /O flags at once; e.g. '/O2y-' for '/O2 /Oy-' - /o Set output file or directory (ends in / or \) + /o Deprecated (set output file name); use /Fe or /Fe /P Preprocess to file /Qvec- Disable the loop vectorization passes /Qvec Enable the loop vectorization passes - /showFilenames- Don't print the name of each compiled file (default) + /showFilenames- Do not print the name of each compiled file (default) /showFilenames Print the name of each compiled file /showIncludes Print info about included files to stderr - /source-charset: Source encoding, supports only UTF-8 - /std: Language standard to compile for + /source-charset: Set source encoding, supports only UTF-8 + /std: Set C++ version (c++14,c++17,c++latest) /TC Treat all source files as C - /Tc Specify a C source file + /Tc Treat as C source file /TP Treat all source files as C++ - /Tp Specify a C++ source file + /Tp Treat as C++ source file /utf-8 Set source and runtime encoding to UTF-8 (default) /U Undefine macro /vd Control vtordisp placement @@ -3105,17 +3105,19 @@ Execute ``clang-cl /?`` to see a list of supported options: /W3 Enable -Wall /W4 Enable -Wall and -Wextra /Wall Enable -Weverything - /WX- Do not treat warnings as errors + /WX- Do not treat warnings as errors (default) /WX Treat warnings as errors /w Disable all warnings - /X Don't add %INCLUDE% to the include search path + /X Do not add %INCLUDE% to include search path /Y- Disable precompiled headers, overrides /Yc and /Yu /Yc Generate a pch file for all code up to and including /Yu Load a pch file and use it instead of all code up to and including /Z7 Enable CodeView debug information in object files - /Zc:char8_t Enable C++2a char8_t type - /Zc:char8_t- Disable C++2a char8_t type - /Zc:dllexportInlines- Don't dllexport/dllimport inline member functions of dllexport/import classes + /Zc:alignedNew- Disable C++17 aligned allocation functions + /Zc:alignedNew Enable C++17 aligned allocation functions + /Zc:char8_t- Disable char8_t from c++2a + /Zc:char8_t Enable char8_t from C++2a + /Zc:dllexportInlines- Do not dllexport/dllimport inline member functions of dllexport/import classes /Zc:dllexportInlines dllexport/dllimport inline member functions of dllexport/import classes (default) /Zc:sizedDealloc- Disable C++14 sized global deallocation functions /Zc:sizedDealloc Enable C++14 sized global deallocation functions @@ -3124,13 +3126,13 @@ Execute ``clang-cl /?`` to see a list of supported options: /Zc:threadSafeInit Enable thread-safe initialization of static variables /Zc:trigraphs- Disable trigraphs (default) /Zc:trigraphs Enable trigraphs - /Zc:twoPhase- Disable two-phase name lookup in templates + /Zc:twoPhase- Disable two-phase name lookup in templates (default) /Zc:twoPhase Enable two-phase name lookup in templates /Zd Emit debug line number tables only - /Zi Alias for /Z7. Does not produce PDBs. - /Zl Don't mention any default libraries in the object file - /Zp Set the default maximum struct packing alignment to 1 - /Zp Specify the default maximum struct packing alignment + /Zi Like /Z7 + /Zl Do not let object file auto-link default libraries + /Zp Set default maximum struct packing alignment to 1 + /Zp Set default maximum struct packing alignment /Zs Syntax-check only OPTIONS: @@ -3145,6 +3147,15 @@ Execute ``clang-cl /?`` to see a list of supported options: -fcomplete-member-pointers Require member pointer base types to be complete if they would be significant under the Microsoft ABI -fcoverage-mapping Generate coverage mapping to enable code coverage analysis + -fcs-profile-generate= + Generate instrumented code to collect context sensitive + execution counts into /default.profraw + (overridden by LLVM_PROFILE_FILE env var) + -fcs-profile-generate Generate instrumented code to collect context sensitive + execution counts into default.profraw + (overridden by LLVM_PROFILE_FILE env var) + -fdebug-compilation-dir + The compilation directory to embed in the debug info. -fdebug-macro Emit macro debug information -fdelayed-template-parsing Parse templated function definitions at the end of the translation unit @@ -3172,6 +3183,10 @@ Execute ``clang-cl /?`` to see a list of supported options: -fno-debug-macro Do not emit macro debug information -fno-delayed-template-parsing Disable delayed template parsing + -fno-profile-generate Disable generation of profile instrumentation. + -fno-profile-instr-generate + Disable generation of profile instrumentation. + -fno-profile-instr-use Disable using instrumentation data for profile-guided optimization -fno-sanitize-address-poison-custom-array-cookie Disable poisoning array cookies when using custom operator new[] in AddressSanitizer -fno-sanitize-address-use-after-scope @@ -3200,10 +3215,18 @@ Execute ``clang-cl /?`` to see a list of supported options: Disable trapping for specified sanitizers -fno-standalone-debug Limit debug information produced to reduce size of debug binary -fobjc-runtime= Specify the target Objective-C runtime kind and version + -forder-file-instrumentation + Generate instrumented code to collect order file into default.profraw + file (overridden by '=' form of option or LLVM_PROFILE_FILE env var) -fprofile-exclude-files= Instrument only functions from files where names don't match all the regexes separated by a semi-colon -fprofile-filter-files= Instrument only functions from files where names match any regex separated by a semi-colon + -fprofile-generate= + Generate instrumented code to collect execution counts into + /default.profraw (overridden by LLVM_PROFILE_FILE env var) + -fprofile-generate Generate instrumented code to collect execution counts into + default.profraw (overridden by LLVM_PROFILE_FILE env var) -fprofile-instr-generate= Generate instrumented code to collect execution counts into (overridden by LLVM_PROFILE_FILE env var) @@ -3252,10 +3275,10 @@ Execute ``clang-cl /?`` to see a list of supported options: -fsanitize-trap= Enable trapping for specified sanitizers -fsanitize-undefined-strip-path-components= Strip (or keep only, if negative) a given number of path components when emitting check metadata. - -fsanitize= Turn on runtime checks for various forms of undefined or suspicious - behavior. See user manual for available checks + -fsanitize= Turn on runtime checks for various forms of undefined or suspicious behavior. See user manual for available checks -fsplit-lto-unit Enables splitting of the LTO unit. -fstandalone-debug Emit full debug info for all types used by the program + -fthinlto-index= Perform ThinLTO importing using provided function summary index -fwhole-program-vtables Enables whole-program vtable optimization. Requires -flto -gcodeview-ghash Emit type record hashes in a .debug$H section -gcodeview Generate CodeView debug information @@ -3264,6 +3287,7 @@ Execute ``clang-cl /?`` to see a list of supported options: -miamcu Use Intel MCU ABI -mllvm Additional arguments to forward to LLVM's option processing -nobuiltininc Disable builtin #include directories + -print-supported-cpus Print supported cpu models for the given target (if target is not specified, it will print the supported cpus for the default target) -Qunused-arguments Don't emit warning for unused driver arguments -R Enable the specified remark --target= Generate code for the given target diff --git a/clang/examples/clang-interpreter/main.cpp b/clang/examples/clang-interpreter/main.cpp index 8fb52700a757..69808428a34d 100644 --- a/clang/examples/clang-interpreter/main.cpp +++ b/clang/examples/clang-interpreter/main.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/Orc/CompileUtils.h" +#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" @@ -50,65 +51,69 @@ namespace orc { class SimpleJIT { private: ExecutionSession ES; - std::shared_ptr Resolver; std::unique_ptr TM; const DataLayout DL; - LegacyRTDyldObjectLinkingLayer ObjectLayer; - LegacyIRCompileLayer CompileLayer; + MangleAndInterner Mangle{ES, DL}; + RTDyldObjectLinkingLayer ObjectLayer{ES, createMemMgr}; + IRCompileLayer CompileLayer{ES, ObjectLayer, SimpleCompiler(*TM)}; -public: - SimpleJIT() - : Resolver(createLegacyLookupResolver( - ES, - [this](const std::string &Name) -> JITSymbol { - if (auto Sym = CompileLayer.findSymbol(Name, false)) - return Sym; - else if (auto Err = Sym.takeError()) - return std::move(Err); - if (auto SymAddr = - RTDyldMemoryManager::getSymbolAddressInProcess(Name)) - return JITSymbol(SymAddr, JITSymbolFlags::Exported); - return nullptr; - }, - [](Error Err) { cantFail(std::move(Err), "lookupFlags failed"); })), - TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()), - ObjectLayer(ES, - [this](VModuleKey) { - return LegacyRTDyldObjectLinkingLayer::Resources{ - std::make_shared(), Resolver}; - }), - CompileLayer(ObjectLayer, SimpleCompiler(*TM)) { + static std::unique_ptr createMemMgr() { + return llvm::make_unique(); + } + + SimpleJIT(std::unique_ptr TM, DataLayout DL, + DynamicLibrarySearchGenerator ProcessSymbolsGenerator) + : TM(std::move(TM)), DL(std::move(DL)) { llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); + ES.getMainJITDylib().setGenerator(std::move(ProcessSymbolsGenerator)); } - const TargetMachine &getTargetMachine() const { return *TM; } +public: + static Expected> Create() { + auto JTMB = JITTargetMachineBuilder::detectHost(); + if (!JTMB) + return JTMB.takeError(); + + auto TM = JTMB->createTargetMachine(); + if (!TM) + return TM.takeError(); + + auto DL = (*TM)->createDataLayout(); - VModuleKey addModule(std::unique_ptr M) { - // Add the module to the JIT with a new VModuleKey. - auto K = ES.allocateVModule(); - cantFail(CompileLayer.addModule(K, std::move(M))); - return K; + auto ProcessSymbolsGenerator = + DynamicLibrarySearchGenerator::GetForCurrentProcess( + DL.getGlobalPrefix()); + + if (!ProcessSymbolsGenerator) + return ProcessSymbolsGenerator.takeError(); + + return std::unique_ptr(new SimpleJIT( + std::move(*TM), std::move(DL), std::move(*ProcessSymbolsGenerator))); } - JITSymbol findSymbol(const StringRef &Name) { - std::string MangledName; - raw_string_ostream MangledNameStream(MangledName); - Mangler::getNameWithPrefix(MangledNameStream, Name, DL); - return CompileLayer.findSymbol(MangledNameStream.str(), true); + const TargetMachine &getTargetMachine() const { return *TM; } + + Error addModule(ThreadSafeModule M) { + return CompileLayer.add(ES.getMainJITDylib(), std::move(M)); } - JITTargetAddress getSymbolAddress(const StringRef &Name) { - return cantFail(findSymbol(Name).getAddress()); + Expected findSymbol(const StringRef &Name) { + return ES.lookup({&ES.getMainJITDylib()}, Mangle(Name)); } - void removeModule(VModuleKey K) { - cantFail(CompileLayer.removeModule(K)); + Expected getSymbolAddress(const StringRef &Name) { + auto Sym = findSymbol(Name); + if (!Sym) + return Sym.takeError(); + return Sym->getAddress(); } }; } // end namespace orc } // end namespace llvm +llvm::ExitOnError ExitOnErr; + int main(int argc, const char **argv) { // This just needs to be some symbol in the binary; C++ doesn't // allow taking the address of ::main however. @@ -130,6 +135,8 @@ int main(int argc, const char **argv) { T.setObjectFormat(llvm::Triple::ELF); #endif + ExitOnErr.setBanner("clang interpreter"); + Driver TheDriver(Path, T.str(), Diags); TheDriver.setTitle("clang interpreter"); TheDriver.setCheckInputsExist(false); @@ -204,14 +211,16 @@ int main(int argc, const char **argv) { llvm::InitializeNativeTargetAsmPrinter(); int Res = 255; + std::unique_ptr Ctx(Act->takeLLVMContext()); std::unique_ptr Module = Act->takeModule(); if (Module) { - llvm::orc::SimpleJIT J; - auto H = J.addModule(std::move(Module)); - auto Main = (int(*)(...))J.getSymbolAddress("main"); + auto J = ExitOnErr(llvm::orc::SimpleJIT::Create()); + + ExitOnErr(J->addModule( + llvm::orc::ThreadSafeModule(std::move(Module), std::move(Ctx)))); + auto Main = (int (*)(...))ExitOnErr(J->getSymbolAddress("main")); Res = Main(); - J.removeModule(H); } // Shutdown. diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 28ed6cdfde14..faddbc6d9675 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -185,15 +185,20 @@ class CXXMemberCallExpr final : public CallExpr { static CXXMemberCallExpr *CreateEmpty(const ASTContext &Ctx, unsigned NumArgs, EmptyShell Empty); - /// Retrieves the implicit object argument for the member call. + /// Retrieve the implicit object argument for the member call. /// /// For example, in "x.f(5)", this returns the sub-expression "x". Expr *getImplicitObjectArgument() const; - /// Retrieves the declaration of the called method. + /// Retrieve the type of the object argument. + /// + /// Note that this always returns a non-pointer type. + QualType getObjectType() const; + + /// Retrieve the declaration of the called method. CXXMethodDecl *getMethodDecl() const; - /// Retrieves the CXXRecordDecl for the underlying type of + /// Retrieve the CXXRecordDecl for the underlying type of /// the implicit object argument. /// /// Note that this is may not be the same declaration as that of the class diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def index 984e607a2fc4..08c999af1f10 100644 --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -440,7 +440,7 @@ BUILTIN(__builtin_rotateleft64, "UWiUWiUWi", "nc") BUILTIN(__builtin_rotateright8, "UcUcUc", "nc") BUILTIN(__builtin_rotateright16, "UsUsUs", "nc") BUILTIN(__builtin_rotateright32, "UZiUZiUZi", "nc") -BUILTIN(__builtin_rotateright64, "UWiUWiWi", "nc") +BUILTIN(__builtin_rotateright64, "UWiUWiUWi", "nc") // Random GCC builtins BUILTIN(__builtin_constant_p, "i.", "nctu") diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index eab453ee20ec..12f1a7f6c488 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -91,8 +91,6 @@ def err_no_external_assembler : Error< "there is no external assembler that can be used on this platform">; def err_drv_unable_to_remove_file : Error< "unable to remove file: %0">; -def err_drv_unable_to_set_working_directory : Error < - "unable to set working directory: %0">; def err_drv_command_failure : Error< "unable to execute command: %0">; def err_drv_invalid_darwin_version : Error< diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index effcbad78b23..275c4e4365d1 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -598,6 +598,10 @@ def ext_implicit_lib_function_decl : ExtWarn< def note_include_header_or_declare : Note< "include the header <%0> or explicitly provide a declaration for '%1'">; def note_previous_builtin_declaration : Note<"%0 is a builtin with type %1">; +def warn_implicit_decl_no_jmp_buf + : Warning<"declaration of built-in function '%0' requires the declaration" + " of the 'jmp_buf' type, commonly provided in the header .">, + InGroup>; def warn_implicit_decl_requires_sysheader : Warning< "declaration of built-in function '%1' requires inclusion of the header <%0>">, InGroup; diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 7a8384f5fbc0..c6c966dfbe2c 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1249,15 +1249,9 @@ class TargetInfo : public virtual TransferrableTargetInfo, bool isBigEndian() const { return BigEndian; } bool isLittleEndian() const { return !BigEndian; } - enum CallingConvMethodType { - CCMT_Unknown, - CCMT_Member, - CCMT_NonMember - }; - /// Gets the default calling convention for the given target and /// declaration context. - virtual CallingConv getDefaultCallingConv(CallingConvMethodType MT) const { + virtual CallingConv getDefaultCallingConv() const { // Not all targets will specify an explicit calling convention that we can // express. This will always do the right thing, even though it's not // an explicit calling convention. diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index dfd27fab796e..4ea8bfff0973 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -518,7 +518,7 @@ def cl_mad_enable : Flag<["-"], "cl-mad-enable">, Group, Flags<[CC def cl_no_signed_zeros : Flag<["-"], "cl-no-signed-zeros">, Group, Flags<[CC1Option]>, HelpText<"OpenCL only. Allow use of less precise no signed zeros computations in the generated binary.">; def cl_std_EQ : Joined<["-"], "cl-std=">, Group, Flags<[CC1Option]>, - HelpText<"OpenCL language standard to compile for.">, Values<"cl,CL,cl1.1,CL1.1,cl1.2,CL1.2,cl2.0,CL2.0,c++">; + HelpText<"OpenCL language standard to compile for.">, Values<"cl,CL,cl1.1,CL1.1,cl1.2,CL1.2,cl2.0,CL2.0,clc++,CLC++">; def cl_denorms_are_zero : Flag<["-"], "cl-denorms-are-zero">, Group, Flags<[CC1Option]>, HelpText<"OpenCL only. Allow denormals to be flushed to zero.">; def cl_fp32_correctly_rounded_divide_sqrt : Flag<["-"], "cl-fp32-correctly-rounded-divide-sqrt">, Group, Flags<[CC1Option]>, diff --git a/clang/include/clang/Frontend/LangStandards.def b/clang/include/clang/Frontend/LangStandards.def index 0964e9b90a03..fef7d4dd9ab1 100644 --- a/clang/include/clang/Frontend/LangStandards.def +++ b/clang/include/clang/Frontend/LangStandards.def @@ -165,7 +165,7 @@ LANGSTANDARD(opencl12, "cl1.2", LANGSTANDARD(opencl20, "cl2.0", OpenCL, "OpenCL 2.0", LineComment | C99 | Digraphs | HexFloat | OpenCL) -LANGSTANDARD(openclcpp, "c++", +LANGSTANDARD(openclcpp, "clc++", OpenCL, "C++ for OpenCL", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 | Digraphs | HexFloat | OpenCL) @@ -174,6 +174,7 @@ LANGSTANDARD_ALIAS_DEPR(opencl10, "CL") LANGSTANDARD_ALIAS_DEPR(opencl11, "CL1.1") LANGSTANDARD_ALIAS_DEPR(opencl12, "CL1.2") LANGSTANDARD_ALIAS_DEPR(opencl20, "CL2.0") +LANGSTANDARD_ALIAS_DEPR(openclcpp, "CLC++") // CUDA LANGSTANDARD(cuda, "cuda", CUDA, "NVIDIA CUDA(tm)", diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index af762f74d745..e6c63fd9c015 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11165,6 +11165,7 @@ class Sema { // Emitting members of dllexported classes is delayed until the class // (including field initializers) is fully parsed. SmallVector DelayedDllExportClasses; + SmallVector DelayedDllExportMemberFunctions; private: class SavePendingParsedClassStateRAII { diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 0d69eb90abaf..93bdaafc2ac6 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -9814,10 +9814,25 @@ static GVALinkage basicGVALinkageForVariable(const ASTContext &Context, return StrongLinkage; case TSK_ExplicitSpecialization: - return Context.getTargetInfo().getCXXABI().isMicrosoft() && - VD->isStaticDataMember() - ? GVA_StrongODR - : StrongLinkage; + if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { + // If this is a fully specialized constexpr variable template, pretend it + // was marked inline. MSVC 14.21.27702 headers define _Is_integral in a + // header this way, and we don't want to emit non-discardable definitions + // of these variables in every TU that includes . This + // behavior is non-conforming, since another TU could use an extern + // template declaration for this variable, but for constexpr variables, + // it's unlikely for a user to want to do that. This behavior can be + // removed if the headers change to explicitly mark such variable template + // specializations inline. + if (isa(VD) && VD->isConstexpr()) + return GVA_DiscardableODR; + + // Use ODR linkage for static data members of fully specialized templates + // to prevent duplicate definition errors with MSVC. + if (VD->isStaticDataMember()) + return GVA_StrongODR; + } + return StrongLinkage; case TSK_ExplicitInstantiationDefinition: return GVA_StrongODR; @@ -10035,7 +10050,7 @@ CallingConv ASTContext::getDefaultCallingConvention(bool IsVariadic, break; } } - return Target->getDefaultCallingConv(TargetInfo::CCMT_Unknown); + return Target->getDefaultCallingConv(); } bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const { diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 21cf9da18a8b..aa74da006174 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3332,7 +3332,8 @@ SourceRange FunctionDecl::getExceptionSpecSourceRange() const { /// an externally visible symbol, but "extern inline" will not create an /// externally visible symbol. bool FunctionDecl::isInlineDefinitionExternallyVisible() const { - assert((doesThisDeclarationHaveABody() || willHaveBody()) && + assert((doesThisDeclarationHaveABody() || willHaveBody() || + hasAttr()) && "Must be a function definition"); assert(isInlined() && "Function must be inline"); ASTContext &Context = getASTContext(); diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index b30f785ba8f5..c5f86a4cc12b 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -651,6 +651,13 @@ Expr *CXXMemberCallExpr::getImplicitObjectArgument() const { return nullptr; } +QualType CXXMemberCallExpr::getObjectType() const { + QualType Ty = getImplicitObjectArgument()->getType(); + if (Ty->isPointerType()) + Ty = Ty->getPointeeType(); + return Ty; +} + CXXMethodDecl *CXXMemberCallExpr::getMethodDecl() const { if (const auto *MemExpr = dyn_cast(getCallee()->IgnoreParens())) return cast(MemExpr->getMemberDecl()); diff --git a/clang/lib/AST/ItaniumCXXABI.cpp b/clang/lib/AST/ItaniumCXXABI.cpp index 727a905d08a1..77fb5a1d33b3 100644 --- a/clang/lib/AST/ItaniumCXXABI.cpp +++ b/clang/lib/AST/ItaniumCXXABI.cpp @@ -177,7 +177,7 @@ class ItaniumCXXABI : public CXXABI { if (!isVariadic && T.isWindowsGNUEnvironment() && T.getArch() == llvm::Triple::x86) return CC_X86ThisCall; - return CC_C; + return Context.getTargetInfo().getDefaultCallingConv(); } // We cheat and just check that the class has a vtable pointer, and that it's diff --git a/clang/lib/AST/MicrosoftCXXABI.cpp b/clang/lib/AST/MicrosoftCXXABI.cpp index 4dc4156df9ca..444e55f777fa 100644 --- a/clang/lib/AST/MicrosoftCXXABI.cpp +++ b/clang/lib/AST/MicrosoftCXXABI.cpp @@ -82,7 +82,7 @@ class MicrosoftCXXABI : public CXXABI { if (!isVariadic && Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86) return CC_X86ThisCall; - return CC_C; + return Context.getTargetInfo().getDefaultCallingConv(); } bool isNearlyEmpty(const CXXRecordDecl *RD) const override { diff --git a/clang/lib/Basic/CMakeLists.txt b/clang/lib/Basic/CMakeLists.txt index 18dd7d61fbb4..12a12db43b6a 100644 --- a/clang/lib/Basic/CMakeLists.txt +++ b/clang/lib/Basic/CMakeLists.txt @@ -67,6 +67,7 @@ add_clang_library(clangBasic Targets/ARM.cpp Targets/AVR.cpp Targets/BPF.cpp + Targets/CAHP.cpp Targets/Hexagon.cpp Targets/Lanai.cpp Targets/Le64.cpp @@ -91,4 +92,3 @@ add_clang_library(clangBasic XRayLists.cpp ${version_inc} ) - diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index a08e399e7270..cecd31aba1c5 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -19,6 +19,7 @@ #include "Targets/ARM.h" #include "Targets/AVR.h" #include "Targets/BPF.h" +#include "Targets/CAHP.h" #include "Targets/Hexagon.h" #include "Targets/Lanai.h" #include "Targets/Le64.h" @@ -362,6 +363,9 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple, case llvm::Triple::r600: return new AMDGPUTargetInfo(Triple, Opts); + case llvm::Triple::cahp: + return new CAHPTargetInfo(Triple, Opts); + case llvm::Triple::riscv32: // TODO: add cases for FreeBSD, NetBSD, RTEMS once tested. if (os == llvm::Triple::Linux) diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index 74ac69ab8946..25f2b7b35f41 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -196,9 +196,6 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__ARM_NEON_FP", "0xE"); } - if (FPU & SveMode) - Builder.defineMacro("__ARM_FEATURE_SVE", "1"); - if (HasCRC) Builder.defineMacro("__ARM_FEATURE_CRC32", "1"); @@ -351,10 +348,19 @@ const char *const AArch64TargetInfo::GCCRegNames[] = { "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", - // Vector registers + // Neon vector registers "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", - "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" + "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", + + // SVE vector registers + "z0", "z1", "z2", "z3", "z4", "z5", "z6", "z7", "z8", "z9", "z10", + "z11", "z12", "z13", "z14", "z15", "z16", "z17", "z18", "z19", "z20", "z21", + "z22", "z23", "z24", "z25", "z26", "z27", "z28", "z29", "z30", "z31", + + // SVE predicate registers + "p0", "p1", "p2", "p3", "p4", "p5", "p6", "p7", "p8", "p9", "p10", + "p11", "p12", "p13", "p14", "p15" }; ArrayRef AArch64TargetInfo::getGCCRegNames() const { diff --git a/clang/lib/Basic/Targets/CAHP.cpp b/clang/lib/Basic/Targets/CAHP.cpp new file mode 100644 index 000000000000..c9fba021f126 --- /dev/null +++ b/clang/lib/Basic/Targets/CAHP.cpp @@ -0,0 +1,47 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "CAHP.h" +#include "clang/Basic/MacroBuilder.h" +#include "llvm/ADT/StringSwitch.h" + +using namespace clang; +using namespace clang::targets; + +ArrayRef CAHPTargetInfo::getGCCRegNames() const { + static const char *const GCCRegNames[] = { + "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", + "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15"}; + return llvm::makeArrayRef(GCCRegNames); +} + +ArrayRef CAHPTargetInfo::getGCCRegAliases() const { + static const TargetInfo::GCCRegAlias GCCRegAliases[] = { + {{"ra"}, "x0"}, {{"sp"}, "x1"}, {{"fp"}, "x2"}, {{"s0"}, "x3"}, + {{"s1"}, "x4"}, {{"s2"}, "x5"}, {{"s3"}, "x6"}, {{"s4"}, "x7"}, + {{"a0"}, "x8"}, {{"a1"}, "x9"}, {{"a2"}, "x10"}, {{"a3"}, "x11"}, + {{"a4"}, "x12"}, {{"a5"}, "x13"}, {{"t0"}, "x15"}, {{"t1"}, "x15"}}; + return llvm::makeArrayRef(GCCRegAliases); +} + +void CAHPTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + + Builder.defineMacro("__cahp__"); + Builder.defineMacro("__cahpv3__"); +} + +bool CAHPTargetInfo::isValidCPUName(StringRef Name) const { + if (Name == "generic") + return true; + + CPUKind CPU = llvm::StringSwitch(Name) + .Case("emerald", CK_EMERALD) + .Default(CK_NONE); + return CPU != CK_NONE; +} + +bool CAHPTargetInfo::setCPU(const std::string &Name) { + return isValidCPUName(Name); +} diff --git a/clang/lib/Basic/Targets/CAHP.h b/clang/lib/Basic/Targets/CAHP.h new file mode 100644 index 000000000000..12755280028f --- /dev/null +++ b/clang/lib/Basic/Targets/CAHP.h @@ -0,0 +1,92 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#ifndef LLVM_CLANG_LIB_BASIC_TARGETS_CAHP_H +#define LLVM_CLANG_LIB_BASIC_TARGETS_CAHP_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 { + +// CAHP Target +class LLVM_LIBRARY_VISIBILITY CAHPTargetInfo : public TargetInfo { + // Class for CAHP. + // The CPU profiles supported by the CAHP backend + enum CPUKind { + CK_NONE, + CK_EMERALD, + }; + +public: + CAHPTargetInfo(const llvm::Triple &Triple, const TargetOptions &) + : TargetInfo(Triple) { + TLSSupported = false; + PointerWidth = 16; + PointerAlign = 16; + IntWidth = 16; + IntAlign = 16; + LongWidth = 32; + LongAlign = 16; + LongLongWidth = 32; + LongLongAlign = 16; + SuitableAlign = 16; + DefaultAlignForAttributeAligned = 16; + HalfWidth = 8; + HalfAlign = 8; + FloatWidth = 32; + FloatAlign = 16; + DoubleWidth = 32; + DoubleAlign = 16; + DoubleFormat = &llvm::APFloat::IEEEsingle(); + LongDoubleWidth = 32; + LongDoubleAlign = 16; + LongDoubleFormat = &llvm::APFloat::IEEEsingle(); + SizeType = UnsignedInt; + PtrDiffType = SignedInt; + IntPtrType = SignedInt; + Char16Type = UnsignedInt; + WIntType = SignedInt; + Char32Type = UnsignedLong; + SigAtomicType = SignedChar; + + resetDataLayout("e" // Little endian + "-m:e" // ELF name manging + "-p:16:16" // 16-bit pointers, 16 bit aligned + "-i16:16" // 16 bit integers, 16 bit aligned + "-n16" // 16 bit native integer width + "-S16" // 16 bit natural stack alignment + ); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool isValidCPUName(StringRef Name) const override; + bool setCPU(const std::string &Name) override; + + ArrayRef getTargetBuiltins() const override { return None; } + + BuiltinVaListKind getBuiltinVaListKind() const override { + return TargetInfo::VoidPtrBuiltinVaList; + } + + const char *getClobbers() const override { return ""; } + + ArrayRef getGCCRegNames() const override; + + ArrayRef getGCCRegAliases() const override; + + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { + return false; + } +}; +} // namespace targets +} // namespace clang + +#endif // LLVM_CLANG_LIB_BASIC_TARGETS_CAHP_H diff --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h index 8542311ffa41..c0373ffaa444 100644 --- a/clang/lib/Basic/Targets/OSTargets.h +++ b/clang/lib/Basic/Targets/OSTargets.h @@ -618,8 +618,11 @@ class LLVM_LIBRARY_VISIBILITY SolarisTargetInfo : public OSTargetInfo { Builder.defineMacro("_XOPEN_SOURCE", "600"); else Builder.defineMacro("_XOPEN_SOURCE", "500"); - if (Opts.CPlusPlus) + if (Opts.CPlusPlus) { Builder.defineMacro("__C99FEATURES__"); + Builder.defineMacro("_FILE_OFFSET_BITS", "64"); + } + // GCC restricts the next two to C++. Builder.defineMacro("_LARGEFILE_SOURCE"); Builder.defineMacro("_LARGEFILE64_SOURCE"); Builder.defineMacro("__EXTENSIONS__"); diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index f800bb0b25da..930b825e94d2 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -56,6 +56,14 @@ bool RISCVTargetInfo::validateAsmConstraint( // A 5-bit unsigned immediate for CSR access instructions. Info.setRequiresImmediate(0, 31); return true; + case 'f': + // A floating-point register. + Info.setAllowsRegister(); + return true; + case 'A': + // An address that is held in a general-purpose register. + Info.setAllowsMemory(); + return true; } } @@ -65,9 +73,18 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__riscv"); bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64; Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32"); - // TODO: modify when more code models and ABIs are supported. + // TODO: modify when more code models are supported. Builder.defineMacro("__riscv_cmodel_medlow"); - Builder.defineMacro("__riscv_float_abi_soft"); + + StringRef ABIName = getABI(); + if (ABIName == "ilp32f" || ABIName == "lp64f") + Builder.defineMacro("__riscv_float_abi_single"); + else if (ABIName == "ilp32d" || ABIName == "lp64d") + Builder.defineMacro("__riscv_float_abi_double"); + else if (ABIName == "ilp32e") + Builder.defineMacro("__riscv_abi_rve"); + else + Builder.defineMacro("__riscv_float_abi_soft"); if (HasM) { Builder.defineMacro("__riscv_mul"); diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h index bc814b79ce51..9118494a87ab 100644 --- a/clang/lib/Basic/Targets/RISCV.h +++ b/clang/lib/Basic/Targets/RISCV.h @@ -87,13 +87,19 @@ class LLVM_LIBRARY_VISIBILITY RISCV32TargetInfo : public RISCVTargetInfo { } bool setABI(const std::string &Name) override { - // TODO: support ilp32f and ilp32d ABIs. - if (Name == "ilp32") { + if (Name == "ilp32" || Name == "ilp32f" || Name == "ilp32d") { ABI = Name; return true; } return false; } + + void setMaxAtomicWidth() override { + MaxAtomicPromoteWidth = 128; + + if (HasA) + MaxAtomicInlineWidth = 32; + } }; class LLVM_LIBRARY_VISIBILITY RISCV64TargetInfo : public RISCVTargetInfo { public: @@ -105,13 +111,19 @@ class LLVM_LIBRARY_VISIBILITY RISCV64TargetInfo : public RISCVTargetInfo { } bool setABI(const std::string &Name) override { - // TODO: support lp64f and lp64d ABIs. - if (Name == "lp64") { + if (Name == "lp64" || Name == "lp64f" || Name == "lp64d") { ABI = Name; return true; } return false; } + + void setMaxAtomicWidth() override { + MaxAtomicPromoteWidth = 128; + + if (HasA) + MaxAtomicInlineWidth = 64; + } }; } // namespace targets } // namespace clang diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h index 6023c868dbdc..802ccf8b671e 100644 --- a/clang/lib/Basic/Targets/SPIR.h +++ b/clang/lib/Basic/Targets/SPIR.h @@ -88,7 +88,7 @@ class LLVM_LIBRARY_VISIBILITY SPIRTargetInfo : public TargetInfo { : CCCR_Warning; } - CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override { + CallingConv getDefaultCallingConv() const override { return CC_SpirFunction; } diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index 588b6d3da1d6..dd1e7db6c81e 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -320,8 +320,8 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo { } } - CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override { - return MT == CCMT_Member ? CC_X86ThisCall : CC_C; + CallingConv getDefaultCallingConv() const override { + return CC_C; } bool hasSjLjLowering() const override { return true; } @@ -659,7 +659,7 @@ class LLVM_LIBRARY_VISIBILITY X86_64TargetInfo : public X86TargetInfo { } } - CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override { + CallingConv getDefaultCallingConv() const override { return CC_C; } diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index a300bab49f9c..cadce507412b 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -8011,6 +8011,151 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, return Builder.CreateExtractElement(Ops[0], EmitScalarExpr(E->getArg(1)), "vgetq_lane"); } + case AArch64::BI_BitScanForward: + case AArch64::BI_BitScanForward64: + return EmitMSVCBuiltinExpr(MSVCIntrin::_BitScanForward, E); + case AArch64::BI_BitScanReverse: + case AArch64::BI_BitScanReverse64: + return EmitMSVCBuiltinExpr(MSVCIntrin::_BitScanReverse, E); + case AArch64::BI_InterlockedAnd64: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd, E); + case AArch64::BI_InterlockedExchange64: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange, E); + case AArch64::BI_InterlockedExchangeAdd64: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd, E); + case AArch64::BI_InterlockedExchangeSub64: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeSub, E); + case AArch64::BI_InterlockedOr64: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr, E); + case AArch64::BI_InterlockedXor64: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor, E); + case AArch64::BI_InterlockedDecrement64: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement, E); + case AArch64::BI_InterlockedIncrement64: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement, E); + case AArch64::BI_InterlockedExchangeAdd8_acq: + case AArch64::BI_InterlockedExchangeAdd16_acq: + case AArch64::BI_InterlockedExchangeAdd_acq: + case AArch64::BI_InterlockedExchangeAdd64_acq: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd_acq, E); + case AArch64::BI_InterlockedExchangeAdd8_rel: + case AArch64::BI_InterlockedExchangeAdd16_rel: + case AArch64::BI_InterlockedExchangeAdd_rel: + case AArch64::BI_InterlockedExchangeAdd64_rel: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd_rel, E); + case AArch64::BI_InterlockedExchangeAdd8_nf: + case AArch64::BI_InterlockedExchangeAdd16_nf: + case AArch64::BI_InterlockedExchangeAdd_nf: + case AArch64::BI_InterlockedExchangeAdd64_nf: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd_nf, E); + case AArch64::BI_InterlockedExchange8_acq: + case AArch64::BI_InterlockedExchange16_acq: + case AArch64::BI_InterlockedExchange_acq: + case AArch64::BI_InterlockedExchange64_acq: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange_acq, E); + case AArch64::BI_InterlockedExchange8_rel: + case AArch64::BI_InterlockedExchange16_rel: + case AArch64::BI_InterlockedExchange_rel: + case AArch64::BI_InterlockedExchange64_rel: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange_rel, E); + case AArch64::BI_InterlockedExchange8_nf: + case AArch64::BI_InterlockedExchange16_nf: + case AArch64::BI_InterlockedExchange_nf: + case AArch64::BI_InterlockedExchange64_nf: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange_nf, E); + case AArch64::BI_InterlockedCompareExchange8_acq: + case AArch64::BI_InterlockedCompareExchange16_acq: + case AArch64::BI_InterlockedCompareExchange_acq: + case AArch64::BI_InterlockedCompareExchange64_acq: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedCompareExchange_acq, E); + case AArch64::BI_InterlockedCompareExchange8_rel: + case AArch64::BI_InterlockedCompareExchange16_rel: + case AArch64::BI_InterlockedCompareExchange_rel: + case AArch64::BI_InterlockedCompareExchange64_rel: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedCompareExchange_rel, E); + case AArch64::BI_InterlockedCompareExchange8_nf: + case AArch64::BI_InterlockedCompareExchange16_nf: + case AArch64::BI_InterlockedCompareExchange_nf: + case AArch64::BI_InterlockedCompareExchange64_nf: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedCompareExchange_nf, E); + case AArch64::BI_InterlockedOr8_acq: + case AArch64::BI_InterlockedOr16_acq: + case AArch64::BI_InterlockedOr_acq: + case AArch64::BI_InterlockedOr64_acq: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr_acq, E); + case AArch64::BI_InterlockedOr8_rel: + case AArch64::BI_InterlockedOr16_rel: + case AArch64::BI_InterlockedOr_rel: + case AArch64::BI_InterlockedOr64_rel: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr_rel, E); + case AArch64::BI_InterlockedOr8_nf: + case AArch64::BI_InterlockedOr16_nf: + case AArch64::BI_InterlockedOr_nf: + case AArch64::BI_InterlockedOr64_nf: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr_nf, E); + case AArch64::BI_InterlockedXor8_acq: + case AArch64::BI_InterlockedXor16_acq: + case AArch64::BI_InterlockedXor_acq: + case AArch64::BI_InterlockedXor64_acq: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor_acq, E); + case AArch64::BI_InterlockedXor8_rel: + case AArch64::BI_InterlockedXor16_rel: + case AArch64::BI_InterlockedXor_rel: + case AArch64::BI_InterlockedXor64_rel: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor_rel, E); + case AArch64::BI_InterlockedXor8_nf: + case AArch64::BI_InterlockedXor16_nf: + case AArch64::BI_InterlockedXor_nf: + case AArch64::BI_InterlockedXor64_nf: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor_nf, E); + case AArch64::BI_InterlockedAnd8_acq: + case AArch64::BI_InterlockedAnd16_acq: + case AArch64::BI_InterlockedAnd_acq: + case AArch64::BI_InterlockedAnd64_acq: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd_acq, E); + case AArch64::BI_InterlockedAnd8_rel: + case AArch64::BI_InterlockedAnd16_rel: + case AArch64::BI_InterlockedAnd_rel: + case AArch64::BI_InterlockedAnd64_rel: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd_rel, E); + case AArch64::BI_InterlockedAnd8_nf: + case AArch64::BI_InterlockedAnd16_nf: + case AArch64::BI_InterlockedAnd_nf: + case AArch64::BI_InterlockedAnd64_nf: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd_nf, E); + case AArch64::BI_InterlockedIncrement16_acq: + case AArch64::BI_InterlockedIncrement_acq: + case AArch64::BI_InterlockedIncrement64_acq: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement_acq, E); + case AArch64::BI_InterlockedIncrement16_rel: + case AArch64::BI_InterlockedIncrement_rel: + case AArch64::BI_InterlockedIncrement64_rel: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement_rel, E); + case AArch64::BI_InterlockedIncrement16_nf: + case AArch64::BI_InterlockedIncrement_nf: + case AArch64::BI_InterlockedIncrement64_nf: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement_nf, E); + case AArch64::BI_InterlockedDecrement16_acq: + case AArch64::BI_InterlockedDecrement_acq: + case AArch64::BI_InterlockedDecrement64_acq: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement_acq, E); + case AArch64::BI_InterlockedDecrement16_rel: + case AArch64::BI_InterlockedDecrement_rel: + case AArch64::BI_InterlockedDecrement64_rel: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement_rel, E); + case AArch64::BI_InterlockedDecrement16_nf: + case AArch64::BI_InterlockedDecrement_nf: + case AArch64::BI_InterlockedDecrement64_nf: + return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement_nf, E); + + case AArch64::BI_InterlockedAdd: { + Value *Arg0 = EmitScalarExpr(E->getArg(0)); + Value *Arg1 = EmitScalarExpr(E->getArg(1)); + AtomicRMWInst *RMWI = Builder.CreateAtomicRMW( + AtomicRMWInst::Add, Arg0, Arg1, + llvm::AtomicOrdering::SequentiallyConsistent); + return Builder.CreateAdd(RMWI, Arg1); + } } llvm::VectorType *VTy = GetNeonType(this, Type); @@ -9128,151 +9273,6 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, Int = Intrinsic::aarch64_neon_suqadd; return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vuqadd"); } - case AArch64::BI_BitScanForward: - case AArch64::BI_BitScanForward64: - return EmitMSVCBuiltinExpr(MSVCIntrin::_BitScanForward, E); - case AArch64::BI_BitScanReverse: - case AArch64::BI_BitScanReverse64: - return EmitMSVCBuiltinExpr(MSVCIntrin::_BitScanReverse, E); - case AArch64::BI_InterlockedAnd64: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd, E); - case AArch64::BI_InterlockedExchange64: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange, E); - case AArch64::BI_InterlockedExchangeAdd64: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd, E); - case AArch64::BI_InterlockedExchangeSub64: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeSub, E); - case AArch64::BI_InterlockedOr64: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr, E); - case AArch64::BI_InterlockedXor64: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor, E); - case AArch64::BI_InterlockedDecrement64: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement, E); - case AArch64::BI_InterlockedIncrement64: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement, E); - case AArch64::BI_InterlockedExchangeAdd8_acq: - case AArch64::BI_InterlockedExchangeAdd16_acq: - case AArch64::BI_InterlockedExchangeAdd_acq: - case AArch64::BI_InterlockedExchangeAdd64_acq: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd_acq, E); - case AArch64::BI_InterlockedExchangeAdd8_rel: - case AArch64::BI_InterlockedExchangeAdd16_rel: - case AArch64::BI_InterlockedExchangeAdd_rel: - case AArch64::BI_InterlockedExchangeAdd64_rel: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd_rel, E); - case AArch64::BI_InterlockedExchangeAdd8_nf: - case AArch64::BI_InterlockedExchangeAdd16_nf: - case AArch64::BI_InterlockedExchangeAdd_nf: - case AArch64::BI_InterlockedExchangeAdd64_nf: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchangeAdd_nf, E); - case AArch64::BI_InterlockedExchange8_acq: - case AArch64::BI_InterlockedExchange16_acq: - case AArch64::BI_InterlockedExchange_acq: - case AArch64::BI_InterlockedExchange64_acq: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange_acq, E); - case AArch64::BI_InterlockedExchange8_rel: - case AArch64::BI_InterlockedExchange16_rel: - case AArch64::BI_InterlockedExchange_rel: - case AArch64::BI_InterlockedExchange64_rel: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange_rel, E); - case AArch64::BI_InterlockedExchange8_nf: - case AArch64::BI_InterlockedExchange16_nf: - case AArch64::BI_InterlockedExchange_nf: - case AArch64::BI_InterlockedExchange64_nf: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange_nf, E); - case AArch64::BI_InterlockedCompareExchange8_acq: - case AArch64::BI_InterlockedCompareExchange16_acq: - case AArch64::BI_InterlockedCompareExchange_acq: - case AArch64::BI_InterlockedCompareExchange64_acq: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedCompareExchange_acq, E); - case AArch64::BI_InterlockedCompareExchange8_rel: - case AArch64::BI_InterlockedCompareExchange16_rel: - case AArch64::BI_InterlockedCompareExchange_rel: - case AArch64::BI_InterlockedCompareExchange64_rel: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedCompareExchange_rel, E); - case AArch64::BI_InterlockedCompareExchange8_nf: - case AArch64::BI_InterlockedCompareExchange16_nf: - case AArch64::BI_InterlockedCompareExchange_nf: - case AArch64::BI_InterlockedCompareExchange64_nf: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedCompareExchange_nf, E); - case AArch64::BI_InterlockedOr8_acq: - case AArch64::BI_InterlockedOr16_acq: - case AArch64::BI_InterlockedOr_acq: - case AArch64::BI_InterlockedOr64_acq: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr_acq, E); - case AArch64::BI_InterlockedOr8_rel: - case AArch64::BI_InterlockedOr16_rel: - case AArch64::BI_InterlockedOr_rel: - case AArch64::BI_InterlockedOr64_rel: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr_rel, E); - case AArch64::BI_InterlockedOr8_nf: - case AArch64::BI_InterlockedOr16_nf: - case AArch64::BI_InterlockedOr_nf: - case AArch64::BI_InterlockedOr64_nf: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedOr_nf, E); - case AArch64::BI_InterlockedXor8_acq: - case AArch64::BI_InterlockedXor16_acq: - case AArch64::BI_InterlockedXor_acq: - case AArch64::BI_InterlockedXor64_acq: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor_acq, E); - case AArch64::BI_InterlockedXor8_rel: - case AArch64::BI_InterlockedXor16_rel: - case AArch64::BI_InterlockedXor_rel: - case AArch64::BI_InterlockedXor64_rel: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor_rel, E); - case AArch64::BI_InterlockedXor8_nf: - case AArch64::BI_InterlockedXor16_nf: - case AArch64::BI_InterlockedXor_nf: - case AArch64::BI_InterlockedXor64_nf: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedXor_nf, E); - case AArch64::BI_InterlockedAnd8_acq: - case AArch64::BI_InterlockedAnd16_acq: - case AArch64::BI_InterlockedAnd_acq: - case AArch64::BI_InterlockedAnd64_acq: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd_acq, E); - case AArch64::BI_InterlockedAnd8_rel: - case AArch64::BI_InterlockedAnd16_rel: - case AArch64::BI_InterlockedAnd_rel: - case AArch64::BI_InterlockedAnd64_rel: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd_rel, E); - case AArch64::BI_InterlockedAnd8_nf: - case AArch64::BI_InterlockedAnd16_nf: - case AArch64::BI_InterlockedAnd_nf: - case AArch64::BI_InterlockedAnd64_nf: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedAnd_nf, E); - case AArch64::BI_InterlockedIncrement16_acq: - case AArch64::BI_InterlockedIncrement_acq: - case AArch64::BI_InterlockedIncrement64_acq: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement_acq, E); - case AArch64::BI_InterlockedIncrement16_rel: - case AArch64::BI_InterlockedIncrement_rel: - case AArch64::BI_InterlockedIncrement64_rel: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement_rel, E); - case AArch64::BI_InterlockedIncrement16_nf: - case AArch64::BI_InterlockedIncrement_nf: - case AArch64::BI_InterlockedIncrement64_nf: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedIncrement_nf, E); - case AArch64::BI_InterlockedDecrement16_acq: - case AArch64::BI_InterlockedDecrement_acq: - case AArch64::BI_InterlockedDecrement64_acq: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement_acq, E); - case AArch64::BI_InterlockedDecrement16_rel: - case AArch64::BI_InterlockedDecrement_rel: - case AArch64::BI_InterlockedDecrement64_rel: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement_rel, E); - case AArch64::BI_InterlockedDecrement16_nf: - case AArch64::BI_InterlockedDecrement_nf: - case AArch64::BI_InterlockedDecrement64_nf: - return EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedDecrement_nf, E); - - case AArch64::BI_InterlockedAdd: { - Value *Arg0 = EmitScalarExpr(E->getArg(0)); - Value *Arg1 = EmitScalarExpr(E->getArg(1)); - AtomicRMWInst *RMWI = Builder.CreateAtomicRMW( - AtomicRMWInst::Add, Arg0, Arg1, - llvm::AtomicOrdering::SequentiallyConsistent); - return Builder.CreateAdd(RMWI, Arg1); - } } } diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 695facd50b67..0a57870a7c58 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -1495,6 +1495,13 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { // initializers throws an exception. SmallVector cleanups; llvm::Instruction *cleanupDominator = nullptr; + auto addCleanup = [&](const EHScopeStack::stable_iterator &cleanup) { + cleanups.push_back(cleanup); + if (!cleanupDominator) // create placeholder once needed + cleanupDominator = CGF.Builder.CreateAlignedLoad( + CGF.Int8Ty, llvm::Constant::getNullValue(CGF.Int8PtrTy), + CharUnits::One()); + }; unsigned curInitIndex = 0; @@ -1519,7 +1526,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { if (QualType::DestructionKind dtorKind = Base.getType().isDestructedType()) { CGF.pushDestroy(dtorKind, V, Base.getType()); - cleanups.push_back(CGF.EHStack.stable_begin()); + addCleanup(CGF.EHStack.stable_begin()); } } } @@ -1596,15 +1603,9 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { = field->getType().isDestructedType()) { assert(LV.isSimple()); if (CGF.needsEHCleanup(dtorKind)) { - if (!cleanupDominator) - cleanupDominator = CGF.Builder.CreateAlignedLoad( - CGF.Int8Ty, - llvm::Constant::getNullValue(CGF.Int8PtrTy), - CharUnits::One()); // placeholder - CGF.pushDestroy(EHCleanup, LV.getAddress(), field->getType(), CGF.getDestroyer(dtorKind), false); - cleanups.push_back(CGF.EHStack.stable_begin()); + addCleanup(CGF.EHStack.stable_begin()); pushedCleanup = true; } } @@ -1620,6 +1621,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { // Deactivate all the partial cleanups in reverse order, which // generally means popping them. + assert((cleanupDominator || cleanups.empty()) && + "Missing cleanupDominator before deactivating cleanup blocks"); for (unsigned i = cleanups.size(); i != 0; --i) CGF.DeactivateCleanupBlock(cleanups[i-1], cleanupDominator); diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index dd0dea5b94a0..40ab79509f98 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -1846,11 +1846,9 @@ llvm::Value* CodeGenFunction::EmitAsmInput( InputExpr->EvaluateAsRValue(EVResult, getContext(), true); llvm::APSInt IntResult; - if (!EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(), - getContext())) - llvm_unreachable("Invalid immediate constant!"); - - return llvm::ConstantInt::get(getLLVMContext(), IntResult); + if (EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(), + getContext())) + return llvm::ConstantInt::get(getLLVMContext(), IntResult); } Expr::EvalResult Result; diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 6ff72ec045e6..1fd4e4cf8b8f 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -4355,17 +4355,22 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) { // Create a reference to the named value. This ensures that it is emitted // if a deferred decl. llvm::Constant *Aliasee; - if (isa(DeclTy)) + llvm::GlobalValue::LinkageTypes LT; + if (isa(DeclTy)) { Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GD, /*ForVTable=*/false); - else + LT = getFunctionLinkage(GD); + } else { Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(), llvm::PointerType::getUnqual(DeclTy), /*D=*/nullptr); + LT = getLLVMLinkageVarDefinition(cast(GD.getDecl()), + D->getType().isConstQualified()); + } // Create the new alias itself, but don't set a name yet. - auto *GA = llvm::GlobalAlias::create( - DeclTy, 0, llvm::Function::ExternalLinkage, "", Aliasee, &getModule()); + auto *GA = + llvm::GlobalAlias::create(DeclTy, 0, LT, "", Aliasee, &getModule()); if (Entry) { if (GA->getAliasee() == Entry) { diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 3b2413d960d6..51a2561a4552 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -1755,10 +1755,11 @@ llvm::Value *ItaniumCXXABI::EmitVirtualDestructorCall( CGCallee Callee = CGCallee::forVirtual(CE, GD, This, Ty); QualType ThisTy; - if (CE) - ThisTy = CE->getImplicitObjectArgument()->getType()->getPointeeType(); - else + if (CE) { + ThisTy = CE->getObjectType(); + } else { ThisTy = D->getDestroyedType(); + } CGF.EmitCXXDestructorCall(GD, Callee, This.getPointer(), ThisTy, nullptr, QualType(), nullptr); diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index fa34414de5da..ca06ad3f042b 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -1921,10 +1921,11 @@ llvm::Value *MicrosoftCXXABI::EmitVirtualDestructorCall( DtorType == Dtor_Deleting); QualType ThisTy; - if (CE) - ThisTy = CE->getImplicitObjectArgument()->getType()->getPointeeType(); - else + if (CE) { + ThisTy = CE->getObjectType(); + } else { ThisTy = D->getDestroyedType(); + } This = adjustThisArgumentForVirtualFunctionCall(CGF, GD, This, true); RValue RV = CGF.EmitCXXDestructorCall(GD, Callee, This.getPointer(), ThisTy, diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 5da988fb8a3c..1e1038dbfe95 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -9188,25 +9188,45 @@ static bool getTypeString(SmallStringEnc &Enc, const Decl *D, namespace { class RISCVABIInfo : public DefaultABIInfo { private: - unsigned XLen; // Size of the integer ('x') registers in bits. + // Size of the integer ('x') registers in bits. + unsigned XLen; + // Size of the floating point ('f') registers in bits. Note that the target + // ISA might have a wider FLen than the selected ABI (e.g. an RV32IF target + // with soft float ABI has FLen==0). + unsigned FLen; static const int NumArgGPRs = 8; + static const int NumArgFPRs = 8; + bool detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff, + llvm::Type *&Field1Ty, + CharUnits &Field1Off, + llvm::Type *&Field2Ty, + CharUnits &Field2Off) const; public: - RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen) - : DefaultABIInfo(CGT), XLen(XLen) {} + RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen) + : DefaultABIInfo(CGT), XLen(XLen), FLen(FLen) {} // DefaultABIInfo's classifyReturnType and classifyArgumentType are // non-virtual, but computeInfo is virtual, so we overload it. void computeInfo(CGFunctionInfo &FI) const override; - ABIArgInfo classifyArgumentType(QualType Ty, bool IsFixed, - int &ArgGPRsLeft) const; + ABIArgInfo classifyArgumentType(QualType Ty, bool IsFixed, int &ArgGPRsLeft, + int &ArgFPRsLeft) const; ABIArgInfo classifyReturnType(QualType RetTy) const; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; ABIArgInfo extendType(QualType Ty) const; + + bool detectFPCCEligibleStruct(QualType Ty, llvm::Type *&Field1Ty, + CharUnits &Field1Off, llvm::Type *&Field2Ty, + CharUnits &Field2Off, int &NeededArgGPRs, + int &NeededArgFPRs) const; + ABIArgInfo coerceAndExpandFPCCEligibleStruct(llvm::Type *Field1Ty, + CharUnits Field1Off, + llvm::Type *Field2Ty, + CharUnits Field2Off) const; }; } // end anonymous namespace @@ -9228,18 +9248,215 @@ void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const { // different for variadic arguments, we must also track whether we are // examining a vararg or not. int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs; + int ArgFPRsLeft = FLen ? NumArgFPRs : 0; int NumFixedArgs = FI.getNumRequiredArgs(); int ArgNum = 0; for (auto &ArgInfo : FI.arguments()) { bool IsFixed = ArgNum < NumFixedArgs; - ArgInfo.info = classifyArgumentType(ArgInfo.type, IsFixed, ArgGPRsLeft); + ArgInfo.info = + classifyArgumentType(ArgInfo.type, IsFixed, ArgGPRsLeft, ArgFPRsLeft); ArgNum++; } } +// Returns true if the struct is a potential candidate for the floating point +// calling convention. If this function returns true, the caller is +// responsible for checking that if there is only a single field then that +// field is a float. +bool RISCVABIInfo::detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff, + llvm::Type *&Field1Ty, + CharUnits &Field1Off, + llvm::Type *&Field2Ty, + CharUnits &Field2Off) const { + bool IsInt = Ty->isIntegralOrEnumerationType(); + bool IsFloat = Ty->isRealFloatingType(); + + if (IsInt || IsFloat) { + uint64_t Size = getContext().getTypeSize(Ty); + if (IsInt && Size > XLen) + return false; + // Can't be eligible if larger than the FP registers. Half precision isn't + // currently supported on RISC-V and the ABI hasn't been confirmed, so + // default to the integer ABI in that case. + if (IsFloat && (Size > FLen || Size < 32)) + return false; + // Can't be eligible if an integer type was already found (int+int pairs + // are not eligible). + if (IsInt && Field1Ty && Field1Ty->isIntegerTy()) + return false; + if (!Field1Ty) { + Field1Ty = CGT.ConvertType(Ty); + Field1Off = CurOff; + return true; + } + if (!Field2Ty) { + Field2Ty = CGT.ConvertType(Ty); + Field2Off = CurOff; + return true; + } + return false; + } + + if (auto CTy = Ty->getAs()) { + if (Field1Ty) + return false; + QualType EltTy = CTy->getElementType(); + if (getContext().getTypeSize(EltTy) > FLen) + return false; + Field1Ty = CGT.ConvertType(EltTy); + Field1Off = CurOff; + assert(CurOff.isZero() && "Unexpected offset for first field"); + Field2Ty = Field1Ty; + Field2Off = Field1Off + getContext().getTypeSizeInChars(EltTy); + return true; + } + + if (const ConstantArrayType *ATy = getContext().getAsConstantArrayType(Ty)) { + uint64_t ArraySize = ATy->getSize().getZExtValue(); + QualType EltTy = ATy->getElementType(); + CharUnits EltSize = getContext().getTypeSizeInChars(EltTy); + for (uint64_t i = 0; i < ArraySize; ++i) { + bool Ret = detectFPCCEligibleStructHelper(EltTy, CurOff, Field1Ty, + Field1Off, Field2Ty, Field2Off); + if (!Ret) + return false; + CurOff += EltSize; + } + return true; + } + + if (const auto *RTy = Ty->getAs()) { + // Structures with either a non-trivial destructor or a non-trivial + // copy constructor are not eligible for the FP calling convention. + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT.getCXXABI())) + return false; + if (isEmptyRecord(getContext(), Ty, true)) + return true; + const RecordDecl *RD = RTy->getDecl(); + // Unions aren't eligible unless they're empty (which is caught above). + if (RD->isUnion()) + return false; + int ZeroWidthBitFieldCount = 0; + for (const FieldDecl *FD : RD->fields()) { + const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); + uint64_t FieldOffInBits = Layout.getFieldOffset(FD->getFieldIndex()); + QualType QTy = FD->getType(); + if (FD->isBitField()) { + unsigned BitWidth = FD->getBitWidthValue(getContext()); + // Allow a bitfield with a type greater than XLen as long as the + // bitwidth is XLen or less. + if (getContext().getTypeSize(QTy) > XLen && BitWidth <= XLen) + QTy = getContext().getIntTypeForBitwidth(XLen, false); + if (BitWidth == 0) { + ZeroWidthBitFieldCount++; + continue; + } + } + + bool Ret = detectFPCCEligibleStructHelper( + QTy, CurOff + getContext().toCharUnitsFromBits(FieldOffInBits), + Field1Ty, Field1Off, Field2Ty, Field2Off); + if (!Ret) + return false; + + // As a quirk of the ABI, zero-width bitfields aren't ignored for fp+fp + // or int+fp structs, but are ignored for a struct with an fp field and + // any number of zero-width bitfields. + if (Field2Ty && ZeroWidthBitFieldCount > 0) + return false; + } + return Field1Ty != nullptr; + } + + return false; +} + +// Determine if a struct is eligible for passing according to the floating +// point calling convention (i.e., when flattened it contains a single fp +// value, fp+fp, or int+fp of appropriate size). If so, NeededArgFPRs and +// NeededArgGPRs are incremented appropriately. +bool RISCVABIInfo::detectFPCCEligibleStruct(QualType Ty, llvm::Type *&Field1Ty, + CharUnits &Field1Off, + llvm::Type *&Field2Ty, + CharUnits &Field2Off, + int &NeededArgGPRs, + int &NeededArgFPRs) const { + Field1Ty = nullptr; + Field2Ty = nullptr; + NeededArgGPRs = 0; + NeededArgFPRs = 0; + bool IsCandidate = detectFPCCEligibleStructHelper( + Ty, CharUnits::Zero(), Field1Ty, Field1Off, Field2Ty, Field2Off); + // Not really a candidate if we have a single int but no float. + if (Field1Ty && !Field2Ty && !Field1Ty->isFloatingPointTy()) + return IsCandidate = false; + if (!IsCandidate) + return false; + if (Field1Ty && Field1Ty->isFloatingPointTy()) + NeededArgFPRs++; + else if (Field1Ty) + NeededArgGPRs++; + if (Field2Ty && Field2Ty->isFloatingPointTy()) + NeededArgFPRs++; + else if (Field2Ty) + NeededArgGPRs++; + return IsCandidate; +} + +// Call getCoerceAndExpand for the two-element flattened struct described by +// Field1Ty, Field1Off, Field2Ty, Field2Off. This method will create an +// appropriate coerceToType and unpaddedCoerceToType. +ABIArgInfo RISCVABIInfo::coerceAndExpandFPCCEligibleStruct( + llvm::Type *Field1Ty, CharUnits Field1Off, llvm::Type *Field2Ty, + CharUnits Field2Off) const { + SmallVector CoerceElts; + SmallVector UnpaddedCoerceElts; + if (!Field1Off.isZero()) + CoerceElts.push_back(llvm::ArrayType::get( + llvm::Type::getInt8Ty(getVMContext()), Field1Off.getQuantity())); + + CoerceElts.push_back(Field1Ty); + UnpaddedCoerceElts.push_back(Field1Ty); + + if (!Field2Ty) { + return ABIArgInfo::getCoerceAndExpand( + llvm::StructType::get(getVMContext(), CoerceElts, !Field1Off.isZero()), + UnpaddedCoerceElts[0]); + } + + CharUnits Field2Align = + CharUnits::fromQuantity(getDataLayout().getABITypeAlignment(Field2Ty)); + CharUnits Field1Size = + CharUnits::fromQuantity(getDataLayout().getTypeStoreSize(Field1Ty)); + CharUnits Field2OffNoPadNoPack = Field1Size.alignTo(Field2Align); + + CharUnits Padding = CharUnits::Zero(); + if (Field2Off > Field2OffNoPadNoPack) + Padding = Field2Off - Field2OffNoPadNoPack; + else if (Field2Off != Field2Align && Field2Off > Field1Size) + Padding = Field2Off - Field1Size; + + bool IsPacked = !Field2Off.isMultipleOf(Field2Align); + + if (!Padding.isZero()) + CoerceElts.push_back(llvm::ArrayType::get( + llvm::Type::getInt8Ty(getVMContext()), Padding.getQuantity())); + + CoerceElts.push_back(Field2Ty); + UnpaddedCoerceElts.push_back(Field2Ty); + + auto CoerceToType = + llvm::StructType::get(getVMContext(), CoerceElts, IsPacked); + auto UnpaddedCoerceToType = + llvm::StructType::get(getVMContext(), UnpaddedCoerceElts, IsPacked); + + return ABIArgInfo::getCoerceAndExpand(CoerceToType, UnpaddedCoerceToType); +} + ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, - int &ArgGPRsLeft) const { + int &ArgGPRsLeft, + int &ArgFPRsLeft) const { assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow"); Ty = useFirstFieldIfTransparentUnion(Ty); @@ -9257,6 +9474,42 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, return ABIArgInfo::getIgnore(); uint64_t Size = getContext().getTypeSize(Ty); + + // Pass floating point values via FPRs if possible. + if (IsFixed && Ty->isFloatingType() && FLen >= Size && ArgFPRsLeft) { + ArgFPRsLeft--; + return ABIArgInfo::getDirect(); + } + + // Complex types for the hard float ABI must be passed direct rather than + // using CoerceAndExpand. + if (IsFixed && Ty->isComplexType() && FLen && ArgFPRsLeft >= 2) { + QualType EltTy = Ty->getAs()->getElementType(); + if (getContext().getTypeSize(EltTy) <= FLen) { + ArgFPRsLeft -= 2; + return ABIArgInfo::getDirect(); + } + } + + if (IsFixed && FLen && Ty->isStructureOrClassType()) { + llvm::Type *Field1Ty = nullptr; + llvm::Type *Field2Ty = nullptr; + CharUnits Field1Off = CharUnits::Zero(); + CharUnits Field2Off = CharUnits::Zero(); + int NeededArgGPRs; + int NeededArgFPRs; + bool IsCandidate = + detectFPCCEligibleStruct(Ty, Field1Ty, Field1Off, Field2Ty, Field2Off, + NeededArgGPRs, NeededArgFPRs); + if (IsCandidate && NeededArgGPRs <= ArgGPRsLeft && + NeededArgFPRs <= ArgFPRsLeft) { + ArgGPRsLeft -= NeededArgGPRs; + ArgFPRsLeft -= NeededArgFPRs; + return coerceAndExpandFPCCEligibleStruct(Field1Ty, Field1Off, Field2Ty, + Field2Off); + } + } + uint64_t NeededAlign = getContext().getTypeAlign(Ty); bool MustUseStack = false; // Determine the number of GPRs needed to pass the current argument @@ -9315,10 +9568,12 @@ ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy) const { return ABIArgInfo::getIgnore(); int ArgGPRsLeft = 2; + int ArgFPRsLeft = FLen ? 2 : 0; // The rules for return and argument types are the same, so defer to // classifyArgumentType. - return classifyArgumentType(RetTy, /*IsFixed=*/true, ArgGPRsLeft); + return classifyArgumentType(RetTy, /*IsFixed=*/true, ArgGPRsLeft, + ArgFPRsLeft); } Address RISCVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, @@ -9353,8 +9608,9 @@ ABIArgInfo RISCVABIInfo::extendType(QualType Ty) const { namespace { class RISCVTargetCodeGenInfo : public TargetCodeGenInfo { public: - RISCVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen) - : TargetCodeGenInfo(new RISCVABIInfo(CGT, XLen)) {} + RISCVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, + unsigned FLen) + : TargetCodeGenInfo(new RISCVABIInfo(CGT, XLen, FLen)) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override { @@ -9493,9 +9749,16 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { return SetCGInfo(new MSP430TargetCodeGenInfo(Types)); case llvm::Triple::riscv32: - return SetCGInfo(new RISCVTargetCodeGenInfo(Types, 32)); - case llvm::Triple::riscv64: - return SetCGInfo(new RISCVTargetCodeGenInfo(Types, 64)); + case llvm::Triple::riscv64: { + StringRef ABIStr = getTarget().getABI(); + unsigned XLen = getTarget().getPointerWidth(0); + unsigned ABIFLen = 0; + if (ABIStr.endswith("f")) + ABIFLen = 32; + else if (ABIStr.endswith("d")) + ABIFLen = 64; + return SetCGInfo(new RISCVTargetCodeGenInfo(Types, XLen, ABIFLen)); + } case llvm::Triple::systemz: { bool HasVector = getTarget().getABI() == "vector"; diff --git a/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp b/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp index 6d7d69da4db5..1a66faeb3239 100644 --- a/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp +++ b/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -335,7 +334,7 @@ std::unique_ptr clang::DirectoryWatcher::create( InotifyFD, Path.str().c_str(), IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MODIFY | IN_MOVED_FROM | IN_MOVE_SELF | IN_MOVED_TO | IN_ONLYDIR | IN_IGNORED -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) +#ifdef IN_EXCL_UNLINK | IN_EXCL_UNLINK #endif ); diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt index d90c0ff43607..bee1f52e87f7 100644 --- a/clang/lib/Driver/CMakeLists.txt +++ b/clang/lib/Driver/CMakeLists.txt @@ -24,6 +24,7 @@ add_clang_library(clangDriver ToolChain.cpp ToolChains/Arch/AArch64.cpp ToolChains/Arch/ARM.cpp + ToolChains/Arch/CAHP.cpp ToolChains/Arch/Mips.cpp ToolChains/Arch/PPC.cpp ToolChains/Arch/RISCV.cpp @@ -34,6 +35,7 @@ add_clang_library(clangDriver ToolChains/AMDGPU.cpp ToolChains/AVR.cpp ToolChains/BareMetal.cpp + ToolChains/CAHP.cpp ToolChains/Clang.cpp ToolChains/CloudABI.cpp ToolChains/CommonArgs.cpp diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 396ddf4dd816..3b0938d83253 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -12,6 +12,7 @@ #include "ToolChains/AVR.h" #include "ToolChains/Ananas.h" #include "ToolChains/BareMetal.h" +#include "ToolChains/CAHP.h" #include "ToolChains/Clang.h" #include "ToolChains/CloudABI.h" #include "ToolChains/Contiki.h" @@ -133,7 +134,7 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple, // Provide a sane fallback if no VFS is specified. if (!this->VFS) - this->VFS = llvm::vfs::createPhysicalFileSystem().release(); + this->VFS = llvm::vfs::getRealFileSystem(); Name = llvm::sys::path::filename(ClangExecutable); Dir = llvm::sys::path::parent_path(ClangExecutable); @@ -1010,11 +1011,6 @@ Compilation *Driver::BuildCompilation(ArrayRef ArgList) { } } - // Check for working directory option before accessing any files - if (Arg *WD = Args.getLastArg(options::OPT_working_directory)) - if (VFS->setCurrentWorkingDirectory(WD->getValue())) - Diag(diag::err_drv_unable_to_set_working_directory) << WD->getValue(); - // FIXME: This stuff needs to go into the Compilation, not the driver. bool CCCPrintPhases; @@ -1995,11 +1991,20 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value, if (Value == "-") return true; - if (getVFS().exists(Value)) + SmallString<64> Path(Value); + if (Arg *WorkDir = Args.getLastArg(options::OPT_working_directory)) { + if (!llvm::sys::path::is_absolute(Path)) { + SmallString<64> Directory(WorkDir->getValue()); + llvm::sys::path::append(Directory, Value); + Path.assign(Directory); + } + } + + if (getVFS().exists(Path)) return true; if (IsCLMode()) { - if (!llvm::sys::path::is_absolute(Twine(Value)) && + if (!llvm::sys::path::is_absolute(Twine(Path)) && llvm::sys::Process::FindInEnvPath("LIB", Value)) return true; @@ -2025,12 +2030,12 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value, if (getOpts().findNearest(Value, Nearest, IncludedFlagsBitmask, ExcludedFlagsBitmask) <= 1) { Diag(clang::diag::err_drv_no_such_file_with_suggestion) - << Value << Nearest; + << Path << Nearest; return false; } } - Diag(clang::diag::err_drv_no_such_file) << Value; + Diag(clang::diag::err_drv_no_such_file) << Path; return false; } @@ -4716,6 +4721,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, TC = llvm::make_unique(*this, Target, Args); break; + case llvm::Triple::cahp: + TC = llvm::make_unique(*this, Target, Args); + break; case llvm::Triple::riscv32: case llvm::Triple::riscv64: TC = llvm::make_unique(*this, Target, Args); diff --git a/clang/lib/Driver/ToolChains/Arch/CAHP.cpp b/clang/lib/Driver/ToolChains/Arch/CAHP.cpp new file mode 100644 index 000000000000..fce8c8670bd5 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/CAHP.cpp @@ -0,0 +1,21 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "CAHP.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace llvm::opt; + +std::string cahp::getCAHPTargetCPU(const ArgList &Args) { + // If we have -mcpu, use that. + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { + return A->getValue(); + } + + // Otherwise use 'generic'. + return "generic"; +} diff --git a/clang/lib/Driver/ToolChains/Arch/CAHP.h b/clang/lib/Driver/ToolChains/Arch/CAHP.h new file mode 100644 index 000000000000..73e3a3f7f9c3 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Arch/CAHP.h @@ -0,0 +1,22 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_CAHP_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_CAHP_H + +#include "llvm/Option/Option.h" + +namespace clang { +namespace driver { +namespace tools { +namespace cahp { + +std::string getCAHPTargetCPU(const llvm::opt::ArgList &Args); + +} // namespace cahp +} // namespace tools +} // namespace driver +} // namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_CAHP_H diff --git a/clang/lib/Driver/ToolChains/CAHP.cpp b/clang/lib/Driver/ToolChains/CAHP.cpp new file mode 100644 index 000000000000..bc7efbc460a4 --- /dev/null +++ b/clang/lib/Driver/ToolChains/CAHP.cpp @@ -0,0 +1,68 @@ +#include "CAHP.h" +#include "CommonArgs.h" +#include "InputInfo.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +CAHPToolChain::CAHPToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : Generic_ELF(D, Triple, Args) { + if (!D.SysRoot.empty()) + getFilePaths().push_back(D.SysRoot); +} + +Tool *CAHPToolChain::buildLinker() const { + return new tools::CAHP::Linker(*this); +} + +void CAHP::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const ToolChain &ToolChain = getToolChain(); + const Driver &D = ToolChain.getDriver(); + ArgStringList CmdArgs; + + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + std::string Linker = getToolChain().GetProgramPath(getShortName()); + + bool WantCRTs = + !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); + + if (WantCRTs) { + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); + } + + Args.AddAllArgs(CmdArgs, options::OPT_L); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + + if (!Args.hasArg(options::OPT_nostdlib) && + !Args.hasArg(options::OPT_nodefaultlibs)) { + CmdArgs.push_back("-lc"); + } + + CmdArgs.push_back( + Args.MakeArgString("--script=" + ToolChain.GetFilePath("cahp.lds"))); + + // To make the output as small as possible. + CmdArgs.push_back("--nmagic"); + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + C.addCommand(llvm::make_unique(JA, *this, Args.MakeArgString(Linker), + CmdArgs, Inputs)); +} diff --git a/clang/lib/Driver/ToolChains/CAHP.h b/clang/lib/Driver/ToolChains/CAHP.h new file mode 100644 index 000000000000..08f890e36e95 --- /dev/null +++ b/clang/lib/Driver/ToolChains/CAHP.h @@ -0,0 +1,58 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CAHP_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CAHP_H + +#include "Gnu.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY CAHPToolChain : public Generic_ELF { +public: + CAHPToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + bool IsIntegratedAssemblerDefault() const override { return true; } + + // No support for finding a C++ standard library yet. + void addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override { + } + void + addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override {} + + // No default include flags. + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override {} + +protected: + Tool *buildLinker() const override; +}; + +} // end namespace toolchains + +namespace tools { +namespace CAHP { +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: + Linker(const ToolChain &TC) : GnuTool("CAHP::Linker", "ld.lld", TC) {} + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; +} // namespace CAHP +} // namespace tools +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CAHP_H diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index cb861f27aeda..363bf79c0a3f 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -501,8 +501,6 @@ static codegenoptions::DebugInfoKind DebugLevelToInfoKind(const Arg &A) { return codegenoptions::LimitedDebugInfo; } -enum class FramePointerKind { None, NonLeaf, All }; - static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) { switch (Triple.getArch()){ default: @@ -517,9 +515,6 @@ static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) { static bool useFramePointerForTargetByDefault(const ArgList &Args, const llvm::Triple &Triple) { - if (Args.hasArg(options::OPT_pg)) - return true; - switch (Triple.getArch()) { case llvm::Triple::xcore: case llvm::Triple::wasm32: @@ -528,6 +523,7 @@ static bool useFramePointerForTargetByDefault(const ArgList &Args, // XCore never wants frame pointers, regardless of OS. // WebAssembly never wants frame pointers. return false; + case llvm::Triple::cahp: case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: @@ -579,34 +575,45 @@ static bool useFramePointerForTargetByDefault(const ArgList &Args, return true; } -static FramePointerKind getFramePointerKind(const ArgList &Args, - const llvm::Triple &Triple) { - Arg *A = Args.getLastArg(options::OPT_fomit_frame_pointer, - options::OPT_fno_omit_frame_pointer); - bool OmitFP = A && A->getOption().matches(options::OPT_fomit_frame_pointer); - bool NoOmitFP = - A && A->getOption().matches(options::OPT_fno_omit_frame_pointer); - if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) || - (!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) { - if (Args.hasFlag(options::OPT_momit_leaf_frame_pointer, - options::OPT_mno_omit_leaf_frame_pointer, - Triple.isPS4CPU())) - return FramePointerKind::NonLeaf; - return FramePointerKind::All; - } - return FramePointerKind::None; +static bool shouldUseFramePointer(const ArgList &Args, + const llvm::Triple &Triple) { + if (Arg *A = Args.getLastArg(options::OPT_fno_omit_frame_pointer, + options::OPT_fomit_frame_pointer)) + return A->getOption().matches(options::OPT_fno_omit_frame_pointer) || + mustUseNonLeafFramePointerForTarget(Triple); + + if (Args.hasArg(options::OPT_pg)) + return true; + + return useFramePointerForTargetByDefault(Args, Triple); +} + +static bool shouldUseLeafFramePointer(const ArgList &Args, + const llvm::Triple &Triple) { + if (Arg *A = Args.getLastArg(options::OPT_mno_omit_leaf_frame_pointer, + options::OPT_momit_leaf_frame_pointer)) + return A->getOption().matches(options::OPT_mno_omit_leaf_frame_pointer); + + if (Args.hasArg(options::OPT_pg)) + return true; + + if (Triple.isPS4CPU()) + return false; + + return useFramePointerForTargetByDefault(Args, Triple); } /// Add a CC1 option to specify the debug compilation directory. -static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs, - const llvm::vfs::FileSystem &VFS) { +static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs) { if (Arg *A = Args.getLastArg(options::OPT_fdebug_compilation_dir)) { CmdArgs.push_back("-fdebug-compilation-dir"); CmdArgs.push_back(A->getValue()); - } else if (llvm::ErrorOr CWD = - VFS.getCurrentWorkingDirectory()) { - CmdArgs.push_back("-fdebug-compilation-dir"); - CmdArgs.push_back(Args.MakeArgString(*CWD)); + } else { + SmallString<128> cwd; + if (!llvm::sys::fs::current_path(cwd)) { + CmdArgs.push_back("-fdebug-compilation-dir"); + CmdArgs.push_back(Args.MakeArgString(cwd)); + } } } @@ -872,8 +879,13 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, else OutputFilename = llvm::sys::path::filename(Output.getBaseInput()); SmallString<128> CoverageFilename = OutputFilename; - if (llvm::sys::path::is_relative(CoverageFilename)) - (void)D.getVFS().makeAbsolute(CoverageFilename); + if (llvm::sys::path::is_relative(CoverageFilename)) { + SmallString<128> Pwd; + if (!llvm::sys::fs::current_path(Pwd)) { + llvm::sys::path::append(Pwd, CoverageFilename); + CoverageFilename.swap(Pwd); + } + } llvm::sys::path::replace_extension(CoverageFilename, "gcno"); CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); @@ -3946,12 +3958,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false)) CmdArgs.push_back("-fdefault-calling-conv=stdcall"); - FramePointerKind FPKeepKind = getFramePointerKind(Args, RawTriple); - if (FPKeepKind != FramePointerKind::None) { + if (shouldUseFramePointer(Args, RawTriple)) CmdArgs.push_back("-mdisable-fp-elim"); - if (FPKeepKind == FramePointerKind::NonLeaf) - CmdArgs.push_back("-momit-leaf-frame-pointer"); - } if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss, options::OPT_fno_zero_initialized_in_bss)) CmdArgs.push_back("-mno-zero-initialized-in-bss"); @@ -4136,6 +4144,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } + if (!shouldUseLeafFramePointer(Args, RawTriple)) + CmdArgs.push_back("-momit-leaf-frame-pointer"); + // Explicitly error on some things we know we don't support and can't just // ignore. if (!Args.hasArg(options::OPT_fallow_unsupported)) { @@ -4361,7 +4372,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fno-autolink"); // Add in -fdebug-compilation-dir if necessary. - addDebugCompDirArg(Args, CmdArgs, D.getVFS()); + addDebugCompDirArg(Args, CmdArgs); addDebugPrefixMapArg(D, Args, CmdArgs); @@ -5489,7 +5500,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } if (Arg *A = Args.getLastArg(options::OPT_pg)) - if (FPKeepKind == FramePointerKind::None) + if (!shouldUseFramePointer(Args, Triple)) D.Diag(diag::err_drv_argument_not_allowed_with) << "-fomit-frame-pointer" << A->getAsString(Args); @@ -6088,7 +6099,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, DebugInfoKind = (WantDebug ? codegenoptions::LimitedDebugInfo : codegenoptions::NoDebugInfo); // Add the -fdebug-compilation-dir flag if needed. - addDebugCompDirArg(Args, CmdArgs, C.getDriver().getVFS()); + addDebugCompDirArg(Args, CmdArgs); addDebugPrefixMapArg(getToolChain().getDriver(), Args, CmdArgs); diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 99691cb43dc4..dd96b68ba568 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -9,6 +9,7 @@ #include "CommonArgs.h" #include "Arch/AArch64.h" #include "Arch/ARM.h" +#include "Arch/CAHP.h" #include "Arch/Mips.h" #include "Arch/PPC.h" #include "Arch/SystemZ.h" @@ -335,6 +336,9 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, case llvm::Triple::wasm32: case llvm::Triple::wasm64: return getWebAssemblyTargetCPU(Args); + + case llvm::Triple::cahp: + return cahp::getCAHPTargetCPU(Args); } } diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index 7445a94cfe59..783d1f9d0919 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -435,7 +435,6 @@ void ASTUnit::CacheCodeCompletionResults() { | (1LL << CodeCompletionContext::CCC_UnionTag) | (1LL << CodeCompletionContext::CCC_ClassOrStructTag) | (1LL << CodeCompletionContext::CCC_Type) - | (1LL << CodeCompletionContext::CCC_Symbol) | (1LL << CodeCompletionContext::CCC_SymbolOrNewName) | (1LL << CodeCompletionContext::CCC_ParenthesizedExpression); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 8a9844096f08..bc54e38a1a63 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -2408,7 +2408,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, .Cases("cl1.1", "CL1.1", LangStandard::lang_opencl11) .Cases("cl1.2", "CL1.2", LangStandard::lang_opencl12) .Cases("cl2.0", "CL2.0", LangStandard::lang_opencl20) - .Case("c++", LangStandard::lang_openclcpp) + .Cases("clc++", "CLC++", LangStandard::lang_openclcpp) .Default(LangStandard::lang_unspecified); if (OpenCLLangStd == LangStandard::lang_unspecified) { diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index 3906e2ae1b98..6feb7bcbd4b7 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -437,17 +437,17 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, default: llvm_unreachable("Unsupported OpenCL version"); } - Builder.defineMacro("CL_VERSION_1_0", "100"); - Builder.defineMacro("CL_VERSION_1_1", "110"); - Builder.defineMacro("CL_VERSION_1_2", "120"); - Builder.defineMacro("CL_VERSION_2_0", "200"); + } + Builder.defineMacro("CL_VERSION_1_0", "100"); + Builder.defineMacro("CL_VERSION_1_1", "110"); + Builder.defineMacro("CL_VERSION_1_2", "120"); + Builder.defineMacro("CL_VERSION_2_0", "200"); - if (TI.isLittleEndian()) - Builder.defineMacro("__ENDIAN_LITTLE__"); + if (TI.isLittleEndian()) + Builder.defineMacro("__ENDIAN_LITTLE__"); - if (LangOpts.FastRelaxedMath) - Builder.defineMacro("__FAST_RELAXED_MATH__"); - } + if (LangOpts.FastRelaxedMath) + Builder.defineMacro("__FAST_RELAXED_MATH__"); } // Not "standard" per se, but available even with the -undef flag. if (LangOpts.AsmPreprocessor) diff --git a/clang/lib/Headers/emmintrin.h b/clang/lib/Headers/emmintrin.h index 3d55f5f2710f..c8fefdfc792a 100644 --- a/clang/lib/Headers/emmintrin.h +++ b/clang/lib/Headers/emmintrin.h @@ -4029,7 +4029,7 @@ _mm_storeu_si128(__m128i_u *__p, __m128i __b) /// \param __b /// A 128-bit integer vector containing the value to be stored. static __inline__ void __DEFAULT_FN_ATTRS -_mm_storeu_si64(void const *__p, __m128i __b) +_mm_storeu_si64(void *__p, __m128i __b) { struct __storeu_si64 { long long __v; @@ -4050,7 +4050,7 @@ _mm_storeu_si64(void const *__p, __m128i __b) /// \param __b /// A 128-bit integer vector containing the value to be stored. static __inline__ void __DEFAULT_FN_ATTRS -_mm_storeu_si32(void const *__p, __m128i __b) +_mm_storeu_si32(void *__p, __m128i __b) { struct __storeu_si32 { int __v; @@ -4071,7 +4071,7 @@ _mm_storeu_si32(void const *__p, __m128i __b) /// \param __b /// A 128-bit integer vector containing the value to be stored. static __inline__ void __DEFAULT_FN_ATTRS -_mm_storeu_si16(void const *__p, __m128i __b) +_mm_storeu_si16(void *__p, __m128i __b) { struct __storeu_si16 { short __v; diff --git a/clang/lib/Headers/opencl-c-base.h b/clang/lib/Headers/opencl-c-base.h index a82954ddd326..9a23333a33e6 100644 --- a/clang/lib/Headers/opencl-c-base.h +++ b/clang/lib/Headers/opencl-c-base.h @@ -126,7 +126,7 @@ typedef double double8 __attribute__((ext_vector_type(8))); typedef double double16 __attribute__((ext_vector_type(16))); #endif -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) #define NULL ((void*)0) #endif @@ -276,7 +276,7 @@ typedef uint cl_mem_fence_flags; */ #define CLK_GLOBAL_MEM_FENCE 0x02 -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) typedef enum memory_scope { memory_scope_work_item = __OPENCL_MEMORY_SCOPE_WORK_ITEM, @@ -288,9 +288,6 @@ typedef enum memory_scope { #endif } memory_scope; -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 - -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 /** * Queue a memory fence to ensure correct ordering of memory * operations between work-items of a work-group to @@ -313,7 +310,7 @@ typedef enum memory_order memory_order_seq_cst = __ATOMIC_SEQ_CST } memory_order; -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) // OpenCL v1.1 s6.11.3, v1.2 s6.12.14, v2.0 s6.13.14 - Image Read and Write Functions @@ -389,14 +386,10 @@ typedef enum memory_order #endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 // OpenCL v2.0 s6.13.16 - Pipe Functions -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) #define CLK_NULL_RESERVE_ID (__builtin_astype(((void*)(__SIZE_MAX__)), reserve_id_t)) -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 - // OpenCL v2.0 s6.13.17 - Enqueue Kernels -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 - #define CL_COMPLETE 0x0 #define CL_RUNNING 0x1 #define CL_SUBMITTED 0x2 @@ -435,7 +428,7 @@ typedef struct { size_t localWorkSize[MAX_WORK_DIM]; } ndrange_t; -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) #ifdef cl_intel_device_side_avc_motion_estimation #pragma OPENCL EXTENSION cl_intel_device_side_avc_motion_estimation : begin diff --git a/clang/lib/Headers/opencl-c.h b/clang/lib/Headers/opencl-c.h index 4207c53ccedb..06c5ab6a72f0 100644 --- a/clang/lib/Headers/opencl-c.h +++ b/clang/lib/Headers/opencl-c.h @@ -11,11 +11,11 @@ #include "opencl-c-base.h" -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) #ifndef cl_khr_depth_images #define cl_khr_depth_images #endif //cl_khr_depth_images -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) #if __OPENCL_C_VERSION__ < CL_VERSION_2_0 #ifdef cl_khr_3d_image_writes @@ -23,10 +23,10 @@ #endif //cl_khr_3d_image_writes #endif //__OPENCL_C_VERSION__ < CL_VERSION_2_0 -#if __OPENCL_C_VERSION__ >= CL_VERSION_1_2 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2) #pragma OPENCL EXTENSION cl_intel_planar_yuv : begin #pragma OPENCL EXTENSION cl_intel_planar_yuv : end -#endif // __OPENCL_C_VERSION__ >= CL_VERSION_1_2 +#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2) #define __ovld __attribute__((overloadable)) #define __conv __attribute__((convergent)) @@ -6517,11 +6517,11 @@ size_t __ovld __cnfn get_group_id(uint dimindx); */ size_t __ovld __cnfn get_global_offset(uint dimindx); -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) size_t __ovld get_enqueued_local_size(uint dimindx); size_t __ovld get_global_linear_id(void); size_t __ovld get_local_linear_id(void); -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) // OpenCL v1.1 s6.11.2, v1.2 s6.12.2, v2.0 s6.13.2 - Math functions @@ -7352,7 +7352,7 @@ half16 __ovld __cnfn fmod(half16 x, half16 y); * Returns fmin(x - floor (x), 0x1.fffffep-1f ). * floor(x) is returned in iptr. */ -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) float __ovld fract(float x, float *iptr); float2 __ovld fract(float2 x, float2 *iptr); float3 __ovld fract(float3 x, float3 *iptr); @@ -7434,7 +7434,7 @@ half4 __ovld fract(half4 x, __private half4 *iptr); half8 __ovld fract(half8 x, __private half8 *iptr); half16 __ovld fract(half16 x, __private half16 *iptr); #endif //cl_khr_fp16 -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * Extract mantissa and exponent from x. For each @@ -7442,7 +7442,7 @@ half16 __ovld fract(half16 x, __private half16 *iptr); * magnitude in the interval [1/2, 1) or 0. Each * component of x equals mantissa returned * 2^exp. */ -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) float __ovld frexp(float x, int *exp); float2 __ovld frexp(float2 x, int2 *exp); float3 __ovld frexp(float3 x, int3 *exp); @@ -7524,7 +7524,7 @@ half4 __ovld frexp(half4 x, __private int4 *exp); half8 __ovld frexp(half8 x, __private int8 *exp); half16 __ovld frexp(half16 x, __private int16 *exp); #endif //cl_khr_fp16 -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * Compute the value of the square root of x^2 + y^2 @@ -7649,7 +7649,7 @@ half8 __ovld __cnfn lgamma(half8 x); half16 __ovld __cnfn lgamma(half16 x); #endif //cl_khr_fp16 -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) float __ovld lgamma_r(float x, int *signp); float2 __ovld lgamma_r(float2 x, int2 *signp); float3 __ovld lgamma_r(float3 x, int3 *signp); @@ -7731,7 +7731,7 @@ half4 __ovld lgamma_r(half4 x, __private int4 *signp); half8 __ovld lgamma_r(half8 x, __private int8 *signp); half16 __ovld lgamma_r(half16 x, __private int16 *signp); #endif //cl_khr_fp16 -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * Compute natural logarithm. @@ -7955,7 +7955,7 @@ half16 __ovld __cnfn minmag(half16 x, half16 y); * the argument. It stores the integral part in the object * pointed to by iptr. */ -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) float __ovld modf(float x, float *iptr); float2 __ovld modf(float2 x, float2 *iptr); float3 __ovld modf(float3 x, float3 *iptr); @@ -8037,7 +8037,7 @@ half4 __ovld modf(half4 x, __private half4 *iptr); half8 __ovld modf(half8 x, __private half8 *iptr); half16 __ovld modf(half16 x, __private half16 *iptr); #endif //cl_khr_fp16 -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * Returns a quiet NaN. The nancode may be placed @@ -8215,7 +8215,7 @@ half16 __ovld __cnfn remainder(half16 x, half16 y); * sign as x/y. It stores this signed value in the object * pointed to by quo. */ -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) float __ovld remquo(float x, float y, int *quo); float2 __ovld remquo(float2 x, float2 y, int2 *quo); float3 __ovld remquo(float3 x, float3 y, int3 *quo); @@ -8298,7 +8298,7 @@ half4 __ovld remquo(half4 x, half4 y, __private int4 *quo); half8 __ovld remquo(half8 x, half8 y, __private int8 *quo); half16 __ovld remquo(half16 x, half16 y, __private int16 *quo); #endif //cl_khr_fp16 -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * Round to integral value (using round to nearest * even rounding mode) in floating-point format. @@ -8439,7 +8439,7 @@ half16 __ovld __cnfn sin(half16); * is the return value and computed cosine is returned * in cosval. */ -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) float __ovld sincos(float x, float *cosval); float2 __ovld sincos(float2 x, float2 *cosval); float3 __ovld sincos(float3 x, float3 *cosval); @@ -8521,7 +8521,7 @@ half4 __ovld sincos(half4 x, __private half4 *cosval); half8 __ovld sincos(half8 x, __private half8 *cosval); half16 __ovld sincos(half16 x, __private half16 *cosval); #endif //cl_khr_fp16 -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * Compute hyperbolic sine. @@ -9446,7 +9446,7 @@ ulong16 __ovld __cnfn clz(ulong16 x); * returns the size in bits of the type of x or * component type of x, if x is a vector. */ -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) char __ovld ctz(char x); uchar __ovld ctz(uchar x); char2 __ovld ctz(char2 x); @@ -9495,7 +9495,7 @@ long8 __ovld ctz(long8 x); ulong8 __ovld ctz(ulong8 x); long16 __ovld ctz(long16 x); ulong16 __ovld ctz(ulong16 x); -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * Returns mul_hi(a, b) + c. @@ -11340,7 +11340,7 @@ half8 __ovld vload8(size_t offset, const __constant half *p); half16 __ovld vload16(size_t offset, const __constant half *p); #endif //cl_khr_fp16 -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) char2 __ovld vload2(size_t offset, const char *p); uchar2 __ovld vload2(size_t offset, const uchar *p); short2 __ovld vload2(size_t offset, const short *p); @@ -11578,9 +11578,9 @@ half4 __ovld vload4(size_t offset, const __private half *p); half8 __ovld vload8(size_t offset, const __private half *p); half16 __ovld vload16(size_t offset, const __private half *p); #endif //cl_khr_fp16 -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) void __ovld vstore2(char2 data, size_t offset, char *p); void __ovld vstore2(uchar2 data, size_t offset, uchar *p); void __ovld vstore2(short2 data, size_t offset, short *p); @@ -11814,7 +11814,7 @@ void __ovld vstore4(half4 data, size_t offset, __private half *p); void __ovld vstore8(half8 data, size_t offset, __private half *p); void __ovld vstore16(half16 data, size_t offset, __private half *p); #endif //cl_khr_fp16 -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * Read sizeof (half) bytes of data from address @@ -11825,13 +11825,13 @@ void __ovld vstore16(half16 data, size_t offset, __private half *p); * must be 16-bit aligned. */ float __ovld vload_half(size_t offset, const __constant half *p); -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) float __ovld vload_half(size_t offset, const half *p); #else float __ovld vload_half(size_t offset, const __global half *p); float __ovld vload_half(size_t offset, const __local half *p); float __ovld vload_half(size_t offset, const __private half *p); -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * Read sizeof (halfn) bytes of data from address @@ -11846,7 +11846,7 @@ float3 __ovld vload_half3(size_t offset, const __constant half *p); float4 __ovld vload_half4(size_t offset, const __constant half *p); float8 __ovld vload_half8(size_t offset, const __constant half *p); float16 __ovld vload_half16(size_t offset, const __constant half *p); -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) float2 __ovld vload_half2(size_t offset, const half *p); float3 __ovld vload_half3(size_t offset, const half *p); float4 __ovld vload_half4(size_t offset, const half *p); @@ -11868,7 +11868,7 @@ float3 __ovld vload_half3(size_t offset, const __private half *p); float4 __ovld vload_half4(size_t offset, const __private half *p); float8 __ovld vload_half8(size_t offset, const __private half *p); float16 __ovld vload_half16(size_t offset, const __private half *p); -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * The float value given by data is first @@ -11881,7 +11881,7 @@ float16 __ovld vload_half16(size_t offset, const __private half *p); * The default current rounding mode is round to * nearest even. */ -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) void __ovld vstore_half(float data, size_t offset, half *p); void __ovld vstore_half_rte(float data, size_t offset, half *p); void __ovld vstore_half_rtz(float data, size_t offset, half *p); @@ -11927,7 +11927,7 @@ void __ovld vstore_half_rtz(double data, size_t offset, __private half *p); void __ovld vstore_half_rtp(double data, size_t offset, __private half *p); void __ovld vstore_half_rtn(double data, size_t offset, __private half *p); #endif //cl_khr_fp64 -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * The floatn value given by data is converted to @@ -11940,7 +11940,7 @@ void __ovld vstore_half_rtn(double data, size_t offset, __private half *p); * The default current rounding mode is round to * nearest even. */ -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) void __ovld vstore_half2(float2 data, size_t offset, half *p); void __ovld vstore_half3(float3 data, size_t offset, half *p); void __ovld vstore_half4(float4 data, size_t offset, half *p); @@ -12146,7 +12146,7 @@ void __ovld vstore_half4_rtn(double4 data, size_t offset, __private half *p); void __ovld vstore_half8_rtn(double8 data, size_t offset, __private half *p); void __ovld vstore_half16_rtn(double16 data, size_t offset, __private half *p); #endif //cl_khr_fp64 -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * For n = 1, 2, 4, 8 and 16 read sizeof (halfn) @@ -12167,7 +12167,7 @@ float3 __ovld vloada_half3(size_t offset, const __constant half *p); float4 __ovld vloada_half4(size_t offset, const __constant half *p); float8 __ovld vloada_half8(size_t offset, const __constant half *p); float16 __ovld vloada_half16(size_t offset, const __constant half *p); -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) float __ovld vloada_half(size_t offset, const half *p); float2 __ovld vloada_half2(size_t offset, const half *p); float3 __ovld vloada_half3(size_t offset, const half *p); @@ -12193,7 +12193,7 @@ float3 __ovld vloada_half3(size_t offset, const __private half *p); float4 __ovld vloada_half4(size_t offset, const __private half *p); float8 __ovld vloada_half8(size_t offset, const __private half *p); float16 __ovld vloada_half16(size_t offset, const __private half *p); -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * The floatn value given by data is converted to @@ -12211,7 +12211,7 @@ float16 __ovld vloada_half16(size_t offset, const __private half *p); * mode. The default current rounding mode is * round to nearest even. */ -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) void __ovld vstorea_half(float data, size_t offset, half *p); void __ovld vstorea_half2(float2 data, size_t offset, half *p); void __ovld vstorea_half3(float3 data, size_t offset, half *p); @@ -12496,7 +12496,7 @@ void __ovld vstorea_half4_rtn(double4 data,size_t offset, __private half *p); void __ovld vstorea_half8_rtn(double8 data,size_t offset, __private half *p); void __ovld vstorea_half16_rtn(double16 data,size_t offset, __private half *p); #endif //cl_khr_fp64 -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) // OpenCL v1.1 s6.11.8, v1.2 s6.12.8, v2.0 s6.13.8 - Synchronization Functions @@ -12532,10 +12532,10 @@ void __ovld vstorea_half16_rtn(double16 data,size_t offset, __private half *p); void __ovld __conv barrier(cl_mem_fence_flags flags); -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) void __ovld __conv work_group_barrier(cl_mem_fence_flags flags, memory_scope scope); void __ovld __conv work_group_barrier(cl_mem_fence_flags flags); -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) // OpenCL v1.1 s6.11.9, v1.2 s6.12.9 - Explicit Memory Fence Functions @@ -12580,7 +12580,7 @@ void __ovld write_mem_fence(cl_mem_fence_flags flags); // OpenCL v2.0 s6.13.9 - Address Space Qualifier Functions -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) cl_mem_fence_flags __ovld get_fence(const void *ptr); cl_mem_fence_flags __ovld get_fence(void *ptr); @@ -12591,7 +12591,7 @@ cl_mem_fence_flags __ovld get_fence(void *ptr); * where gentype is builtin type or user defined type. */ -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) // OpenCL v1.1 s6.11.10, v1.2 s6.12.10, v2.0 s6.13.10 - Async Copies from Global to Local Memory, Local to Global Memory, and Prefetch @@ -13371,7 +13371,7 @@ unsigned long __ovld atom_xor(volatile __local unsigned long *p, unsigned long v // OpenCL v2.0 s6.13.11 - Atomics Functions -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) // double atomics support requires extensions cl_khr_int64_base_atomics and cl_khr_int64_extended_atomics #if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) @@ -13692,7 +13692,7 @@ void __ovld atomic_flag_clear(volatile atomic_flag *object); void __ovld atomic_flag_clear_explicit(volatile atomic_flag *object, memory_order order); void __ovld atomic_flag_clear_explicit(volatile atomic_flag *object, memory_order order, memory_scope scope); -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) // OpenCL v1.1 s6.11.12, v1.2 s6.12.12, v2.0 s6.13.12 - Miscellaneous Vector Functions @@ -14186,7 +14186,7 @@ half16 __ovld __cnfn shuffle2(half8 x, half8 y, ushort16 mask); half16 __ovld __cnfn shuffle2(half16 x, half16 y, ushort16 mask); #endif //cl_khr_fp16 -#if __OPENCL_C_VERSION__ >= CL_VERSION_1_2 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2) // OpenCL v1.2 s6.12.13, v2.0 s6.13.13 - printf int printf(__constant const char* st, ...) __attribute__((format(printf, 1, 2))); @@ -14307,7 +14307,7 @@ int4 __purefn __ovld read_imagei(read_only image3d_t image, sampler_t sampler, f uint4 __purefn __ovld read_imageui(read_only image3d_t image, sampler_t sampler, int4 coord); uint4 __purefn __ovld read_imageui(read_only image3d_t image, sampler_t sampler, float4 coord); -#if __OPENCL_C_VERSION__ >= CL_VERSION_1_2 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2) float4 __purefn __ovld read_imagef(read_only image2d_array_t image_array, sampler_t sampler, int4 coord); float4 __purefn __ovld read_imagef(read_only image2d_array_t image_array, sampler_t sampler, float4 coord); @@ -14315,7 +14315,7 @@ int4 __purefn __ovld read_imagei(read_only image2d_array_t image_array, sampler_ int4 __purefn __ovld read_imagei(read_only image2d_array_t image_array, sampler_t sampler, float4 coord); uint4 __purefn __ovld read_imageui(read_only image2d_array_t image_array, sampler_t sampler, int4 coord); uint4 __purefn __ovld read_imageui(read_only image2d_array_t image_array, sampler_t sampler, float4 coord); -#endif // __OPENCL_C_VERSION__ >= CL_VERSION_1_2 +#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2) float4 __purefn __ovld read_imagef(read_only image1d_t image, sampler_t sampler, int coord); float4 __purefn __ovld read_imagef(read_only image1d_t image, sampler_t sampler, float coord); @@ -14325,7 +14325,7 @@ int4 __purefn __ovld read_imagei(read_only image1d_t image, sampler_t sampler, f uint4 __purefn __ovld read_imageui(read_only image1d_t image, sampler_t sampler, int coord); uint4 __purefn __ovld read_imageui(read_only image1d_t image, sampler_t sampler, float coord); -#if __OPENCL_C_VERSION__ >= CL_VERSION_1_2 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2) float4 __purefn __ovld read_imagef(read_only image1d_array_t image_array, sampler_t sampler, int2 coord); float4 __purefn __ovld read_imagef(read_only image1d_array_t image_array, sampler_t sampler, float2 coord); @@ -14333,7 +14333,7 @@ int4 __purefn __ovld read_imagei(read_only image1d_array_t image_array, sampler_ int4 __purefn __ovld read_imagei(read_only image1d_array_t image_array, sampler_t sampler, float2 coord); uint4 __purefn __ovld read_imageui(read_only image1d_array_t image_array, sampler_t sampler, int2 coord); uint4 __purefn __ovld read_imageui(read_only image1d_array_t image_array, sampler_t sampler, float2 coord); -#endif // __OPENCL_C_VERSION__ >= CL_VERSION_1_2 +#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2) #ifdef cl_khr_depth_images float __purefn __ovld read_imagef(read_only image2d_depth_t image, sampler_t sampler, float2 coord); @@ -14358,7 +14358,7 @@ float __purefn __ovld read_imagef(read_only image2d_array_msaa_depth_t image, in #endif //cl_khr_gl_msaa_sharing // OpenCL Extension v2.0 s9.18 - Mipmaps -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) #ifdef cl_khr_mipmap_image float4 __purefn __ovld read_imagef(read_only image1d_t image, sampler_t sampler, float coord, float lod); @@ -14410,9 +14410,9 @@ int4 __purefn __ovld read_imagei(read_only image3d_t image, sampler_t sampler, f uint4 __purefn __ovld read_imageui(read_only image3d_t image, sampler_t sampler, float4 coord, float4 gradientX, float4 gradientY); #endif //cl_khr_mipmap_image -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) -#if __OPENCL_C_VERSION__ >= CL_VERSION_1_2 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2) /** * Sampler-less Image Access @@ -14447,7 +14447,7 @@ float4 __purefn __ovld read_imagef(read_only image3d_t image, int4 coord); int4 __purefn __ovld read_imagei(read_only image3d_t image, int4 coord); uint4 __purefn __ovld read_imageui(read_only image3d_t image, int4 coord); -#endif // __OPENCL_C_VERSION__ >= CL_VERSION_1_2 +#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2) // Image read functions returning half4 type #ifdef cl_khr_fp16 @@ -14457,7 +14457,7 @@ half4 __purefn __ovld read_imageh(read_only image2d_t image, sampler_t sampler, half4 __purefn __ovld read_imageh(read_only image2d_t image, sampler_t sampler, float2 coord); half4 __purefn __ovld read_imageh(read_only image3d_t image, sampler_t sampler, int4 coord); half4 __purefn __ovld read_imageh(read_only image3d_t image, sampler_t sampler, float4 coord); -#if __OPENCL_C_VERSION__ >= CL_VERSION_1_2 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2) half4 __purefn __ovld read_imageh(read_only image1d_array_t image, sampler_t sampler, int2 coord); half4 __purefn __ovld read_imageh(read_only image1d_array_t image, sampler_t sampler, float2 coord); half4 __purefn __ovld read_imageh(read_only image2d_array_t image, sampler_t sampler, int4 coord); @@ -14471,11 +14471,11 @@ half4 __purefn __ovld read_imageh(read_only image3d_t image, int4 coord); half4 __purefn __ovld read_imageh(read_only image1d_array_t image, int2 coord); half4 __purefn __ovld read_imageh(read_only image2d_array_t image, int4 coord); half4 __purefn __ovld read_imageh(read_only image1d_buffer_t image, int coord); -#endif // __OPENCL_C_VERSION__ >= CL_VERSION_1_2 +#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2) #endif //cl_khr_fp16 // Image read functions for read_write images -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) float4 __purefn __ovld read_imagef(read_write image1d_t image, int coord); int4 __purefn __ovld read_imagei(read_write image1d_t image, int coord); uint4 __purefn __ovld read_imageui(read_write image1d_t image, int coord); @@ -14518,7 +14518,7 @@ float __purefn __ovld read_imagef(read_write image2d_msaa_depth_t image, int2 co float __purefn __ovld read_imagef(read_write image2d_array_msaa_depth_t image, int4 coord, int sample); #endif //cl_khr_gl_msaa_sharing -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) #ifdef cl_khr_mipmap_image float4 __purefn __ovld read_imagef(read_write image1d_t image, sampler_t sampler, float coord, float lod); int4 __purefn __ovld read_imagei(read_write image1d_t image, sampler_t sampler, float coord, float lod); @@ -14569,7 +14569,7 @@ int4 __purefn __ovld read_imagei(read_write image3d_t image, sampler_t sampler, uint4 __purefn __ovld read_imageui(read_write image3d_t image, sampler_t sampler, float4 coord, float4 gradientX, float4 gradientY); #endif //cl_khr_mipmap_image -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) // Image read functions returning half4 type #ifdef cl_khr_fp16 @@ -14580,7 +14580,7 @@ half4 __purefn __ovld read_imageh(read_write image1d_array_t image, int2 coord); half4 __purefn __ovld read_imageh(read_write image2d_array_t image, int4 coord); half4 __purefn __ovld read_imageh(read_write image1d_buffer_t image, int coord); #endif //cl_khr_fp16 -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * Write color value to location specified by coordinate @@ -14681,7 +14681,7 @@ void __ovld write_imagef(write_only image2d_array_depth_t image, int4 coord, flo #endif //cl_khr_depth_images // OpenCL Extension v2.0 s9.18 - Mipmaps -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) #ifdef cl_khr_mipmap_image void __ovld write_imagef(write_only image1d_t image, int coord, int lod, float4 color); void __ovld write_imagei(write_only image1d_t image, int coord, int lod, int4 color); @@ -14708,7 +14708,7 @@ void __ovld write_imagei(write_only image3d_t image, int4 coord, int lod, int4 c void __ovld write_imageui(write_only image3d_t image, int4 coord, int lod, uint4 color); #endif #endif //cl_khr_mipmap_image -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) // Image write functions for half4 type #ifdef cl_khr_fp16 @@ -14723,7 +14723,7 @@ void __ovld write_imageh(write_only image1d_buffer_t image, int coord, half4 col #endif //cl_khr_fp16 // Image write functions for read_write images -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) void __ovld write_imagef(read_write image2d_t image, int2 coord, float4 color); void __ovld write_imagei(read_write image2d_t image, int2 coord, int4 color); void __ovld write_imageui(read_write image2d_t image, int2 coord, uint4 color); @@ -14755,7 +14755,7 @@ void __ovld write_imagef(read_write image2d_depth_t image, int2 coord, float col void __ovld write_imagef(read_write image2d_array_depth_t image, int4 coord, float color); #endif //cl_khr_depth_images -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) #ifdef cl_khr_mipmap_image void __ovld write_imagef(read_write image1d_t image, int coord, int lod, float4 color); void __ovld write_imagei(read_write image1d_t image, int coord, int lod, int4 color); @@ -14782,7 +14782,7 @@ void __ovld write_imagei(read_write image3d_t image, int4 coord, int lod, int4 c void __ovld write_imageui(read_write image3d_t image, int4 coord, int lod, uint4 color); #endif #endif //cl_khr_mipmap_image -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) // Image write functions for half4 type #ifdef cl_khr_fp16 @@ -14795,7 +14795,7 @@ void __ovld write_imageh(read_write image1d_array_t image, int2 coord, half4 col void __ovld write_imageh(read_write image2d_array_t image, int4 coord, half4 color); void __ovld write_imageh(read_write image1d_buffer_t image, int coord, half4 color); #endif //cl_khr_fp16 -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) // Note: In OpenCL v1.0/1.1/1.2, image argument of image query builtin functions does not have // access qualifier, which by default assume read_only access qualifier. Image query builtin @@ -14843,7 +14843,7 @@ int __ovld __cnfn get_image_width(write_only image2d_array_msaa_t image); int __ovld __cnfn get_image_width(write_only image2d_array_msaa_depth_t image); #endif //cl_khr_gl_msaa_sharing -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) int __ovld __cnfn get_image_width(read_write image1d_t image); int __ovld __cnfn get_image_width(read_write image1d_buffer_t image); int __ovld __cnfn get_image_width(read_write image2d_t image); @@ -14860,7 +14860,7 @@ int __ovld __cnfn get_image_width(read_write image2d_msaa_depth_t image); int __ovld __cnfn get_image_width(read_write image2d_array_msaa_t image); int __ovld __cnfn get_image_width(read_write image2d_array_msaa_depth_t image); #endif //cl_khr_gl_msaa_sharing -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * Return the image height in pixels. @@ -14895,7 +14895,7 @@ int __ovld __cnfn get_image_height(write_only image2d_array_msaa_t image); int __ovld __cnfn get_image_height(write_only image2d_array_msaa_depth_t image); #endif //cl_khr_gl_msaa_sharing -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) int __ovld __cnfn get_image_height(read_write image2d_t image); int __ovld __cnfn get_image_height(read_write image3d_t image); int __ovld __cnfn get_image_height(read_write image2d_array_t image); @@ -14909,7 +14909,7 @@ int __ovld __cnfn get_image_height(read_write image2d_msaa_depth_t image); int __ovld __cnfn get_image_height(read_write image2d_array_msaa_t image); int __ovld __cnfn get_image_height(read_write image2d_array_msaa_depth_t image); #endif //cl_khr_gl_msaa_sharing -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * Return the image depth in pixels. @@ -14920,12 +14920,12 @@ int __ovld __cnfn get_image_depth(read_only image3d_t image); int __ovld __cnfn get_image_depth(write_only image3d_t image); #endif -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) int __ovld __cnfn get_image_depth(read_write image3d_t image); -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) // OpenCL Extension v2.0 s9.18 - Mipmaps -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) #ifdef cl_khr_mipmap_image /** * Return the image miplevels. @@ -14961,7 +14961,7 @@ int __ovld get_image_num_mip_levels(read_write image2d_array_depth_t image); int __ovld get_image_num_mip_levels(read_write image2d_depth_t image); #endif //cl_khr_mipmap_image -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * Return the channel data type. Valid values are: @@ -15018,7 +15018,7 @@ int __ovld __cnfn get_image_channel_data_type(write_only image2d_array_msaa_t im int __ovld __cnfn get_image_channel_data_type(write_only image2d_array_msaa_depth_t image); #endif //cl_khr_gl_msaa_sharing -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) int __ovld __cnfn get_image_channel_data_type(read_write image1d_t image); int __ovld __cnfn get_image_channel_data_type(read_write image1d_buffer_t image); int __ovld __cnfn get_image_channel_data_type(read_write image2d_t image); @@ -15035,7 +15035,7 @@ int __ovld __cnfn get_image_channel_data_type(read_write image2d_msaa_depth_t im int __ovld __cnfn get_image_channel_data_type(read_write image2d_array_msaa_t image); int __ovld __cnfn get_image_channel_data_type(read_write image2d_array_msaa_depth_t image); #endif //cl_khr_gl_msaa_sharing -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * Return the image channel order. Valid values are: @@ -15090,7 +15090,7 @@ int __ovld __cnfn get_image_channel_order(write_only image2d_array_msaa_t image) int __ovld __cnfn get_image_channel_order(write_only image2d_array_msaa_depth_t image); #endif //cl_khr_gl_msaa_sharing -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) int __ovld __cnfn get_image_channel_order(read_write image1d_t image); int __ovld __cnfn get_image_channel_order(read_write image1d_buffer_t image); int __ovld __cnfn get_image_channel_order(read_write image2d_t image); @@ -15107,7 +15107,7 @@ int __ovld __cnfn get_image_channel_order(read_write image2d_msaa_depth_t image) int __ovld __cnfn get_image_channel_order(read_write image2d_array_msaa_t image); int __ovld __cnfn get_image_channel_order(read_write image2d_array_msaa_depth_t image); #endif //cl_khr_gl_msaa_sharing -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * Return the 2D image width and height as an int2 @@ -15140,7 +15140,7 @@ int2 __ovld __cnfn get_image_dim(write_only image2d_array_msaa_t image); int2 __ovld __cnfn get_image_dim(write_only image2d_array_msaa_depth_t image); #endif //cl_khr_gl_msaa_sharing -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) int2 __ovld __cnfn get_image_dim(read_write image2d_t image); int2 __ovld __cnfn get_image_dim(read_write image2d_array_t image); #ifdef cl_khr_depth_images @@ -15153,7 +15153,7 @@ int2 __ovld __cnfn get_image_dim(read_write image2d_msaa_depth_t image); int2 __ovld __cnfn get_image_dim(read_write image2d_array_msaa_t image); int2 __ovld __cnfn get_image_dim(read_write image2d_array_msaa_depth_t image); #endif //cl_khr_gl_msaa_sharing -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * Return the 3D image width, height, and depth as an @@ -15165,9 +15165,9 @@ int4 __ovld __cnfn get_image_dim(read_only image3d_t image); #ifdef cl_khr_3d_image_writes int4 __ovld __cnfn get_image_dim(write_only image3d_t image); #endif -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) int4 __ovld __cnfn get_image_dim(read_write image3d_t image); -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * Return the image array size. @@ -15193,7 +15193,7 @@ size_t __ovld __cnfn get_image_array_size(write_only image2d_array_msaa_t image_ size_t __ovld __cnfn get_image_array_size(write_only image2d_array_msaa_depth_t image_array); #endif //cl_khr_gl_msaa_sharing -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) size_t __ovld __cnfn get_image_array_size(read_write image1d_array_t image_array); size_t __ovld __cnfn get_image_array_size(read_write image2d_array_t image_array); #ifdef cl_khr_depth_images @@ -15203,7 +15203,7 @@ size_t __ovld __cnfn get_image_array_size(read_write image2d_array_depth_t image size_t __ovld __cnfn get_image_array_size(read_write image2d_array_msaa_t image_array); size_t __ovld __cnfn get_image_array_size(read_write image2d_array_msaa_depth_t image_array); #endif //cl_khr_gl_msaa_sharing -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) /** * Return the number of samples associated with image @@ -15219,17 +15219,17 @@ int __ovld get_image_num_samples(write_only image2d_msaa_depth_t image); int __ovld get_image_num_samples(write_only image2d_array_msaa_t image); int __ovld get_image_num_samples(write_only image2d_array_msaa_depth_t image); -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) int __ovld get_image_num_samples(read_write image2d_msaa_t image); int __ovld get_image_num_samples(read_write image2d_msaa_depth_t image); int __ovld get_image_num_samples(read_write image2d_array_msaa_t image); int __ovld get_image_num_samples(read_write image2d_array_msaa_depth_t image); -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) #endif // OpenCL v2.0 s6.13.15 - Work-group Functions -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) int __ovld __conv work_group_all(int predicate); int __ovld __conv work_group_any(int predicate); @@ -15327,16 +15327,16 @@ double __ovld __conv work_group_scan_inclusive_min(double x); double __ovld __conv work_group_scan_inclusive_max(double x); #endif //cl_khr_fp64 -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) // OpenCL v2.0 s6.13.16 - Pipe Functions -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) bool __ovld is_valid_reserve_id(reserve_id_t reserve_id); -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) // OpenCL v2.0 s6.13.17 - Enqueue Kernels -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) ndrange_t __ovld ndrange_1D(size_t); ndrange_t __ovld ndrange_1D(size_t, size_t); @@ -15350,7 +15350,7 @@ ndrange_t __ovld ndrange_3D(const size_t[3]); ndrange_t __ovld ndrange_3D(const size_t[3], const size_t[3]); ndrange_t __ovld ndrange_3D(const size_t[3], const size_t[3], const size_t[3]); -int __ovld enqueue_marker(queue_t, uint, const __private clk_event_t*, __private clk_event_t*); +int __ovld enqueue_marker(queue_t, uint, const clk_event_t*, clk_event_t*); void __ovld retain_event(clk_event_t); @@ -15365,7 +15365,7 @@ bool __ovld is_valid_event (clk_event_t event); void __ovld capture_event_profiling_info(clk_event_t, clk_profiling_info, __global void* value); queue_t __ovld get_default_queue(void); -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) // OpenCL Extension v2.0 s9.17 - Sub-groups @@ -15374,16 +15374,16 @@ queue_t __ovld get_default_queue(void); uint __ovld get_sub_group_size(void); uint __ovld get_max_sub_group_size(void); uint __ovld get_num_sub_groups(void); -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) uint __ovld get_enqueued_num_sub_groups(void); -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) uint __ovld get_sub_group_id(void); uint __ovld get_sub_group_local_id(void); void __ovld __conv sub_group_barrier(cl_mem_fence_flags flags); -#if __OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) void __ovld __conv sub_group_barrier(cl_mem_fence_flags flags, memory_scope scope); -#endif //__OPENCL_C_VERSION__ >= CL_VERSION_2_0 +#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) int __ovld __conv sub_group_all(int predicate); int __ovld __conv sub_group_any(int predicate); @@ -15573,12 +15573,12 @@ uint2 __ovld __conv intel_sub_group_block_read2( read_only image2d_t image, in uint4 __ovld __conv intel_sub_group_block_read4( read_only image2d_t image, int2 coord ); uint8 __ovld __conv intel_sub_group_block_read8( read_only image2d_t image, int2 coord ); -#if (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) uint __ovld __conv intel_sub_group_block_read(read_write image2d_t image, int2 coord); uint2 __ovld __conv intel_sub_group_block_read2(read_write image2d_t image, int2 coord); uint4 __ovld __conv intel_sub_group_block_read4(read_write image2d_t image, int2 coord); uint8 __ovld __conv intel_sub_group_block_read8(read_write image2d_t image, int2 coord); -#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) uint __ovld __conv intel_sub_group_block_read( const __global uint* p ); uint2 __ovld __conv intel_sub_group_block_read2( const __global uint* p ); @@ -15590,12 +15590,12 @@ void __ovld __conv intel_sub_group_block_write2(write_only image2d_t image, i void __ovld __conv intel_sub_group_block_write4(write_only image2d_t image, int2 coord, uint4 data); void __ovld __conv intel_sub_group_block_write8(write_only image2d_t image, int2 coord, uint8 data); -#if (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) void __ovld __conv intel_sub_group_block_write(read_write image2d_t image, int2 coord, uint data); void __ovld __conv intel_sub_group_block_write2(read_write image2d_t image, int2 coord, uint2 data); void __ovld __conv intel_sub_group_block_write4(read_write image2d_t image, int2 coord, uint4 data); void __ovld __conv intel_sub_group_block_write8(read_write image2d_t image, int2 coord, uint8 data); -#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) void __ovld __conv intel_sub_group_block_write( __global uint* p, uint data ); void __ovld __conv intel_sub_group_block_write2( __global uint* p, uint2 data ); @@ -15713,12 +15713,12 @@ uint2 __ovld __conv intel_sub_group_block_read_ui2( read_only image2d_t ima uint4 __ovld __conv intel_sub_group_block_read_ui4( read_only image2d_t image, int2 byte_coord ); uint8 __ovld __conv intel_sub_group_block_read_ui8( read_only image2d_t image, int2 byte_coord ); -#if (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) uint __ovld __conv intel_sub_group_block_read_ui( read_write image2d_t image, int2 byte_coord ); uint2 __ovld __conv intel_sub_group_block_read_ui2( read_write image2d_t image, int2 byte_coord ); uint4 __ovld __conv intel_sub_group_block_read_ui4( read_write image2d_t image, int2 byte_coord ); uint8 __ovld __conv intel_sub_group_block_read_ui8( read_write image2d_t image, int2 byte_coord ); -#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) uint __ovld __conv intel_sub_group_block_read_ui( const __global uint* p ); uint2 __ovld __conv intel_sub_group_block_read_ui2( const __global uint* p ); @@ -15730,12 +15730,12 @@ void __ovld __conv intel_sub_group_block_write_ui2( read_only image2d_t im void __ovld __conv intel_sub_group_block_write_ui4( read_only image2d_t image, int2 byte_coord, uint4 data ); void __ovld __conv intel_sub_group_block_write_ui8( read_only image2d_t image, int2 byte_coord, uint8 data ); -#if (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) void __ovld __conv intel_sub_group_block_write_ui( read_write image2d_t image, int2 byte_coord, uint data ); void __ovld __conv intel_sub_group_block_write_ui2( read_write image2d_t image, int2 byte_coord, uint2 data ); void __ovld __conv intel_sub_group_block_write_ui4( read_write image2d_t image, int2 byte_coord, uint4 data ); void __ovld __conv intel_sub_group_block_write_ui8( read_write image2d_t image, int2 byte_coord, uint8 data ); -#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) void __ovld __conv intel_sub_group_block_write_ui( __global uint* p, uint data ); void __ovld __conv intel_sub_group_block_write_ui2( __global uint* p, uint2 data ); @@ -15747,12 +15747,12 @@ ushort2 __ovld __conv intel_sub_group_block_read_us2( read_only image2d_t im ushort4 __ovld __conv intel_sub_group_block_read_us4( read_only image2d_t image, int2 coord ); ushort8 __ovld __conv intel_sub_group_block_read_us8( read_only image2d_t image, int2 coord ); -#if (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) ushort __ovld __conv intel_sub_group_block_read_us(read_write image2d_t image, int2 coord); ushort2 __ovld __conv intel_sub_group_block_read_us2(read_write image2d_t image, int2 coord); ushort4 __ovld __conv intel_sub_group_block_read_us4(read_write image2d_t image, int2 coord); ushort8 __ovld __conv intel_sub_group_block_read_us8(read_write image2d_t image, int2 coord); -#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) ushort __ovld __conv intel_sub_group_block_read_us( const __global ushort* p ); ushort2 __ovld __conv intel_sub_group_block_read_us2( const __global ushort* p ); @@ -15764,12 +15764,12 @@ void __ovld __conv intel_sub_group_block_write_us2(write_only image2d_t i void __ovld __conv intel_sub_group_block_write_us4(write_only image2d_t image, int2 coord, ushort4 data); void __ovld __conv intel_sub_group_block_write_us8(write_only image2d_t image, int2 coord, ushort8 data); -#if (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) void __ovld __conv intel_sub_group_block_write_us(read_write image2d_t image, int2 coord, ushort data); void __ovld __conv intel_sub_group_block_write_us2(read_write image2d_t image, int2 coord, ushort2 data); void __ovld __conv intel_sub_group_block_write_us4(read_write image2d_t image, int2 coord, ushort4 data); void __ovld __conv intel_sub_group_block_write_us8(read_write image2d_t image, int2 coord, ushort8 data); -#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif // defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) void __ovld __conv intel_sub_group_block_write_us( __global ushort* p, ushort data ); void __ovld __conv intel_sub_group_block_write_us2( __global ushort* p, ushort2 data ); diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 2756042f23eb..5658f46c99de 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -33,6 +33,7 @@ #include "clang/Lex/Token.h" #include "clang/Lex/VariadicMacroSupport.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/STLExtras.h" @@ -2399,6 +2400,13 @@ MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody( Token Tok; LexUnexpandedToken(Tok); + // Ensure we consume the rest of the macro body if errors occur. + auto _ = llvm::make_scope_exit([&]() { + // The flag indicates if we are still waiting for 'eod'. + if (CurLexer->ParsingPreprocessorDirective) + DiscardUntilEndOfDirective(); + }); + // Used to un-poison and then re-poison identifiers of the __VA_ARGS__ ilk // within their appropriate context. VariadicMacroScopeGuard VariadicMacroScopeGuard(*this); @@ -2420,12 +2428,8 @@ MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody( } else if (Tok.is(tok::l_paren)) { // This is a function-like macro definition. Read the argument list. MI->setIsFunctionLike(); - if (ReadMacroParameterList(MI, LastTok)) { - // Throw away the rest of the line. - if (CurPPLexer->ParsingPreprocessorDirective) - DiscardUntilEndOfDirective(); + if (ReadMacroParameterList(MI, LastTok)) return nullptr; - } // If this is a definition of an ISO C/C++ variadic function-like macro (not // using the GNU named varargs extension) inform our variadic scope guard diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 11fed28b52db..485d39e2c9e8 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -961,6 +961,7 @@ void Sema::ActOnEndOfTranslationUnit() { // All dllexport classes should have been processed already. assert(DelayedDllExportClasses.empty()); + assert(DelayedDllExportMemberFunctions.empty()); // Remove file scoped decls that turned out to be used. UnusedFileScopedDecls.erase( diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index a6c52b7d4b2b..8f19edbc4f36 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1984,10 +1984,27 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, ASTContext::GetBuiltinTypeError Error; QualType R = Context.GetBuiltinType(ID, Error); if (Error) { - if (ForRedeclaration) - Diag(Loc, diag::warn_implicit_decl_requires_sysheader) - << getHeaderName(Context.BuiltinInfo, ID, Error) + if (!ForRedeclaration) + return nullptr; + + // If we have a builtin without an associated type we should not emit a + // warning when we were not able to find a type for it. + if (Error == ASTContext::GE_Missing_type) + return nullptr; + + // If we could not find a type for setjmp it is because the jmp_buf type was + // not defined prior to the setjmp declaration. + if (Error == ASTContext::GE_Missing_setjmp) { + Diag(Loc, diag::warn_implicit_decl_no_jmp_buf) << Context.BuiltinInfo.getName(ID); + return nullptr; + } + + // Generally, we emit a warning that the declaration requires the + // appropriate header. + Diag(Loc, diag::warn_implicit_decl_requires_sysheader) + << getHeaderName(Context.BuiltinInfo, ID, Error) + << Context.BuiltinInfo.getName(ID); return nullptr; } @@ -11527,9 +11544,12 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { // Check for self-references within variable initializers. // Variables declared within a function/method body (except for references) // are handled by a dataflow analysis. - if (!VDecl->hasLocalStorage() || VDecl->getType()->isRecordType() || - VDecl->getType()->isReferenceType()) { - CheckSelfReference(*this, RealDecl, Init, DirectInit); + // This is undefined behavior in C++, but valid in C. + if (getLangOpts().CPlusPlus) { + if (!VDecl->hasLocalStorage() || VDecl->getType()->isRecordType() || + VDecl->getType()->isReferenceType()) { + CheckSelfReference(*this, RealDecl, Init, DirectInit); + } } // If the type changed, it means we had an incomplete type that was diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 9a6385f28319..2f9e4f961f4d 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1030,8 +1030,10 @@ static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T, TemplateArgumentListInfo Args(Loc, Loc); Args.addArgument(getTrivialTypeTemplateArgument(S, Loc, T)); - // If there's no tuple_size specialization, it's not tuple-like. - if (lookupStdTypeTraitMember(S, R, Loc, "tuple_size", Args, /*DiagID*/0)) + // If there's no tuple_size specialization or the lookup of 'value' is empty, + // it's not tuple-like. + if (lookupStdTypeTraitMember(S, R, Loc, "tuple_size", Args, /*DiagID*/ 0) || + R.empty()) return IsTupleLike::NotTupleLike; // If we get this far, we've committed to the tuple interpretation, but @@ -1048,11 +1050,6 @@ static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T, } } Diagnoser(R, Args); - if (R.empty()) { - Diagnoser.diagnoseNotICE(S, Loc, SourceRange()); - return IsTupleLike::Error; - } - ExprResult E = S.BuildDeclarationNameExpr(CXXScopeSpec(), R, /*NeedsADL*/false); if (E.isInvalid()) @@ -1228,7 +1225,8 @@ static bool checkTupleLikeDecomposition(Sema &S, if (E.isInvalid()) return true; RefVD->setInit(E.get()); - RefVD->checkInitIsICE(); + if (!E.get()->isValueDependent()) + RefVD->checkInitIsICE(); E = S.BuildDeclarationNameExpr(CXXScopeSpec(), DeclarationNameInfo(B->getDeclName(), Loc), @@ -6165,8 +6163,8 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { M->dropAttr(); if (M->hasAttr()) { - DefineImplicitSpecialMember(*this, M, M->getLocation()); - ActOnFinishInlineFunctionDef(M); + // Define after any fields with in-class initializers have been parsed. + DelayedDllExportMemberFunctions.push_back(M); } } }; @@ -11419,6 +11417,21 @@ void Sema::ActOnFinishCXXMemberDecls() { void Sema::ActOnFinishCXXNonNestedClass(Decl *D) { referenceDLLExportedClassMethods(); + + if (!DelayedDllExportMemberFunctions.empty()) { + SmallVector WorkList; + std::swap(DelayedDllExportMemberFunctions, WorkList); + for (CXXMethodDecl *M : WorkList) { + DefineImplicitSpecialMember(*this, M, M->getLocation()); + + // Pass the method to the consumer to get emitted. This is not necessary + // for explicit instantiation definitions, as they will get emitted + // anyway. + if (M->getParent()->getTemplateSpecializationKind() != + TSK_ExplicitInstantiationDefinition) + ActOnFinishInlineFunctionDef(M); + } + } } void Sema::referenceDLLExportedClassMethods() { diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 705e3b9bd7fb..c1c08969c7bd 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -6794,14 +6794,10 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, // it's legal for the type to be incomplete if this is a pseudo-destructor // call. We'll do more incomplete-type checks later in the lookup process, // so just skip this check for ObjC types. - if (BaseType->isObjCObjectOrInterfaceType()) { + if (!BaseType->isRecordType()) { ObjectType = ParsedType::make(BaseType); MayBePseudoDestructor = true; return Base; - } else if (!BaseType->isRecordType()) { - ObjectType = nullptr; - MayBePseudoDestructor = true; - return Base; } // The object type must be complete (or dependent), or diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index bc1069609336..60f34775c6b2 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -1289,7 +1289,16 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // FIXME: Better EqualLoc? InitializationKind Kind = InitializationKind::CreateCopy(expr->getBeginLoc(), SourceLocation()); - InitializationSequence Seq(SemaRef, Entity, Kind, expr, + + // Vector elements can be initialized from other vectors in which case + // we need initialization entity with a type of a vector (and not a vector + // element!) initializing multiple vector elements. + auto TmpEntity = + (ElemType->isExtVectorType() && !Entity.getType()->isExtVectorType()) + ? InitializedEntity::InitializeTemporary(ElemType) + : Entity; + + InitializationSequence Seq(SemaRef, TmpEntity, Kind, expr, /*TopLevelOfInitList*/ true); // C++14 [dcl.init.aggr]p13: @@ -1300,8 +1309,7 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // assignment-expression. if (Seq || isa(expr)) { if (!VerifyOnly) { - ExprResult Result = - Seq.Perform(SemaRef, Entity, Kind, expr); + ExprResult Result = Seq.Perform(SemaRef, TmpEntity, Kind, expr); if (Result.isInvalid()) hadError = true; @@ -8108,7 +8116,7 @@ ExprResult InitializationSequence::Perform(Sema &S, // argument passing. assert(Step->Type->isSamplerT() && "Sampler initialization on non-sampler type."); - Expr *Init = CurInit.get(); + Expr *Init = CurInit.get()->IgnoreParens(); QualType SourceType = Init->getType(); // Case 1 if (Entity.isParameterKind()) { diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index bd68011c18b2..4ac87469bf44 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -139,6 +139,7 @@ class DSAStackTy { /// clause, false otherwise. llvm::Optional> OrderedRegion; unsigned AssociatedLoops = 1; + bool HasMutipleLoops = false; const Decl *PossiblyLoopCounter = nullptr; bool NowaitRegion = false; bool CancelRegion = false; @@ -678,12 +679,19 @@ class DSAStackTy { /// Set collapse value for the region. void setAssociatedLoops(unsigned Val) { getTopOfStack().AssociatedLoops = Val; + if (Val > 1) + getTopOfStack().HasMutipleLoops = true; } /// Return collapse value for region. unsigned getAssociatedLoops() const { const SharingMapTy *Top = getTopOfStackOrNull(); return Top ? Top->AssociatedLoops : 0; } + /// Returns true if the construct is associated with multiple loops. + bool hasMutipleLoops() const { + const SharingMapTy *Top = getTopOfStackOrNull(); + return Top ? Top->HasMutipleLoops : false; + } /// Marks current target region as one with closely nested teams /// region. @@ -1874,6 +1882,13 @@ bool Sema::isOpenMPPrivateDecl(const ValueDecl *D, unsigned Level) const { !isOpenMPSimdDirective(DSAStack->getCurrentDirective())) return true; } + if (const auto *VD = dyn_cast(D)) { + if (DSAStack->isThreadPrivate(const_cast(VD)) && + DSAStack->isForceVarCapturing() && + !DSAStack->hasExplicitDSA( + D, [](OpenMPClauseKind K) { return K == OMPC_copyin; }, Level)) + return true; + } return DSAStack->hasExplicitDSA( D, [](OpenMPClauseKind K) { return K == OMPC_private; }, Level) || (DSAStack->isClauseParsingMode() && @@ -5604,13 +5619,14 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { if (!ISC.checkAndSetInit(Init, /*EmitDiags=*/false)) { if (ValueDecl *D = ISC.getLoopDecl()) { auto *VD = dyn_cast(D); + DeclRefExpr *PrivateRef = nullptr; if (!VD) { if (VarDecl *Private = isOpenMPCapturedDecl(D)) { VD = Private; } else { - DeclRefExpr *Ref = buildCapture(*this, D, ISC.getLoopDeclRefExpr(), - /*WithInit=*/false); - VD = cast(Ref->getDecl()); + PrivateRef = buildCapture(*this, D, ISC.getLoopDeclRefExpr(), + /*WithInit=*/false); + VD = cast(PrivateRef->getDecl()); } } DSAStack->addLoopControlVariable(D, VD); @@ -5623,6 +5639,49 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { Var->getType().getNonLValueExprType(Context), ForLoc, /*RefersToCapture=*/true)); } + OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); + // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables + // Referenced in a Construct, C/C++]. The loop iteration variable in the + // associated for-loop of a simd construct with just one associated + // for-loop may be listed in a linear clause with a constant-linear-step + // that is the increment of the associated for-loop. The loop iteration + // variable(s) in the associated for-loop(s) of a for or parallel for + // construct may be listed in a private or lastprivate clause. + DSAStackTy::DSAVarData DVar = + DSAStack->getTopDSA(D, /*FromParent=*/false); + // If LoopVarRefExpr is nullptr it means the corresponding loop variable + // is declared in the loop and it is predetermined as a private. + Expr *LoopDeclRefExpr = ISC.getLoopDeclRefExpr(); + OpenMPClauseKind PredeterminedCKind = + isOpenMPSimdDirective(DKind) + ? (DSAStack->hasMutipleLoops() ? OMPC_lastprivate : OMPC_linear) + : OMPC_private; + if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && + DVar.CKind != PredeterminedCKind && DVar.RefExpr && + (LangOpts.OpenMP <= 45 || (DVar.CKind != OMPC_lastprivate && + DVar.CKind != OMPC_private))) || + ((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop || + isOpenMPDistributeDirective(DKind)) && + !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && + DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) && + (DVar.CKind != OMPC_private || DVar.RefExpr)) { + Diag(Init->getBeginLoc(), diag::err_omp_loop_var_dsa) + << getOpenMPClauseName(DVar.CKind) + << getOpenMPDirectiveName(DKind) + << getOpenMPClauseName(PredeterminedCKind); + if (DVar.RefExpr == nullptr) + DVar.CKind = PredeterminedCKind; + reportOriginalDsa(*this, DSAStack, D, DVar, + /*IsLoopIterVar=*/true); + } else if (LoopDeclRefExpr) { + // Make the loop iteration variable private (for worksharing + // constructs), linear (for simd directives with the only one + // associated loop) or lastprivate (for simd directives with several + // collapsed or ordered loops). + if (DVar.CKind == OMPC_unknown) + DSAStack->addDSA(D, LoopDeclRefExpr, PredeterminedCKind, + PrivateRef); + } } } DSAStack->setAssociatedLoops(AssociatedLoops - 1); @@ -5677,8 +5736,6 @@ static bool checkOpenMPIterationSpace( // Check loop variable's type. if (ValueDecl *LCDecl = ISC.getLoopDecl()) { - Expr *LoopDeclRefExpr = ISC.getLoopDeclRefExpr(); - // OpenMP [2.6, Canonical Loop Form] // Var is one of the following: // A variable of signed or unsigned integer type. @@ -5704,46 +5761,6 @@ static bool checkOpenMPIterationSpace( // sharing attributes. VarsWithImplicitDSA.erase(LCDecl); - // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced - // in a Construct, C/C++]. - // The loop iteration variable in the associated for-loop of a simd - // construct with just one associated for-loop may be listed in a linear - // clause with a constant-linear-step that is the increment of the - // associated for-loop. - // The loop iteration variable(s) in the associated for-loop(s) of a for or - // parallel for construct may be listed in a private or lastprivate clause. - DSAStackTy::DSAVarData DVar = DSA.getTopDSA(LCDecl, false); - // If LoopVarRefExpr is nullptr it means the corresponding loop variable is - // declared in the loop and it is predetermined as a private. - OpenMPClauseKind PredeterminedCKind = - isOpenMPSimdDirective(DKind) - ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate) - : OMPC_private; - if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && - DVar.CKind != PredeterminedCKind && DVar.RefExpr && - (SemaRef.getLangOpts().OpenMP <= 45 || - (DVar.CKind != OMPC_lastprivate && DVar.CKind != OMPC_private))) || - ((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop || - isOpenMPDistributeDirective(DKind)) && - !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && - DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) && - (DVar.CKind != OMPC_private || DVar.RefExpr)) { - SemaRef.Diag(Init->getBeginLoc(), diag::err_omp_loop_var_dsa) - << getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind) - << getOpenMPClauseName(PredeterminedCKind); - if (DVar.RefExpr == nullptr) - DVar.CKind = PredeterminedCKind; - reportOriginalDsa(SemaRef, &DSA, LCDecl, DVar, /*IsLoopIterVar=*/true); - HasErrors = true; - } else if (LoopDeclRefExpr != nullptr) { - // Make the loop iteration variable private (for worksharing constructs), - // linear (for simd directives with the only one associated loop) or - // lastprivate (for simd directives with several collapsed or ordered - // loops). - if (DVar.CKind == OMPC_unknown) - DSA.addDSA(LCDecl, LoopDeclRefExpr, PredeterminedCKind); - } - assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars"); // Check test-expr. diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index b123a739a7ab..9b051e02d127 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -383,25 +383,19 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, } else if (Info.requiresImmediateConstant() && !Info.allowsRegister()) { if (!InputExpr->isValueDependent()) { Expr::EvalResult EVResult; - if (!InputExpr->EvaluateAsRValue(EVResult, Context, true)) - return StmtError( - Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected) - << Info.getConstraintStr() << InputExpr->getSourceRange()); - - // For compatibility with GCC, we also allow pointers that would be - // integral constant expressions if they were cast to int. - llvm::APSInt IntResult; - if (!EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(), - Context)) - return StmtError( - Diag(InputExpr->getBeginLoc(), diag::err_asm_immediate_expected) - << Info.getConstraintStr() << InputExpr->getSourceRange()); - - if (!Info.isValidAsmImmediate(IntResult)) - return StmtError(Diag(InputExpr->getBeginLoc(), - diag::err_invalid_asm_value_for_constraint) - << IntResult.toString(10) << Info.getConstraintStr() - << InputExpr->getSourceRange()); + if (InputExpr->EvaluateAsRValue(EVResult, Context, true)) { + // For compatibility with GCC, we also allow pointers that would be + // integral constant expressions if they were cast to int. + llvm::APSInt IntResult; + if (EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(), + Context)) + if (!Info.isValidAsmImmediate(IntResult)) + return StmtError(Diag(InputExpr->getBeginLoc(), + diag::err_invalid_asm_value_for_constraint) + << IntResult.toString(10) + << Info.getConstraintStr() + << InputExpr->getSourceRange()); + } } } else { diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 3212281cc34d..135ca2b25cbe 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -362,13 +362,27 @@ bool Sema::LookupTemplateName(LookupResult &Found, // x->B::f, and we are looking into the type of the object. assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); LookupCtx = computeDeclContext(ObjectType); - IsDependent = !LookupCtx; + IsDependent = !LookupCtx && ObjectType->isDependentType(); assert((IsDependent || !ObjectType->isIncompleteType() || ObjectType->castAs()->isBeingDefined()) && "Caller should have completed object type"); - // Template names cannot appear inside an Objective-C class or object type. - if (ObjectType->isObjCObjectOrInterfaceType()) { + // Template names cannot appear inside an Objective-C class or object type + // or a vector type. + // + // FIXME: This is wrong. For example: + // + // template using Vec = T __attribute__((ext_vector_type(4))); + // Vec vi; + // vi.Vec::~Vec(); + // + // ... should be accepted but we will not treat 'Vec' as a template name + // here. The right thing to do would be to check if the name is a valid + // vector component name, and look up a template name if not. And similarly + // for lookups into Objective-C class and object types, where the same + // problem can arise. + if (ObjectType->isObjCObjectOrInterfaceType() || + ObjectType->isVectorType()) { Found.clear(); return false; } @@ -4678,6 +4692,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, for (unsigned i = 0, e = Param->getDepth(); i != e; ++i) TemplateArgLists.addOuterTemplateArguments(None); + Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext()); EnterExpressionEvaluationContext ConstantEvaluated( SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); return SemaRef.SubstExpr(Param->getDefaultArgument(), TemplateArgLists); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 29acf6177eb9..2b9d06814d7a 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -7390,8 +7390,22 @@ static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State, bool IsPointee = ChunkIndex > 0 && (D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Pointer || - D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::BlockPointer || - D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Reference); + D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Reference || + D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::BlockPointer); + // For pointers/references to arrays the next chunk is always an array + // followed by any number of parentheses. + if (!IsPointee && ChunkIndex > 1) { + auto AdjustedCI = ChunkIndex - 1; + if (D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Array) + AdjustedCI--; + // Skip over all parentheses. + while (AdjustedCI > 0 && + D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Paren) + AdjustedCI--; + if (D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Pointer || + D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Reference) + IsPointee = true; + } bool IsFuncReturnType = ChunkIndex > 0 && D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Function; diff --git a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp index 736d80ef9ec7..a6539098c89a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp @@ -91,6 +91,22 @@ void EnumCastOutOfRangeChecker::reportWarning(CheckerContext &C) const { void EnumCastOutOfRangeChecker::checkPreStmt(const CastExpr *CE, CheckerContext &C) const { + + // Only perform enum range check on casts where such checks are valid. For + // all other cast kinds (where enum range checks are unnecessary or invalid), + // just return immediately. TODO: The set of casts whitelisted for enum + // range checking may be incomplete. Better to add a missing cast kind to + // enable a missing check than to generate false negatives and have to remove + // those later. + switch (CE->getCastKind()) { + case CK_IntegralCast: + break; + + default: + return; + break; + } + // Get the value of the expression to cast. const llvm::Optional ValueToCast = C.getSVal(CE->getSubExpr()).getAs(); diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp index 6f1060b5f26d..600458a743ea 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp @@ -406,13 +406,15 @@ void IteratorChecker::checkPreCall(const CallEvent &Call, } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) { if (const auto *InstCall = dyn_cast(&Call)) { // Check for out-of-range incrementions and decrementions - if (Call.getNumArgs() >= 1) { + if (Call.getNumArgs() >= 1 && + Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) { verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(), InstCall->getCXXThisVal(), Call.getArgSVal(0)); } } else { - if (Call.getNumArgs() >= 2) { + if (Call.getNumArgs() >= 2 && + Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) { verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(), Call.getArgSVal(0), Call.getArgSVal(1)); } @@ -590,14 +592,16 @@ void IteratorChecker::checkPostCall(const CallEvent &Call, return; } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) { if (const auto *InstCall = dyn_cast(&Call)) { - if (Call.getNumArgs() >= 1) { + if (Call.getNumArgs() >= 1 && + Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) { handleRandomIncrOrDecr(C, Func->getOverloadedOperator(), Call.getReturnValue(), InstCall->getCXXThisVal(), Call.getArgSVal(0)); return; } } else { - if (Call.getNumArgs() >= 2) { + if (Call.getNumArgs() >= 2 && + Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) { handleRandomIncrOrDecr(C, Func->getOverloadedOperator(), Call.getReturnValue(), Call.getArgSVal(0), Call.getArgSVal(1)); diff --git a/clang/test/Analysis/Inputs/system-header-simulator-cxx.h b/clang/test/Analysis/Inputs/system-header-simulator-cxx.h index 5b37e96f6027..30b25b85944b 100644 --- a/clang/test/Analysis/Inputs/system-header-simulator-cxx.h +++ b/clang/test/Analysis/Inputs/system-header-simulator-cxx.h @@ -70,6 +70,9 @@ template struct __vector_iterator { return ptr -= n; } + template + difference_type operator-(const __vector_iterator &rhs); + Ref operator*() const { return *ptr; } Ptr operator->() const { return *ptr; } diff --git a/clang/test/Analysis/diagnostics/explicit-suppression.cpp b/clang/test/Analysis/diagnostics/explicit-suppression.cpp index 2bb969059ffb..6bc01479b815 100644 --- a/clang/test/Analysis/diagnostics/explicit-suppression.cpp +++ b/clang/test/Analysis/diagnostics/explicit-suppression.cpp @@ -19,6 +19,6 @@ class C { void testCopyNull(C *I, C *E) { std::copy(I, E, (C *)0); #ifndef SUPPRESSED - // expected-warning@../Inputs/system-header-simulator-cxx.h:677 {{Called C++ object pointer is null}} + // expected-warning@../Inputs/system-header-simulator-cxx.h:680 {{Called C++ object pointer is null}} #endif } diff --git a/clang/test/Analysis/enum-cast-out-of-range.c b/clang/test/Analysis/enum-cast-out-of-range.c new file mode 100644 index 000000000000..03e1100c38f4 --- /dev/null +++ b/clang/test/Analysis/enum-cast-out-of-range.c @@ -0,0 +1,34 @@ +// RUN: %clang_analyze_cc1 \ +// RUN: -analyzer-checker=core,alpha.cplusplus.EnumCastOutOfRange \ +// RUN: -verify %s + +enum En_t { + En_0 = -4, + En_1, + En_2 = 1, + En_3, + En_4 = 4 +}; + +void unscopedUnspecifiedCStyle() { + enum En_t Below = (enum En_t)(-5); // expected-warning {{not in the valid range}} + enum En_t NegVal1 = (enum En_t)(-4); // OK. + enum En_t NegVal2 = (enum En_t)(-3); // OK. + enum En_t InRange1 = (enum En_t)(-2); // expected-warning {{not in the valid range}} + enum En_t InRange2 = (enum En_t)(-1); // expected-warning {{not in the valid range}} + enum En_t InRange3 = (enum En_t)(0); // expected-warning {{not in the valid range}} + enum En_t PosVal1 = (enum En_t)(1); // OK. + enum En_t PosVal2 = (enum En_t)(2); // OK. + enum En_t InRange4 = (enum En_t)(3); // expected-warning {{not in the valid range}} + enum En_t PosVal3 = (enum En_t)(4); // OK. + enum En_t Above = (enum En_t)(5); // expected-warning {{not in the valid range}} +} + +enum En_t unused; +void unusedExpr() { + // Following line is not something that EnumCastOutOfRangeChecker should + // evaluate. Checker should either ignore this line or process it without + // producing any warnings. However, compilation will (and should) still + // generate a warning having nothing to do with this checker. + unused; // expected-warning {{expression result unused}} +} diff --git a/clang/test/Analysis/enum-cast-out-of-range.cpp b/clang/test/Analysis/enum-cast-out-of-range.cpp index e77339b551e0..b600367f8c14 100644 --- a/clang/test/Analysis/enum-cast-out-of-range.cpp +++ b/clang/test/Analysis/enum-cast-out-of-range.cpp @@ -150,7 +150,15 @@ void scopedSpecifiedCStyle() { scoped_specified_t InvalidAfterRangeEnd = (scoped_specified_t)(5); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}} } -void rangeContstrained1(int input) { +unscoped_unspecified_t unused; +void unusedExpr() { + // following line is not something that EnumCastOutOfRangeChecker should evaluate. checker should either ignore this line + // or process it without producing any warnings. However, compilation will (and should) still generate a warning having + // nothing to do with this checker. + unused; // expected-warning {{expression result unused}} +} + +void rangeConstrained1(int input) { if (input > -5 && input < 5) auto value = static_cast(input); // OK. Being conservative, this is a possibly good value. } diff --git a/clang/test/Analysis/iterator-range.cpp b/clang/test/Analysis/iterator-range.cpp index 6fc8939c8e84..bc7e08263ae2 100644 --- a/clang/test/Analysis/iterator-range.cpp +++ b/clang/test/Analysis/iterator-range.cpp @@ -236,3 +236,8 @@ void good_derived(simple_container c) { *i0; // no-warning } } + +void iter_diff(std::vector &V) { + auto i0 = V.begin(), i1 = V.end(); + ptrdiff_t len = i1 - i0; // no-crash +} diff --git a/clang/test/Analysis/retain-release.m b/clang/test/Analysis/retain-release.m index ad79d72d1aa1..e459fb7a0b85 100644 --- a/clang/test/Analysis/retain-release.m +++ b/clang/test/Analysis/retain-release.m @@ -2,7 +2,7 @@ // RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10\ // RUN: -analyzer-checker=core,osx.coreFoundation.CFRetainRelease\ // RUN: -analyzer-checker=osx.cocoa.ClassRelease,osx.cocoa.RetainCount\ -// RUN: -analyzer-checker=debug.ExprInspection -fblocks -verify=expected,C %s\ +// RUN: -analyzer-checker=debug.ExprInspection -fblocks -verify %s\ // RUN: -Wno-objc-root-class -analyzer-output=plist -o %t.objc.plist // RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10\ // RUN: -analyzer-checker=core,osx.coreFoundation.CFRetainRelease\ @@ -1231,7 +1231,7 @@ void rdar_7184450_pos(CGContextRef myContext, CGFloat x, CGPoint myStartPoint, typedef unsigned long __darwin_pthread_key_t; typedef __darwin_pthread_key_t pthread_key_t; -int pthread_create(pthread_t *, const pthread_attr_t *, // C-warning{{declaration of built-in function 'pthread_create' requires inclusion of the header }} +int pthread_create(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *); int pthread_setspecific(pthread_key_t key, const void *value); diff --git a/clang/test/CXX/dcl.decl/dcl.decomp/p3.cpp b/clang/test/CXX/dcl.decl/dcl.decomp/p3.cpp index b3f0cf187446..ce5eefc6bfdb 100644 --- a/clang/test/CXX/dcl.decl/dcl.decomp/p3.cpp +++ b/clang/test/CXX/dcl.decl/dcl.decomp/p3.cpp @@ -12,7 +12,7 @@ void no_tuple_size_2() { auto [x, y] = A(); } // ok, decompose elementwise struct Bad1 { int a, b; }; template<> struct std::tuple_size {}; -void no_tuple_size_3() { auto [x, y] = Bad1(); } // expected-error {{cannot decompose this type; 'std::tuple_size::value' is not a valid integral constant expression}} +void no_tuple_size_3() { auto [x, y] = Bad1(); } // ok, omitting value is valid after DR2386 struct Bad2 {}; template<> struct std::tuple_size { const int value = 5; }; @@ -127,7 +127,7 @@ void referenced_type() { using ConstInt3 = decltype(bcr2); } -struct C { template int get(); }; +struct C { template int get() const; }; template<> struct std::tuple_size { static const int value = 1; }; template<> struct std::tuple_element<0, C> { typedef int type; }; @@ -138,6 +138,12 @@ int member_get() { return c; } +constexpr C c = C(); +template void dependent_binding_PR40674() { + const auto &[c] = *p; + (void)c; +} + struct D { // FIXME: Emit a note here explaining why this was ignored. template struct get {}; diff --git a/clang/test/CXX/drs/dr22xx.cpp b/clang/test/CXX/drs/dr22xx.cpp index 70a26db757c3..8896281e9ca4 100644 --- a/clang/test/CXX/drs/dr22xx.cpp +++ b/clang/test/CXX/drs/dr22xx.cpp @@ -26,3 +26,12 @@ void f() { } } #endif + +namespace dr2292 { // dr2292: 9 +#if __cplusplus >= 201103L + template using id = T; + void test(int *p) { + p->template id::~id(); + } +#endif +} diff --git a/clang/test/CXX/drs/dr23xx.cpp b/clang/test/CXX/drs/dr23xx.cpp index 8e7a9a880bfb..763abd5368ef 100644 --- a/clang/test/CXX/drs/dr23xx.cpp +++ b/clang/test/CXX/drs/dr23xx.cpp @@ -40,6 +40,27 @@ namespace dr2353 { // dr2353: 9 #pragma clang __debug dump not_use_2 } +#if __cplusplus >= 201707L +// Otherwise, if the qualified-id std::tuple_size names a complete class +// type **with a member value**, the expression std::tuple_size::value shall +// be a well-formed integral constant expression +namespace dr2386 { // dr2386: 9 +struct Bad1 { int a, b; }; +struct Bad2 { int a, b; }; +} // namespace dr2386 +namespace std { +template struct tuple_size; +template <> struct std::tuple_size {}; +template <> struct std::tuple_size { + static const int value = 42; +}; +} // namespace std +namespace dr2386 { +void no_value() { auto [x, y] = Bad1(); } +void wrong_value() { auto [x, y] = Bad2(); } // expected-error {{decomposes into 42 elements}} +} // namespace dr2386 +#endif + namespace dr2387 { // dr2387: 9 #if __cplusplus >= 201402L template int a = 0; diff --git a/clang/test/CXX/drs/dr4xx.cpp b/clang/test/CXX/drs/dr4xx.cpp index 00393cc2e4c0..8eeb7715cadf 100644 --- a/clang/test/CXX/drs/dr4xx.cpp +++ b/clang/test/CXX/drs/dr4xx.cpp @@ -318,8 +318,8 @@ namespace dr420 { // dr420: yes q->~id(); p->id::~id(); q->id::~id(); - p->template id::~id(); // expected-error {{'template' keyword not permitted here}} expected-error {{base type 'int' is not a struct}} - q->template id::~id(); // expected-error {{'template' keyword not permitted here}} expected-error {{base type 'int' is not a struct}} + p->template id::~id(); // OK since dr2292 + q->template id::~id(); // OK since dr2292 p->A::template id::~id(); q->A::template id::~id(); } diff --git a/clang/test/CodeGen/aarch64-sve-inline-asm.c b/clang/test/CodeGen/aarch64-sve-inline-asm.c new file mode 100644 index 000000000000..90e7777925b9 --- /dev/null +++ b/clang/test/CodeGen/aarch64-sve-inline-asm.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK + +void test_sve_asm() { + asm volatile( + "ptrue p0.d\n" + "ptrue p15.d\n" + "add z0.d, p0/m, z0.d, z0.d\n" + "add z31.d, p0/m, z31.d, z31.d\n" + : + : + : "z0", "z31", "p0", "p15"); + // CHECK: "~{z0},~{z31},~{p0},~{p15}" +} diff --git a/clang/test/CodeGen/alias.c b/clang/test/CodeGen/alias.c index 78b020454a9f..f5bdf3c0587e 100644 --- a/clang/test/CodeGen/alias.c +++ b/clang/test/CodeGen/alias.c @@ -2,6 +2,7 @@ // RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECKBASIC %s // RUN: %clang_cc1 -triple armv7a-eabi -mfloat-abi hard -emit-llvm -o - %s | FileCheck -check-prefix=CHECKCC %s // RUN: %clang_cc1 -triple armv7a-eabi -mfloat-abi hard -S -o - %s | FileCheck -check-prefix=CHECKASM %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefix=CHECKGLOBALS %s int g0; // CHECKBASIC-DAG: @g0 = common global i32 0 @@ -88,3 +89,18 @@ void test8_zed() __attribute__((alias("test8_foo"))); void test9_bar(void) { } void test9_zed(void) __attribute__((section("test"))); void test9_zed(void) __attribute__((alias("test9_bar"))); + +// Test that the alias gets its linkage from its declared qual type. +// CHECKGLOBALS: @test10_foo = internal +// CHECKGLOBALS-NOT: @test10_foo = dso_local +int test10; +static int test10_foo __attribute__((alias("test10"))); +// CHECKGLOBALS: @test11_foo = internal +// CHECKGLOBALS-NOT: @test11_foo = dso_local +void test11(void) {} +static void test11_foo(void) __attribute__((alias("test11"))); + +// Test that gnu_inline+alias work. +// CHECKGLOBALS: @test12_alias = alias void (), void ()* @test12 +void test12(void) {} +inline void test12_alias(void) __attribute__((gnu_inline, alias("test12"))); diff --git a/clang/test/CodeGen/arm64-microsoft-intrinsics.c b/clang/test/CodeGen/arm64-microsoft-intrinsics.c index eeb09e89727d..4a9642e173c1 100644 --- a/clang/test/CodeGen/arm64-microsoft-intrinsics.c +++ b/clang/test/CodeGen/arm64-microsoft-intrinsics.c @@ -8,6 +8,10 @@ long test_InterlockedAdd(long volatile *Addend, long Value) { return _InterlockedAdd(Addend, Value); } +long test_InterlockedAdd_constant(long volatile *Addend) { + return _InterlockedAdd(Addend, -1); +} + // CHECK-LABEL: define {{.*}} i32 @test_InterlockedAdd(i32* %Addend, i32 %Value) {{.*}} { // CHECK-MSVC: %[[OLDVAL:[0-9]+]] = atomicrmw add i32* %1, i32 %2 seq_cst // CHECK-MSVC: %[[NEWVAL:[0-9]+]] = add i32 %[[OLDVAL:[0-9]+]], %2 diff --git a/clang/test/CodeGen/avr-builtins.c b/clang/test/CodeGen/avr-builtins.c index cbba6b2f2a2e..8fa983a78239 100644 --- a/clang/test/CodeGen/avr-builtins.c +++ b/clang/test/CodeGen/avr-builtins.c @@ -1,5 +1,9 @@ // RUN: %clang_cc1 -triple avr-unknown-unknown -emit-llvm -o - %s | FileCheck %s +// Check that the parameter types match. This verifies pr43309. +// RUN: %clang_cc1 -triple avr-unknown-unknown -Wconversion -verify %s +// expected-no-diagnostics + unsigned char bitrev8(unsigned char data) { return __builtin_bitreverse8(data); } diff --git a/clang/test/CodeGen/pr41027.c b/clang/test/CodeGen/pr41027.c new file mode 100644 index 000000000000..c16e232931c0 --- /dev/null +++ b/clang/test/CodeGen/pr41027.c @@ -0,0 +1,20 @@ +// REQUIRES: x86-registered-target +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -S -O2 -o - %s | FileCheck %s + +// CHECK-LABEL: f: +// CHECK: movl $1, %eax +// CHECK-NEXT: #APP +// CHECK-NEXT: outl %eax, $1 +// CHECK-NEXT: #NO_APP + +static inline void pr41027(unsigned a, unsigned b) { + if (__builtin_constant_p(a)) { + __asm__ volatile("outl %0,%w1" : : "a"(b), "n"(a)); + } else { + __asm__ volatile("outl %0,%w1" : : "a"(b), "d"(a)); + } +} + +void f(unsigned port) { + pr41027(1, 1); +} diff --git a/clang/test/CodeGen/riscv-atomics.c b/clang/test/CodeGen/riscv-atomics.c new file mode 100644 index 000000000000..9966543be1b6 --- /dev/null +++ b/clang/test/CodeGen/riscv-atomics.c @@ -0,0 +1,68 @@ +// RUN: %clang_cc1 -triple riscv32 -O1 -emit-llvm %s -o - \ +// RUN: | FileCheck %s -check-prefix=RV32I +// RUN: %clang_cc1 -triple riscv32 -target-feature +a -O1 -emit-llvm %s -o - \ +// RUN: | FileCheck %s -check-prefix=RV32IA +// RUN: %clang_cc1 -triple riscv64 -O1 -emit-llvm %s -o - \ +// RUN: | FileCheck %s -check-prefix=RV64I +// RUN: %clang_cc1 -triple riscv64 -target-feature +a -O1 -emit-llvm %s -o - \ +// RUN: | FileCheck %s -check-prefix=RV64IA + +// This test demonstrates that MaxAtomicInlineWidth is set appropriately when +// the atomics instruction set extension is enabled. + +#include +#include + +void test_i8_atomics(_Atomic(int8_t) * a, int8_t b) { + // RV32I: call zeroext i8 @__atomic_load_1 + // RV32I: call void @__atomic_store_1 + // RV32I: call zeroext i8 @__atomic_fetch_add_1 + // RV32IA: load atomic i8, i8* %a seq_cst, align 1 + // RV32IA: store atomic i8 %b, i8* %a seq_cst, align 1 + // RV32IA: atomicrmw add i8* %a, i8 %b seq_cst + // RV64I: call zeroext i8 @__atomic_load_1 + // RV64I: call void @__atomic_store_1 + // RV64I: call zeroext i8 @__atomic_fetch_add_1 + // RV64IA: load atomic i8, i8* %a seq_cst, align 1 + // RV64IA: store atomic i8 %b, i8* %a seq_cst, align 1 + // RV64IA: atomicrmw add i8* %a, i8 %b seq_cst + __c11_atomic_load(a, memory_order_seq_cst); + __c11_atomic_store(a, b, memory_order_seq_cst); + __c11_atomic_fetch_add(a, b, memory_order_seq_cst); +} + +void test_i32_atomics(_Atomic(int32_t) * a, int32_t b) { + // RV32I: call i32 @__atomic_load_4 + // RV32I: call void @__atomic_store_4 + // RV32I: call i32 @__atomic_fetch_add_4 + // RV32IA: load atomic i32, i32* %a seq_cst, align 4 + // RV32IA: store atomic i32 %b, i32* %a seq_cst, align 4 + // RV32IA: atomicrmw add i32* %a, i32 %b seq_cst + // RV64I: call signext i32 @__atomic_load_4 + // RV64I: call void @__atomic_store_4 + // RV64I: call signext i32 @__atomic_fetch_add_4 + // RV64IA: load atomic i32, i32* %a seq_cst, align 4 + // RV64IA: store atomic i32 %b, i32* %a seq_cst, align 4 + // RV64IA: atomicrmw add i32* %a, i32 %b seq_cst + __c11_atomic_load(a, memory_order_seq_cst); + __c11_atomic_store(a, b, memory_order_seq_cst); + __c11_atomic_fetch_add(a, b, memory_order_seq_cst); +} + +void test_i64_atomics(_Atomic(int64_t) * a, int64_t b) { + // RV32I: call i64 @__atomic_load_8 + // RV32I: call void @__atomic_store_8 + // RV32I: call i64 @__atomic_fetch_add_8 + // RV32IA: call i64 @__atomic_load_8 + // RV32IA: call void @__atomic_store_8 + // RV32IA: call i64 @__atomic_fetch_add_8 + // RV64I: call i64 @__atomic_load_8 + // RV64I: call void @__atomic_store_8 + // RV64I: call i64 @__atomic_fetch_add_8 + // RV64IA: load atomic i64, i64* %a seq_cst, align 8 + // RV64IA: store atomic i64 %b, i64* %a seq_cst, align 8 + // RV64IA: atomicrmw add i64* %a, i64 %b seq_cst + __c11_atomic_load(a, memory_order_seq_cst); + __c11_atomic_store(a, b, memory_order_seq_cst); + __c11_atomic_fetch_add(a, b, memory_order_seq_cst); +} diff --git a/clang/test/CodeGen/riscv-inline-asm.c b/clang/test/CodeGen/riscv-inline-asm.c index 2d23b7e35e2b..2c92d15ca90a 100644 --- a/clang/test/CodeGen/riscv-inline-asm.c +++ b/clang/test/CodeGen/riscv-inline-asm.c @@ -26,3 +26,21 @@ void test_K() { // CHECK: call void asm sideeffect "", "K"(i32 0) asm volatile ("" :: "K"(0)); } + +float f; +double d; +void test_f() { +// CHECK-LABEL: define void @test_f() +// CHECK: [[FLT_ARG:%[a-zA-Z_0-9]+]] = load float, float* @f +// CHECK: call void asm sideeffect "", "f"(float [[FLT_ARG]]) + asm volatile ("" :: "f"(f)); +// CHECK: [[FLT_ARG:%[a-zA-Z_0-9]+]] = load double, double* @d +// CHECK: call void asm sideeffect "", "f"(double [[FLT_ARG]]) + asm volatile ("" :: "f"(d)); +} + +void test_A(int *p) { +// CHECK-LABEL: define void @test_A(i32* %p) +// CHECK: call void asm sideeffect "", "*A"(i32* %p) + asm volatile("" :: "A"(*p)); +} diff --git a/clang/test/CodeGen/riscv32-ilp32-ilp32f-abi.c b/clang/test/CodeGen/riscv32-ilp32-ilp32f-abi.c index 0c2f0791e316..677040626f57 100644 --- a/clang/test/CodeGen/riscv32-ilp32-ilp32f-abi.c +++ b/clang/test/CodeGen/riscv32-ilp32-ilp32f-abi.c @@ -1,4 +1,6 @@ // RUN: %clang_cc1 -triple riscv32 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \ +// RUN: | FileCheck %s // This file contains test cases that will have the same output for the ilp32 // and ilp32f ABIs. @@ -35,8 +37,8 @@ int f_scalar_stack_1(int32_t a, int64_t b, int32_t c, double d, long double e, // the presence of large return values that consume a register due to the need // to pass a pointer. -// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret %agg.result, i32 %a, i64 %b, i64 %c, fp128 %d, i8 zeroext %e, i8 %f, i8 %g) -struct large f_scalar_stack_2(int32_t a, int64_t b, int64_t c, long double d, +// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret %agg.result, i32 %a, i64 %b, double %c, fp128 %d, i8 zeroext %e, i8 %f, i8 %g) +struct large f_scalar_stack_2(int32_t a, int64_t b, double c, long double d, uint8_t e, int8_t f, uint8_t g) { return (struct large){a, e, f, g}; } diff --git a/clang/test/CodeGen/riscv32-ilp32-ilp32f-ilp32d-abi.c b/clang/test/CodeGen/riscv32-ilp32-ilp32f-ilp32d-abi.c index 12837fce9422..fa11c1772d72 100644 --- a/clang/test/CodeGen/riscv32-ilp32-ilp32f-ilp32d-abi.c +++ b/clang/test/CodeGen/riscv32-ilp32-ilp32f-ilp32d-abi.c @@ -1,6 +1,10 @@ // RUN: %clang_cc1 -triple riscv32 -emit-llvm %s -o - | FileCheck %s // RUN: %clang_cc1 -triple riscv32 -emit-llvm -fforce-enable-int128 %s -o - \ // RUN: | FileCheck %s -check-prefixes=CHECK,CHECK-FORCEINT128 +// RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \ +// RUN: | FileCheck %s +// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-abi ilp32d -emit-llvm %s -o - \ +// RUN: | FileCheck %s // This file contains test cases that will have the same output for the ilp32, // ilp32f, and ilp32d ABIs. diff --git a/clang/test/CodeGen/riscv32-ilp32d-abi.c b/clang/test/CodeGen/riscv32-ilp32d-abi.c new file mode 100644 index 000000000000..b10656cf123e --- /dev/null +++ b/clang/test/CodeGen/riscv32-ilp32d-abi.c @@ -0,0 +1,282 @@ +// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-abi ilp32d -emit-llvm %s -o - \ +// RUN: | FileCheck %s + +#include + +// Verify that the tracking of used GPRs and FPRs works correctly by checking +// that small integers are sign/zero extended when passed in registers. + +// Doubles are passed in FPRs, so argument 'i' will be passed zero-extended +// because it will be passed in a GPR. + +// CHECK: define void @f_fpr_tracking(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, i8 zeroext %i) +void f_fpr_tracking(double a, double b, double c, double d, double e, double f, + double g, double h, uint8_t i) {} + +// Check that fp, fp+fp, and int+fp structs are lowered correctly. These will +// be passed in FPR, FPR+FPR, or GPR+FPR regs if sufficient registers are +// available the widths are <= XLEN and FLEN, and should be expanded to +// separate arguments in IR. They are passed by the same rules for returns, +// but will be lowered to simple two-element structs if necessary (as LLVM IR +// functions cannot return multiple values). + +// A struct containing just one floating-point real is passed as though it +// were a standalone floating-point real. + +struct double_s { double f; }; + +// CHECK: define void @f_double_s_arg(double) +void f_double_s_arg(struct double_s a) {} + +// CHECK: define double @f_ret_double_s() +struct double_s f_ret_double_s() { + return (struct double_s){1.0}; +} + +// A struct containing a double and any number of zero-width bitfields is +// passed as though it were a standalone floating-point real. + +struct zbf_double_s { int : 0; double f; }; +struct zbf_double_zbf_s { int : 0; double f; int : 0; }; + +// CHECK: define void @f_zbf_double_s_arg(double) +void f_zbf_double_s_arg(struct zbf_double_s a) {} + +// CHECK: define double @f_ret_zbf_double_s() +struct zbf_double_s f_ret_zbf_double_s() { + return (struct zbf_double_s){1.0}; +} + +// CHECK: define void @f_zbf_double_zbf_s_arg(double) +void f_zbf_double_zbf_s_arg(struct zbf_double_zbf_s a) {} + +// CHECK: define double @f_ret_zbf_double_zbf_s() +struct zbf_double_zbf_s f_ret_zbf_double_zbf_s() { + return (struct zbf_double_zbf_s){1.0}; +} + +// Check that structs containing two floating point values (FLEN <= width) are +// expanded provided sufficient FPRs are available. + +struct double_double_s { double f; double g; }; +struct double_float_s { double f; float g; }; + +// CHECK: define void @f_double_double_s_arg(double, double) +void f_double_double_s_arg(struct double_double_s a) {} + +// CHECK: define { double, double } @f_ret_double_double_s() +struct double_double_s f_ret_double_double_s() { + return (struct double_double_s){1.0, 2.0}; +} + +// CHECK: define void @f_double_float_s_arg(double, float) +void f_double_float_s_arg(struct double_float_s a) {} + +// CHECK: define { double, float } @f_ret_double_float_s() +struct double_float_s f_ret_double_float_s() { + return (struct double_float_s){1.0, 2.0}; +} + +// CHECK: define void @f_double_double_s_arg_insufficient_fprs(float %a, double %b, double %c, double %d, double %e, double %f, double %g, %struct.double_double_s* %h) +void f_double_double_s_arg_insufficient_fprs(float a, double b, double c, double d, + double e, double f, double g, struct double_double_s h) {} + +// Check that structs containing int+double values are expanded, provided +// sufficient FPRs and GPRs are available. The integer components are neither +// sign or zero-extended. + +struct double_int8_s { double f; int8_t i; }; +struct double_uint8_s { double f; uint8_t i; }; +struct double_int32_s { double f; int32_t i; }; +struct double_int64_s { double f; int64_t i; }; +struct double_int64bf_s { double f; int64_t i : 32; }; +struct double_int8_zbf_s { double f; int8_t i; int : 0; }; + +// CHECK: define void @f_double_int8_s_arg(double, i8) +void f_double_int8_s_arg(struct double_int8_s a) {} + +// CHECK: define { double, i8 } @f_ret_double_int8_s() +struct double_int8_s f_ret_double_int8_s() { + return (struct double_int8_s){1.0, 2}; +} + +// CHECK: define void @f_double_uint8_s_arg(double, i8) +void f_double_uint8_s_arg(struct double_uint8_s a) {} + +// CHECK: define { double, i8 } @f_ret_double_uint8_s() +struct double_uint8_s f_ret_double_uint8_s() { + return (struct double_uint8_s){1.0, 2}; +} + +// CHECK: define void @f_double_int32_s_arg(double, i32) +void f_double_int32_s_arg(struct double_int32_s a) {} + +// CHECK: define { double, i32 } @f_ret_double_int32_s() +struct double_int32_s f_ret_double_int32_s() { + return (struct double_int32_s){1.0, 2}; +} + +// CHECK: define void @f_double_int64_s_arg(%struct.double_int64_s* %a) +void f_double_int64_s_arg(struct double_int64_s a) {} + +// CHECK: define void @f_ret_double_int64_s(%struct.double_int64_s* noalias sret %agg.result) +struct double_int64_s f_ret_double_int64_s() { + return (struct double_int64_s){1.0, 2}; +} + +// CHECK: define void @f_double_int64bf_s_arg(double, i32) +void f_double_int64bf_s_arg(struct double_int64bf_s a) {} + +// CHECK: define { double, i32 } @f_ret_double_int64bf_s() +struct double_int64bf_s f_ret_double_int64bf_s() { + return (struct double_int64bf_s){1.0, 2}; +} + +// The zero-width bitfield means the struct can't be passed according to the +// floating point calling convention. + +// CHECK: define void @f_double_int8_zbf_s(double, i8) +void f_double_int8_zbf_s(struct double_int8_zbf_s a) {} + +// CHECK: define { double, i8 } @f_ret_double_int8_zbf_s() +struct double_int8_zbf_s f_ret_double_int8_zbf_s() { + return (struct double_int8_zbf_s){1.0, 2}; +} + +// CHECK: define void @f_double_int8_s_arg_insufficient_gprs(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h, %struct.double_int8_s* %i) +void f_double_int8_s_arg_insufficient_gprs(int a, int b, int c, int d, int e, + int f, int g, int h, struct double_int8_s i) {} + +// CHECK: define void @f_struct_double_int8_insufficient_fprs(float %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, %struct.double_int8_s* %i) +void f_struct_double_int8_insufficient_fprs(float a, double b, double c, double d, + double e, double f, double g, double h, struct double_int8_s i) {} + +// Complex floating-point values or structs containing a single complex +// floating-point value should be passed as if it were an fp+fp struct. + +// CHECK: define void @f_doublecomplex(double %a.coerce0, double %a.coerce1) +void f_doublecomplex(double __complex__ a) {} + +// CHECK: define { double, double } @f_ret_doublecomplex() +double __complex__ f_ret_doublecomplex() { + return 1.0; +} + +struct doublecomplex_s { double __complex__ c; }; + +// CHECK: define void @f_doublecomplex_s_arg(double, double) +void f_doublecomplex_s_arg(struct doublecomplex_s a) {} + +// CHECK: define { double, double } @f_ret_doublecomplex_s() +struct doublecomplex_s f_ret_doublecomplex_s() { + return (struct doublecomplex_s){1.0}; +} + +// Test single or two-element structs that need flattening. e.g. those +// containing nested structs, doubles in small arrays, zero-length structs etc. + +struct doublearr1_s { double a[1]; }; + +// CHECK: define void @f_doublearr1_s_arg(double) +void f_doublearr1_s_arg(struct doublearr1_s a) {} + +// CHECK: define double @f_ret_doublearr1_s() +struct doublearr1_s f_ret_doublearr1_s() { + return (struct doublearr1_s){{1.0}}; +} + +struct doublearr2_s { double a[2]; }; + +// CHECK: define void @f_doublearr2_s_arg(double, double) +void f_doublearr2_s_arg(struct doublearr2_s a) {} + +// CHECK: define { double, double } @f_ret_doublearr2_s() +struct doublearr2_s f_ret_doublearr2_s() { + return (struct doublearr2_s){{1.0, 2.0}}; +} + +struct doublearr2_tricky1_s { struct { double f[1]; } g[2]; }; + +// CHECK: define void @f_doublearr2_tricky1_s_arg(double, double) +void f_doublearr2_tricky1_s_arg(struct doublearr2_tricky1_s a) {} + +// CHECK: define { double, double } @f_ret_doublearr2_tricky1_s() +struct doublearr2_tricky1_s f_ret_doublearr2_tricky1_s() { + return (struct doublearr2_tricky1_s){{{{1.0}}, {{2.0}}}}; +} + +struct doublearr2_tricky2_s { struct {}; struct { double f[1]; } g[2]; }; + +// CHECK: define void @f_doublearr2_tricky2_s_arg(double, double) +void f_doublearr2_tricky2_s_arg(struct doublearr2_tricky2_s a) {} + +// CHECK: define { double, double } @f_ret_doublearr2_tricky2_s() +struct doublearr2_tricky2_s f_ret_doublearr2_tricky2_s() { + return (struct doublearr2_tricky2_s){{}, {{{1.0}}, {{2.0}}}}; +} + +struct doublearr2_tricky3_s { union {}; struct { double f[1]; } g[2]; }; + +// CHECK: define void @f_doublearr2_tricky3_s_arg(double, double) +void f_doublearr2_tricky3_s_arg(struct doublearr2_tricky3_s a) {} + +// CHECK: define { double, double } @f_ret_doublearr2_tricky3_s() +struct doublearr2_tricky3_s f_ret_doublearr2_tricky3_s() { + return (struct doublearr2_tricky3_s){{}, {{{1.0}}, {{2.0}}}}; +} + +struct doublearr2_tricky4_s { union {}; struct { struct {}; double f[1]; } g[2]; }; + +// CHECK: define void @f_doublearr2_tricky4_s_arg(double, double) +void f_doublearr2_tricky4_s_arg(struct doublearr2_tricky4_s a) {} + +// CHECK: define { double, double } @f_ret_doublearr2_tricky4_s() +struct doublearr2_tricky4_s f_ret_doublearr2_tricky4_s() { + return (struct doublearr2_tricky4_s){{}, {{{}, {1.0}}, {{}, {2.0}}}}; +} + +// Test structs that should be passed according to the normal integer calling +// convention. + +struct int_double_int_s { int a; double b; int c; }; + +// CHECK: define void @f_int_double_int_s_arg(%struct.int_double_int_s* %a) +void f_int_double_int_s_arg(struct int_double_int_s a) {} + +// CHECK: define void @f_ret_int_double_int_s(%struct.int_double_int_s* noalias sret %agg.result) +struct int_double_int_s f_ret_int_double_int_s() { + return (struct int_double_int_s){1, 2.0, 3}; +} + +struct int64_double_s { int64_t a; double b; }; + +// CHECK: define void @f_int64_double_s_arg(%struct.int64_double_s* %a) +void f_int64_double_s_arg(struct int64_double_s a) {} + +// CHECK: define void @f_ret_int64_double_s(%struct.int64_double_s* noalias sret %agg.result) +struct int64_double_s f_ret_int64_double_s() { + return (struct int64_double_s){1, 2.0}; +} + +struct char_char_double_s { char a; char b; double c; }; + +// CHECK-LABEL: define void @f_char_char_double_s_arg(%struct.char_char_double_s* %a) +void f_char_char_double_s_arg(struct char_char_double_s a) {} + +// CHECK: define void @f_ret_char_char_double_s(%struct.char_char_double_s* noalias sret %agg.result) +struct char_char_double_s f_ret_char_char_double_s() { + return (struct char_char_double_s){1, 2, 3.0}; +} + +// Unions are always passed according to the integer calling convention, even +// if they can only contain a double. + +union double_u { double a; }; + +// CHECK: define void @f_double_u_arg(i64 %a.coerce) +void f_double_u_arg(union double_u a) {} + +// CHECK: define i64 @f_ret_double_u() +union double_u f_ret_double_u() { + return (union double_u){1.0}; +} diff --git a/clang/test/CodeGen/riscv32-ilp32f-abi.c b/clang/test/CodeGen/riscv32-ilp32f-abi.c new file mode 100644 index 000000000000..76092958aedd --- /dev/null +++ b/clang/test/CodeGen/riscv32-ilp32f-abi.c @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \ +// RUN: | FileCheck %s + +#include + +// Doubles are still passed in GPRs, so the 'e' argument will be anyext as +// GPRs are exhausted. + +// CHECK: define void @f_fpr_tracking(double %a, double %b, double %c, double %d, i8 %e) +void f_fpr_tracking(double a, double b, double c, double d, int8_t e) {} + +// Lowering for doubles is unnmodified, as 64 > FLEN. + +struct double_s { double d; }; + +// CHECK: define void @f_double_s_arg(i64 %a.coerce) +void f_double_s_arg(struct double_s a) {} + +// CHECK: define i64 @f_ret_double_s() +struct double_s f_ret_double_s() { + return (struct double_s){1.0}; +} + +struct double_double_s { double d; double e; }; + +// CHECK: define void @f_double_double_s_arg(%struct.double_double_s* %a) +void f_double_double_s_arg(struct double_double_s a) {} + +// CHECK: define void @f_ret_double_double_s(%struct.double_double_s* noalias sret %agg.result) +struct double_double_s f_ret_double_double_s() { + return (struct double_double_s){1.0, 2.0}; +} + +struct double_int8_s { double d; int64_t i; }; + +struct int_double_s { int a; double b; }; + +// CHECK: define void @f_int_double_s_arg(%struct.int_double_s* %a) +void f_int_double_s_arg(struct int_double_s a) {} + +// CHECK: define void @f_ret_int_double_s(%struct.int_double_s* noalias sret %agg.result) +struct int_double_s f_ret_int_double_s() { + return (struct int_double_s){1, 2.0}; +} + diff --git a/clang/test/CodeGen/riscv32-ilp32f-ilp32d-abi.c b/clang/test/CodeGen/riscv32-ilp32f-ilp32d-abi.c new file mode 100644 index 000000000000..b960513655b1 --- /dev/null +++ b/clang/test/CodeGen/riscv32-ilp32f-ilp32d-abi.c @@ -0,0 +1,275 @@ +// RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \ +// RUN: | FileCheck %s +// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-abi ilp32d -emit-llvm %s -o - \ +// RUN: | FileCheck %s + +#include + +// Verify that the tracking of used GPRs and FPRs works correctly by checking +// that small integers are sign/zero extended when passed in registers. + +// Floats are passed in FPRs, so argument 'i' will be passed zero-extended +// because it will be passed in a GPR. + +// CHECK: define void @f_fpr_tracking(float %a, float %b, float %c, float %d, float %e, float %f, float %g, float %h, i8 zeroext %i) +void f_fpr_tracking(float a, float b, float c, float d, float e, float f, + float g, float h, uint8_t i) {} + +// Check that fp, fp+fp, and int+fp structs are lowered correctly. These will +// be passed in FPR, FPR+FPR, or GPR+FPR regs if sufficient registers are +// available the widths are <= XLEN and FLEN, and should be expanded to +// separate arguments in IR. They are passed by the same rules for returns, +// but will be lowered to simple two-element structs if necessary (as LLVM IR +// functions cannot return multiple values). + +// A struct containing just one floating-point real is passed as though it +// were a standalone floating-point real. + +struct float_s { float f; }; + +// CHECK: define void @f_float_s_arg(float) +void f_float_s_arg(struct float_s a) {} + +// CHECK: define float @f_ret_float_s() +struct float_s f_ret_float_s() { + return (struct float_s){1.0}; +} + +// A struct containing a float and any number of zero-width bitfields is +// passed as though it were a standalone floating-point real. + +struct zbf_float_s { int : 0; float f; }; +struct zbf_float_zbf_s { int : 0; float f; int : 0; }; + +// CHECK: define void @f_zbf_float_s_arg(float) +void f_zbf_float_s_arg(struct zbf_float_s a) {} + +// CHECK: define float @f_ret_zbf_float_s() +struct zbf_float_s f_ret_zbf_float_s() { + return (struct zbf_float_s){1.0}; +} + +// CHECK: define void @f_zbf_float_zbf_s_arg(float) +void f_zbf_float_zbf_s_arg(struct zbf_float_zbf_s a) {} + +// CHECK: define float @f_ret_zbf_float_zbf_s() +struct zbf_float_zbf_s f_ret_zbf_float_zbf_s() { + return (struct zbf_float_zbf_s){1.0}; +} + +// Check that structs containing two float values (FLEN <= width) are expanded +// provided sufficient FPRs are available. + +struct float_float_s { float f; float g; }; + +// CHECK: define void @f_float_float_s_arg(float, float) +void f_float_float_s_arg(struct float_float_s a) {} + +// CHECK: define { float, float } @f_ret_float_float_s() +struct float_float_s f_ret_float_float_s() { + return (struct float_float_s){1.0, 2.0}; +} + +// CHECK: define void @f_float_float_s_arg_insufficient_fprs(float %a, float %b, float %c, float %d, float %e, float %f, float %g, [2 x i32] %h.coerce) +void f_float_float_s_arg_insufficient_fprs(float a, float b, float c, float d, + float e, float f, float g, struct float_float_s h) {} + +// Check that structs containing int+float values are expanded, provided +// sufficient FPRs and GPRs are available. The integer components are neither +// sign or zero-extended. + +struct float_int8_s { float f; int8_t i; }; +struct float_uint8_s { float f; uint8_t i; }; +struct float_int32_s { float f; int32_t i; }; +struct float_int64_s { float f; int64_t i; }; +struct float_int64bf_s { float f; int64_t i : 32; }; +struct float_int8_zbf_s { float f; int8_t i; int : 0; }; + +// CHECK: define void @f_float_int8_s_arg(float, i8) +void f_float_int8_s_arg(struct float_int8_s a) {} + +// CHECK: define { float, i8 } @f_ret_float_int8_s() +struct float_int8_s f_ret_float_int8_s() { + return (struct float_int8_s){1.0, 2}; +} + +// CHECK: define void @f_float_uint8_s_arg(float, i8) +void f_float_uint8_s_arg(struct float_uint8_s a) {} + +// CHECK: define { float, i8 } @f_ret_float_uint8_s() +struct float_uint8_s f_ret_float_uint8_s() { + return (struct float_uint8_s){1.0, 2}; +} + +// CHECK: define void @f_float_int32_s_arg(float, i32) +void f_float_int32_s_arg(struct float_int32_s a) {} + +// CHECK: define { float, i32 } @f_ret_float_int32_s() +struct float_int32_s f_ret_float_int32_s() { + return (struct float_int32_s){1.0, 2}; +} + +// CHECK: define void @f_float_int64_s_arg(%struct.float_int64_s* %a) +void f_float_int64_s_arg(struct float_int64_s a) {} + +// CHECK: define void @f_ret_float_int64_s(%struct.float_int64_s* noalias sret %agg.result) +struct float_int64_s f_ret_float_int64_s() { + return (struct float_int64_s){1.0, 2}; +} + +// CHECK: define void @f_float_int64bf_s_arg(float, i32) +void f_float_int64bf_s_arg(struct float_int64bf_s a) {} + +// CHECK: define { float, i32 } @f_ret_float_int64bf_s() +struct float_int64bf_s f_ret_float_int64bf_s() { + return (struct float_int64bf_s){1.0, 2}; +} + +// The zero-width bitfield means the struct can't be passed according to the +// floating point calling convention. + +// CHECK: define void @f_float_int8_zbf_s(float, i8) +void f_float_int8_zbf_s(struct float_int8_zbf_s a) {} + +// CHECK: define { float, i8 } @f_ret_float_int8_zbf_s() +struct float_int8_zbf_s f_ret_float_int8_zbf_s() { + return (struct float_int8_zbf_s){1.0, 2}; +} + +// CHECK: define void @f_float_int8_s_arg_insufficient_gprs(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h, [2 x i32] %i.coerce) +void f_float_int8_s_arg_insufficient_gprs(int a, int b, int c, int d, int e, + int f, int g, int h, struct float_int8_s i) {} + +// CHECK: define void @f_struct_float_int8_insufficient_fprs(float %a, float %b, float %c, float %d, float %e, float %f, float %g, float %h, [2 x i32] %i.coerce) +void f_struct_float_int8_insufficient_fprs(float a, float b, float c, float d, + float e, float f, float g, float h, struct float_int8_s i) {} + +// Complex floating-point values or structs containing a single complex +// floating-point value should be passed as if it were an fp+fp struct. + +// CHECK: define void @f_floatcomplex(float %a.coerce0, float %a.coerce1) +void f_floatcomplex(float __complex__ a) {} + +// CHECK: define { float, float } @f_ret_floatcomplex() +float __complex__ f_ret_floatcomplex() { + return 1.0; +} + +struct floatcomplex_s { float __complex__ c; }; + +// CHECK: define void @f_floatcomplex_s_arg(float, float) +void f_floatcomplex_s_arg(struct floatcomplex_s a) {} + +// CHECK: define { float, float } @f_ret_floatcomplex_s() +struct floatcomplex_s f_ret_floatcomplex_s() { + return (struct floatcomplex_s){1.0}; +} + +// Test single or two-element structs that need flattening. e.g. those +// containing nested structs, floats in small arrays, zero-length structs etc. + +struct floatarr1_s { float a[1]; }; + +// CHECK: define void @f_floatarr1_s_arg(float) +void f_floatarr1_s_arg(struct floatarr1_s a) {} + +// CHECK: define float @f_ret_floatarr1_s() +struct floatarr1_s f_ret_floatarr1_s() { + return (struct floatarr1_s){{1.0}}; +} + +struct floatarr2_s { float a[2]; }; + +// CHECK: define void @f_floatarr2_s_arg(float, float) +void f_floatarr2_s_arg(struct floatarr2_s a) {} + +// CHECK: define { float, float } @f_ret_floatarr2_s() +struct floatarr2_s f_ret_floatarr2_s() { + return (struct floatarr2_s){{1.0, 2.0}}; +} + +struct floatarr2_tricky1_s { struct { float f[1]; } g[2]; }; + +// CHECK: define void @f_floatarr2_tricky1_s_arg(float, float) +void f_floatarr2_tricky1_s_arg(struct floatarr2_tricky1_s a) {} + +// CHECK: define { float, float } @f_ret_floatarr2_tricky1_s() +struct floatarr2_tricky1_s f_ret_floatarr2_tricky1_s() { + return (struct floatarr2_tricky1_s){{{{1.0}}, {{2.0}}}}; +} + +struct floatarr2_tricky2_s { struct {}; struct { float f[1]; } g[2]; }; + +// CHECK: define void @f_floatarr2_tricky2_s_arg(float, float) +void f_floatarr2_tricky2_s_arg(struct floatarr2_tricky2_s a) {} + +// CHECK: define { float, float } @f_ret_floatarr2_tricky2_s() +struct floatarr2_tricky2_s f_ret_floatarr2_tricky2_s() { + return (struct floatarr2_tricky2_s){{}, {{{1.0}}, {{2.0}}}}; +} + +struct floatarr2_tricky3_s { union {}; struct { float f[1]; } g[2]; }; + +// CHECK: define void @f_floatarr2_tricky3_s_arg(float, float) +void f_floatarr2_tricky3_s_arg(struct floatarr2_tricky3_s a) {} + +// CHECK: define { float, float } @f_ret_floatarr2_tricky3_s() +struct floatarr2_tricky3_s f_ret_floatarr2_tricky3_s() { + return (struct floatarr2_tricky3_s){{}, {{{1.0}}, {{2.0}}}}; +} + +struct floatarr2_tricky4_s { union {}; struct { struct {}; float f[1]; } g[2]; }; + +// CHECK: define void @f_floatarr2_tricky4_s_arg(float, float) +void f_floatarr2_tricky4_s_arg(struct floatarr2_tricky4_s a) {} + +// CHECK: define { float, float } @f_ret_floatarr2_tricky4_s() +struct floatarr2_tricky4_s f_ret_floatarr2_tricky4_s() { + return (struct floatarr2_tricky4_s){{}, {{{}, {1.0}}, {{}, {2.0}}}}; +} + +// Test structs that should be passed according to the normal integer calling +// convention. + +struct int_float_int_s { int a; float b; int c; }; + +// CHECK: define void @f_int_float_int_s_arg(%struct.int_float_int_s* %a) +void f_int_float_int_s_arg(struct int_float_int_s a) {} + +// CHECK: define void @f_ret_int_float_int_s(%struct.int_float_int_s* noalias sret %agg.result) +struct int_float_int_s f_ret_int_float_int_s() { + return (struct int_float_int_s){1, 2.0, 3}; +} + +struct int64_float_s { int64_t a; float b; }; + +// CHECK: define void @f_int64_float_s_arg(%struct.int64_float_s* %a) +void f_int64_float_s_arg(struct int64_float_s a) {} + +// CHECK: define void @f_ret_int64_float_s(%struct.int64_float_s* noalias sret %agg.result) +struct int64_float_s f_ret_int64_float_s() { + return (struct int64_float_s){1, 2.0}; +} + +struct char_char_float_s { char a; char b; float c; }; + +// CHECK-LABEL: define void @f_char_char_float_s_arg([2 x i32] %a.coerce) +void f_char_char_float_s_arg(struct char_char_float_s a) {} + +// CHECK: define [2 x i32] @f_ret_char_char_float_s() +struct char_char_float_s f_ret_char_char_float_s() { + return (struct char_char_float_s){1, 2, 3.0}; +} + +// Unions are always passed according to the integer calling convention, even +// if they can only contain a float. + +union float_u { float a; }; + +// CHECK: define void @f_float_u_arg(i32 %a.coerce) +void f_float_u_arg(union float_u a) {} + +// CHECK: define i32 @f_ret_float_u() +union float_u f_ret_float_u() { + return (union float_u){1.0}; +} diff --git a/clang/test/CodeGen/riscv64-lp64-lp64f-abi.c b/clang/test/CodeGen/riscv64-lp64-lp64f-abi.c index 3b944e716a2a..d457bdf3c64e 100644 --- a/clang/test/CodeGen/riscv64-lp64-lp64f-abi.c +++ b/clang/test/CodeGen/riscv64-lp64-lp64f-abi.c @@ -1,4 +1,6 @@ // RUN: %clang_cc1 -triple riscv64 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-abi lp64f -emit-llvm %s -o - \ +// RUN: | FileCheck %s // This file contains test cases that will have the same output for the lp64 // and lp64f ABIs. diff --git a/clang/test/CodeGen/riscv64-lp64-lp64f-lp64d-abi.c b/clang/test/CodeGen/riscv64-lp64-lp64f-lp64d-abi.c index f51d8252b8f4..f3523702e9a2 100644 --- a/clang/test/CodeGen/riscv64-lp64-lp64f-lp64d-abi.c +++ b/clang/test/CodeGen/riscv64-lp64-lp64f-lp64d-abi.c @@ -1,4 +1,8 @@ // RUN: %clang_cc1 -triple riscv64 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-abi lp64f -emit-llvm %s -o - \ +// RUN: | FileCheck %s +// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-abi lp64d -emit-llvm %s -o - \ +// RUN: | FileCheck %s // This file contains test cases that will have the same output for the lp64, // lp64f, and lp64d ABIs. diff --git a/clang/test/CodeGen/riscv64-lp64d-abi.c b/clang/test/CodeGen/riscv64-lp64d-abi.c new file mode 100644 index 000000000000..00967b5fca85 --- /dev/null +++ b/clang/test/CodeGen/riscv64-lp64d-abi.c @@ -0,0 +1,272 @@ +// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-abi lp64d -emit-llvm %s -o - \ +// RUN: | FileCheck %s + +#include + +// Verify that the tracking of used GPRs and FPRs works correctly by checking +// that small integers are sign/zero extended when passed in registers. + +// Doubles are passed in FPRs, so argument 'i' will be passed zero-extended +// because it will be passed in a GPR. + +// CHECK: define void @f_fpr_tracking(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, i8 zeroext %i) +void f_fpr_tracking(double a, double b, double c, double d, double e, double f, + double g, double h, uint8_t i) {} + +// Check that fp, fp+fp, and int+fp structs are lowered correctly. These will +// be passed in FPR, FPR+FPR, or GPR+FPR regs if sufficient registers are +// available the widths are <= XLEN and FLEN, and should be expanded to +// separate arguments in IR. They are passed by the same rules for returns, +// but will be lowered to simple two-element structs if necessary (as LLVM IR +// functions cannot return multiple values). + +// A struct containing just one floating-point real is passed as though it +// were a standalone floating-point real. + +struct double_s { double f; }; + +// CHECK: define void @f_double_s_arg(double) +void f_double_s_arg(struct double_s a) {} + +// CHECK: define double @f_ret_double_s() +struct double_s f_ret_double_s() { + return (struct double_s){1.0}; +} + +// A struct containing a double and any number of zero-width bitfields is +// passed as though it were a standalone floating-point real. + +struct zbf_double_s { int : 0; double f; }; +struct zbf_double_zbf_s { int : 0; double f; int : 0; }; + +// CHECK: define void @f_zbf_double_s_arg(double) +void f_zbf_double_s_arg(struct zbf_double_s a) {} + +// CHECK: define double @f_ret_zbf_double_s() +struct zbf_double_s f_ret_zbf_double_s() { + return (struct zbf_double_s){1.0}; +} + +// CHECK: define void @f_zbf_double_zbf_s_arg(double) +void f_zbf_double_zbf_s_arg(struct zbf_double_zbf_s a) {} + +// CHECK: define double @f_ret_zbf_double_zbf_s() +struct zbf_double_zbf_s f_ret_zbf_double_zbf_s() { + return (struct zbf_double_zbf_s){1.0}; +} + +// Check that structs containing two floating point values (FLEN <= width) are +// expanded provided sufficient FPRs are available. + +struct double_double_s { double f; double g; }; +struct double_float_s { double f; float g; }; + +// CHECK: define void @f_double_double_s_arg(double, double) +void f_double_double_s_arg(struct double_double_s a) {} + +// CHECK: define { double, double } @f_ret_double_double_s() +struct double_double_s f_ret_double_double_s() { + return (struct double_double_s){1.0, 2.0}; +} + +// CHECK: define void @f_double_float_s_arg(double, float) +void f_double_float_s_arg(struct double_float_s a) {} + +// CHECK: define { double, float } @f_ret_double_float_s() +struct double_float_s f_ret_double_float_s() { + return (struct double_float_s){1.0, 2.0}; +} + +// CHECK: define void @f_double_double_s_arg_insufficient_fprs(float %a, double %b, double %c, double %d, double %e, double %f, double %g, [2 x i64] %h.coerce) +void f_double_double_s_arg_insufficient_fprs(float a, double b, double c, double d, + double e, double f, double g, struct double_double_s h) {} + +// Check that structs containing int+double values are expanded, provided +// sufficient FPRs and GPRs are available. The integer components are neither +// sign or zero-extended. + +struct double_int8_s { double f; int8_t i; }; +struct double_uint8_s { double f; uint8_t i; }; +struct double_int32_s { double f; int32_t i; }; +struct double_int64_s { double f; int64_t i; }; +struct double_int128bf_s { double f; __int128_t i : 64; }; +struct double_int8_zbf_s { double f; int8_t i; int : 0; }; + +// CHECK: define void @f_double_int8_s_arg(double, i8) +void f_double_int8_s_arg(struct double_int8_s a) {} + +// CHECK: define { double, i8 } @f_ret_double_int8_s() +struct double_int8_s f_ret_double_int8_s() { + return (struct double_int8_s){1.0, 2}; +} + +// CHECK: define void @f_double_uint8_s_arg(double, i8) +void f_double_uint8_s_arg(struct double_uint8_s a) {} + +// CHECK: define { double, i8 } @f_ret_double_uint8_s() +struct double_uint8_s f_ret_double_uint8_s() { + return (struct double_uint8_s){1.0, 2}; +} + +// CHECK: define void @f_double_int32_s_arg(double, i32) +void f_double_int32_s_arg(struct double_int32_s a) {} + +// CHECK: define { double, i32 } @f_ret_double_int32_s() +struct double_int32_s f_ret_double_int32_s() { + return (struct double_int32_s){1.0, 2}; +} + +// CHECK: define void @f_double_int64_s_arg(double, i64) +void f_double_int64_s_arg(struct double_int64_s a) {} + +// CHECK: define { double, i64 } @f_ret_double_int64_s() +struct double_int64_s f_ret_double_int64_s() { + return (struct double_int64_s){1.0, 2}; +} + +// CHECK: define void @f_double_int128bf_s_arg(double, i64) +void f_double_int128bf_s_arg(struct double_int128bf_s a) {} + +// CHECK: define { double, i64 } @f_ret_double_int128bf_s() +struct double_int128bf_s f_ret_double_int128bf_s() { + return (struct double_int128bf_s){1.0, 2}; +} + +// The zero-width bitfield means the struct can't be passed according to the +// floating point calling convention. + +// CHECK: define void @f_double_int8_zbf_s(double, i8) +void f_double_int8_zbf_s(struct double_int8_zbf_s a) {} + +// CHECK: define { double, i8 } @f_ret_double_int8_zbf_s() +struct double_int8_zbf_s f_ret_double_int8_zbf_s() { + return (struct double_int8_zbf_s){1.0, 2}; +} + +// CHECK: define void @f_double_int8_s_arg_insufficient_gprs(i32 signext %a, i32 signext %b, i32 signext %c, i32 signext %d, i32 signext %e, i32 signext %f, i32 signext %g, i32 signext %h, [2 x i64] %i.coerce) +void f_double_int8_s_arg_insufficient_gprs(int a, int b, int c, int d, int e, + int f, int g, int h, struct double_int8_s i) {} + +// CHECK: define void @f_struct_double_int8_insufficient_fprs(float %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, [2 x i64] %i.coerce) +void f_struct_double_int8_insufficient_fprs(float a, double b, double c, double d, + double e, double f, double g, double h, struct double_int8_s i) {} + +// Complex floating-point values or structs containing a single complex +// floating-point value should be passed as if it were an fp+fp struct. + +// CHECK: define void @f_doublecomplex(double %a.coerce0, double %a.coerce1) +void f_doublecomplex(double __complex__ a) {} + +// CHECK: define { double, double } @f_ret_doublecomplex() +double __complex__ f_ret_doublecomplex() { + return 1.0; +} + +struct doublecomplex_s { double __complex__ c; }; + +// CHECK: define void @f_doublecomplex_s_arg(double, double) +void f_doublecomplex_s_arg(struct doublecomplex_s a) {} + +// CHECK: define { double, double } @f_ret_doublecomplex_s() +struct doublecomplex_s f_ret_doublecomplex_s() { + return (struct doublecomplex_s){1.0}; +} + +// Test single or two-element structs that need flattening. e.g. those +// containing nested structs, doubles in small arrays, zero-length structs etc. + +struct doublearr1_s { double a[1]; }; + +// CHECK: define void @f_doublearr1_s_arg(double) +void f_doublearr1_s_arg(struct doublearr1_s a) {} + +// CHECK: define double @f_ret_doublearr1_s() +struct doublearr1_s f_ret_doublearr1_s() { + return (struct doublearr1_s){{1.0}}; +} + +struct doublearr2_s { double a[2]; }; + +// CHECK: define void @f_doublearr2_s_arg(double, double) +void f_doublearr2_s_arg(struct doublearr2_s a) {} + +// CHECK: define { double, double } @f_ret_doublearr2_s() +struct doublearr2_s f_ret_doublearr2_s() { + return (struct doublearr2_s){{1.0, 2.0}}; +} + +struct doublearr2_tricky1_s { struct { double f[1]; } g[2]; }; + +// CHECK: define void @f_doublearr2_tricky1_s_arg(double, double) +void f_doublearr2_tricky1_s_arg(struct doublearr2_tricky1_s a) {} + +// CHECK: define { double, double } @f_ret_doublearr2_tricky1_s() +struct doublearr2_tricky1_s f_ret_doublearr2_tricky1_s() { + return (struct doublearr2_tricky1_s){{{{1.0}}, {{2.0}}}}; +} + +struct doublearr2_tricky2_s { struct {}; struct { double f[1]; } g[2]; }; + +// CHECK: define void @f_doublearr2_tricky2_s_arg(double, double) +void f_doublearr2_tricky2_s_arg(struct doublearr2_tricky2_s a) {} + +// CHECK: define { double, double } @f_ret_doublearr2_tricky2_s() +struct doublearr2_tricky2_s f_ret_doublearr2_tricky2_s() { + return (struct doublearr2_tricky2_s){{}, {{{1.0}}, {{2.0}}}}; +} + +struct doublearr2_tricky3_s { union {}; struct { double f[1]; } g[2]; }; + +// CHECK: define void @f_doublearr2_tricky3_s_arg(double, double) +void f_doublearr2_tricky3_s_arg(struct doublearr2_tricky3_s a) {} + +// CHECK: define { double, double } @f_ret_doublearr2_tricky3_s() +struct doublearr2_tricky3_s f_ret_doublearr2_tricky3_s() { + return (struct doublearr2_tricky3_s){{}, {{{1.0}}, {{2.0}}}}; +} + +struct doublearr2_tricky4_s { union {}; struct { struct {}; double f[1]; } g[2]; }; + +// CHECK: define void @f_doublearr2_tricky4_s_arg(double, double) +void f_doublearr2_tricky4_s_arg(struct doublearr2_tricky4_s a) {} + +// CHECK: define { double, double } @f_ret_doublearr2_tricky4_s() +struct doublearr2_tricky4_s f_ret_doublearr2_tricky4_s() { + return (struct doublearr2_tricky4_s){{}, {{{}, {1.0}}, {{}, {2.0}}}}; +} + +// Test structs that should be passed according to the normal integer calling +// convention. + +struct int_double_int_s { int a; double b; int c; }; + +// CHECK: define void @f_int_double_int_s_arg(%struct.int_double_int_s* %a) +void f_int_double_int_s_arg(struct int_double_int_s a) {} + +// CHECK: define void @f_ret_int_double_int_s(%struct.int_double_int_s* noalias sret %agg.result) +struct int_double_int_s f_ret_int_double_int_s() { + return (struct int_double_int_s){1, 2.0, 3}; +} + +struct char_char_double_s { char a; char b; double c; }; + +// CHECK-LABEL: define void @f_char_char_double_s_arg([2 x i64] %a.coerce) +void f_char_char_double_s_arg(struct char_char_double_s a) {} + +// CHECK: define [2 x i64] @f_ret_char_char_double_s() +struct char_char_double_s f_ret_char_char_double_s() { + return (struct char_char_double_s){1, 2, 3.0}; +} + +// Unions are always passed according to the integer calling convention, even +// if they can only contain a double. + +union double_u { double a; }; + +// CHECK: define void @f_double_u_arg(i64 %a.coerce) +void f_double_u_arg(union double_u a) {} + +// CHECK: define i64 @f_ret_double_u() +union double_u f_ret_double_u() { + return (union double_u){1.0}; +} diff --git a/clang/test/CodeGen/riscv64-lp64f-lp64d-abi.c b/clang/test/CodeGen/riscv64-lp64f-lp64d-abi.c new file mode 100644 index 000000000000..eee2bc1bdcc6 --- /dev/null +++ b/clang/test/CodeGen/riscv64-lp64f-lp64d-abi.c @@ -0,0 +1,265 @@ +// RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-abi lp64f -emit-llvm %s -o - \ +// RUN: | FileCheck %s +// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-abi lp64d -emit-llvm %s -o - \ +// RUN: | FileCheck %s + +#include + +// Verify that the tracking of used GPRs and FPRs works correctly by checking +// that small integers are sign/zero extended when passed in registers. + +// Floats are passed in FPRs, so argument 'i' will be passed zero-extended +// because it will be passed in a GPR. + +// CHECK: define void @f_fpr_tracking(float %a, float %b, float %c, float %d, float %e, float %f, float %g, float %h, i8 zeroext %i) +void f_fpr_tracking(float a, float b, float c, float d, float e, float f, + float g, float h, uint8_t i) {} + +// Check that fp, fp+fp, and int+fp structs are lowered correctly. These will +// be passed in FPR, FPR+FPR, or GPR+FPR regs if sufficient registers are +// available the widths are <= XLEN and FLEN, and should be expanded to +// separate arguments in IR. They are passed by the same rules for returns, +// but will be lowered to simple two-element structs if necessary (as LLVM IR +// functions cannot return multiple values). + +// A struct containing just one floating-point real is passed as though it +// were a standalone floating-point real. + +struct float_s { float f; }; + +// CHECK: define void @f_float_s_arg(float) +void f_float_s_arg(struct float_s a) {} + +// CHECK: define float @f_ret_float_s() +struct float_s f_ret_float_s() { + return (struct float_s){1.0}; +} + +// A struct containing a float and any number of zero-width bitfields is +// passed as though it were a standalone floating-point real. + +struct zbf_float_s { int : 0; float f; }; +struct zbf_float_zbf_s { int : 0; float f; int : 0; }; + +// CHECK: define void @f_zbf_float_s_arg(float) +void f_zbf_float_s_arg(struct zbf_float_s a) {} + +// CHECK: define float @f_ret_zbf_float_s() +struct zbf_float_s f_ret_zbf_float_s() { + return (struct zbf_float_s){1.0}; +} + +// CHECK: define void @f_zbf_float_zbf_s_arg(float) +void f_zbf_float_zbf_s_arg(struct zbf_float_zbf_s a) {} + +// CHECK: define float @f_ret_zbf_float_zbf_s() +struct zbf_float_zbf_s f_ret_zbf_float_zbf_s() { + return (struct zbf_float_zbf_s){1.0}; +} + +// Check that structs containing two float values (FLEN <= width) are expanded +// provided sufficient FPRs are available. + +struct float_float_s { float f; float g; }; + +// CHECK: define void @f_float_float_s_arg(float, float) +void f_float_float_s_arg(struct float_float_s a) {} + +// CHECK: define { float, float } @f_ret_float_float_s() +struct float_float_s f_ret_float_float_s() { + return (struct float_float_s){1.0, 2.0}; +} + +// CHECK: define void @f_float_float_s_arg_insufficient_fprs(float %a, float %b, float %c, float %d, float %e, float %f, float %g, i64 %h.coerce) +void f_float_float_s_arg_insufficient_fprs(float a, float b, float c, float d, + float e, float f, float g, struct float_float_s h) {} + +// Check that structs containing int+float values are expanded, provided +// sufficient FPRs and GPRs are available. The integer components are neither +// sign or zero-extended. + +struct float_int8_s { float f; int8_t i; }; +struct float_uint8_s { float f; uint8_t i; }; +struct float_int32_s { float f; int32_t i; }; +struct float_int64_s { float f; int64_t i; }; +struct float_int128bf_s { float f; __int128_t i : 64; }; +struct float_int8_zbf_s { float f; int8_t i; int : 0; }; + +// CHECK: define void @f_float_int8_s_arg(float, i8) +void f_float_int8_s_arg(struct float_int8_s a) {} + +// CHECK: define { float, i8 } @f_ret_float_int8_s() +struct float_int8_s f_ret_float_int8_s() { + return (struct float_int8_s){1.0, 2}; +} + +// CHECK: define void @f_float_uint8_s_arg(float, i8) +void f_float_uint8_s_arg(struct float_uint8_s a) {} + +// CHECK: define { float, i8 } @f_ret_float_uint8_s() +struct float_uint8_s f_ret_float_uint8_s() { + return (struct float_uint8_s){1.0, 2}; +} + +// CHECK: define void @f_float_int32_s_arg(float, i32) +void f_float_int32_s_arg(struct float_int32_s a) {} + +// CHECK: define { float, i32 } @f_ret_float_int32_s() +struct float_int32_s f_ret_float_int32_s() { + return (struct float_int32_s){1.0, 2}; +} + +// CHECK: define void @f_float_int64_s_arg(float, i64) +void f_float_int64_s_arg(struct float_int64_s a) {} + +// CHECK: define { float, i64 } @f_ret_float_int64_s() +struct float_int64_s f_ret_float_int64_s() { + return (struct float_int64_s){1.0, 2}; +} + +// CHECK: define void @f_float_int128bf_s_arg(float, i64) +void f_float_int128bf_s_arg(struct float_int128bf_s a) {} + +// CHECK: define <{ float, i64 }> @f_ret_float_int128bf_s() +struct float_int128bf_s f_ret_float_int128bf_s() { + return (struct float_int128bf_s){1.0, 2}; +} + +// The zero-width bitfield means the struct can't be passed according to the +// floating point calling convention. + +// CHECK: define void @f_float_int8_zbf_s(float, i8) +void f_float_int8_zbf_s(struct float_int8_zbf_s a) {} + +// CHECK: define { float, i8 } @f_ret_float_int8_zbf_s() +struct float_int8_zbf_s f_ret_float_int8_zbf_s() { + return (struct float_int8_zbf_s){1.0, 2}; +} + +// CHECK: define void @f_float_int8_s_arg_insufficient_gprs(i32 signext %a, i32 signext %b, i32 signext %c, i32 signext %d, i32 signext %e, i32 signext %f, i32 signext %g, i32 signext %h, i64 %i.coerce) +void f_float_int8_s_arg_insufficient_gprs(int a, int b, int c, int d, int e, + int f, int g, int h, struct float_int8_s i) {} + +// CHECK: define void @f_struct_float_int8_insufficient_fprs(float %a, float %b, float %c, float %d, float %e, float %f, float %g, float %h, i64 %i.coerce) +void f_struct_float_int8_insufficient_fprs(float a, float b, float c, float d, + float e, float f, float g, float h, struct float_int8_s i) {} + +// Complex floating-point values or structs containing a single complex +// floating-point value should be passed as if it were an fp+fp struct. + +// CHECK: define void @f_floatcomplex(float %a.coerce0, float %a.coerce1) +void f_floatcomplex(float __complex__ a) {} + +// CHECK: define { float, float } @f_ret_floatcomplex() +float __complex__ f_ret_floatcomplex() { + return 1.0; +} + +struct floatcomplex_s { float __complex__ c; }; + +// CHECK: define void @f_floatcomplex_s_arg(float, float) +void f_floatcomplex_s_arg(struct floatcomplex_s a) {} + +// CHECK: define { float, float } @f_ret_floatcomplex_s() +struct floatcomplex_s f_ret_floatcomplex_s() { + return (struct floatcomplex_s){1.0}; +} + +// Test single or two-element structs that need flattening. e.g. those +// containing nested structs, floats in small arrays, zero-length structs etc. + +struct floatarr1_s { float a[1]; }; + +// CHECK: define void @f_floatarr1_s_arg(float) +void f_floatarr1_s_arg(struct floatarr1_s a) {} + +// CHECK: define float @f_ret_floatarr1_s() +struct floatarr1_s f_ret_floatarr1_s() { + return (struct floatarr1_s){{1.0}}; +} + +struct floatarr2_s { float a[2]; }; + +// CHECK: define void @f_floatarr2_s_arg(float, float) +void f_floatarr2_s_arg(struct floatarr2_s a) {} + +// CHECK: define { float, float } @f_ret_floatarr2_s() +struct floatarr2_s f_ret_floatarr2_s() { + return (struct floatarr2_s){{1.0, 2.0}}; +} + +struct floatarr2_tricky1_s { struct { float f[1]; } g[2]; }; + +// CHECK: define void @f_floatarr2_tricky1_s_arg(float, float) +void f_floatarr2_tricky1_s_arg(struct floatarr2_tricky1_s a) {} + +// CHECK: define { float, float } @f_ret_floatarr2_tricky1_s() +struct floatarr2_tricky1_s f_ret_floatarr2_tricky1_s() { + return (struct floatarr2_tricky1_s){{{{1.0}}, {{2.0}}}}; +} + +struct floatarr2_tricky2_s { struct {}; struct { float f[1]; } g[2]; }; + +// CHECK: define void @f_floatarr2_tricky2_s_arg(float, float) +void f_floatarr2_tricky2_s_arg(struct floatarr2_tricky2_s a) {} + +// CHECK: define { float, float } @f_ret_floatarr2_tricky2_s() +struct floatarr2_tricky2_s f_ret_floatarr2_tricky2_s() { + return (struct floatarr2_tricky2_s){{}, {{{1.0}}, {{2.0}}}}; +} + +struct floatarr2_tricky3_s { union {}; struct { float f[1]; } g[2]; }; + +// CHECK: define void @f_floatarr2_tricky3_s_arg(float, float) +void f_floatarr2_tricky3_s_arg(struct floatarr2_tricky3_s a) {} + +// CHECK: define { float, float } @f_ret_floatarr2_tricky3_s() +struct floatarr2_tricky3_s f_ret_floatarr2_tricky3_s() { + return (struct floatarr2_tricky3_s){{}, {{{1.0}}, {{2.0}}}}; +} + +struct floatarr2_tricky4_s { union {}; struct { struct {}; float f[1]; } g[2]; }; + +// CHECK: define void @f_floatarr2_tricky4_s_arg(float, float) +void f_floatarr2_tricky4_s_arg(struct floatarr2_tricky4_s a) {} + +// CHECK: define { float, float } @f_ret_floatarr2_tricky4_s() +struct floatarr2_tricky4_s f_ret_floatarr2_tricky4_s() { + return (struct floatarr2_tricky4_s){{}, {{{}, {1.0}}, {{}, {2.0}}}}; +} + +// Test structs that should be passed according to the normal integer calling +// convention. + +struct int_float_int_s { int a; float b; int c; }; + +// CHECK: define void @f_int_float_int_s_arg([2 x i64] %a.coerce) +void f_int_float_int_s_arg(struct int_float_int_s a) {} + +// CHECK: define [2 x i64] @f_ret_int_float_int_s() +struct int_float_int_s f_ret_int_float_int_s() { + return (struct int_float_int_s){1, 2.0, 3}; +} + +struct char_char_float_s { char a; char b; float c; }; + +// CHECK-LABEL: define void @f_char_char_float_s_arg(i64 %a.coerce) +void f_char_char_float_s_arg(struct char_char_float_s a) {} + +// CHECK: define i64 @f_ret_char_char_float_s() +struct char_char_float_s f_ret_char_char_float_s() { + return (struct char_char_float_s){1, 2, 3.0}; +} + +// Unions are always passed according to the integer calling convention, even +// if they can only contain a float. + +union float_u { float a; }; + +// CHECK: define void @f_float_u_arg(i64 %a.coerce) +void f_float_u_arg(union float_u a) {} + +// CHECK: define i64 @f_ret_float_u() +union float_u f_ret_float_u() { + return (union float_u){1.0}; +} diff --git a/clang/test/CodeGenCXX/PR42665.cpp b/clang/test/CodeGenCXX/PR42665.cpp new file mode 100644 index 000000000000..99e180171a3e --- /dev/null +++ b/clang/test/CodeGenCXX/PR42665.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -std=c++17 -O0 %s -emit-llvm -o /dev/null -verify -triple %itanium_abi_triple +// RUN: %clang_cc1 -std=c++17 -O0 %s -emit-llvm -o /dev/null -verify -triple %ms_abi_triple + +// Minimal reproducer for PR42665. +// expected-no-diagnostics + +struct Foo { + Foo() = default; + virtual ~Foo() = default; +}; + +template +struct Pair { + Foo first; + Deleter second; +}; + +template +Pair(Foo, Deleter) -> Pair; + +template +void deleter(T& t) { t.~T(); } + +auto make_pair() { + return Pair{ Foo(), deleter }; +} + +void foobar() { + auto p = make_pair(); + auto& f = p.first; + auto& d = p.second; + d(f); // Invoke virtual destructor of Foo through d. +} // p's destructor is invoked. + diff --git a/clang/test/CodeGenCXX/dllexport.cpp b/clang/test/CodeGenCXX/dllexport.cpp index 16cfb8465845..59ba6d854883 100644 --- a/clang/test/CodeGenCXX/dllexport.cpp +++ b/clang/test/CodeGenCXX/dllexport.cpp @@ -851,6 +851,22 @@ struct __declspec(dllexport) Baz { // Baz's operator=, causing instantiation of Foo after which // ActOnFinishCXXNonNestedClass is called, and we would bite our own tail. // M32-DAG: define weak_odr dso_local dllexport x86_thiscallcc dereferenceable(1) %"struct.InClassInits::Baz"* @"??4Baz@InClassInits@@QAEAAU01@ABU01@@Z" + +// Trying to define the explicitly defaulted ctor must be delayed until the +// in-class initializer for x has been processed. +struct PR40006 { + __declspec(dllexport) PR40006() = default; + int x = 42; +}; +// M32-DAG: define weak_odr dso_local dllexport x86_thiscallcc %"struct.InClassInits::PR40006"* @"??0PR40006@InClassInits@@QAE@XZ" + +// PR42857: Clang would try to emit the non-trivial explicitly defaulted +// dllexport ctor twice when doing an explicit instantiation definition. +struct Qux { Qux(); }; +template struct PR42857 { __declspec(dllexport) PR42857() = default; Qux q; }; +template struct PR42857; +// M32-DAG: define weak_odr dso_local dllexport x86_thiscallcc %"struct.InClassInits::PR42857"* @"??0?$PR42857@H@InClassInits@@QAE@XZ" + } // We had an issue where instantiating A would force emission of B's delayed diff --git a/clang/test/CodeGenCXX/mangle-address-space.cpp b/clang/test/CodeGenCXX/mangle-address-space.cpp index 549ae54dfbe4..2c5cdfc3dadb 100644 --- a/clang/test/CodeGenCXX/mangle-address-space.cpp +++ b/clang/test/CodeGenCXX/mangle-address-space.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -emit-llvm -triple %itanium_abi_triple -o - %s | FileCheck %s --check-prefixes=CHECK,CHECKNOOCL // RUN: %clang_cc1 -emit-llvm -triple x86_64-windows-msvc -o - %s | FileCheck %s --check-prefixes=WIN,WINNOOCL -// RUN: %clang_cc1 -cl-std=c++ -emit-llvm -triple %itanium_abi_triple -o - %s | FileCheck %s --check-prefixes=CHECK,CHECKOCL -// RUN: %clang_cc1 -cl-std=c++ -emit-llvm -triple x86_64-windows-msvc -o - %s | FileCheck %s --check-prefixes=WIN,WINOCL +// RUN: %clang_cc1 -cl-std=clc++ -emit-llvm -triple %itanium_abi_triple -o - %s | FileCheck %s --check-prefixes=CHECK,CHECKOCL +// RUN: %clang_cc1 -cl-std=clc++ -emit-llvm -triple x86_64-windows-msvc -o - %s | FileCheck %s --check-prefixes=WIN,WINOCL // CHECKNOOCL-LABEL: define {{.*}}void @_Z2f0Pc // WINNOOCL-LABEL: define {{.*}}void @"?f0@@YAXPEAD@Z" diff --git a/clang/test/CodeGenCXX/ms-constexpr-var-template.cpp b/clang/test/CodeGenCXX/ms-constexpr-var-template.cpp new file mode 100644 index 000000000000..a40f7aacac03 --- /dev/null +++ b/clang/test/CodeGenCXX/ms-constexpr-var-template.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -emit-llvm -triple=x86_64-windows-msvc -fms-compatibility %s -o - | FileCheck %s + +template constexpr bool _Is_integer = false; +template <> constexpr bool _Is_integer = true; +template <> constexpr bool _Is_integer = false; +extern "C" const bool *escape = &_Is_integer; + +// CHECK: @"??$_Is_integer@H@@3_NB" = linkonce_odr dso_local constant i8 1, comdat, align 1 +// Should not emit _Is_integer, since it's not referenced. +// CHECK-NOT: @"??$_Is_integer@D@@3_NB" +// CHECK: @escape = dso_local global i8* @"??$_Is_integer@H@@3_NB", align 8 diff --git a/clang/test/CodeGenCXX/pr40771-ctad-with-lambda-copy-capture.cpp b/clang/test/CodeGenCXX/pr40771-ctad-with-lambda-copy-capture.cpp new file mode 100644 index 000000000000..36cec1e7068e --- /dev/null +++ b/clang/test/CodeGenCXX/pr40771-ctad-with-lambda-copy-capture.cpp @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm --std=c++17 -fcxx-exceptions -fexceptions -discard-value-names %s -o - | FileCheck %s + +struct Q { Q(); }; +struct R { R(Q); ~R(); }; +struct S { S(Q); ~S(); }; +struct T : R, S {}; + +Q q; +T t { R{q}, S{q} }; + +// CHECK-LABEL: define internal void @__cxx_global_var_init.1() {{.*}} { +// CHECK-NEXT: [[TMP_R:%[a-z0-9.]+]] = alloca %struct.R, align 1 +// CHECK-NEXT: [[TMP_Q1:%[a-z0-9.]+]] = alloca %struct.Q, align 1 +// CHECK-NEXT: [[TMP_S:%[a-z0-9.]+]] = alloca %struct.S, align 1 +// CHECK-NEXT: [[TMP_Q2:%[a-z0-9.]+]] = alloca %struct.Q, align 1 +// CHECK-NEXT: [[XPT:%[a-z0-9.]+]] = alloca i8* +// CHECK-NEXT: [[SLOT:%[a-z0-9.]+]] = alloca i32 +// CHECK-NEXT: [[ACTIVE:%[a-z0-9.]+]] = alloca i1, align 1 +// CHECK-NEXT: call void @_ZN1RC1E1Q(%struct.R* [[TMP_R]]) +// CHECK-NEXT: store i1 true, i1* [[ACTIVE]], align 1 +// CHECK-NEXT: invoke void @_ZN1SC1E1Q(%struct.S* [[TMP_S]]) +// CHECK-NEXT: to label %[[L1:[a-z0-9.]+]] unwind label %[[L2:[a-z0-9.]+]] +// CHECK-EMPTY: +// CHECK-NEXT: [[L1]]: +// CHECK-NEXT: store i1 false, i1* [[ACTIVE]], align 1 +// CHECK-NEXT: call void @_ZN1SD1Ev(%struct.S* +// CHECK-NEXT: call void @_ZN1RD1Ev(%struct.R* +// CHECK-NEXT: [[EXIT:%[a-z0-9.]+]] = call i32 @__cxa_atexit( +// CHECK-NEXT: ret void +// CHECK-EMPTY: +// CHECK-NEXT: [[L2]]: +// CHECK-NEXT: [[LP:%[a-z0-9.]+]] = landingpad { i8*, i32 } +// CHECK-NEXT: cleanup +// CHECK-NEXT: [[X1:%[a-z0-9.]+]] = extractvalue { i8*, i32 } [[LP]], 0 +// CHECK-NEXT: store i8* [[X1]], i8** [[XPT]], align 8 +// CHECK-NEXT: [[X2:%[a-z0-9.]+]] = extractvalue { i8*, i32 } [[LP]], 1 +// CHECK-NEXT: store i32 [[X2]], i32* [[SLOT]], align 4 +// CHECK-NEXT: [[IS_ACT:%[a-z0-9.]+]] = load i1, i1* [[ACTIVE]], align 1 +// CHECK-NEXT: br i1 [[IS_ACT]], label %[[L3:[a-z0-9.]+]], label %[[L4:[a-z0-9.]+]] +// CHECK-EMPTY: +// CHECK-NEXT: [[L3]]: +// CHECK-NEXT: call void @_ZN1RD1Ev(%struct.R* +// CHECK-NEXT: br label %[[L4]] +// CHECK-EMPTY: +// CHECK-NEXT: [[L4]]: +// CHECK-NEXT: call void @_ZN1RD1Ev(%struct.R* [[TMP_R]]) +// CHECK-NEXT: br label %[[L5:[a-z0-9.]+]] +// CHECK-EMPTY: +// CHECK-NEXT: [[L5]]: +// CHECK-NEXT: [[EXN:%[a-z0-9.]+]] = load i8*, i8** [[XPT]], align 8 +// CHECK-NEXT: [[SEL:%[a-z0-9.]+]] = load i32, i32* [[SLOT]], align 4 +// CHECK-NEXT: [[LV1:%[a-z0-9.]+]] = insertvalue { i8*, i32 } undef, i8* [[EXN]], 0 +// CHECK-NEXT: [[LV2:%[a-z0-9.]+]] = insertvalue { i8*, i32 } [[LV1]], i32 [[SEL]], 1 +// CHECK-NEXT: resume { i8*, i32 } [[LV2]] +// CHECK-NEXT: } diff --git a/clang/test/CodeGenOpenCL/builtins.cl b/clang/test/CodeGenOpenCL/builtins.cl index 1ef7d2a6d551..36a6fb6b664c 100644 --- a/clang/test/CodeGenOpenCL/builtins.cl +++ b/clang/test/CodeGenOpenCL/builtins.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -finclude-default-header -cl-std=c++ -fblocks -O0 -emit-llvm -o - -triple "spir-unknown-unknown" | FileCheck %s +// RUN: %clang_cc1 %s -finclude-default-header -cl-std=clc++ -fblocks -O0 -emit-llvm -o - -triple "spir-unknown-unknown" | FileCheck %s void testBranchingOnEnqueueKernel(queue_t default_queue, unsigned flags, ndrange_t ndrange) { // Ensure `enqueue_kernel` can be branched upon. diff --git a/clang/test/CodeGenOpenCL/images.cl b/clang/test/CodeGenOpenCL/images.cl index baa919784706..326322d3d4a6 100644 --- a/clang/test/CodeGenOpenCL/images.cl +++ b/clang/test/CodeGenOpenCL/images.cl @@ -1,5 +1,5 @@ // RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -O0 -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -O0 -emit-llvm -o - -cl-std=c++ | FileCheck %s +// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -O0 -emit-llvm -o - -cl-std=clc++ | FileCheck %s __attribute__((overloadable)) void read_image(read_only image1d_t img_ro); __attribute__((overloadable)) void read_image(write_only image1d_t img_wo); diff --git a/clang/test/CodeGenOpenCL/logical-ops.cl b/clang/test/CodeGenOpenCL/logical-ops.cl index 77334d3b37b7..f083a8580ee7 100644 --- a/clang/test/CodeGenOpenCL/logical-ops.cl +++ b/clang/test/CodeGenOpenCL/logical-ops.cl @@ -1,5 +1,5 @@ // RUN: %clang_cc1 %s -emit-llvm -o - -cl-std=CL1.2 -O1 -triple x86_64-unknown-linux-gnu | FileCheck %s -// RUN: %clang_cc1 %s -emit-llvm -o - -cl-std=c++ -O1 -triple x86_64-unknown-linux-gnu | FileCheck %s +// RUN: %clang_cc1 %s -emit-llvm -o - -cl-std=clc++ -O1 -triple x86_64-unknown-linux-gnu | FileCheck %s #pragma OPENCL EXTENSION cl_khr_fp64 : enable diff --git a/clang/test/CodeGenOpenCL/pipe_builtin.cl b/clang/test/CodeGenOpenCL/pipe_builtin.cl index 1a001f9bd61f..02b9669b7ab1 100644 --- a/clang/test/CodeGenOpenCL/pipe_builtin.cl +++ b/clang/test/CodeGenOpenCL/pipe_builtin.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -cl-ext=+cl_khr_subgroups -O0 -cl-std=c++ -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm -cl-ext=+cl_khr_subgroups -O0 -cl-std=clc++ -o - %s | FileCheck %s // FIXME: Add MS ABI manglings of OpenCL things and remove %itanium_abi_triple // above to support OpenCL in the MS C++ ABI. diff --git a/clang/test/CodeGenOpenCL/sampler.cl b/clang/test/CodeGenOpenCL/sampler.cl index 1ef1f538b256..ed3f32d6c53c 100644 --- a/clang/test/CodeGenOpenCL/sampler.cl +++ b/clang/test/CodeGenOpenCL/sampler.cl @@ -1,6 +1,6 @@ // RUN: %clang_cc1 %s -emit-llvm -triple spir-unknown-unknown -o - -O0 | FileCheck %s // RUN: %clang_cc1 %s -cl-std=CL2.0 -emit-llvm -triple spir-unknown-unknown -o - -O0 | FileCheck %s -// RUN: %clang_cc1 %s -cl-std=c++ -emit-llvm -triple spir-unknown-unknown -o - -O0 | FileCheck %s +// RUN: %clang_cc1 %s -cl-std=clc++ -emit-llvm -triple spir-unknown-unknown -o - -O0 | FileCheck %s // // This test covers 5 cases of sampler initialzation: // 1. function argument passing diff --git a/clang/test/CodeGenOpenCL/spir_version.cl b/clang/test/CodeGenOpenCL/spir_version.cl index 03f3f20885de..39893de0f56d 100644 --- a/clang/test/CodeGenOpenCL/spir_version.cl +++ b/clang/test/CodeGenOpenCL/spir_version.cl @@ -6,7 +6,7 @@ // RUN: %clang_cc1 %s -triple "spir64-unknown-unknown" -emit-llvm -o - -cl-std=CL2.0 | FileCheck %s --check-prefix=CHECK-SPIR-CL20 -// RUN: %clang_cc1 %s -triple "spir64-unknown-unknown" -emit-llvm -o - -cl-std=c++ | FileCheck %s --check-prefix=CHECK-SPIR-CL20 +// RUN: %clang_cc1 %s -triple "spir64-unknown-unknown" -emit-llvm -o - -cl-std=clc++ | FileCheck %s --check-prefix=CHECK-SPIR-CL20 // RUN: %clang_cc1 %s -triple "amdgcn--amdhsa" -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-AMDGCN-CL10 // RUN: %clang_cc1 %s -triple "amdgcn--amdhsa" -emit-llvm -o - -cl-std=CL1.2 | FileCheck %s --check-prefix=CHECK-AMDGCN-CL12 diff --git a/clang/test/CodeGenOpenCL/to_addr_builtin.cl b/clang/test/CodeGenOpenCL/to_addr_builtin.cl index 19b8a107df33..52dd72f18a34 100644 --- a/clang/test/CodeGenOpenCL/to_addr_builtin.cl +++ b/clang/test/CodeGenOpenCL/to_addr_builtin.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple spir-unknown-unknown -emit-llvm -O0 -cl-std=c++ -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple spir-unknown-unknown -emit-llvm -O0 -cl-std=clc++ -o - %s | FileCheck %s // CHECK: %[[A:.*]] = type { float, float, float } typedef struct { diff --git a/clang/test/CodeGenOpenCL/vector_literals_nested.cl b/clang/test/CodeGenOpenCL/vector_literals_nested.cl deleted file mode 100644 index b9013d0482f9..000000000000 --- a/clang/test/CodeGenOpenCL/vector_literals_nested.cl +++ /dev/null @@ -1,23 +0,0 @@ -// RUN: %clang_cc1 %s -emit-llvm -O3 -o - | FileCheck %s - -typedef int int2 __attribute((ext_vector_type(2))); -typedef int int4 __attribute((ext_vector_type(4))); - -__constant const int4 itest1 = (int4)(1, 2, ((int2)(3, 4))); -// CHECK: constant <4 x i32> -__constant const int4 itest2 = (int4)(1, 2, ((int2)(3))); -// CHECK: constant <4 x i32> - -typedef float float2 __attribute((ext_vector_type(2))); -typedef float float4 __attribute((ext_vector_type(4))); - -void ftest1(float4 *p) { - *p = (float4)(1.1f, 1.2f, ((float2)(1.3f, 1.4f))); -// CHECK: store <4 x float> -} - -float4 ftest2(float4 *p) { - *p = (float4)(1.1f, 1.2f, ((float2)(1.3f))); -// CHECK: store <4 x float> -} - diff --git a/clang/test/CodeGenOpenCL/vector_literals_valid.cl b/clang/test/CodeGenOpenCL/vector_literals_valid.cl index bba5b23e23bd..249c95cd756d 100644 --- a/clang/test/CodeGenOpenCL/vector_literals_valid.cl +++ b/clang/test/CodeGenOpenCL/vector_literals_valid.cl @@ -1,22 +1,65 @@ -// RUN: %clang_cc1 -emit-llvm %s -o %t +// RUN: %clang_cc1 -emit-llvm %s -o - -O0 | FileCheck %s +// RUN: %clang_cc1 -emit-llvm %s -o - -cl-std=clc++ -O0 | FileCheck %s -typedef __attribute__(( ext_vector_type(2) )) int int2; -typedef __attribute__(( ext_vector_type(3) )) int int3; -typedef __attribute__(( ext_vector_type(4) )) int int4; -typedef __attribute__(( ext_vector_type(8) )) int int8; -typedef __attribute__(( ext_vector_type(4) )) float float4; +typedef __attribute__((ext_vector_type(2))) int int2; +typedef __attribute__((ext_vector_type(3))) int int3; +typedef __attribute__((ext_vector_type(4))) int int4; +typedef __attribute__((ext_vector_type(8))) int int8; +typedef __attribute__((ext_vector_type(4))) float float4; + +__constant const int4 c1 = (int4)(1, 2, ((int2)(3))); +// CHECK: constant <4 x i32> + +__constant const int4 c2 = (int4)(1, 2, ((int2)(3, 4))); +// CHECK: constant <4 x i32> void vector_literals_valid() { - int4 a_1_1_1_1 = (int4)(1,2,3,4); - int4 a_2_1_1 = (int4)((int2)(1,2),3,4); - int4 a_1_2_1 = (int4)(1,(int2)(2,3),4); - int4 a_1_1_2 = (int4)(1,2,(int2)(3,4)); - int4 a_2_2 = (int4)((int2)(1,2),(int2)(3,4)); - int4 a_3_1 = (int4)((int3)(1,2,3),4); - int4 a_1_3 = (int4)(1,(int3)(2,3,4)); + //CHECK: insertelement <4 x i32> , i32 %{{.+}}, i32 2 + //CHECK: insertelement <4 x i32> %{{.+}}, i32 %{{.+}}, i32 3 + int4 a_1_1_1_1 = (int4)(1, 2, c1.s2, c2.s3); + + //CHECK: store <2 x i32> , <2 x i32>* + //CHECK: shufflevector <2 x i32> %{{[0-9]+}}, <2 x i32> undef, <4 x i32> + //CHECK: shufflevector <4 x i32> %{{.+}}, <4 x i32> undef, <4 x i32> + //CHECK: insertelement <4 x i32> %{{.+}}, i32 3, i32 2 + //CHECK: insertelement <4 x i32> %{{.+}}, i32 4, i32 3 + int4 a_2_1_1 = (int4)((int2)(1, 2), 3, 4); + + //CHECK: store <2 x i32> , <2 x i32>* + //CHECK: shufflevector <2 x i32> %{{[0-9]+}}, <2 x i32> undef, <4 x i32> + //CHECK: shufflevector <4 x i32> , <4 x i32> %{{.+}}, <4 x i32> + //CHECK: insertelement <4 x i32> %{{.+}}, i32 4, i32 3 + int4 a_1_2_1 = (int4)(1, (int2)(2, 3), 4); + + //CHECK: store <2 x i32> , <2 x i32>* + //CHECK: shufflevector <2 x i32> %{{[0-9]+}}, <2 x i32> undef, <4 x i32> + //CHECK: shufflevector <4 x i32> , <4 x i32> %{{.+}}, <4 x i32> + int4 a_1_1_2 = (int4)(1, 2, (int2)(3, 4)); + + //CHECK: store <2 x i32> , <2 x i32>* + //CHECK: shufflevector <2 x i32> %{{[0-9]+}}, <2 x i32> undef, <4 x i32> + //CHECK: shufflevector <4 x i32> %{{.+}}, <4 x i32> undef, <4 x i32> + //CHECK: shufflevector <4 x i32> %{{.+}}, <4 x i32> , <4 x i32> + int4 a_2_2 = (int4)((int2)(1, 2), (int2)(3)); + + //CHECK: store <4 x i32> , <4 x i32>* + //CHECK: shufflevector <4 x i32> %{{.+}}, <4 x i32> undef, <3 x i32> + //CHECK: shufflevector <3 x i32> %{{.+}}, <3 x i32> undef, <4 x i32> + //CHECK: shufflevector <4 x i32> , <4 x i32> %{{.+}}, <4 x i32> + int4 a_1_3 = (int4)(1, (int3)(2, 3, 4)); + + //CHECK: store <4 x i32> , <4 x i32>* %a int4 a = (int4)(1); - int8 b = (int8)(1,2,a.xy,a); - float4 V2 = (float4) (1); -} + //CHECK: load <4 x i32>, <4 x i32>* %a + //CHECK: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> undef, <2 x i32> + //CHECK: shufflevector <2 x i32> %{{[0-9]+}}, <2 x i32> undef, <8 x i32> + //CHECK: shufflevector <8 x i32> , <8 x i32> %{{.+}}, <8 x i32> + //CHECK: load <4 x i32>, <4 x i32>* %a + //CHECK: shufflevector <4 x i32> %{{[0-9]+}}, <4 x i32> undef, <8 x i32> + //CHECK: shufflevector <8 x i32> %{{.+}}, <8 x i32> %{{.+}}, <8 x i32> + int8 b = (int8)(1, 2, a.xy, a); + //CHECK: store <4 x float> , <4 x float>* %V2 + float4 V2 = (float4)(1); +} diff --git a/clang/test/CodeGenOpenCLCXX/address-space-castoperators.cpp b/clang/test/CodeGenOpenCLCXX/address-space-castoperators.cpp index e5c3ee880ccc..61308323e82b 100644 --- a/clang/test/CodeGenOpenCLCXX/address-space-castoperators.cpp +++ b/clang/test/CodeGenOpenCLCXX/address-space-castoperators.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -emit-llvm -O0 -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -emit-llvm -O0 -o - | FileCheck %s void test_reinterpret_cast(){ __private float x; diff --git a/clang/test/CodeGenOpenCLCXX/address-space-deduction.cl b/clang/test/CodeGenOpenCLCXX/address-space-deduction.cl index a6c8bc617ae1..a6ae5af01eba 100644 --- a/clang/test/CodeGenOpenCLCXX/address-space-deduction.cl +++ b/clang/test/CodeGenOpenCLCXX/address-space-deduction.cl @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -O0 -emit-llvm -o - | FileCheck %s -check-prefixes=COMMON,PTR -// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -O0 -emit-llvm -o - -DREF | FileCheck %s -check-prefixes=COMMON,REF +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -O0 -emit-llvm -o - | FileCheck %s -check-prefixes=COMMON,PTR +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -O0 -emit-llvm -o - -DREF | FileCheck %s -check-prefixes=COMMON,REF #ifdef REF #define PTR & diff --git a/clang/test/CodeGenOpenCLCXX/address-space-deduction2.cl b/clang/test/CodeGenOpenCLCXX/address-space-deduction2.cl index 6772cdcb11d0..36e89499c954 100644 --- a/clang/test/CodeGenOpenCLCXX/address-space-deduction2.cl +++ b/clang/test/CodeGenOpenCLCXX/address-space-deduction2.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -O0 -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -O0 -emit-llvm -o - | FileCheck %s class P { public: diff --git a/clang/test/CodeGenOpenCLCXX/addrspace-conversion.cl b/clang/test/CodeGenOpenCLCXX/addrspace-conversion.cl index 38422c24e859..a80662f72334 100644 --- a/clang/test/CodeGenOpenCLCXX/addrspace-conversion.cl +++ b/clang/test/CodeGenOpenCLCXX/addrspace-conversion.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -emit-llvm -O0 -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -emit-llvm -O0 -o - | FileCheck %s void bar(__generic volatile unsigned int* ptr) { diff --git a/clang/test/CodeGenOpenCLCXX/addrspace-derived-base.cl b/clang/test/CodeGenOpenCLCXX/addrspace-derived-base.cl index 59e29ee41719..916bb50ae822 100644 --- a/clang/test/CodeGenOpenCLCXX/addrspace-derived-base.cl +++ b/clang/test/CodeGenOpenCLCXX/addrspace-derived-base.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -triple spir -cl-std=c++ -emit-llvm -O0 -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple spir -cl-std=clc++ -emit-llvm -O0 -o - | FileCheck %s struct B { int mb; @@ -12,11 +12,11 @@ public: void foo() { D d; //CHECK: addrspacecast %class.D* %d to %class.D addrspace(4)* - //CHECK: call i32 @_ZNU3AS41D5getmbEv(%class.D addrspace(4)* + //CHECK: call spir_func i32 @_ZNU3AS41D5getmbEv(%class.D addrspace(4)* d.getmb(); } //Derived and Base are in the same address space. -//CHECK: define linkonce_odr i32 @_ZNU3AS41D5getmbEv(%class.D addrspace(4)* %this) +//CHECK: define linkonce_odr spir_func i32 @_ZNU3AS41D5getmbEv(%class.D addrspace(4)* %this) //CHECK: bitcast %class.D addrspace(4)* %this1 to %struct.B addrspace(4)* diff --git a/clang/test/CodeGenOpenCLCXX/addrspace-of-this.cl b/clang/test/CodeGenOpenCLCXX/addrspace-of-this.cl index aa1a91e4dc76..8a282ac21d4b 100644 --- a/clang/test/CodeGenOpenCLCXX/addrspace-of-this.cl +++ b/clang/test/CodeGenOpenCLCXX/addrspace-of-this.cl @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -emit-llvm -pedantic -verify -O0 -o - -DDECL | FileCheck %s --check-prefixes="COMMON,EXPL" -// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -emit-llvm -pedantic -verify -O0 -o - -DDECL -DUSE_DEFLT | FileCheck %s --check-prefixes="COMMON,IMPL" -// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -emit-llvm -pedantic -verify -O0 -o - | FileCheck %s --check-prefixes="COMMON,IMPL" +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -emit-llvm -pedantic -verify -O0 -o - -DDECL | FileCheck %s --check-prefixes="COMMON,EXPL" +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -emit-llvm -pedantic -verify -O0 -o - -DDECL -DUSE_DEFLT | FileCheck %s --check-prefixes="COMMON,IMPL" +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -emit-llvm -pedantic -verify -O0 -o - | FileCheck %s --check-prefixes="COMMON,IMPL" // expected-no-diagnostics // Test that the 'this' pointer is in the __generic address space. @@ -81,32 +81,32 @@ __kernel void test__global() { // COMMON: @_ZNU3AS41C7outsideEv(%class.C addrspace(4)* %this) // EXPL-LABEL: @__cxx_global_var_init() -// EXPL: call void @_ZNU3AS41CC1Ev(%class.C addrspace(4)* addrspacecast (%class.C addrspace(1)* @c to %class.C addrspace(4)*)) +// EXPL: call spir_func void @_ZNU3AS41CC1Ev(%class.C addrspace(4)* addrspacecast (%class.C addrspace(1)* @c to %class.C addrspace(4)*)) // COMMON-LABEL: @test__global() // Test the address space of 'this' when invoking a method. -// COMMON: call i32 @_ZNU3AS41C3getEv(%class.C addrspace(4)* addrspacecast (%class.C addrspace(1)* @c to %class.C addrspace(4)*)) +// COMMON: call spir_func i32 @_ZNU3AS41C3getEv(%class.C addrspace(4)* addrspacecast (%class.C addrspace(1)* @c to %class.C addrspace(4)*)) // Test the address space of 'this' when invoking a method using a pointer to the object. -// COMMON: call i32 @_ZNU3AS41C3getEv(%class.C addrspace(4)* addrspacecast (%class.C addrspace(1)* @c to %class.C addrspace(4)*)) +// COMMON: call spir_func i32 @_ZNU3AS41C3getEv(%class.C addrspace(4)* addrspacecast (%class.C addrspace(1)* @c to %class.C addrspace(4)*)) // Test the address space of 'this' when invoking a method that is declared in the file contex. -// COMMON: call i32 @_ZNU3AS41C7outsideEv(%class.C addrspace(4)* addrspacecast (%class.C addrspace(1)* @c to %class.C addrspace(4)*)) +// COMMON: call spir_func i32 @_ZNU3AS41C7outsideEv(%class.C addrspace(4)* addrspacecast (%class.C addrspace(1)* @c to %class.C addrspace(4)*)) // Test the address space of 'this' when invoking copy-constructor. // COMMON: [[C1GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c1 to %class.C addrspace(4)* // IMPL: [[C1VOID:%[0-9]+]] = bitcast %class.C* %c1 to i8* // IMPL: call void @llvm.memcpy.p0i8.p4i8.i32(i8* {{.*}}[[C1VOID]], i8 addrspace(4)* {{.*}}addrspacecast (i8 addrspace(1)* bitcast (%class.C addrspace(1)* @c to i8 addrspace(1)*) to i8 addrspace(4)*) -// EXPL: call void @_ZNU3AS41CC1ERU3AS4KS_(%class.C addrspace(4)* [[C1GEN]], %class.C addrspace(4)* dereferenceable(4) addrspacecast (%class.C addrspace(1)* @c to %class.C addrspace(4)*)) +// EXPL: call spir_func void @_ZNU3AS41CC1ERU3AS4KS_(%class.C addrspace(4)* [[C1GEN]], %class.C addrspace(4)* dereferenceable(4) addrspacecast (%class.C addrspace(1)* @c to %class.C addrspace(4)*)) // Test the address space of 'this' when invoking a constructor. // EXPL: [[C2GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c2 to %class.C addrspace(4)* -// EXPL: call void @_ZNU3AS41CC1Ev(%class.C addrspace(4)* [[C2GEN]]) +// EXPL: call spir_func void @_ZNU3AS41CC1Ev(%class.C addrspace(4)* [[C2GEN]]) // Test the address space of 'this' when invoking assignment operator. // COMMON: [[C1GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c1 to %class.C addrspace(4)* // COMMON: [[C2GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c2 to %class.C addrspace(4)* -// EXPL: call dereferenceable(4) %class.C addrspace(4)* @_ZNU3AS41CaSERU3AS4KS_(%class.C addrspace(4)* [[C2GEN]], %class.C addrspace(4)* dereferenceable(4) [[C1GEN]]) +// EXPL: call spir_func dereferenceable(4) %class.C addrspace(4)* @_ZNU3AS41CaSERU3AS4KS_(%class.C addrspace(4)* [[C2GEN]], %class.C addrspace(4)* dereferenceable(4) [[C1GEN]]) // IMPL: [[C2GENVOID:%[0-9]+]] = bitcast %class.C addrspace(4)* [[C2GEN]] to i8 addrspace(4)* // IMPL: [[C1GENVOID:%[0-9]+]] = bitcast %class.C addrspace(4)* [[C1GEN]] to i8 addrspace(4)* // IMPL: call void @llvm.memcpy.p4i8.p4i8.i32(i8 addrspace(4)* {{.*}}[[C2GENVOID]], i8 addrspace(4)* {{.*}}[[C1GENVOID]] @@ -114,12 +114,12 @@ __kernel void test__global() { // Test the address space of 'this' when invoking the operator+ // COMMON: [[C1GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c1 to %class.C addrspace(4)* // COMMON: [[C2GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c2 to %class.C addrspace(4)* -// COMMON: call void @_ZNU3AS41CplERU3AS4KS_(%class.C* sret %c3, %class.C addrspace(4)* [[C1GEN]], %class.C addrspace(4)* dereferenceable(4) [[C2GEN]]) +// COMMON: call spir_func void @_ZNU3AS41CplERU3AS4KS_(%class.C* sret %c3, %class.C addrspace(4)* [[C1GEN]], %class.C addrspace(4)* dereferenceable(4) [[C2GEN]]) // Test the address space of 'this' when invoking the move constructor // COMMON: [[C4GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c4 to %class.C addrspace(4)* // COMMON: [[CALL:%call[0-9]+]] = call spir_func dereferenceable(4) %class.C addrspace(4)* @_Z3foov() -// EXPL: call void @_ZNU3AS41CC1EOU3AS4S_(%class.C addrspace(4)* [[C4GEN]], %class.C addrspace(4)* dereferenceable(4) [[CALL]]) +// EXPL: call spir_func void @_ZNU3AS41CC1EOU3AS4S_(%class.C addrspace(4)* [[C4GEN]], %class.C addrspace(4)* dereferenceable(4) [[CALL]]) // IMPL: [[C4VOID:%[0-9]+]] = bitcast %class.C* %c4 to i8* // IMPL: [[CALLVOID:%[0-9]+]] = bitcast %class.C addrspace(4)* [[CALL]] to i8 addrspace(4)* // IMPL: call void @llvm.memcpy.p0i8.p4i8.i32(i8* {{.*}}[[C4VOID]], i8 addrspace(4)* {{.*}}[[CALLVOID]] @@ -127,7 +127,7 @@ __kernel void test__global() { // Test the address space of 'this' when invoking the move assignment // COMMON: [[C5GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c5 to %class.C addrspace(4)* // COMMON: [[CALL:%call[0-9]+]] = call spir_func dereferenceable(4) %class.C addrspace(4)* @_Z3foov() -// EXPL: call void @_ZNU3AS41CC1EOU3AS4S_(%class.C addrspace(4)* [[C5GEN]], %class.C addrspace(4)* dereferenceable(4) [[CALL]]) +// EXPL: call spir_func void @_ZNU3AS41CC1EOU3AS4S_(%class.C addrspace(4)* [[C5GEN]], %class.C addrspace(4)* dereferenceable(4) [[CALL]]) // IMPL: [[C5VOID:%[0-9]+]] = bitcast %class.C* %c5 to i8* // IMPL: [[CALLVOID:%[0-9]+]] = bitcast %class.C addrspace(4)* [[CALL]] to i8 addrspace(4)* // IMPL: call void @llvm.memcpy.p0i8.p4i8.i32(i8* {{.*}}[[C5VOID]], i8 addrspace(4)* {{.*}}[[CALLVOID]] @@ -149,25 +149,25 @@ TEST(__local) // COMMON-LABEL: @test__local // Test that we don't initialize an object in local address space. -// EXPL-NOT: call void @_ZNU3AS41CC1Ev(%class.C addrspace(4)* addrspacecast (%class.C addrspace(3)* @_ZZ11test__localE1c to %class.C addrspace(4)*)) +// EXPL-NOT: call spir_func void @_ZNU3AS41CC1Ev(%class.C addrspace(4)* addrspacecast (%class.C addrspace(3)* @_ZZ11test__localE1c to %class.C addrspace(4)*)) // Test the address space of 'this' when invoking a method. -// COMMON: call i32 @_ZNU3AS41C3getEv(%class.C addrspace(4)* addrspacecast (%class.C addrspace(3)* @_ZZ11test__localE1c to %class.C addrspace(4)*)) +// COMMON: call spir_func i32 @_ZNU3AS41C3getEv(%class.C addrspace(4)* addrspacecast (%class.C addrspace(3)* @_ZZ11test__localE1c to %class.C addrspace(4)*)) // Test the address space of 'this' when invoking copy-constructor. // COMMON: [[C1GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c1 to %class.C addrspace(4)* -// EXPL: call void @_ZNU3AS41CC1ERU3AS4KS_(%class.C addrspace(4)* [[C1GEN]], %class.C addrspace(4)* dereferenceable(4) addrspacecast (%class.C addrspace(3)* @_ZZ11test__localE1c to %class.C addrspace(4)*)) +// EXPL: call spir_func void @_ZNU3AS41CC1ERU3AS4KS_(%class.C addrspace(4)* [[C1GEN]], %class.C addrspace(4)* dereferenceable(4) addrspacecast (%class.C addrspace(3)* @_ZZ11test__localE1c to %class.C addrspace(4)*)) // IMPL: [[C1VOID:%[0-9]+]] = bitcast %class.C* %c1 to i8* // IMPL: call void @llvm.memcpy.p0i8.p4i8.i32(i8* {{.*}}[[C1VOID]], i8 addrspace(4)* {{.*}}addrspacecast (i8 addrspace(3)* bitcast (%class.C addrspace(3)* @_ZZ11test__localE1c to i8 addrspace(3)*) to i8 addrspace(4)*), i32 4, i1 false) // Test the address space of 'this' when invoking a constructor. // EXPL: [[C2GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c2 to %class.C addrspace(4)* -// EXPL: call void @_ZNU3AS41CC1Ev(%class.C addrspace(4)* [[C2GEN]]) +// EXPL: call spir_func void @_ZNU3AS41CC1Ev(%class.C addrspace(4)* [[C2GEN]]) // Test the address space of 'this' when invoking assignment operator. // COMMON: [[C1GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c1 to %class.C addrspace(4)* // COMMON: [[C2GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c2 to %class.C addrspace(4)* -// EXPL: call dereferenceable(4) %class.C addrspace(4)* @_ZNU3AS41CaSERU3AS4KS_(%class.C addrspace(4)* [[C2GEN]], %class.C addrspace(4)* dereferenceable(4) [[C1GEN]]) +// EXPL: call spir_func dereferenceable(4) %class.C addrspace(4)* @_ZNU3AS41CaSERU3AS4KS_(%class.C addrspace(4)* [[C2GEN]], %class.C addrspace(4)* dereferenceable(4) [[C1GEN]]) // IMPL: [[C2GENVOID:%[0-9]+]] = bitcast %class.C addrspace(4)* [[C2GEN]] to i8 addrspace(4)* // IMPL: [[C1GENVOID:%[0-9]+]] = bitcast %class.C addrspace(4)* [[C1GEN]] to i8 addrspace(4)* // IMPL: call void @llvm.memcpy.p4i8.p4i8.i32(i8 addrspace(4)* {{.*}}[[C2GENVOID]], i8 addrspace(4)* {{.*}}[[C1GENVOID]] @@ -178,28 +178,28 @@ TEST(__private) // Test the address space of 'this' when invoking a constructor for an object in non-default address space // EXPL: [[CGEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c to %class.C addrspace(4)* -// EXPL: call void @_ZNU3AS41CC1Ev(%class.C addrspace(4)* [[CGEN]]) +// EXPL: call spir_func void @_ZNU3AS41CC1Ev(%class.C addrspace(4)* [[CGEN]]) // Test the address space of 'this' when invoking a method. // COMMON: [[CGEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c to %class.C addrspace(4)* -// COMMON: call i32 @_ZNU3AS41C3getEv(%class.C addrspace(4)* [[CGEN]]) +// COMMON: call spir_func i32 @_ZNU3AS41C3getEv(%class.C addrspace(4)* [[CGEN]]) // Test the address space of 'this' when invoking a copy-constructor. // COMMON: [[C1GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c1 to %class.C addrspace(4)* // COMMON: [[CGEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c to %class.C addrspace(4)* -// EXPL: call void @_ZNU3AS41CC1ERU3AS4KS_(%class.C addrspace(4)* [[C1GEN]], %class.C addrspace(4)* dereferenceable(4) [[CGEN]]) +// EXPL: call spir_func void @_ZNU3AS41CC1ERU3AS4KS_(%class.C addrspace(4)* [[C1GEN]], %class.C addrspace(4)* dereferenceable(4) [[CGEN]]) // IMPL: [[C1VOID:%[0-9]+]] = bitcast %class.C* %c1 to i8* // IMPL: [[CGENVOID:%[0-9]+]] = bitcast %class.C addrspace(4)* [[CGEN]] to i8 addrspace(4)* // IMPL: call void @llvm.memcpy.p0i8.p4i8.i32(i8* {{.*}}[[C1VOID]], i8 addrspace(4)* {{.*}}[[CGENVOID]] // Test the address space of 'this' when invoking a constructor. // EXPL: [[C2GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c2 to %class.C addrspace(4)* -// EXPL: call void @_ZNU3AS41CC1Ev(%class.C addrspace(4)* [[C2GEN]]) +// EXPL: call spir_func void @_ZNU3AS41CC1Ev(%class.C addrspace(4)* [[C2GEN]]) // Test the address space of 'this' when invoking a copy-assignment. // COMMON: [[C1GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c1 to %class.C addrspace(4)* // COMMON: [[C2GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c2 to %class.C addrspace(4)* -// EXPL: call dereferenceable(4) %class.C addrspace(4)* @_ZNU3AS41CaSERU3AS4KS_(%class.C addrspace(4)* [[C2GEN]], %class.C addrspace(4)* dereferenceable(4) [[C1GEN]]) +// EXPL: call spir_func dereferenceable(4) %class.C addrspace(4)* @_ZNU3AS41CaSERU3AS4KS_(%class.C addrspace(4)* [[C2GEN]], %class.C addrspace(4)* dereferenceable(4) [[C1GEN]]) // IMPL: [[C2GENVOID:%[0-9]+]] = bitcast %class.C addrspace(4)* [[C2GEN]] to i8 addrspace(4)* // IMPL: [[C1GENVOID:%[0-9]+]] = bitcast %class.C addrspace(4)* [[C1GEN]] to i8 addrspace(4)* // IMPL: call void @llvm.memcpy.p4i8.p4i8.i32(i8 addrspace(4)* {{.*}}[[C2GENVOID]], i8 addrspace(4)* {{.*}}[[C1GENVOID]] diff --git a/clang/test/CodeGenOpenCLCXX/addrspace-operators.cl b/clang/test/CodeGenOpenCLCXX/addrspace-operators.cl index 254be1bb85b7..11a164a5f265 100644 --- a/clang/test/CodeGenOpenCLCXX/addrspace-operators.cl +++ b/clang/test/CodeGenOpenCLCXX/addrspace-operators.cl @@ -1,4 +1,4 @@ -//RUN: %clang_cc1 %s -triple spir -cl-std=c++ -emit-llvm -O0 -o - | FileCheck %s +//RUN: %clang_cc1 %s -triple spir -cl-std=clc++ -emit-llvm -O0 -o - | FileCheck %s enum E { a, @@ -20,10 +20,10 @@ __global int globI; void bar() { C c; //CHECK: [[A1:%[.a-z0-9]+]] = addrspacecast %class.C* [[C:%[a-z0-9]+]] to %class.C addrspace(4)* - //CHECK: call void @_ZNU3AS41C6AssignE1E(%class.C addrspace(4)* [[A1]], i32 0) + //CHECK: call spir_func void @_ZNU3AS41C6AssignE1E(%class.C addrspace(4)* [[A1]], i32 0) c.Assign(a); //CHECK: [[A2:%[.a-z0-9]+]] = addrspacecast %class.C* [[C]] to %class.C addrspace(4)* - //CHECK: call void @_ZNU3AS41C8OrAssignE1E(%class.C addrspace(4)* [[A2]], i32 0) + //CHECK: call spir_func void @_ZNU3AS41C8OrAssignE1E(%class.C addrspace(4)* [[A2]], i32 0) c.OrAssign(a); E e; @@ -45,7 +45,7 @@ void bar() { globVI -= a; } -//CHECK: define linkonce_odr void @_ZNU3AS41C6AssignE1E(%class.C addrspace(4)*{{[ %a-z0-9]*}}, i32{{[ %a-z0-9]*}}) +//CHECK: define linkonce_odr spir_func void @_ZNU3AS41C6AssignE1E(%class.C addrspace(4)*{{[ %a-z0-9]*}}, i32{{[ %a-z0-9]*}}) //CHECK: [[THIS_ADDR:%[.a-z0-9]+]] = alloca %class.C addrspace(4) //CHECK: [[E_ADDR:%[.a-z0-9]+]] = alloca i32 //CHECK: store %class.C addrspace(4)* {{%[a-z0-9]+}}, %class.C addrspace(4)** [[THIS_ADDR]] @@ -55,7 +55,7 @@ void bar() { //CHECK: [[ME:%[a-z0-9]+]] = getelementptr inbounds %class.C, %class.C addrspace(4)* [[THIS1]], i32 0, i32 0 //CHECK: store i32 [[E]], i32 addrspace(4)* [[ME]] -//CHECK: define linkonce_odr void @_ZNU3AS41C8OrAssignE1E(%class.C addrspace(4)*{{[ %a-z0-9]*}}, i32{{[ %a-z0-9]*}}) +//CHECK: define linkonce_odr spir_func void @_ZNU3AS41C8OrAssignE1E(%class.C addrspace(4)*{{[ %a-z0-9]*}}, i32{{[ %a-z0-9]*}}) //CHECK: [[THIS_ADDR:%[.a-z0-9]+]] = alloca %class.C addrspace(4) //CHECK: [[E_ADDR:%[.a-z0-9]+]] = alloca i32 //CHECK: store %class.C addrspace(4)* {{%[a-z0-9]+}}, %class.C addrspace(4)** [[THIS_ADDR]] diff --git a/clang/test/CodeGenOpenCLCXX/addrspace-references.cl b/clang/test/CodeGenOpenCLCXX/addrspace-references.cl index 303d75ad3e02..75a11c44395e 100644 --- a/clang/test/CodeGenOpenCLCXX/addrspace-references.cl +++ b/clang/test/CodeGenOpenCLCXX/addrspace-references.cl @@ -1,4 +1,4 @@ -//RUN: %clang_cc1 %s -cl-std=c++ -triple spir -emit-llvm -o - | FileCheck %s +//RUN: %clang_cc1 %s -cl-std=clc++ -triple spir -emit-llvm -o - | FileCheck %s int bar(const unsigned int &i); // CHECK-LABEL: define spir_func void @_Z3foov() diff --git a/clang/test/CodeGenOpenCLCXX/addrspace-with-class.cl b/clang/test/CodeGenOpenCLCXX/addrspace-with-class.cl index 21ba1ca251d8..9f19bfe5cc4f 100644 --- a/clang/test/CodeGenOpenCLCXX/addrspace-with-class.cl +++ b/clang/test/CodeGenOpenCLCXX/addrspace-with-class.cl @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -emit-llvm -O0 -o - | FileCheck %s -// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -emit-llvm -O0 -o - | FileCheck %s --check-prefix=CHECK-DEFINITIONS +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -emit-llvm -O0 -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=CLC++ -emit-llvm -O0 -o - | FileCheck %s --check-prefix=CHECK-DEFINITIONS // This test ensures the proper address spaces and address space cast are used // for constructors, member functions and destructors. @@ -23,17 +23,17 @@ __constant MyType const2(2); // CHECK: @glob = addrspace(1) global %struct.MyType zeroinitializer MyType glob(1); -// CHECK: call void @_ZNU3AS26MyTypeC1Ei(%struct.MyType addrspace(2)* @const1, i32 1) -// CHECK: call void @_ZNU3AS26MyTypeC1Ei(%struct.MyType addrspace(2)* @const2, i32 2) -// CHECK: call void @_ZNU3AS46MyTypeC1Ei(%struct.MyType addrspace(4)* addrspacecast (%struct.MyType addrspace(1)* @glob to %struct.MyType addrspace(4)*), i32 1) +// CHECK: call spir_func void @_ZNU3AS26MyTypeC1Ei(%struct.MyType addrspace(2)* @const1, i32 1) +// CHECK: call spir_func void @_ZNU3AS26MyTypeC1Ei(%struct.MyType addrspace(2)* @const2, i32 2) +// CHECK: call spir_func void @_ZNU3AS46MyTypeC1Ei(%struct.MyType addrspace(4)* addrspacecast (%struct.MyType addrspace(1)* @glob to %struct.MyType addrspace(4)*), i32 1) // CHECK-LABEL: define spir_kernel void @fooGlobal() kernel void fooGlobal() { - // CHECK: call i32 @_ZNU3AS46MyType3barEv(%struct.MyType addrspace(4)* addrspacecast (%struct.MyType addrspace(1)* @glob to %struct.MyType addrspace(4)*)) + // CHECK: call spir_func i32 @_ZNU3AS46MyType3barEv(%struct.MyType addrspace(4)* addrspacecast (%struct.MyType addrspace(1)* @glob to %struct.MyType addrspace(4)*)) glob.bar(); - // CHECK: call i32 @_ZNU3AS26MyType3barEv(%struct.MyType addrspace(2)* @const1) + // CHECK: call spir_func i32 @_ZNU3AS26MyType3barEv(%struct.MyType addrspace(2)* @const1) const1.bar(); - // CHECK: call void @_ZNU3AS26MyTypeD1Ev(%struct.MyType addrspace(2)* @const1) + // CHECK: call spir_func void @_ZNU3AS26MyTypeD1Ev(%struct.MyType addrspace(2)* @const1) const1.~MyType(); } @@ -41,19 +41,19 @@ kernel void fooGlobal() { kernel void fooLocal() { // CHECK: [[VAR:%.*]] = alloca %struct.MyType // CHECK: [[REG:%.*]] = addrspacecast %struct.MyType* [[VAR]] to %struct.MyType addrspace(4)* - // CHECK: call void @_ZNU3AS46MyTypeC1Ei(%struct.MyType addrspace(4)* [[REG]], i32 3) + // CHECK: call spir_func void @_ZNU3AS46MyTypeC1Ei(%struct.MyType addrspace(4)* [[REG]], i32 3) MyType myLocal(3); // CHECK: [[REG:%.*]] = addrspacecast %struct.MyType* [[VAR]] to %struct.MyType addrspace(4)* - // CHECK: call i32 @_ZNU3AS46MyType3barEv(%struct.MyType addrspace(4)* [[REG]]) + // CHECK: call spir_func i32 @_ZNU3AS46MyType3barEv(%struct.MyType addrspace(4)* [[REG]]) myLocal.bar(); // CHECK: [[REG:%.*]] = addrspacecast %struct.MyType* [[VAR]] to %struct.MyType addrspace(4)* - // CHECK: call void @_ZNU3AS46MyTypeD1Ev(%struct.MyType addrspace(4)* [[REG]]) + // CHECK: call spir_func void @_ZNU3AS46MyTypeD1Ev(%struct.MyType addrspace(4)* [[REG]]) } // Ensure all members are defined for all the required address spaces. -// CHECK-DEFINITIONS-DAG: define linkonce_odr void @_ZNU3AS26MyTypeC1Ei(%struct.MyType addrspace(2)* %this, i32 %i) -// CHECK-DEFINITIONS-DAG: define linkonce_odr void @_ZNU3AS46MyTypeC1Ei(%struct.MyType addrspace(4)* %this, i32 %i) -// CHECK-DEFINITIONS-DAG: define linkonce_odr void @_ZNU3AS26MyTypeD1Ev(%struct.MyType addrspace(2)* %this) -// CHECK-DEFINITIONS-DAG: define linkonce_odr void @_ZNU3AS46MyTypeD1Ev(%struct.MyType addrspace(4)* %this) -// CHECK-DEFINITIONS-DAG: define linkonce_odr i32 @_ZNU3AS26MyType3barEv(%struct.MyType addrspace(2)* %this) -// CHECK-DEFINITIONS-DAG: define linkonce_odr i32 @_ZNU3AS46MyType3barEv(%struct.MyType addrspace(4)* %this) +// CHECK-DEFINITIONS-DAG: define linkonce_odr spir_func void @_ZNU3AS26MyTypeC1Ei(%struct.MyType addrspace(2)* %this, i32 %i) +// CHECK-DEFINITIONS-DAG: define linkonce_odr spir_func void @_ZNU3AS46MyTypeC1Ei(%struct.MyType addrspace(4)* %this, i32 %i) +// CHECK-DEFINITIONS-DAG: define linkonce_odr spir_func void @_ZNU3AS26MyTypeD1Ev(%struct.MyType addrspace(2)* %this) +// CHECK-DEFINITIONS-DAG: define linkonce_odr spir_func void @_ZNU3AS46MyTypeD1Ev(%struct.MyType addrspace(4)* %this) +// CHECK-DEFINITIONS-DAG: define linkonce_odr spir_func i32 @_ZNU3AS26MyType3barEv(%struct.MyType addrspace(2)* %this) +// CHECK-DEFINITIONS-DAG: define linkonce_odr spir_func i32 @_ZNU3AS46MyType3barEv(%struct.MyType addrspace(4)* %this) diff --git a/clang/test/CodeGenOpenCLCXX/atexit.cl b/clang/test/CodeGenOpenCLCXX/atexit.cl index b4571f96a1a2..7bcaede2c2a1 100644 --- a/clang/test/CodeGenOpenCLCXX/atexit.cl +++ b/clang/test/CodeGenOpenCLCXX/atexit.cl @@ -1,4 +1,4 @@ -//RUN: %clang_cc1 %s -triple spir -cl-std=c++ -emit-llvm -O0 -o - | FileCheck %s +//RUN: %clang_cc1 %s -triple spir -cl-std=clc++ -emit-llvm -O0 -o - | FileCheck %s struct S { ~S(){}; diff --git a/clang/test/CodeGenOpenCLCXX/global_init.cl b/clang/test/CodeGenOpenCLCXX/global_init.cl index 9452cf6ca307..9f602beda5ba 100644 --- a/clang/test/CodeGenOpenCLCXX/global_init.cl +++ b/clang/test/CodeGenOpenCLCXX/global_init.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -triple spir -cl-std=c++ -emit-llvm -O0 -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple spir -cl-std=clc++ -emit-llvm -O0 -o - | FileCheck %s struct S { S() {} diff --git a/clang/test/CodeGenOpenCLCXX/local_addrspace_init.cl b/clang/test/CodeGenOpenCLCXX/local_addrspace_init.cl index 4424ff4ff2c8..e892e674ad14 100644 --- a/clang/test/CodeGenOpenCLCXX/local_addrspace_init.cl +++ b/clang/test/CodeGenOpenCLCXX/local_addrspace_init.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -triple spir -cl-std=c++ -emit-llvm -O0 -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple spir -cl-std=clc++ -emit-llvm -O0 -o - | FileCheck %s // Test that we don't initialize local address space objects. //CHECK: @_ZZ4testE1i = internal addrspace(3) global i32 undef diff --git a/clang/test/CodeGenOpenCLCXX/method-overload-address-space.cl b/clang/test/CodeGenOpenCLCXX/method-overload-address-space.cl index 0864589b051e..d090c79ebf4a 100644 --- a/clang/test/CodeGenOpenCLCXX/method-overload-address-space.cl +++ b/clang/test/CodeGenOpenCLCXX/method-overload-address-space.cl @@ -1,4 +1,4 @@ -//RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -emit-llvm -O0 -o - | FileCheck %s +//RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -emit-llvm -O0 -o - | FileCheck %s struct C { void foo() __local; @@ -15,21 +15,21 @@ __kernel void k() { __global C &c_ref = c1; __global C *c_ptr; - // CHECK: call void @_ZNU3AS11C3fooEv(%struct.C addrspace(1)* + // CHECK: call spir_func void @_ZNU3AS11C3fooEv(%struct.C addrspace(1)* c1.foo(); - // CHECK: call void @_ZNU3AS31C3fooEv(%struct.C addrspace(3)* + // CHECK: call spir_func void @_ZNU3AS31C3fooEv(%struct.C addrspace(3)* c2.foo(); - // CHECK: call void @_ZNU3AS41C3fooEv(%struct.C addrspace(4)* + // CHECK: call spir_func void @_ZNU3AS41C3fooEv(%struct.C addrspace(4)* c3.foo(); - // CHECK: call void @_ZNU3AS11C3fooEv(%struct.C addrspace(1)* + // CHECK: call spir_func void @_ZNU3AS11C3fooEv(%struct.C addrspace(1)* c_ptr->foo(); - // CHECK: void @_ZNU3AS11C3fooEv(%struct.C addrspace(1)* + // CHECK: spir_func void @_ZNU3AS11C3fooEv(%struct.C addrspace(1)* c_ref.foo(); - // CHECK: call void @_ZNU3AS41C3barEv(%struct.C addrspace(4)* addrspacecast (%struct.C addrspace(1)* @c1 to %struct.C addrspace(4)*)) + // CHECK: call spir_func void @_ZNU3AS41C3barEv(%struct.C addrspace(4)* addrspacecast (%struct.C addrspace(1)* @c1 to %struct.C addrspace(4)*)) c1.bar(); //FIXME: Doesn't compile yet //c_ptr->bar(); - // CHECK: call void @_ZNU3AS41C3barEv(%struct.C addrspace(4)* addrspacecast (%struct.C addrspace(1)* @c1 to %struct.C addrspace(4)*)) + // CHECK: call spir_func void @_ZNU3AS41C3barEv(%struct.C addrspace(4)* addrspacecast (%struct.C addrspace(1)* @c1 to %struct.C addrspace(4)*)) c_ref.bar(); } diff --git a/clang/test/CodeGenOpenCLCXX/template-address-spaces.cl b/clang/test/CodeGenOpenCLCXX/template-address-spaces.cl index 4ceb7b44b473..fcd8655eb9a0 100644 --- a/clang/test/CodeGenOpenCLCXX/template-address-spaces.cl +++ b/clang/test/CodeGenOpenCLCXX/template-address-spaces.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -cl-std=c++ %s -emit-llvm -o - -O0 -triple spir-unknown-unknown | FileCheck %s +// RUN: %clang_cc1 -cl-std=clc++ %s -emit-llvm -o - -O0 -triple spir-unknown-unknown | FileCheck %s template struct S{ @@ -14,11 +14,11 @@ T S::foo() { return a;} // CHECK: %struct.S.1 = type { i32 addrspace(1)* } // CHECK: [[A1:%[.a-z0-9]+]] = addrspacecast %struct.S* %{{[a-z0-9]+}} to %struct.S addrspace(4)* -// CHECK: %call = call i32 @_ZNU3AS41SIiE3fooEv(%struct.S addrspace(4)* [[A1]]) #1 +// CHECK: %call = call spir_func i32 @_ZNU3AS41SIiE3fooEv(%struct.S addrspace(4)* [[A1]]) #1 // CHECK: [[A2:%[.a-z0-9]+]] = addrspacecast %struct.S.0* %{{[a-z0-9]+}} to %struct.S.0 addrspace(4)* -// CHECK: %call1 = call i32 addrspace(4)* @_ZNU3AS41SIPU3AS4iE3fooEv(%struct.S.0 addrspace(4)* [[A2]]) #1 +// CHECK: %call1 = call spir_func i32 addrspace(4)* @_ZNU3AS41SIPU3AS4iE3fooEv(%struct.S.0 addrspace(4)* [[A2]]) #1 // CHECK: [[A3:%[.a-z0-9]+]] = addrspacecast %struct.S.1* %{{[a-z0-9]+}} to %struct.S.1 addrspace(4)* -// CHECK: %call2 = call i32 addrspace(1)* @_ZNU3AS41SIPU3AS1iE3fooEv(%struct.S.1 addrspace(4)* [[A3]]) #1 +// CHECK: %call2 = call spir_func i32 addrspace(1)* @_ZNU3AS41SIPU3AS1iE3fooEv(%struct.S.1 addrspace(4)* [[A3]]) #1 void bar(){ S sint; diff --git a/clang/test/Driver/autocomplete.c b/clang/test/Driver/autocomplete.c index 7805c3bc7894..5c0bfb69f9a3 100644 --- a/clang/test/Driver/autocomplete.c +++ b/clang/test/Driver/autocomplete.c @@ -34,8 +34,8 @@ // RUN: %clang --autocomplete=-cl-std=,CL2 | FileCheck %s -check-prefix=CLSTD // CLSTD: CL2.0 // RUN: %clang --autocomplete=-cl-std= | FileCheck %s -check-prefix=CLSTDALL -// CLSTDALL: c++ -// CLSTDALL-NEXT: cl + +// CLSTDALL: cl // CLSTDALL-NEXT: CL // CLSTDALL-NEXT: cl1.1 // CLSTDALL-NEXT: CL1.1 @@ -43,6 +43,8 @@ // CLSTDALL-NEXT: CL1.2 // CLSTDALL-NEXT: cl2.0 // CLSTDALL-NEXT: CL2.0 +// CLSTDALL-NEXT: clc++ +// CLSTDALL-NEXT: CLC++ // RUN: %clang --autocomplete=-fno-sanitize-coverage=,f | FileCheck %s -check-prefix=FNOSANICOVER // FNOSANICOVER: func // RUN: %clang --autocomplete=-fno-sanitize-coverage= | FileCheck %s -check-prefix=FNOSANICOVERALL diff --git a/clang/test/Driver/cl-options.c b/clang/test/Driver/cl-options.c index 51a98e535093..04aa08a5576e 100644 --- a/clang/test/Driver/cl-options.c +++ b/clang/test/Driver/cl-options.c @@ -161,28 +161,28 @@ // RUN: %clang_cl /Os --target=i686-pc-windows-msvc -### -- %s 2>&1 | FileCheck -check-prefix=Os %s // RUN: %clang_cl /Os --target=x86_64-pc-windows-msvc -### -- %s 2>&1 | FileCheck -check-prefix=Os %s // Os-NOT: -mdisable-fp-elim -// Os-NOT: -momit-leaf-frame-pointer +// Os: -momit-leaf-frame-pointer // Os: -Os // RUN: %clang_cl /Ot --target=i686-pc-windows-msvc -### -- %s 2>&1 | FileCheck -check-prefix=Ot %s // RUN: %clang_cl /Ot --target=x86_64-pc-windows-msvc -### -- %s 2>&1 | FileCheck -check-prefix=Ot %s // Ot-NOT: -mdisable-fp-elim -// Ot-NOT: -momit-leaf-frame-pointer +// Ot: -momit-leaf-frame-pointer // Ot: -O2 // RUN: %clang_cl /Ox --target=i686-pc-windows-msvc -### -- %s 2>&1 | FileCheck -check-prefix=Ox %s // RUN: %clang_cl /Ox --target=x86_64-pc-windows-msvc -### -- %s 2>&1 | FileCheck -check-prefix=Ox %s // Ox-NOT: -mdisable-fp-elim -// Ox-NOT: -momit-leaf-frame-pointer +// Ox: -momit-leaf-frame-pointer // Ox: -O2 // RUN: %clang_cl --target=i686-pc-win32 /O2sy- -### -- %s 2>&1 | FileCheck -check-prefix=PR24003 %s // PR24003: -mdisable-fp-elim -// PR24003-NOT: -momit-leaf-frame-pointer +// PR24003: -momit-leaf-frame-pointer // PR24003: -Os // RUN: %clang_cl --target=i686-pc-win32 -Werror /Oy- /O2 -### -- %s 2>&1 | FileCheck -check-prefix=Oy_2 %s -// Oy_2-NOT: -momit-leaf-frame-pointer +// Oy_2: -momit-leaf-frame-pointer // Oy_2: -O2 // RUN: %clang_cl --target=aarch64-pc-windows-msvc -Werror /Oy- /O2 -### -- %s 2>&1 | FileCheck -check-prefix=Oy_aarch64 %s diff --git a/clang/test/Driver/clang_f_opts.c b/clang/test/Driver/clang_f_opts.c index 17feaab26ab7..d3d80fdec41a 100644 --- a/clang/test/Driver/clang_f_opts.c +++ b/clang/test/Driver/clang_f_opts.c @@ -548,6 +548,11 @@ // CHECK-NO-NULL-POINTER-CHECKS: "-fno-delete-null-pointer-checks" // CHECK-NULL-POINTER-CHECKS-NOT: "-fno-delete-null-pointer-checks" +// RUN: %clang -### -S -fomit-frame-pointer -pg %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-OMIT-FP-PG %s +// RUN: %clang -### -S -fomit-frame-pointer -fno-omit-frame-pointer -pg %s 2>&1 | FileCheck -check-prefix=CHECK-MIX-NO-OMIT-FP-PG %s +// CHECK-NO-MIX-OMIT-FP-PG: '-fomit-frame-pointer' not allowed with '-pg' +// CHECK-MIX-NO-OMIT-FP-PG-NOT: '-fomit-frame-pointer' not allowed with '-pg' + // RUN: %clang -### -S -target x86_64-unknown-linux -frecord-gcc-switches %s 2>&1 | FileCheck -check-prefix=CHECK-RECORD-GCC-SWITCHES %s // RUN: %clang -### -S -target x86_64-unknown-linux -fno-record-gcc-switches %s 2>&1 | FileCheck -check-prefix=CHECK-NO-RECORD-GCC-SWITCHES %s // RUN: %clang -### -S -target x86_64-unknown-linux -fno-record-gcc-switches -frecord-gcc-switches %s 2>&1 | FileCheck -check-prefix=CHECK-RECORD-GCC-SWITCHES %s diff --git a/clang/test/Driver/frame-pointer-elim.c b/clang/test/Driver/frame-pointer-elim.c index f035860bf039..300953f2e88b 100644 --- a/clang/test/Driver/frame-pointer-elim.c +++ b/clang/test/Driver/frame-pointer-elim.c @@ -1,74 +1,48 @@ -// KEEP-ALL: "-mdisable-fp-elim" -// KEEP-ALL-NOT: "-momit-leaf-frame-pointer" +// For these next two tests when optimized we should omit the leaf frame +// pointer, for unoptimized we should have a leaf frame pointer. +// RUN: %clang -### -target i386-pc-linux-gnu -S -O1 %s 2>&1 | \ +// RUN: FileCheck --check-prefix=LINUX-OPT %s +// LINUX-OPT: "-momit-leaf-frame-pointer" -// KEEP-NON-LEAF: "-mdisable-fp-elim" -// KEEP-NON-LEAF: "-momit-leaf-frame-pointer" - -// KEEP-NONE-NOT: "-mdisable-fp-elim" -// KEEP-NONE-NOT: "-momit-leaf-frame-pointer" - -// On Linux x86, omit frame pointer when optimization is enabled. -// RUN: %clang -### -target i386-linux -S -fomit-frame-pointer %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NONE %s -// RUN: %clang -### -target i386-linux -S -O1 %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NONE %s - -// -fno-omit-frame-pointer or -pg disables frame pointer omission. -// RUN: %clang -### -target i386-linux -S %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-ALL %s -// RUN: %clang -### -target i386-linux -S -O1 -fno-omit-frame-pointer %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-ALL %s -// RUN: %clang -### -target i386-linux -S -O1 -pg %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-ALL %s - -// -momit-leaf-frame-pointer omits leaf frame pointer. -// -fno-omit-frame-pointer loses out to -momit-leaf-frame-pointer. -// RUN: %clang -### -target i386 -S -momit-leaf-frame-pointer %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s -// RUN: %clang -### -target i386-linux -S -O1 -fno-omit-frame-pointer -momit-leaf-frame-pointer %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s -// RUN: %clang -### -target i386-linux -S -O1 -momit-leaf-frame-pointer %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NONE %s - -// Explicit or default -fomit-frame-pointer wins over -mno-omit-leaf-frame-pointer. -// RUN: %clang -### -target i386 -S %s -fomit-frame-pointer -mno-omit-leaf-frame-pointer 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NONE %s -// RUN: %clang -### -target i386-linux -S %s -O1 -mno-omit-leaf-frame-pointer 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NONE %s - -// -pg -fomit-frame-pointer => error. -// RUN: %clang -### -S -fomit-frame-pointer -pg %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-OMIT-FP-PG %s -// RUN: %clang -### -S -fomit-frame-pointer -fno-omit-frame-pointer -pg %s 2>&1 | FileCheck -check-prefix=CHECK-MIX-NO-OMIT-FP-PG %s -// CHECK-NO-MIX-OMIT-FP-PG: '-fomit-frame-pointer' not allowed with '-pg' -// CHECK-MIX-NO-OMIT-FP-PG-NOT: '-fomit-frame-pointer' not allowed with '-pg' +// RUN: %clang -### -target i386-pc-linux-gnu -S %s 2>&1 | \ +// RUN: FileCheck --check-prefix=LINUX %s +// LINUX-NOT: "-momit-leaf-frame-pointer" // CloudABI follows the same rules as Linux. // RUN: %clang -### -target x86_64-unknown-cloudabi -S -O1 %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NONE %s +// RUN: FileCheck --check-prefix=CLOUDABI-OPT %s +// CLOUDABI-OPT: "-momit-leaf-frame-pointer" // RUN: %clang -### -target x86_64-unknown-cloudabi -S %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-ALL %s +// RUN: FileCheck --check-prefix=CLOUDABI %s +// CLOUDABI-NOT: "-momit-leaf-frame-pointer" // NetBSD follows the same rules as Linux. // RUN: %clang -### -target x86_64-unknown-netbsd -S -O1 %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NONE %s +// RUN: FileCheck --check-prefix=NETBSD-OPT %s +// NETBSD-OPT: "-momit-leaf-frame-pointer" // RUN: %clang -### -target x86_64-unknown-netbsd -S %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-ALL %s +// RUN: FileCheck --check-prefix=NETBSD %s +// NETBSD-NOT: "-momit-leaf-frame-pointer" // Darwin disables omitting the leaf frame pointer even under optimization // unless the command lines are given. // RUN: %clang -### -target i386-apple-darwin -S %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-ALL %s +// RUN: FileCheck --check-prefix=DARWIN %s +// DARWIN: "-mdisable-fp-elim" // RUN: %clang -### -target i386-apple-darwin -S -O1 %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-ALL %s +// RUN: FileCheck --check-prefix=DARWIN-OPT %s +// DARWIN-OPT-NOT: "-momit-leaf-frame-pointer" // RUN: %clang -### -target i386-darwin -S -fomit-frame-pointer %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NONE %s +// RUN: FileCheck --check-prefix=OMIT_ALL %s +// OMIT_ALL-NOT: "-mdisable-fp-elim" // RUN: %clang -### -target i386-darwin -S -momit-leaf-frame-pointer %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=OMIT_LEAF %s +// OMIT_LEAF: "-momit-leaf-frame-pointer" // RUN: %clang -### -target armv7s-apple-ios -fomit-frame-pointer %s 2>&1 | \ // RUN: FileCheck --check-prefix=WARN-OMIT-7S %s @@ -89,15 +63,17 @@ // WARN-OMIT-LEAF-7S: "-momit-leaf-frame-pointer" // On the PS4, we default to omitting the frame pointer on leaf functions +// (OMIT_LEAF check line is above) // RUN: %clang -### -target x86_64-scei-ps4 -S %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=OMIT_LEAF %s // RUN: %clang -### -target x86_64-scei-ps4 -S -O2 %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NON-LEAF %s +// RUN: FileCheck --check-prefix=OMIT_LEAF %s // RUN: %clang -### -target powerpc64 -S %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-ALL %s +// RUN: FileCheck --check-prefix=KEEP_ALL %s +// KEEP_ALL: "-mdisable-fp-elim" // RUN: %clang -### -target powerpc64 -S -O1 %s 2>&1 | \ -// RUN: FileCheck --check-prefix=KEEP-NONE %s +// RUN: FileCheck --check-prefix=OMIT_ALL %s void f0() {} void f1() { f0(); } diff --git a/clang/test/Driver/opencl.cl b/clang/test/Driver/opencl.cl index baff86fb9067..63b04bc1af41 100644 --- a/clang/test/Driver/opencl.cl +++ b/clang/test/Driver/opencl.cl @@ -2,7 +2,7 @@ // RUN: %clang -S -### -cl-std=CL1.1 %s 2>&1 | FileCheck --check-prefix=CHECK-CL11 %s // RUN: %clang -S -### -cl-std=CL1.2 %s 2>&1 | FileCheck --check-prefix=CHECK-CL12 %s // RUN: %clang -S -### -cl-std=CL2.0 %s 2>&1 | FileCheck --check-prefix=CHECK-CL20 %s -// RUN: %clang -S -### -cl-std=c++ %s 2>&1 | FileCheck --check-prefix=CHECK-CLCPP %s +// RUN: %clang -S -### -cl-std=clc++ %s 2>&1 | FileCheck --check-prefix=CHECK-CLCPP %s // RUN: %clang -S -### -cl-opt-disable %s 2>&1 | FileCheck --check-prefix=CHECK-OPT-DISABLE %s // RUN: %clang -S -### -cl-strict-aliasing %s 2>&1 | FileCheck --check-prefix=CHECK-STRICT-ALIASING %s // RUN: %clang -S -### -cl-single-precision-constant %s 2>&1 | FileCheck --check-prefix=CHECK-SINGLE-PRECISION-CONST %s @@ -22,7 +22,7 @@ // CHECK-CL11: "-cc1" {{.*}} "-cl-std=CL1.1" // CHECK-CL12: "-cc1" {{.*}} "-cl-std=CL1.2" // CHECK-CL20: "-cc1" {{.*}} "-cl-std=CL2.0" -// CHECK-CLCPP: "-cc1" {{.*}} "-cl-std=c++" +// CHECK-CLCPP: "-cc1" {{.*}} "-cl-std=clc++" // CHECK-OPT-DISABLE: "-cc1" {{.*}} "-cl-opt-disable" // CHECK-STRICT-ALIASING: "-cc1" {{.*}} "-cl-strict-aliasing" // CHECK-SINGLE-PRECISION-CONST: "-cc1" {{.*}} "-cl-single-precision-constant" diff --git a/clang/test/Driver/riscv-abi.c b/clang/test/Driver/riscv-abi.c index 6a97ff671ddb..1a4c7ed477b6 100644 --- a/clang/test/Driver/riscv-abi.c +++ b/clang/test/Driver/riscv-abi.c @@ -9,17 +9,15 @@ // CHECK-ILP32: "-target-abi" "ilp32" -// TODO: ilp32f support. -// RUN: not %clang -target riscv32-unknown-elf %s -o %t.o -mabi=ilp32f 2>&1 \ +// RUN: %clang -target riscv32-unknown-elf %s -### -o %t.o -march=rv32if -mabi=ilp32f 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-ILP32F %s -// CHECK-ILP32F: error: unknown target ABI 'ilp32f' +// CHECK-ILP32F: "-target-abi" "ilp32f" -// TODO: ilp32d support. -// RUN: not %clang -target riscv32-unknown-elf %s -o %t.o -mabi=ilp32d 2>&1 \ +// RUN: %clang -target riscv32-unknown-elf %s -### -o %t.o -march=rv32ifd -mabi=ilp32d 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-ILP32D %s -// CHECK-ILP32D: error: unknown target ABI 'ilp32d' +// CHECK-ILP32D: "-target-abi" "ilp32d" // RUN: not %clang -target riscv32-unknown-elf %s -o %t.o -mabi=lp64 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-RV32-LP64 %s @@ -37,17 +35,15 @@ // CHECK-LP64: "-target-abi" "lp64" -// TODO: lp64f support. -// RUN: not %clang -target riscv64-unknown-elf %s -o %t.o -mabi=lp64f 2>&1 \ +// RUN: %clang -target riscv64-unknown-elf %s -### -o %t.o -march=rv64f -mabi=lp64f 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-LP64F %s -// CHECK-LP64F: error: unknown target ABI 'lp64f' +// CHECK-LP64F: "-target-abi" "lp64f" -// TODO: lp64d support. -// RUN: not %clang -target riscv64-unknown-elf %s -o %t.o -mabi=lp64d 2>&1 \ +// RUN: %clang -target riscv64-unknown-elf %s -### -o %t.o -march=rv64d -mabi=lp64d 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-LP64D %s -// CHECK-LP64D: error: unknown target ABI 'lp64d' +// CHECK-LP64D: "-target-abi" "lp64d" // RUN: not %clang -target riscv64-unknown-elf %s -o %t.o -mabi=ilp32 2>&1 \ // RUN: | FileCheck -check-prefix=CHECK-RV64-ILP32 %s diff --git a/clang/test/Driver/riscv32-toolchain.c b/clang/test/Driver/riscv32-toolchain.c index d4160d1b5826..117c773ec970 100644 --- a/clang/test/Driver/riscv32-toolchain.c +++ b/clang/test/Driver/riscv32-toolchain.c @@ -105,6 +105,10 @@ typedef __builtin_va_list va_list; typedef __SIZE_TYPE__ size_t; typedef __PTRDIFF_TYPE__ ptrdiff_t; typedef __WCHAR_TYPE__ wchar_t; +typedef __WINT_TYPE__ wint_t; + + +// Check Alignments // CHECK: @align_c = dso_local global i32 1 int align_c = __alignof(char); @@ -118,6 +122,9 @@ int align_i = __alignof(int); // CHECK: @align_wc = dso_local global i32 4 int align_wc = __alignof(wchar_t); +// CHECK: @align_wi = dso_local global i32 4 +int align_wi = __alignof(wint_t); + // CHECK: @align_l = dso_local global i32 4 int align_l = __alignof(long); @@ -139,6 +146,88 @@ int align_ld = __alignof(long double); // CHECK: @align_vl = dso_local global i32 4 int align_vl = __alignof(va_list); +// CHECK: @align_a_c = dso_local global i32 1 +int align_a_c = __alignof(_Atomic(char)); + +// CHECK: @align_a_s = dso_local global i32 2 +int align_a_s = __alignof(_Atomic(short)); + +// CHECK: @align_a_i = dso_local global i32 4 +int align_a_i = __alignof(_Atomic(int)); + +// CHECK: @align_a_wc = dso_local global i32 4 +int align_a_wc = __alignof(_Atomic(wchar_t)); + +// CHECK: @align_a_wi = dso_local global i32 4 +int align_a_wi = __alignof(_Atomic(wint_t)); + +// CHECK: @align_a_l = dso_local global i32 4 +int align_a_l = __alignof(_Atomic(long)); + +// CHECK: @align_a_ll = dso_local global i32 8 +int align_a_ll = __alignof(_Atomic(long long)); + +// CHECK: @align_a_p = dso_local global i32 4 +int align_a_p = __alignof(_Atomic(void*)); + +// CHECK: @align_a_f = dso_local global i32 4 +int align_a_f = __alignof(_Atomic(float)); + +// CHECK: @align_a_d = dso_local global i32 8 +int align_a_d = __alignof(_Atomic(double)); + +// CHECK: @align_a_ld = dso_local global i32 16 +int align_a_ld = __alignof(_Atomic(long double)); + +// CHECK: @align_a_s4 = dso_local global i32 4 +int align_a_s4 = __alignof(_Atomic(struct { char s[4]; })); + +// CHECK: @align_a_s8 = dso_local global i32 8 +int align_a_s8 = __alignof(_Atomic(struct { char s[8]; })); + +// CHECK: @align_a_s16 = dso_local global i32 16 +int align_a_s16 = __alignof(_Atomic(struct { char s[16]; })); + +// CHECK: @align_a_s32 = dso_local global i32 1 +int align_a_s32 = __alignof(_Atomic(struct { char s[32]; })); + + +// Check Sizes + +// CHECK: @size_a_c = dso_local global i32 1 +int size_a_c = sizeof(_Atomic(char)); + +// CHECK: @size_a_s = dso_local global i32 2 +int size_a_s = sizeof(_Atomic(short)); + +// CHECK: @size_a_i = dso_local global i32 4 +int size_a_i = sizeof(_Atomic(int)); + +// CHECK: @size_a_wc = dso_local global i32 4 +int size_a_wc = sizeof(_Atomic(wchar_t)); + +// CHECK: @size_a_wi = dso_local global i32 4 +int size_a_wi = sizeof(_Atomic(wint_t)); + +// CHECK: @size_a_l = dso_local global i32 4 +int size_a_l = sizeof(_Atomic(long)); + +// CHECK: @size_a_ll = dso_local global i32 8 +int size_a_ll = sizeof(_Atomic(long long)); + +// CHECK: @size_a_p = dso_local global i32 4 +int size_a_p = sizeof(_Atomic(void*)); + +// CHECK: @size_a_f = dso_local global i32 4 +int size_a_f = sizeof(_Atomic(float)); + +// CHECK: @size_a_d = dso_local global i32 8 +int size_a_d = sizeof(_Atomic(double)); + +// CHECK: @size_a_ld = dso_local global i32 16 +int size_a_ld = sizeof(_Atomic(long double)); + + // Check types // CHECK: zeroext i8 @check_char() diff --git a/clang/test/Driver/riscv64-toolchain.c b/clang/test/Driver/riscv64-toolchain.c index b8069858eba2..3d574947c68a 100644 --- a/clang/test/Driver/riscv64-toolchain.c +++ b/clang/test/Driver/riscv64-toolchain.c @@ -105,6 +105,10 @@ typedef __builtin_va_list va_list; typedef __SIZE_TYPE__ size_t; typedef __PTRDIFF_TYPE__ ptrdiff_t; typedef __WCHAR_TYPE__ wchar_t; +typedef __WINT_TYPE__ wint_t; + + +// Check Alignments // CHECK: @align_c = dso_local global i32 1 int align_c = __alignof(char); @@ -118,6 +122,9 @@ int align_i = __alignof(int); // CHECK: @align_wc = dso_local global i32 4 int align_wc = __alignof(wchar_t); +// CHECK: @align_wi = dso_local global i32 4 +int align_wi = __alignof(wint_t); + // CHECK: @align_l = dso_local global i32 8 int align_l = __alignof(long); @@ -139,6 +146,88 @@ int align_ld = __alignof(long double); // CHECK: @align_vl = dso_local global i32 8 int align_vl = __alignof(va_list); +// CHECK: @align_a_c = dso_local global i32 1 +int align_a_c = __alignof(_Atomic(char)); + +// CHECK: @align_a_s = dso_local global i32 2 +int align_a_s = __alignof(_Atomic(short)); + +// CHECK: @align_a_i = dso_local global i32 4 +int align_a_i = __alignof(_Atomic(int)); + +// CHECK: @align_a_wc = dso_local global i32 4 +int align_a_wc = __alignof(_Atomic(wchar_t)); + +// CHECK: @align_a_wi = dso_local global i32 4 +int align_a_wi = __alignof(_Atomic(wint_t)); + +// CHECK: @align_a_l = dso_local global i32 8 +int align_a_l = __alignof(_Atomic(long)); + +// CHECK: @align_a_ll = dso_local global i32 8 +int align_a_ll = __alignof(_Atomic(long long)); + +// CHECK: @align_a_p = dso_local global i32 8 +int align_a_p = __alignof(_Atomic(void*)); + +// CHECK @align_a_f = dso_local global i32 4 +int align_a_f = __alignof(_Atomic(float)); + +// CHECK: @align_a_d = dso_local global i32 8 +int align_a_d = __alignof(_Atomic(double)); + +// CHECK: @align_a_ld = dso_local global i32 16 +int align_a_ld = __alignof(_Atomic(long double)); + +// CHECK: @align_a_s4 = dso_local global i32 4 +int align_a_s4 = __alignof(_Atomic(struct { char _[4]; })); + +// CHECK: @align_a_s8 = dso_local global i32 8 +int align_a_s8 = __alignof(_Atomic(struct { char _[8]; })); + +// CHECK: @align_a_s16 = dso_local global i32 16 +int align_a_s16 = __alignof(_Atomic(struct { char _[16]; })); + +// CHECK: @align_a_s32 = dso_local global i32 1 +int align_a_s32 = __alignof(_Atomic(struct { char _[32]; })); + + +// Check Sizes + +// CHECK: @size_a_c = dso_local global i32 1 +int size_a_c = sizeof(_Atomic(char)); + +// CHECK: @size_a_s = dso_local global i32 2 +int size_a_s = sizeof(_Atomic(short)); + +// CHECK: @size_a_i = dso_local global i32 4 +int size_a_i = sizeof(_Atomic(int)); + +// CHECK: @size_a_wc = dso_local global i32 4 +int size_a_wc = sizeof(_Atomic(wchar_t)); + +// CHECK: @size_a_wi = dso_local global i32 4 +int size_a_wi = sizeof(_Atomic(wint_t)); + +// CHECK: @size_a_l = dso_local global i32 8 +int size_a_l = sizeof(_Atomic(long)); + +// CHECK: @size_a_ll = dso_local global i32 8 +int size_a_ll = sizeof(_Atomic(long long)); + +// CHECK: @size_a_p = dso_local global i32 8 +int size_a_p = sizeof(_Atomic(void*)); + +// CHECK: @size_a_f = dso_local global i32 4 +int size_a_f = sizeof(_Atomic(float)); + +// CHECK: @size_a_d = dso_local global i32 8 +int size_a_d = sizeof(_Atomic(double)); + +// CHECK: @size_a_ld = dso_local global i32 16 +int size_a_ld = sizeof(_Atomic(long double)); + + // Check types // CHECK: define dso_local zeroext i8 @check_char() diff --git a/clang/test/Driver/unknown-std.cl b/clang/test/Driver/unknown-std.cl index 285582ee0af6..6f371bac13ac 100644 --- a/clang/test/Driver/unknown-std.cl +++ b/clang/test/Driver/unknown-std.cl @@ -10,7 +10,7 @@ // CHECK-NEXT: note: use 'cl1.1' for 'OpenCL 1.1' standard // CHECK-NEXT: note: use 'cl1.2' for 'OpenCL 1.2' standard // CHECK-NEXT: note: use 'cl2.0' for 'OpenCL 2.0' standard -// CHECK-NEXT: note: use 'c++' for 'C++ for OpenCL' standard +// CHECK-NEXT: note: use 'clc++' for 'C++ for OpenCL' standard // Make sure that no other output is present. // CHECK-NOT: {{^.+$}} diff --git a/clang/test/Driver/working-directory.c b/clang/test/Driver/working-directory.c index fbd4ed4f9e10..15ba8f00bd12 100644 --- a/clang/test/Driver/working-directory.c +++ b/clang/test/Driver/working-directory.c @@ -1,11 +1,3 @@ // RUN: %clang -### -working-directory /no/such/dir/ input 2>&1 | FileCheck %s -// RUN: %clang -### -working-directory %p/Inputs no_such_file.cpp -c 2>&1 | FileCheck %s --check-prefix=CHECK_NO_FILE -// RUN: %clang -### -working-directory %p/Inputs pchfile.cpp -c 2>&1 | FileCheck %s --check-prefix=CHECK_WORKS -// CHECK: unable to set working directory: /no/such/dir/ - -// CHECK_NO_FILE: no such file or directory: 'no_such_file.cpp' - -// CHECK_WORKS: "-coverage-notes-file" "{{[^"]+}}test{{/|\\\\}}Driver{{/|\\\\}}Inputs{{/|\\\\}}pchfile.gcno" -// CHECK_WORKS: "-working-directory" "{{[^"]+}}test{{/|\\\\}}Driver{{/|\\\\}}Inputs" -// CHECK_WORKS: "-fdebug-compilation-dir" "{{[^"]+}}test{{/|\\\\}}Driver{{/|\\\\}}Inputs" +//CHECK: no such file or directory: '/no/such/dir/input' diff --git a/clang/test/Driver/xcore-opts.c b/clang/test/Driver/xcore-opts.c index abbc88e10360..9300085724c8 100644 --- a/clang/test/Driver/xcore-opts.c +++ b/clang/test/Driver/xcore-opts.c @@ -4,8 +4,8 @@ // RUN: %clang -target xcore %s -g0 -### -o %t.o 2>&1 | FileCheck -check-prefix CHECK-G0 %s // CHECK: "-nostdsysteminc" +// CHECK: "-momit-leaf-frame-pointer" // CHECK-NOT: "-mdisable-fp-elim" -// CHECK-NOT: "-momit-leaf-frame-pointer" // CHECK: "-fno-signed-char" // CHECK: "-fno-use-cxa-atexit" // CHECK-NOT: "-fcxx-exceptions" diff --git a/clang/test/Frontend/opencl.cl b/clang/test/Frontend/opencl.cl index facc735330d4..ea7d3d4c8731 100644 --- a/clang/test/Frontend/opencl.cl +++ b/clang/test/Frontend/opencl.cl @@ -2,7 +2,7 @@ // RUN: %clang_cc1 %s -verify -fsyntax-only -cl-std=CL1.1 -DSYNTAX // RUN: %clang_cc1 %s -verify -fsyntax-only -cl-std=CL1.2 -DSYNTAX // RUN: %clang_cc1 %s -verify -fsyntax-only -cl-std=CL2.0 -DSYNTAX -// RUN: %clang_cc1 %s -verify -fsyntax-only -cl-std=c++ -DSYNTAX +// RUN: %clang_cc1 %s -verify -fsyntax-only -cl-std=clc++ -DSYNTAX // RUN: %clang_cc1 %s -verify -fsyntax-only -fblocks -DBLOCKS -DSYNTAX // RUN: %clang_cc1 %s -verify -fsyntax-only -cl-std=CL1.1 -fblocks -DBLOCKS -DSYNTAX // RUN: %clang_cc1 %s -verify -fsyntax-only -cl-std=CL1.2 -fblocks -DBLOCKS -DSYNTAX diff --git a/clang/test/Frontend/stdlang.c b/clang/test/Frontend/stdlang.c index 2b24c2dfea31..51484999e37a 100644 --- a/clang/test/Frontend/stdlang.c +++ b/clang/test/Frontend/stdlang.c @@ -4,11 +4,12 @@ // RUN: %clang_cc1 -x cl -cl-std=cl1.1 -DOPENCL %s // RUN: %clang_cc1 -x cl -cl-std=cl1.2 -DOPENCL %s // RUN: %clang_cc1 -x cl -cl-std=cl2.0 -DOPENCL %s -// RUN: %clang_cc1 -x cl -cl-std=c++ -DOPENCL %s +// RUN: %clang_cc1 -x cl -cl-std=clc++ -DOPENCL %s // RUN: %clang_cc1 -x cl -cl-std=CL -DOPENCL %s // RUN: %clang_cc1 -x cl -cl-std=CL1.1 -DOPENCL %s // RUN: %clang_cc1 -x cl -cl-std=CL1.2 -DOPENCL %s // RUN: %clang_cc1 -x cl -cl-std=CL2.0 -DOPENCL %s +// RUN: %clang_cc1 -x cl -cl-std=CLC++ -DOPENCL %s // RUN: not %clang_cc1 -x cl -std=c99 -DOPENCL %s 2>&1 | FileCheck --check-prefix=CHECK-C99 %s // RUN: not %clang_cc1 -x cl -cl-std=invalid -DOPENCL %s 2>&1 | FileCheck --check-prefix=CHECK-INVALID %s // CHECK-C99: error: invalid argument '-std=c99' not allowed with 'OpenCL' diff --git a/clang/test/Headers/opencl-c-header.cl b/clang/test/Headers/opencl-c-header.cl index 8183a8c1f79a..1b151ffdd16a 100644 --- a/clang/test/Headers/opencl-c-header.cl +++ b/clang/test/Headers/opencl-c-header.cl @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -O0 -triple spir-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -verify | FileCheck %s // RUN: %clang_cc1 -O0 -triple spir-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -verify -cl-std=CL1.1 | FileCheck %s // RUN: %clang_cc1 -O0 -triple spir-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -verify -cl-std=CL1.2 | FileCheck %s -// RUN: %clang_cc1 -O0 -triple spir-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -verify -cl-std=c++ | FileCheck %s --check-prefix=CHECK20 +// RUN: %clang_cc1 -O0 -triple spir-unknown-unknown -internal-isystem ../../lib/Headers -include opencl-c.h -emit-llvm -o - %s -verify -cl-std=clc++ | FileCheck %s --check-prefix=CHECK20 // Test including the default header as a module. // The module should be compiled only once and loaded from cache afterwards. diff --git a/clang/test/Index/complete-qualified-cached.cpp b/clang/test/Index/complete-qualified-cached.cpp new file mode 100644 index 000000000000..b866abec9062 --- /dev/null +++ b/clang/test/Index/complete-qualified-cached.cpp @@ -0,0 +1,22 @@ +namespace a_namespace {}; +class Class { static void foo(); }; +Class:: +// Completion for a_namespace should be available at the start of the line. +// START-OF-LINE: a_namespace +// START-OF-LINE: Class +// -- Using cached completions. +// RUN: env CINDEXTEST_EDITING=1 c-index-test -code-completion-at=%s:3:1 %s \ +// RUN: | FileCheck --check-prefix=START-OF-LINE %s +// -- Without cached completions. +// RUN: c-index-test -code-completion-at=%s:3:1 %s \ +// RUN: | FileCheck --check-prefix=START-OF-LINE %s +// +// +// ... and should not be available after 'Class::^' +// AFTER-QUALIFIER: Class +// -- Using cached completions. +// RUN: env CINDEXTEST_EDITING=1 c-index-test -code-completion-at=%s:3:8 %s \ +// RUN: | FileCheck --implicit-check-not=a_namespace --check-prefix=AFTER-QUALIFIER %s +// -- Without cached completions. +// RUN: c-index-test -code-completion-at=%s:3:8 %s \ +// RUN: | FileCheck --implicit-check-not=a_namespace --check-prefix=AFTER-QUALIFIER %s diff --git a/clang/test/OpenMP/distribute_parallel_for_firstprivate_messages.cpp b/clang/test/OpenMP/distribute_parallel_for_firstprivate_messages.cpp index 1678a27f213b..d283c29c3284 100644 --- a/clang/test/OpenMP/distribute_parallel_for_firstprivate_messages.cpp +++ b/clang/test/OpenMP/distribute_parallel_for_firstprivate_messages.cpp @@ -162,14 +162,14 @@ int foomain(int argc, char **argv) { #pragma omp parallel private(i) #pragma omp target #pragma omp teams -#pragma omp distribute parallel for firstprivate(i) // expected-note {{defined as firstprivate}} - for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp distribute parallel for' directive may not be firstprivate, predetermined as private}} +#pragma omp distribute parallel for firstprivate(i) // expected-note 2 {{defined as firstprivate}} + for (i = 0; i < argc; ++i) // expected-error 2 {{loop iteration variable in the associated loop of 'omp distribute parallel for' directive may not be firstprivate, predetermined as private}} foo(); #pragma omp parallel reduction(+ : i) #pragma omp target #pragma omp teams -#pragma omp distribute parallel for firstprivate(i) // expected-note {{defined as firstprivate}} - for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp distribute parallel for' directive may not be firstprivate, predetermined as private}} +#pragma omp distribute parallel for firstprivate(i) // expected-note 2 {{defined as firstprivate}} + for (i = 0; i < argc; ++i) // expected-error 2 {{loop iteration variable in the associated loop of 'omp distribute parallel for' directive may not be firstprivate, predetermined as private}} foo(); return 0; } diff --git a/clang/test/OpenMP/distribute_parallel_for_simd_firstprivate_messages.cpp b/clang/test/OpenMP/distribute_parallel_for_simd_firstprivate_messages.cpp index aa33807c424d..953cd2097151 100644 --- a/clang/test/OpenMP/distribute_parallel_for_simd_firstprivate_messages.cpp +++ b/clang/test/OpenMP/distribute_parallel_for_simd_firstprivate_messages.cpp @@ -162,14 +162,14 @@ int foomain(int argc, char **argv) { #pragma omp parallel private(i) #pragma omp target #pragma omp teams -#pragma omp distribute parallel for simd firstprivate(i) // expected-note {{defined as firstprivate}} - for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp distribute parallel for simd' directive may not be firstprivate, predetermined as linear}} +#pragma omp distribute parallel for simd firstprivate(i) // expected-note 2 {{defined as firstprivate}} + for (i = 0; i < argc; ++i) // expected-error 2 {{loop iteration variable in the associated loop of 'omp distribute parallel for simd' directive may not be firstprivate, predetermined as linear}} foo(); #pragma omp parallel reduction(+ : i) #pragma omp target #pragma omp teams -#pragma omp distribute parallel for simd firstprivate(i) // expected-note {{defined as firstprivate}} - for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp distribute parallel for simd' directive may not be firstprivate, predetermined as linear}} +#pragma omp distribute parallel for simd firstprivate(i) // expected-note 2 {{defined as firstprivate}} + for (i = 0; i < argc; ++i) // expected-error 2 {{loop iteration variable in the associated loop of 'omp distribute parallel for simd' directive may not be firstprivate, predetermined as linear}} foo(); return 0; } diff --git a/clang/test/OpenMP/distribute_simd_firstprivate_messages.cpp b/clang/test/OpenMP/distribute_simd_firstprivate_messages.cpp index b73ecc274d0d..0e00f31c8b32 100644 --- a/clang/test/OpenMP/distribute_simd_firstprivate_messages.cpp +++ b/clang/test/OpenMP/distribute_simd_firstprivate_messages.cpp @@ -162,14 +162,14 @@ int foomain(int argc, char **argv) { #pragma omp parallel private(i) #pragma omp target #pragma omp teams -#pragma omp distribute simd firstprivate(i) // expected-note {{defined as firstprivate}} - for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp distribute simd' directive may not be firstprivate, predetermined as linear}} +#pragma omp distribute simd firstprivate(i) // expected-note 2 {{defined as firstprivate}} + for (i = 0; i < argc; ++i) // expected-error 2 {{loop iteration variable in the associated loop of 'omp distribute simd' directive may not be firstprivate, predetermined as linear}} foo(); #pragma omp parallel reduction(+ : i) #pragma omp target #pragma omp teams -#pragma omp distribute simd firstprivate(i) // expected-note {{defined as firstprivate}} - for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp distribute simd' directive may not be firstprivate, predetermined as linear}} +#pragma omp distribute simd firstprivate(i) // expected-note 2 {{defined as firstprivate}} + for (i = 0; i < argc; ++i) // expected-error 2 {{loop iteration variable in the associated loop of 'omp distribute simd' directive may not be firstprivate, predetermined as linear}} foo(); return 0; } diff --git a/clang/test/OpenMP/distribute_simd_misc_messages.c b/clang/test/OpenMP/distribute_simd_misc_messages.c index 37dcf8ba7b05..4c82b7a96b03 100644 --- a/clang/test/OpenMP/distribute_simd_misc_messages.c +++ b/clang/test/OpenMP/distribute_simd_misc_messages.c @@ -487,11 +487,11 @@ void test_collapse() { #pragma omp distribute simd collapse(5 - 5) for (i = 0; i < 16; ++i) ; -// expected-note@+3 {{defined as reduction}} +// expected-note@+3 2 {{defined as reduction}} #pragma omp target #pragma omp teams #pragma omp distribute simd collapse(2) reduction(+ : i) - for (i = 0; i < 16; ++i) + for (i = 0; i < 16; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp distribute simd' directive may not be reduction, predetermined as lastprivate}} // expected-note@+1 {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for' directive into a parallel or another task region?}} for (int j = 0; j < 16; ++j) // expected-error@+2 2 {{reduction variable must be shared}} diff --git a/clang/test/OpenMP/for_misc_messages.c b/clang/test/OpenMP/for_misc_messages.c index 324c70bee318..e6559ebcb7bd 100644 --- a/clang/test/OpenMP/for_misc_messages.c +++ b/clang/test/OpenMP/for_misc_messages.c @@ -214,10 +214,10 @@ void test_collapse() { ; #pragma omp parallel #pragma omp for collapse(2) - for (i = 0; i < 16; ++i) + for (i = 0; i < 16; ++i) // expected-note {{defined as private}} // expected-note@+1 {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for' directive into a parallel or another task region?}} for (int j = 0; j < 16; ++j) -// expected-error@+2 {{reduction variable must be shared}} +// expected-error@+2 2 {{reduction variable must be shared}} // expected-error@+1 {{region cannot be closely nested inside 'for' region; perhaps you forget to enclose 'omp for' directive into a parallel region?}} #pragma omp for reduction(+ : i, j) for (int k = 0; k < 16; ++k) diff --git a/clang/test/OpenMP/for_simd_misc_messages.c b/clang/test/OpenMP/for_simd_misc_messages.c index f7c864d135e5..ced5ee50cb59 100644 --- a/clang/test/OpenMP/for_simd_misc_messages.c +++ b/clang/test/OpenMP/for_simd_misc_messages.c @@ -381,10 +381,10 @@ void test_collapse() { ; #pragma omp parallel #pragma omp for simd collapse(2) - for (i = 0; i < 16; ++i) + for (i = 0; i < 16; ++i) // expected-note {{defined as lastprivate}} // expected-note@+1 {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for simd' directive into a parallel or another task region?}} for (int j = 0; j < 16; ++j) -// expected-error@+2 {{reduction variable must be shared}} +// expected-error@+2 2 {{reduction variable must be shared}} // expected-error@+1 {{OpenMP constructs may not be nested inside a simd region}} #pragma omp for simd reduction(+ : i, j) for (int k = 0; k < 16; ++k) diff --git a/clang/test/OpenMP/parallel_copyin_codegen.cpp b/clang/test/OpenMP/parallel_copyin_codegen.cpp index 8fa9edd2c1ac..87c11f040619 100644 --- a/clang/test/OpenMP/parallel_copyin_codegen.cpp +++ b/clang/test/OpenMP/parallel_copyin_codegen.cpp @@ -19,6 +19,7 @@ // RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DLAMBDA -triple x86_64-linux -emit-llvm %s -o - | FileCheck -check-prefix=TLS-LAMBDA %s // RUN: %clang_cc1 -verify -fopenmp -x c++ -fblocks -DBLOCKS -triple x86_64-linux -emit-llvm %s -o - | FileCheck -check-prefix=TLS-BLOCKS %s // RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DARRAY -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck -check-prefix=TLS-ARRAY %s +// RUN: %clang_cc1 -verify -fopenmp -x c++ -DNESTED -triple x86_64-linux -emit-llvm %s -o - | FileCheck %s -check-prefix=NESTED // RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -triple x86_64-linux -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY1 %s // RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -triple x86_64-linux -emit-pch -o %t %s @@ -28,7 +29,7 @@ // RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -std=c++11 -DARRAY -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY1 %s // SIMD-ONLY1-NOT: {{__kmpc|__tgt}} // expected-no-diagnostics -#ifndef ARRAY +#if !defined(ARRAY) && !defined(NESTED) #ifndef HEADER #define HEADER @@ -493,7 +494,7 @@ int main() { // TLS-CHECK: ret void #endif -#else +#elif defined(ARRAY) // ARRAY-LABEL: array_func // TLS-ARRAY-LABEL: array_func @@ -522,6 +523,24 @@ void array_func() { #pragma omp parallel copyin(a, s) ; } -#endif - +#elif defined(NESTED) +int t; +#pragma omp threadprivate(t) +// NESTED: foo +void foo() { + // NESTED: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* @{{.+}}, i32 0, void (i32*, i32*, ...)* bitcast (void (i32*, i32*)* [[OUTLINED:@.+]] to void (i32*, i32*, ...)*)) +#pragma omp parallel +#pragma omp parallel copyin(t) + ++t; +} +// NESTED: define {{.*}}void [[OUTLINED]]( +// NESTED: [[T:%.+]] = call i32* [[THRP_T:@.+]]() +// NESTED: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* @{{.+}}, i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, i32*)* [[OUTLINED1:@.+]] to void (i32*, i32*, ...)*), i32* [[T]]) + +// NESTED: define {{.*}}void [[OUTLINED1]]( +// NESTED: [[T_MASTER:%.+]] = load i32*, i32** % +// NESTED: [[T:%.+]] = call i32* [[THRP_T]]() +// NESTED: [[T_MASTER_VAL:%.+]] = load i32, i32* [[T_MASTER]], +// NESTED: store i32 [[T_MASTER_VAL]], i32* [[T]], +#endif // NESTED diff --git a/clang/test/OpenMP/parallel_for_firstprivate_messages.cpp b/clang/test/OpenMP/parallel_for_firstprivate_messages.cpp index 28a21a49e60e..8a312f47662e 100644 --- a/clang/test/OpenMP/parallel_for_firstprivate_messages.cpp +++ b/clang/test/OpenMP/parallel_for_firstprivate_messages.cpp @@ -127,12 +127,12 @@ int foomain(int argc, char **argv) { for (i = 0; i < argc; ++i) foo(); #pragma omp parallel private(i) -#pragma omp parallel for firstprivate(i) // expected-note {{defined as firstprivate}} - for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp parallel for' directive may not be firstprivate, predetermined as private}} +#pragma omp parallel for firstprivate(i) // expected-note 2 {{defined as firstprivate}} + for (i = 0; i < argc; ++i) // expected-error 2 {{loop iteration variable in the associated loop of 'omp parallel for' directive may not be firstprivate, predetermined as private}} foo(); #pragma omp parallel reduction(+ : i) -#pragma omp parallel for firstprivate(i) // expected-note {{defined as firstprivate}} - for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp parallel for' directive may not be firstprivate, predetermined as private}} +#pragma omp parallel for firstprivate(i) // expected-note 2 {{defined as firstprivate}} + for (i = 0; i < argc; ++i) // expected-error 2 {{loop iteration variable in the associated loop of 'omp parallel for' directive may not be firstprivate, predetermined as private}} foo(); return 0; } diff --git a/clang/test/OpenMP/parallel_for_misc_messages.c b/clang/test/OpenMP/parallel_for_misc_messages.c index 946f6d58ccea..38e50915ddf5 100644 --- a/clang/test/OpenMP/parallel_for_misc_messages.c +++ b/clang/test/OpenMP/parallel_for_misc_messages.c @@ -162,9 +162,9 @@ void test_collapse() { #pragma omp parallel for collapse(5 - 5) for (i = 0; i < 16; ++i) ; -// expected-note@+1 {{defined as firstprivate}} +// expected-note@+1 2 {{defined as firstprivate}} #pragma omp parallel for collapse(2) firstprivate(i) - for (i = 0; i < 16; ++i) + for (i = 0; i < 16; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp parallel for' directive may not be firstprivate, predetermined as private}} // expected-note@+1 {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for' directive into a parallel or another task region?}} for (int j = 0; j < 16; ++j) // expected-error@+2 2 {{reduction variable must be shared}} diff --git a/clang/test/OpenMP/parallel_for_simd_firstprivate_messages.cpp b/clang/test/OpenMP/parallel_for_simd_firstprivate_messages.cpp index 2cd9c065c63b..5f57c65374a3 100644 --- a/clang/test/OpenMP/parallel_for_simd_firstprivate_messages.cpp +++ b/clang/test/OpenMP/parallel_for_simd_firstprivate_messages.cpp @@ -129,12 +129,12 @@ int foomain(int argc, char **argv) { for (i = 0; i < argc; ++i) foo(); #pragma omp parallel private(i) -#pragma omp parallel for simd firstprivate(i) // expected-note {{defined as firstprivate}} - for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp parallel for simd' directive may not be firstprivate, predetermined as linear}} +#pragma omp parallel for simd firstprivate(i) // expected-note 2 {{defined as firstprivate}} + for (i = 0; i < argc; ++i) // expected-error 2 {{loop iteration variable in the associated loop of 'omp parallel for simd' directive may not be firstprivate, predetermined as linear}} foo(); #pragma omp parallel reduction(+ : i) -#pragma omp parallel for simd firstprivate(i) // expected-note {{defined as firstprivate}} - for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp parallel for simd' directive may not be firstprivate, predetermined as linear}} +#pragma omp parallel for simd firstprivate(i) // expected-note 2 {{defined as firstprivate}} + for (i = 0; i < argc; ++i) // expected-error 2 {{loop iteration variable in the associated loop of 'omp parallel for simd' directive may not be firstprivate, predetermined as linear}} foo(); return 0; } diff --git a/clang/test/OpenMP/simd_misc_messages.c b/clang/test/OpenMP/simd_misc_messages.c index 88df2535103c..29dbde4da8ac 100644 --- a/clang/test/OpenMP/simd_misc_messages.c +++ b/clang/test/OpenMP/simd_misc_messages.c @@ -359,10 +359,10 @@ void test_collapse() { #pragma omp simd collapse(5 - 5) for (i = 0; i < 16; ++i) ; -// expected-note@+2 {{defined as reduction}} +// expected-note@+2 2 {{defined as reduction}} #pragma omp parallel #pragma omp simd collapse(2) reduction(+ : i) - for (i = 0; i < 16; ++i) + for (i = 0; i < 16; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp simd' directive may not be reduction, predetermined as lastprivate}} // expected-note@+1 {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for' directive into a parallel or another task region?}} for (int j = 0; j < 16; ++j) // expected-error@+2 2 {{reduction variable must be shared}} diff --git a/clang/test/OpenMP/target_parallel_for_firstprivate_messages.cpp b/clang/test/OpenMP/target_parallel_for_firstprivate_messages.cpp index dd05d84cb4ff..d90c02478c5e 100644 --- a/clang/test/OpenMP/target_parallel_for_firstprivate_messages.cpp +++ b/clang/test/OpenMP/target_parallel_for_firstprivate_messages.cpp @@ -136,12 +136,12 @@ int foomain(int argc, char **argv) { for (i = 0; i < argc; ++i) foo(); #pragma omp parallel private(i) -#pragma omp target parallel for firstprivate(i) // expected-note {{defined as firstprivate}} - for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp target parallel for' directive may not be firstprivate, predetermined as private}} +#pragma omp target parallel for firstprivate(i) // expected-note 2 {{defined as firstprivate}} + for (i = 0; i < argc; ++i) // expected-error 2 {{loop iteration variable in the associated loop of 'omp target parallel for' directive may not be firstprivate, predetermined as private}} foo(); #pragma omp parallel reduction(+ : i) -#pragma omp target parallel for firstprivate(i) // expected-note {{defined as firstprivate}} - for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp target parallel for' directive may not be firstprivate, predetermined as private}} +#pragma omp target parallel for firstprivate(i) // expected-note 2 {{defined as firstprivate}} + for (i = 0; i < argc; ++i) // expected-error 2 {{loop iteration variable in the associated loop of 'omp target parallel for' directive may not be firstprivate, predetermined as private}} foo(); return 0; } diff --git a/clang/test/OpenMP/target_parallel_for_misc_messages.c b/clang/test/OpenMP/target_parallel_for_misc_messages.c index f697cf2e6ca4..789d7e04db26 100644 --- a/clang/test/OpenMP/target_parallel_for_misc_messages.c +++ b/clang/test/OpenMP/target_parallel_for_misc_messages.c @@ -162,9 +162,9 @@ void test_collapse() { #pragma omp target parallel for collapse(5 - 5) for (i = 0; i < 16; ++i) ; -// expected-note@+1 {{defined as firstprivate}} +// expected-note@+1 2 {{defined as firstprivate}} #pragma omp target parallel for collapse(2) firstprivate(i) - for (i = 0; i < 16; ++i) + for (i = 0; i < 16; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp target parallel for' directive may not be firstprivate, predetermined as private}} // expected-note@+1 {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for' directive into a parallel or another task region?}} for (int j = 0; j < 16; ++j) // expected-error@+2 2 {{reduction variable must be shared}} diff --git a/clang/test/OpenMP/target_parallel_for_simd_firstprivate_messages.cpp b/clang/test/OpenMP/target_parallel_for_simd_firstprivate_messages.cpp index d76fedcce836..b2ffe3b3840d 100644 --- a/clang/test/OpenMP/target_parallel_for_simd_firstprivate_messages.cpp +++ b/clang/test/OpenMP/target_parallel_for_simd_firstprivate_messages.cpp @@ -136,12 +136,12 @@ int foomain(int argc, char **argv) { for (i = 0; i < argc; ++i) foo(); #pragma omp parallel private(i) -#pragma omp target parallel for simd firstprivate(i) // expected-note {{defined as firstprivate}} - for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp target parallel for simd' directive may not be firstprivate, predetermined as linear}} +#pragma omp target parallel for simd firstprivate(i) // expected-note 2 {{defined as firstprivate}} + for (i = 0; i < argc; ++i) // expected-error 2 {{loop iteration variable in the associated loop of 'omp target parallel for simd' directive may not be firstprivate, predetermined as linear}} foo(); #pragma omp parallel reduction(+ : i) -#pragma omp target parallel for simd firstprivate(i) // expected-note {{defined as firstprivate}} - for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp target parallel for simd' directive may not be firstprivate, predetermined as linear}} +#pragma omp target parallel for simd firstprivate(i) // expected-note 2 {{defined as firstprivate}} + for (i = 0; i < argc; ++i) // expected-error 2 {{loop iteration variable in the associated loop of 'omp target parallel for simd' directive may not be firstprivate, predetermined as linear}} foo(); return 0; } diff --git a/clang/test/OpenMP/target_parallel_for_simd_misc_messages.c b/clang/test/OpenMP/target_parallel_for_simd_misc_messages.c index 1459d8322a77..b11f57dc7548 100644 --- a/clang/test/OpenMP/target_parallel_for_simd_misc_messages.c +++ b/clang/test/OpenMP/target_parallel_for_simd_misc_messages.c @@ -163,8 +163,8 @@ void test_collapse() { for (i = 0; i < 16; ++i) ; // expected-note@+1 {{defined as firstprivate}} -#pragma omp target parallel for simd collapse(2) firstprivate(i) - for (i = 0; i < 16; ++i) +#pragma omp target parallel for simd collapse(2) firstprivate(i) // expected-note {{defined as firstprivate}} + for (i = 0; i < 16; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp target parallel for simd' directive may not be firstprivate, predetermined as lastprivate}} // expected-note@+1 {{variable with automatic storage duration is predetermined as private; perhaps you forget to enclose 'omp for' directive into a parallel or another task region?}} for (int j = 0; j < 16; ++j) // expected-error@+2 2 {{reduction variable must be shared}} diff --git a/clang/test/OpenMP/target_simd_firstprivate_messages.cpp b/clang/test/OpenMP/target_simd_firstprivate_messages.cpp index c26ef158f87d..651afdde8ab4 100644 --- a/clang/test/OpenMP/target_simd_firstprivate_messages.cpp +++ b/clang/test/OpenMP/target_simd_firstprivate_messages.cpp @@ -136,12 +136,12 @@ int foomain(int argc, char **argv) { for (i = 0; i < argc; ++i) foo(); #pragma omp parallel private(i) -#pragma omp target simd firstprivate(i) // expected-note {{defined as firstprivate}} - for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp target simd' directive may not be firstprivate, predetermined as linear}} +#pragma omp target simd firstprivate(i) // expected-note 2 {{defined as firstprivate}} + for (i = 0; i < argc; ++i) // expected-error 2 {{loop iteration variable in the associated loop of 'omp target simd' directive may not be firstprivate, predetermined as linear}} foo(); #pragma omp parallel reduction(+ : i) -#pragma omp target simd firstprivate(i) // expected-note {{defined as firstprivate}} - for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp target simd' directive may not be firstprivate, predetermined as linear}} +#pragma omp target simd firstprivate(i) // expected-note 2 {{defined as firstprivate}} + for (i = 0; i < argc; ++i) // expected-error 2 {{loop iteration variable in the associated loop of 'omp target simd' directive may not be firstprivate, predetermined as linear}} foo(); return 0; } diff --git a/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_misc_messages.c b/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_misc_messages.c index 07db3991bba6..f2a870ecb900 100644 --- a/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_misc_messages.c +++ b/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_misc_messages.c @@ -164,8 +164,8 @@ void test_collapse() { ; // expected-error@+4 {{OpenMP constructs may not be nested inside a simd region}} -#pragma omp target teams distribute parallel for simd collapse(2) firstprivate(i) - for (i = 0; i < 16; ++i) +#pragma omp target teams distribute parallel for simd collapse(2) firstprivate(i) // expected-note {{defined as firstprivate}} + for (i = 0; i < 16; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp target teams distribute parallel for simd' directive may not be firstprivate, predetermined as lastprivate}} for (int j = 0; j < 16; ++j) #pragma omp parallel for reduction(+ : i, j) for (int k = 0; k < 16; ++k) diff --git a/clang/test/OpenMP/target_teams_distribute_simd_misc_messages.c b/clang/test/OpenMP/target_teams_distribute_simd_misc_messages.c index 45f310ffdf6c..16f595d679bb 100644 --- a/clang/test/OpenMP/target_teams_distribute_simd_misc_messages.c +++ b/clang/test/OpenMP/target_teams_distribute_simd_misc_messages.c @@ -164,8 +164,8 @@ void test_collapse() { ; // expected-error@+4 {{OpenMP constructs may not be nested inside a simd region}} -#pragma omp target teams distribute simd collapse(2) firstprivate(i) - for (i = 0; i < 16; ++i) +#pragma omp target teams distribute simd collapse(2) firstprivate(i) // expected-note {{defined as firstprivate}} + for (i = 0; i < 16; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp target teams distribute simd' directive may not be firstprivate, predetermined as lastprivate}} for (int j = 0; j < 16; ++j) #pragma omp parallel for reduction(+ : i, j) for (int k = 0; k < 16; ++k) diff --git a/clang/test/OpenMP/task_codegen.c b/clang/test/OpenMP/task_codegen.c index 6669c7e73616..69718cc6f4d3 100644 --- a/clang/test/OpenMP/task_codegen.c +++ b/clang/test/OpenMP/task_codegen.c @@ -32,4 +32,19 @@ int main() { // CHECK: call i8* @__kmpc_omp_task_alloc( // CHECK: call i32 @__kmpc_omp_task( // CHECK: call void @__kmpc_end_taskgroup( + +// CHECK-LINE: @bar +void bar() { + // CHECK: call void @__kmpc_for_static_init_4( +#pragma omp for +for (int i = 0; i < 10; ++i) + // CHECK: [[BUF:%.+]] = call i8* @__kmpc_omp_task_alloc(%struct.ident_t* @{{.+}}, i32 %{{.+}}, i32 1, i64 48, + // CHECK: [[BC_BUF:%.+]] = bitcast i8* [[BUF]] to [[TT_WITH_PRIVS:%.+]]* + // CHECK: [[PRIVS:%.+]] = getelementptr inbounds [[TT_WITH_PRIVS]], [[TT_WITH_PRIVS]]* [[BC_BUF]], i32 0, i32 1 + // CHECK: [[I_PRIV:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}} [[PRIVS]], i32 0, i32 0 + // CHECK: store i32 %{{.+}}, i32* [[I_PRIV]], + // CHECK: = call i32 @__kmpc_omp_task(%struct.ident_t* @{{.+}}, i32 %{{.+}}, i8* [[BUF]]) +#pragma omp task +++i; +} #endif diff --git a/clang/test/OpenMP/taskloop_firstprivate_messages.cpp b/clang/test/OpenMP/taskloop_firstprivate_messages.cpp index 9ef869f50ae2..b5311f5e27f9 100644 --- a/clang/test/OpenMP/taskloop_firstprivate_messages.cpp +++ b/clang/test/OpenMP/taskloop_firstprivate_messages.cpp @@ -150,11 +150,11 @@ int foomain(int argc, char **argv) { for (i = 0; i < argc; ++i) foo(); #pragma omp parallel private(i) -#pragma omp taskloop firstprivate(i) // expected-note {{defined as firstprivate}} - for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp taskloop' directive may not be firstprivate, predetermined as private}} +#pragma omp taskloop firstprivate(i) // expected-note 2 {{defined as firstprivate}} + for (i = 0; i < argc; ++i) // expected-error 2 {{loop iteration variable in the associated loop of 'omp taskloop' directive may not be firstprivate, predetermined as private}} foo(); -#pragma omp parallel reduction(+ : i) -#pragma omp taskloop firstprivate(i) // expected-note {{defined as firstprivate}} +#pragma omp parallel reduction(+ : i) // expected-note {{defined as reduction}} +#pragma omp taskloop firstprivate(i) // expected-note {{defined as firstprivate}} expected-error {{argument of a reduction clause of a parallel construct must not appear in a firstprivate clause on a task construct}} for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp taskloop' directive may not be firstprivate, predetermined as private}} foo(); return 0; diff --git a/clang/test/OpenMP/taskloop_simd_firstprivate_messages.cpp b/clang/test/OpenMP/taskloop_simd_firstprivate_messages.cpp index 1aea8c02a043..fdedda93a735 100644 --- a/clang/test/OpenMP/taskloop_simd_firstprivate_messages.cpp +++ b/clang/test/OpenMP/taskloop_simd_firstprivate_messages.cpp @@ -150,11 +150,11 @@ int foomain(int argc, char **argv) { for (i = 0; i < argc; ++i) foo(); #pragma omp parallel private(i) -#pragma omp taskloop simd firstprivate(i) // expected-note {{defined as firstprivate}} - for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp taskloop simd' directive may not be firstprivate, predetermined as linear}} +#pragma omp taskloop simd firstprivate(i) // expected-note 2 {{defined as firstprivate}} + for (i = 0; i < argc; ++i) // expected-error 2 {{loop iteration variable in the associated loop of 'omp taskloop simd' directive may not be firstprivate, predetermined as linear}} foo(); -#pragma omp parallel reduction(+ : i) -#pragma omp taskloop simd firstprivate(i) // expected-note {{defined as firstprivate}} +#pragma omp parallel reduction(+ : i) // expected-note {{defined as reduction}} +#pragma omp taskloop simd firstprivate(i) // expected-note {{defined as firstprivate}} expected-error {{argument of a reduction clause of a parallel construct must not appear in a firstprivate clause on a task construct}} for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp taskloop simd' directive may not be firstprivate, predetermined as linear}} foo(); return 0; @@ -307,9 +307,9 @@ int main(int argc, char **argv) { #pragma omp taskloop simd firstprivate(i) // expected-note {{defined as firstprivate}} for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp taskloop simd' directive may not be firstprivate, predetermined as linear}} foo(); -#pragma omp parallel reduction(+ : i) // expected-note 2 {{defined as reduction}} +#pragma omp parallel reduction(+ : i) // expected-note {{defined as reduction}} #pragma omp taskloop simd firstprivate(i) // expected-error {{argument of a reduction clause of a parallel construct must not appear in a firstprivate clause on a task construct}} - for (i = 0; i < argc; ++i) // expected-error {{reduction variables may not be accessed in an explicit task}} + for (i = 0; i < argc; ++i) foo(); #pragma omp taskloop simd firstprivate(i) //expected-note {{defined as firstprivate}} for (i = 0; i < argc; ++i) // expected-error {{loop iteration variable in the associated loop of 'omp taskloop simd' directive may not be firstprivate, predetermined as linear}} diff --git a/clang/test/Parser/opencl-cxx-keywords.cl b/clang/test/Parser/opencl-cxx-keywords.cl index 0cafcdf28f86..ddc84536f20a 100644 --- a/clang/test/Parser/opencl-cxx-keywords.cl +++ b/clang/test/Parser/opencl-cxx-keywords.cl @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -verify -fsyntax-only -// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -verify -fsyntax-only -fexceptions -fcxx-exceptions +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -verify -fsyntax-only +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -verify -fsyntax-only -fexceptions -fcxx-exceptions // This test checks that various C++ and OpenCL C keywords are not available // in OpenCL. diff --git a/clang/test/Parser/opencl-cxx-virtual.cl b/clang/test/Parser/opencl-cxx-virtual.cl index 53befbc32120..f394a47fadb1 100644 --- a/clang/test/Parser/opencl-cxx-virtual.cl +++ b/clang/test/Parser/opencl-cxx-virtual.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -fsyntax-only -verify +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -fsyntax-only -verify // Test that virtual functions and abstract classes are rejected. class virtual_functions { diff --git a/clang/test/Preprocessor/aarch64-target-features.c b/clang/test/Preprocessor/aarch64-target-features.c index 6964edc96f0b..922c0997d599 100644 --- a/clang/test/Preprocessor/aarch64-target-features.c +++ b/clang/test/Preprocessor/aarch64-target-features.c @@ -88,7 +88,7 @@ // RUN: %clang -target aarch64 -mtune=cyclone -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-MTUNE-CYCLONE %s // RUN: %clang -target aarch64-none-linux-gnu -march=armv8-a+sve -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-SVE %s -// CHECK-SVE: __ARM_FEATURE_SVE 1 +// CHECK-SVE-NOT: __ARM_FEATURE_SVE 1 // RUN: %clang -target aarch64-none-linux-gnu -march=armv8.2a+dotprod -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-DOTPROD %s // CHECK-DOTPROD: __ARM_FEATURE_DOTPROD 1 diff --git a/clang/test/Preprocessor/predefined-macros.c b/clang/test/Preprocessor/predefined-macros.c index 9296b1cf5a50..def105f4c52e 100644 --- a/clang/test/Preprocessor/predefined-macros.c +++ b/clang/test/Preprocessor/predefined-macros.c @@ -131,7 +131,7 @@ // RUN: | FileCheck -match-full-lines %s --check-prefix=CHECK-CL20 // RUN: %clang_cc1 %s -E -dM -o - -x cl -cl-fast-relaxed-math \ // RUN: | FileCheck -match-full-lines %s --check-prefix=CHECK-FRM -// RUN: %clang_cc1 %s -E -dM -o - -x cl -cl-std=c++ \ +// RUN: %clang_cc1 %s -E -dM -o - -x cl -cl-std=clc++ \ // RUN: | FileCheck -match-full-lines %s --check-prefix=CHECK-CLCPP10 // CHECK-CL10: #define CL_VERSION_1_0 100 // CHECK-CL10: #define CL_VERSION_1_1 110 diff --git a/clang/test/Preprocessor/riscv-target-features.c b/clang/test/Preprocessor/riscv-target-features.c index 2c63e0fa29df..36e49c36f033 100644 --- a/clang/test/Preprocessor/riscv-target-features.c +++ b/clang/test/Preprocessor/riscv-target-features.c @@ -47,3 +47,27 @@ // RUN: %clang -target riscv64-unknown-linux-gnu -march=rv64ic -x c -E -dM %s \ // RUN: -o - | FileCheck --check-prefix=CHECK-C-EXT %s // CHECK-C-EXT: __riscv_compressed 1 + +// RUN: %clang -target riscv32-unknown-linux-gnu -march=rv32ifd -x c -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-SOFT %s +// RUN: %clang -target riscv64-unknown-linux-gnu -march=rv64ifd -x c -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-SOFT %s +// CHECK-SOFT: __riscv_float_abi_soft 1 +// CHECK-SOFT-NOT: __riscv_float_abi_single +// CHECK-SOFT-NOT: __riscv_float_abi_double + +// RUN: %clang -target riscv32-unknown-linux-gnu -march=rv32ifd -mabi=ilp32f -x c -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-SINGLE %s +// RUN: %clang -target riscv64-unknown-linux-gnu -march=rv64ifd -mabi=lp64f -x c -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-SINGLE %s +// CHECK-SINGLE: __riscv_float_abi_single 1 +// CHECK-SINGLE-NOT: __riscv_float_abi_soft +// CHECK-SINGLE-NOT: __riscv_float_abi_double + +// RUN: %clang -target riscv32-unknown-linux-gnu -march=rv32ifd -mabi=ilp32d -x c -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-DOUBLE %s +// RUN: %clang -target riscv64-unknown-linux-gnu -march=rv64ifd -mabi=lp64d -x c -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-DOUBLE %s +// CHECK-DOUBLE: __riscv_float_abi_double 1 +// CHECK-DOUBLE-NOT: __riscv_float_abi_soft +// CHECK-DOUBLE-NOT: __riscv_float_abi_single diff --git a/clang/test/Preprocessor/stringize_skipped.c b/clang/test/Preprocessor/stringize_skipped.c new file mode 100644 index 000000000000..e9395fbbb4b3 --- /dev/null +++ b/clang/test/Preprocessor/stringize_skipped.c @@ -0,0 +1,5 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// Ensure we see the error from PP and do not see errors from the parser. + +// expected-error@+1{{'#' is not followed by a macro parameter}} +#define INVALID() #B 10+10 diff --git a/clang/test/Sema/builtin-setjmp.c b/clang/test/Sema/builtin-setjmp.c new file mode 100644 index 000000000000..f8770d88e731 --- /dev/null +++ b/clang/test/Sema/builtin-setjmp.c @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify -DNO_JMP_BUF %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify %s + +#ifdef NO_JMP_BUF +extern long setjmp(long *); // expected-warning {{declaration of built-in function 'setjmp' requires the declaration of the 'jmp_buf' type, commonly provided in the header .}} +#else +typedef long jmp_buf; +extern int setjmp(char); // expected-warning@8 {{incompatible redeclaration of library function 'setjmp'}} + // expected-note@8 {{'setjmp' is a builtin with type 'int (jmp_buf)' (aka 'int (long)')}} +#endif diff --git a/clang/test/Sema/implicit-builtin-decl.c b/clang/test/Sema/implicit-builtin-decl.c index 3c2ff94984c0..3a3dfa935ac1 100644 --- a/clang/test/Sema/implicit-builtin-decl.c +++ b/clang/test/Sema/implicit-builtin-decl.c @@ -55,14 +55,17 @@ main(int argc, char *argv[]) void snprintf() { } -// PR8316 -void longjmp(); // expected-warning{{declaration of built-in function 'longjmp' requires inclusion of the header }} +// PR8316 & PR40692 +void longjmp(); // expected-warning{{declaration of built-in function 'longjmp' requires the declaration of the 'jmp_buf' type, commonly provided in the header .}} extern float fmaxf(float, float); struct __jmp_buf_tag {}; -void sigsetjmp(struct __jmp_buf_tag[1], int); // expected-warning{{declaration of built-in function 'sigsetjmp' requires inclusion of the header }} +void sigsetjmp(struct __jmp_buf_tag[1], int); // expected-warning{{declaration of built-in function 'sigsetjmp' requires the declaration of the 'jmp_buf' type, commonly provided in the header .}} // CHECK: FunctionDecl {{.*}} col:6 sigsetjmp ' // CHECK-NOT: FunctionDecl // CHECK: ReturnsTwiceAttr {{.*}} <{{.*}}> Implicit + +// PR40692 +void pthread_create(); // no warning expected diff --git a/clang/test/Sema/inline-asm-validate-riscv.c b/clang/test/Sema/inline-asm-validate-riscv.c index cba08c865287..744f73e23cf2 100644 --- a/clang/test/Sema/inline-asm-validate-riscv.c +++ b/clang/test/Sema/inline-asm-validate-riscv.c @@ -4,7 +4,6 @@ void I(int i) { static const int BelowMin = -2049; static const int AboveMax = 2048; - asm volatile ("" :: "I"(i)); // expected-error{{constraint 'I' expects an integer constant expression}} asm volatile ("" :: "I"(BelowMin)); // expected-error{{value '-2049' out of range for constraint 'I'}} asm volatile ("" :: "I"(AboveMax)); // expected-error{{value '2048' out of range for constraint 'I'}} } @@ -12,7 +11,6 @@ void I(int i) { void J(int j) { static const int BelowMin = -1; static const int AboveMax = 1; - asm volatile ("" :: "J"(j)); // expected-error{{constraint 'J' expects an integer constant expression}} asm volatile ("" :: "J"(BelowMin)); // expected-error{{value '-1' out of range for constraint 'J'}} asm volatile ("" :: "J"(AboveMax)); // expected-error{{value '1' out of range for constraint 'J'}} } @@ -20,7 +18,6 @@ void J(int j) { void K(int k) { static const int BelowMin = -1; static const int AboveMax = 32; - asm volatile ("" :: "K"(k)); // expected-error{{constraint 'K' expects an integer constant expression}} asm volatile ("" :: "K"(BelowMin)); // expected-error{{value '-1' out of range for constraint 'K'}} asm volatile ("" :: "K"(AboveMax)); // expected-error{{value '32' out of range for constraint 'K'}} } diff --git a/clang/test/Sema/inline-asm-validate-x86.c b/clang/test/Sema/inline-asm-validate-x86.c index c6fa2e1b4fa8..87b60a095530 100644 --- a/clang/test/Sema/inline-asm-validate-x86.c +++ b/clang/test/Sema/inline-asm-validate-x86.c @@ -4,9 +4,6 @@ void I(int i, int j) { static const int BelowMin = -1; static const int AboveMax = 32; - __asm__("xorl %0,%2" - : "=r"(i) - : "0"(i), "I"(j)); // expected-error{{constraint 'I' expects an integer constant expression}} __asm__("xorl %0,%2" : "=r"(i) : "0"(i), "I"(BelowMin)); // expected-error{{value '-1' out of range for constraint 'I'}} @@ -21,9 +18,6 @@ void I(int i, int j) { void J(int i, int j) { static const int BelowMin = -1; static const int AboveMax = 64; - __asm__("xorl %0,%2" - : "=r"(i) - : "0"(i), "J"(j)); // expected-error{{constraint 'J' expects an integer constant expression}} __asm__("xorl %0,%2" : "=r"(i) : "0"(i), "J"(BelowMin)); // expected-error{{value '-1' out of range for constraint 'J'}} @@ -38,9 +32,6 @@ void J(int i, int j) { void K(int i, int j) { static const int BelowMin = -129; static const int AboveMax = 128; - __asm__("xorl %0,%2" - : "=r"(i) - : "0"(i), "K"(j)); // expected-error{{constraint 'K' expects an integer constant expression}} __asm__("xorl %0,%2" : "=r"(i) : "0"(i), "K"(BelowMin)); // expected-error{{value '-129' out of range for constraint 'K'}} @@ -60,9 +51,6 @@ void L(int i, int j) { static const int Valid1 = 0xff; static const int Valid2 = 0xffff; static const int Valid3 = 0xffffffff; - __asm__("xorl %0,%2" - : "=r"(i) - : "0"(i), "L"(j)); // expected-error{{constraint 'L' expects an integer constant expression}} __asm__("xorl %0,%2" : "=r"(i) : "0"(i), "L"(Invalid1)); // expected-error{{value '1' out of range for constraint 'L'}} @@ -89,9 +77,6 @@ void L(int i, int j) { void M(int i, int j) { static const int BelowMin = -1; static const int AboveMax = 4; - __asm__("xorl %0,%2" - : "=r"(i) - : "0"(i), "M"(j)); // expected-error{{constraint 'M' expects an integer constant expression}} __asm__("xorl %0,%2" : "=r"(i) : "0"(i), "M"(BelowMin)); // expected-error{{value '-1' out of range for constraint 'M'}} @@ -106,9 +91,6 @@ void M(int i, int j) { void N(int i, int j) { static const int BelowMin = -1; static const int AboveMax = 256; - __asm__("xorl %0,%2" - : "=r"(i) - : "0"(i), "N"(j)); // expected-error{{constraint 'N' expects an integer constant expression}} __asm__("xorl %0,%2" : "=r"(i) : "0"(i), "N"(BelowMin)); // expected-error{{value '-1' out of range for constraint 'N'}} @@ -123,9 +105,6 @@ void N(int i, int j) { void O(int i, int j) { static const int BelowMin = -1; static const int AboveMax = 128; - __asm__("xorl %0,%2" - : "=r"(i) - : "0"(i), "O"(j)); // expected-error{{constraint 'O' expects an integer constant expression}} __asm__("xorl %0,%2" : "=r"(i) : "0"(i), "O"(BelowMin)); // expected-error{{value '-1' out of range for constraint 'O'}} @@ -146,10 +125,6 @@ void pr40890(void) { __asm__ __volatile__("\n#define S_A abcd%0\n" : : "n"(&((struct s*)0)->a)); // This offset-from-null pointer can be used as an integer constant expression. __asm__ __volatile__("\n#define S_B abcd%0\n" : : "n"(&((struct s*)0)->b)); - // This pointer cannot be used as an integer constant expression. - __asm__ __volatile__("\n#define GLOBAL_A abcd%0\n" : : "n"(&s.a)); // expected-error{{constraint 'n' expects an integer constant expression}} - // Floating-point is also not okay. - __asm__ __volatile__("\n#define PI abcd%0\n" : : "n"(3.14f)); // expected-error{{constraint 'n' expects an integer constant expression}} #ifdef AMD64 // This arbitrary pointer is fine. __asm__ __volatile__("\n#define BEEF abcd%0\n" : : "n"((int*)0xdeadbeeeeeef)); diff --git a/clang/test/Sema/pr41027.c b/clang/test/Sema/pr41027.c deleted file mode 100644 index 94ace6463810..000000000000 --- a/clang/test/Sema/pr41027.c +++ /dev/null @@ -1,10 +0,0 @@ -// RUN: %clang_cc1 -triple x86_64 -fsyntax-only %s -// XFAIL: * - -inline void pr41027(unsigned a, unsigned b) { - if (__builtin_constant_p(a)) { - __asm__ volatile("outl %0,%w1" : : "a"(b), "n"(a)); - } else { - __asm__ volatile("outl %0,%w1" : : "a"(b), "d"(a)); - } -} diff --git a/clang/test/Sema/warn-uninitialized-statement-expression.c b/clang/test/Sema/warn-uninitialized-statement-expression.c new file mode 100644 index 000000000000..4e29ee01eab9 --- /dev/null +++ b/clang/test/Sema/warn-uninitialized-statement-expression.c @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -fsyntax-only -Wuninitialized -verify %s + +void init(int *); + +void foo(void) { + int i = ({ + init(&i); + i; + }); +} + +void foo_bad(void) { + int i = ({ + int z = i; // expected-warning{{variable 'i' is uninitialized when used within its own initialization}} + init(&i); + i; + }); +} + +struct widget { + int x, y; +}; +void init2(struct widget *); + +void bar(void) { + struct widget my_widget = ({ + init2(&my_widget); + my_widget; + }); + struct widget a = (init2(&a), a); +} + +void bar_bad(void) { + struct widget my_widget = ({ + struct widget z = my_widget; // expected-warning{{variable 'my_widget' is uninitialized when used within its own initialization}} + int x = my_widget.x; //FIXME: There should be an uninitialized warning here + init2(&my_widget); + my_widget; + }); +} + +void baz(void) { + struct widget a = ({ + struct widget b = ({ + b = a; // expected-warning{{variable 'a' is uninitialized when used within its own initialization}} + }); + a; + }); +} + +void f(void) { + struct widget *a = ({ + init2(a); // expected-warning{{variable 'a' is uninitialized when used within its own initialization}} + a; + }); +} diff --git a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp index c5deb9fe9195..85312cf1049f 100644 --- a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp +++ b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp @@ -268,13 +268,16 @@ namespace tuple_tests { // Don't get caught by surprise when X<...> doesn't even exist in the // selected specialization! namespace libcxx_2 { - template struct tuple { // expected-note {{candidate}} + template struct tuple { template struct X { static const bool value = false; }; + // Substitution into X::value succeeds but produces the + // value-dependent expression + // tuple::X<>::value + // FIXME: Is that the right behavior? template::value> tuple(U &&...u); - // expected-note@-1 {{substitution failure [with T = <>, U = ]: cannot reference member of primary template because deduced class template specialization 'tuple<>' is an explicit specialization}} }; template <> class tuple<> {}; - tuple a = {1, 2, 3}; // expected-error {{no viable constructor or deduction guide}} + tuple a = {1, 2, 3}; // expected-error {{excess elements in struct initializer}} } namespace libcxx_3 { diff --git a/clang/test/SemaCXX/cxx2a-adl-only-template-id.cpp b/clang/test/SemaCXX/cxx2a-adl-only-template-id.cpp index 4bd9a22f5f44..28ecbade1b1a 100644 --- a/clang/test/SemaCXX/cxx2a-adl-only-template-id.cpp +++ b/clang/test/SemaCXX/cxx2a-adl-only-template-id.cpp @@ -65,3 +65,11 @@ void xf(g x); // expected-error {{variable has incomplete type 'void'}} exp struct B : g { // expected-error {{expected class name}} B() : g() {} // expected-error {{expected class member or base class name}} }; + +namespace vector_components { + typedef __attribute__((__ext_vector_type__(2))) float vector_float2; + bool foo123(vector_float2 &A, vector_float2 &B) + { + return A.x < B.x && B.y > A.y; + } +} diff --git a/clang/test/SemaCXX/pseudo-destructors.cpp b/clang/test/SemaCXX/pseudo-destructors.cpp index 08938bf34a79..fb2d0afdc3fa 100644 --- a/clang/test/SemaCXX/pseudo-destructors.cpp +++ b/clang/test/SemaCXX/pseudo-destructors.cpp @@ -34,7 +34,7 @@ void f(A* a, Foo *f, int *i, double *d, int ii) { g().~Bar(); // expected-error{{non-scalar}} f->::~Bar(); - f->N::~Wibble(); // FIXME: technically, Wibble isn't a class-name + f->N::~Wibble(); // expected-error{{'N' does not refer to a type}} expected-error{{'Wibble' does not refer to a type}} f->::~Bar(17, 42); // expected-error{{cannot have any arguments}} @@ -79,7 +79,7 @@ namespace PR11339 { template void destroy(T* p) { p->~T(); // ok - p->~oops(); // expected-error{{expected the class name after '~' to name a destructor}} + p->~oops(); // expected-error{{identifier 'oops' in object destruction expression does not name a type}} } template void destroy(int*); // expected-note{{in instantiation of function template specialization}} diff --git a/clang/test/SemaCXX/vector.cpp b/clang/test/SemaCXX/vector.cpp index a6a4ceb0e535..295e1e173233 100644 --- a/clang/test/SemaCXX/vector.cpp +++ b/clang/test/SemaCXX/vector.cpp @@ -334,3 +334,27 @@ void Init() { } } // namespace Templates + +typedef int inte2 __attribute__((__ext_vector_type__(2))); + +void test_vector_literal(inte4 res) { + inte2 a = (inte2)(1, 2); //expected-warning{{expression result unused}} + inte4 b = (inte4)(a, a); //expected-error{{C-style cast from vector 'inte2' (vector of 2 'int' values) to vector 'inte4' (vector of 4 'int' values) of different size}} //expected-warning{{expression result unused}} +} + +typedef __attribute__((__ext_vector_type__(4))) float vector_float4; +typedef __attribute__((__ext_vector_type__(4))) int vector_int4; + +namespace swizzle_template_confusion { + template struct xyzw {}; + vector_int4 foo123(vector_float4 &A, vector_float4 &B) { + return A.xyzw < B.x && B.y > A.y; // OK, not a template-id + } +} + +namespace swizzle_typo_correction { + template struct xyzv {}; + vector_int4 foo123(vector_float4 &A, vector_float4 &B) { + return A.xyzw < B.x && B.y > A.y; // OK, not a typo for 'xyzv' + } +} diff --git a/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl b/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl index bbd3919b154b..89cf8e3a8124 100644 --- a/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl +++ b/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl @@ -1,9 +1,9 @@ // RUN: %clang_cc1 %s -ffake-address-space-map -verify -pedantic -fsyntax-only -DCONSTANT -cl-std=CL2.0 // RUN: %clang_cc1 %s -ffake-address-space-map -verify -pedantic -fsyntax-only -DGLOBAL -cl-std=CL2.0 // RUN: %clang_cc1 %s -ffake-address-space-map -verify -pedantic -fsyntax-only -DGENERIC -cl-std=CL2.0 -// RUN: %clang_cc1 %s -ffake-address-space-map -verify -pedantic -fsyntax-only -DCONSTANT -cl-std=c++ -// RUN: %clang_cc1 %s -ffake-address-space-map -verify -pedantic -fsyntax-only -DGLOBAL -cl-std=c++ -// RUN: %clang_cc1 %s -ffake-address-space-map -verify -pedantic -fsyntax-only -DGENERIC -cl-std=c++ +// RUN: %clang_cc1 %s -ffake-address-space-map -verify -pedantic -fsyntax-only -DCONSTANT -cl-std=clc++ +// RUN: %clang_cc1 %s -ffake-address-space-map -verify -pedantic -fsyntax-only -DGLOBAL -cl-std=clc++ +// RUN: %clang_cc1 %s -ffake-address-space-map -verify -pedantic -fsyntax-only -DGENERIC -cl-std=clc++ /* OpenCLC v2.0 adds a set of restrictions for conversions between pointers to * different address spaces, mainly described in Sections 6.5.5 and 6.5.6. diff --git a/clang/test/SemaOpenCL/address-spaces.cl b/clang/test/SemaOpenCL/address-spaces.cl index 13e9442b95c3..55a55dc75050 100644 --- a/clang/test/SemaOpenCL/address-spaces.cl +++ b/clang/test/SemaOpenCL/address-spaces.cl @@ -1,6 +1,6 @@ // RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only // RUN: %clang_cc1 %s -cl-std=CL2.0 -verify -pedantic -fsyntax-only -// RUN: %clang_cc1 %s -cl-std=c++ -verify -pedantic -fsyntax-only +// RUN: %clang_cc1 %s -cl-std=clc++ -verify -pedantic -fsyntax-only __constant int ci = 1; diff --git a/clang/test/SemaOpenCL/builtin.cl b/clang/test/SemaOpenCL/builtin.cl index 4669e3fbb381..b6f215668c87 100644 --- a/clang/test/SemaOpenCL/builtin.cl +++ b/clang/test/SemaOpenCL/builtin.cl @@ -1,5 +1,5 @@ // RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=CL1.2 -// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=c++ +// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=clc++ // expected-no-diagnostics diff --git a/clang/test/SemaOpenCL/clk_event_t.cl b/clang/test/SemaOpenCL/clk_event_t.cl index 4a884bcfa6c0..e9736eaa8f37 100644 --- a/clang/test/SemaOpenCL/clk_event_t.cl +++ b/clang/test/SemaOpenCL/clk_event_t.cl @@ -1,5 +1,5 @@ // RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=CL2.0 -// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=c++ +// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=clc++ // Taken from opencl-c.h #define CLK_NULL_EVENT (__builtin_astype(((void*)(__SIZE_MAX__)), clk_event_t)) diff --git a/clang/test/SemaOpenCL/extension-version.cl b/clang/test/SemaOpenCL/extension-version.cl index d976cfb3a435..19d088495350 100644 --- a/clang/test/SemaOpenCL/extension-version.cl +++ b/clang/test/SemaOpenCL/extension-version.cl @@ -2,12 +2,12 @@ // RUN: %clang_cc1 -x cl -cl-std=CL1.1 %s -verify -triple spir-unknown-unknown // RUN: %clang_cc1 -x cl -cl-std=CL1.2 %s -verify -triple spir-unknown-unknown // RUN: %clang_cc1 -x cl -cl-std=CL2.0 %s -verify -triple spir-unknown-unknown -// RUN: %clang_cc1 -x cl -cl-std=c++ %s -verify -triple spir-unknown-unknown +// RUN: %clang_cc1 -x cl -cl-std=clc++ %s -verify -triple spir-unknown-unknown // RUN: %clang_cc1 -x cl -cl-std=CL %s -verify -triple spir-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES // RUN: %clang_cc1 -x cl -cl-std=CL1.1 %s -verify -triple spir-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES // RUN: %clang_cc1 -x cl -cl-std=CL1.2 %s -verify -triple spir-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES // RUN: %clang_cc1 -x cl -cl-std=CL2.0 %s -verify -triple spir-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES -// RUN: %clang_cc1 -x cl -cl-std=c++ %s -verify -triple spir-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES +// RUN: %clang_cc1 -x cl -cl-std=clc++ %s -verify -triple spir-unknown-unknown -Wpedantic-core-features -DTEST_CORE_FEATURES #if (defined(__OPENCL_CPP_VERSION__) || __OPENCL_C_VERSION__ >= 200) && !defined(TEST_CORE_FEATURES) // expected-no-diagnostics diff --git a/clang/test/SemaOpenCL/extensions.cl b/clang/test/SemaOpenCL/extensions.cl index e9dba69ecd7c..55dbd1d5eede 100644 --- a/clang/test/SemaOpenCL/extensions.cl +++ b/clang/test/SemaOpenCL/extensions.cl @@ -28,7 +28,7 @@ // enabled by default with -cl-std=CL2.0). // // RUN: %clang_cc1 %s -triple amdgcn-unknown-unknown -verify -pedantic -fsyntax-only -cl-std=CL2.0 -finclude-default-header -// RUN: %clang_cc1 %s -triple spir-unknown-unknown -verify -pedantic -fsyntax-only -cl-std=c++ +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -verify -pedantic -fsyntax-only -cl-std=clc++ #ifdef _OPENCL_H_ // expected-no-diagnostics diff --git a/clang/test/SemaOpenCL/invalid-image.cl b/clang/test/SemaOpenCL/invalid-image.cl index 10c44cf4c281..9185cc371ebc 100644 --- a/clang/test/SemaOpenCL/invalid-image.cl +++ b/clang/test/SemaOpenCL/invalid-image.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -cl-std=c++ %s +// RUN: %clang_cc1 -verify -cl-std=clc++ %s // RUN: %clang_cc1 -verify %s // RUN: %clang_cc1 -verify -D=ATTR_TEST -fms-compatibility %s diff --git a/clang/test/SemaOpenCL/invalid-pipes-cl2.0.cl b/clang/test/SemaOpenCL/invalid-pipes-cl2.0.cl index afe5dc6a6085..69fa2b6da823 100644 --- a/clang/test/SemaOpenCL/invalid-pipes-cl2.0.cl +++ b/clang/test/SemaOpenCL/invalid-pipes-cl2.0.cl @@ -1,5 +1,5 @@ // RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=CL2.0 -// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=c++ +// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=clc++ global pipe int gp; // expected-error {{type '__global read_only pipe int' can only be used as a function parameter in OpenCL}} global reserve_id_t rid; // expected-error {{the '__global reserve_id_t' type cannot be used to declare a program scope variable}} diff --git a/clang/test/SemaOpenCL/sampler_t.cl b/clang/test/SemaOpenCL/sampler_t.cl index 28e7a0ad27ec..fe9d997c8960 100644 --- a/clang/test/SemaOpenCL/sampler_t.cl +++ b/clang/test/SemaOpenCL/sampler_t.cl @@ -10,6 +10,9 @@ #define CLK_FILTER_NEAREST 0x10 #define CLK_FILTER_LINEAR 0x20 +typedef float float4 __attribute__((ext_vector_type(4))); +float4 read_imagef(read_only image1d_t, sampler_t, float); + constant sampler_t glb_smp = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_LINEAR; constant sampler_t glb_smp2; // expected-error{{variable in constant address space must be initialized}} global sampler_t glb_smp3 = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_NEAREST; // expected-error{{sampler type cannot be used with the __local and __global address space qualifiers}} expected-error {{global sampler requires a const or constant address space qualifier}} @@ -74,3 +77,7 @@ void bar() { foo(smp1+1); //expected-error{{invalid operands to binary expression ('sampler_t' and 'int')}} } +void smp_args(read_only image1d_t image) { + // Test that parentheses around sampler arguments are ignored. + float4 res = read_imagef(image, (glb_smp10), 0.0f); +} diff --git a/clang/test/SemaOpenCL/vector_literals_const.cl b/clang/test/SemaOpenCL/vector_literals_const.cl deleted file mode 100644 index ee5ae2002a3c..000000000000 --- a/clang/test/SemaOpenCL/vector_literals_const.cl +++ /dev/null @@ -1,27 +0,0 @@ -// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -// expected-no-diagnostics - -typedef int int2 __attribute((ext_vector_type(2))); -typedef int int3 __attribute((ext_vector_type(3))); -typedef int int4 __attribute((ext_vector_type(4))); - -__constant int4 i_1_1_1_1 = (int4)(1,2,3,4); -__constant int4 i_2_1_1 = (int4)((int2)(1,2),3,4); -__constant int4 i_1_2_1 = (int4)(1,(int2)(2,3),4); -__constant int4 i_1_1_2 = (int4)(1,2,(int2)(3,4)); -__constant int4 i_2_2 = (int4)((int2)(1,2),(int2)(3,4)); -__constant int4 i_3_1 = (int4)((int3)(1,2,3),4); -__constant int4 i_1_3 = (int4)(1,(int3)(2,3,4)); - -typedef float float2 __attribute((ext_vector_type(2))); -typedef float float3 __attribute((ext_vector_type(3))); -typedef float float4 __attribute((ext_vector_type(4))); - -__constant float4 f_1_1_1_1 = (float4)(1,2,3,4); -__constant float4 f_2_1_1 = (float4)((float2)(1,2),3,4); -__constant float4 f_1_2_1 = (float4)(1,(float2)(2,3),4); -__constant float4 f_1_1_2 = (float4)(1,2,(float2)(3,4)); -__constant float4 f_2_2 = (float4)((float2)(1,2),(float2)(3,4)); -__constant float4 f_3_1 = (float4)((float3)(1,2,3),4); -__constant float4 f_1_3 = (float4)(1,(float3)(2,3,4)); - diff --git a/clang/test/SemaOpenCLCXX/address-space-deduction.cl b/clang/test/SemaOpenCLCXX/address-space-deduction.cl index 4283ec41e635..ac6b2cabbd0c 100644 --- a/clang/test/SemaOpenCLCXX/address-space-deduction.cl +++ b/clang/test/SemaOpenCLCXX/address-space-deduction.cl @@ -1,4 +1,4 @@ -//RUN: %clang_cc1 %s -cl-std=c++ -pedantic -ast-dump -verify | FileCheck %s +//RUN: %clang_cc1 %s -cl-std=clc++ -pedantic -ast-dump -verify | FileCheck %s //expected-no-diagnostics @@ -78,3 +78,25 @@ __kernel void test() { int foo[10]; xxx(&foo[0]); } + +// Addr space for pointer/reference to an array +//CHECK: FunctionDecl {{.*}} t1 'void (const __generic float (&)[2])' +void t1(const float (&fYZ)[2]); +//CHECK: FunctionDecl {{.*}} t2 'void (const __generic float (*)[2])' +void t2(const float (*fYZ)[2]); +//CHECK: FunctionDecl {{.*}} t3 'void (__generic float (((*)))[2])' +void t3(float(((*fYZ)))[2]); +//CHECK: FunctionDecl {{.*}} t4 'void (__generic float (((*__generic *)))[2])' +void t4(float(((**fYZ)))[2]); +//CHECK: FunctionDecl {{.*}} t5 'void (__generic float (*__generic (*))[2])' +void t5(float (*(*fYZ))[2]); + +__kernel void k() { + __local float x[2]; + __local float(*p)[2]; + t1(x); + t2(&x); + t3(&x); + t4(&p); + t5(&p); +} diff --git a/clang/test/SemaOpenCLCXX/address-space-of-this-class-scope.cl b/clang/test/SemaOpenCLCXX/address-space-of-this-class-scope.cl index ebb76043bbd4..1c0cb3731bd5 100644 --- a/clang/test/SemaOpenCLCXX/address-space-of-this-class-scope.cl +++ b/clang/test/SemaOpenCLCXX/address-space-of-this-class-scope.cl @@ -1,4 +1,4 @@ -//RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -pedantic -verify +//RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -pedantic -verify struct C { auto fGlob() __global -> decltype(this); diff --git a/clang/test/SemaOpenCLCXX/address-space-of-this.cl b/clang/test/SemaOpenCLCXX/address-space-of-this.cl index 7ae3aa63f407..ac79b3411928 100644 --- a/clang/test/SemaOpenCLCXX/address-space-of-this.cl +++ b/clang/test/SemaOpenCLCXX/address-space-of-this.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -pedantic -verify -fsyntax-only +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -pedantic -verify -fsyntax-only // expected-no-diagnostics // Extract from PR38614 diff --git a/clang/test/SemaOpenCLCXX/address-space-references.cl b/clang/test/SemaOpenCLCXX/address-space-references.cl index 851d3023df29..a6c7c842da00 100644 --- a/clang/test/SemaOpenCLCXX/address-space-references.cl +++ b/clang/test/SemaOpenCLCXX/address-space-references.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -pedantic -verify -fsyntax-only +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -pedantic -verify -fsyntax-only __global const int& f(__global float &ref) { return ref; // expected-error{{reference of type 'const __global int &' cannot bind to a temporary object because of address space mismatch}} diff --git a/clang/test/SemaOpenCLCXX/address-space-templates.cl b/clang/test/SemaOpenCLCXX/address-space-templates.cl index 3fb935766e94..0acc5145a632 100644 --- a/clang/test/SemaOpenCLCXX/address-space-templates.cl +++ b/clang/test/SemaOpenCLCXX/address-space-templates.cl @@ -1,4 +1,4 @@ -//RUN: %clang_cc1 %s -cl-std=c++ -pedantic -verify -fsyntax-only +//RUN: %clang_cc1 %s -cl-std=clc++ -pedantic -verify -fsyntax-only template struct S { diff --git a/clang/test/SemaOpenCLCXX/address_space_overloading.cl b/clang/test/SemaOpenCLCXX/address_space_overloading.cl index 6458ade56209..33337ef461df 100644 --- a/clang/test/SemaOpenCLCXX/address_space_overloading.cl +++ b/clang/test/SemaOpenCLCXX/address_space_overloading.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=c++ +// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=clc++ // expected-no-diagnostics struct RetGlob { diff --git a/clang/test/SemaOpenCLCXX/kernel_invalid.cl b/clang/test/SemaOpenCLCXX/kernel_invalid.cl index 43e1243a55ef..2efdb756446d 100644 --- a/clang/test/SemaOpenCLCXX/kernel_invalid.cl +++ b/clang/test/SemaOpenCLCXX/kernel_invalid.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -cl-std=c++ -pedantic -verify -fsyntax-only +// RUN: %clang_cc1 %s -cl-std=clc++ -pedantic -verify -fsyntax-only struct C { kernel void m(); //expected-error{{kernel functions cannot be class members}} diff --git a/clang/test/SemaOpenCLCXX/method-overload-address-space.cl b/clang/test/SemaOpenCLCXX/method-overload-address-space.cl index 64a279549cdd..7c428a570c2c 100644 --- a/clang/test/SemaOpenCLCXX/method-overload-address-space.cl +++ b/clang/test/SemaOpenCLCXX/method-overload-address-space.cl @@ -1,4 +1,4 @@ -//RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -pedantic -verify +//RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -pedantic -verify struct C { void m1() __local __local; //expected-warning{{multiple identical address spaces specified for type}} diff --git a/clang/test/SemaOpenCLCXX/newdelete.cl b/clang/test/SemaOpenCLCXX/newdelete.cl index abc4c0fb6cbd..2ef27843d5ce 100644 --- a/clang/test/SemaOpenCLCXX/newdelete.cl +++ b/clang/test/SemaOpenCLCXX/newdelete.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -pedantic -verify -fsyntax-only +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -pedantic -verify -fsyntax-only class A { public: diff --git a/clang/test/SemaOpenCLCXX/restricted.cl b/clang/test/SemaOpenCLCXX/restricted.cl index 2af4ae137c41..3487285b6081 100644 --- a/clang/test/SemaOpenCLCXX/restricted.cl +++ b/clang/test/SemaOpenCLCXX/restricted.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -pedantic -verify -fsyntax-only +// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=clc++ -pedantic -verify -fsyntax-only // This test checks that various C/C++/OpenCL C constructs are not available in // C++ for OpenCL. diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx11.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx11.cpp index 313114e2cb8e..460b6def5d6f 100644 --- a/clang/test/SemaTemplate/temp_arg_nontype_cxx11.cpp +++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx11.cpp @@ -48,3 +48,20 @@ void Useage() { } } +namespace PR42513 { + template void f(); + constexpr int WidgetCtor(struct X1*); + + struct X1 { + friend constexpr int WidgetCtor(X1*); + }; + template + struct StandardWidget { + friend constexpr int WidgetCtor(X1*) { + return 0; + } + }; + template struct StandardWidget; + + void use() { f(); } +} diff --git a/clang/unittests/Tooling/Syntax/TokensTest.cpp b/clang/unittests/Tooling/Syntax/TokensTest.cpp index 24adba28a294..a1398bd55688 100644 --- a/clang/unittests/Tooling/Syntax/TokensTest.cpp +++ b/clang/unittests/Tooling/Syntax/TokensTest.cpp @@ -298,6 +298,21 @@ file './input.cpp' spelled tokens: no mappings. +)"}, + // Should not crash on errors inside '#define' directives. Error is that + // stringification (#B) does not refer to a macro parameter. + { + R"cpp( +a +#define MACRO() A #B +)cpp", + R"(expanded tokens: + a +file './input.cpp' + spelled tokens: + a # define MACRO ( ) A # B + mappings: + ['#'_1, ''_9) => [''_1, ''_1) )"}}; for (auto &Test : TestCases) EXPECT_EQ(collectAndDump(Test.first), Test.second) diff --git a/compiler-rt/CMakeLists.txt b/compiler-rt/CMakeLists.txt index ae4ed3857dbb..f26ae25ada30 100644 --- a/compiler-rt/CMakeLists.txt +++ b/compiler-rt/CMakeLists.txt @@ -80,7 +80,6 @@ if (COMPILER_RT_STANDALONE_BUILD) endif() # Find Python interpreter. - set(Python_ADDITIONAL_VERSIONS 2.7 2.6 2.5) include(FindPythonInterp) if(NOT PYTHONINTERP_FOUND) message(FATAL_ERROR " diff --git a/compiler-rt/lib/asan/asan_posix.cc b/compiler-rt/lib/asan/asan_posix.cc index 5c5e0359ad6c..cb2dab2ececb 100644 --- a/compiler-rt/lib/asan/asan_posix.cc +++ b/compiler-rt/lib/asan/asan_posix.cc @@ -39,8 +39,8 @@ void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { // ---------------------- TSD ---------------- {{{1 -#if SANITIZER_NETBSD || SANITIZER_FREEBSD -// Thread Static Data cannot be used in early init on NetBSD and FreeBSD. +#if SANITIZER_NETBSD && !ASAN_DYNAMIC +// Thread Static Data cannot be used in early static ASan init on NetBSD. // Reuse the Asan TSD API for compatibility with existing code // with an alternative implementation. diff --git a/compiler-rt/lib/asan/asan_rtl.cc b/compiler-rt/lib/asan/asan_rtl.cc index db8dcd0689a5..c502965c1893 100644 --- a/compiler-rt/lib/asan/asan_rtl.cc +++ b/compiler-rt/lib/asan/asan_rtl.cc @@ -402,7 +402,6 @@ static void AsanInitInternal() { asan_init_is_running = true; CacheBinaryName(); - CheckASLR(); // Initialize flags. This must be done early, because most of the // initialization steps look at flags(). @@ -450,6 +449,7 @@ static void AsanInitInternal() { SetLowLevelAllocateCallback(OnLowLevelAllocate); InitializeAsanInterceptors(); + CheckASLR(); // Enable system log ("adb logcat") on Android. // Doing this before interceptors are initialized crashes in: diff --git a/compiler-rt/lib/builtins/cpu_model.c b/compiler-rt/lib/builtins/cpu_model.c index f953aed959e5..940c5938fef5 100644 --- a/compiler-rt/lib/builtins/cpu_model.c +++ b/compiler-rt/lib/builtins/cpu_model.c @@ -543,7 +543,7 @@ static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf, setFeature(FEATURE_BMI); if (HasLeaf7 && ((EBX >> 5) & 1) && HasAVX) setFeature(FEATURE_AVX2); - if (HasLeaf7 && ((EBX >> 9) & 1)) + if (HasLeaf7 && ((EBX >> 8) & 1)) setFeature(FEATURE_BMI2); if (HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save) setFeature(FEATURE_AVX512F); diff --git a/compiler-rt/lib/interception/interception_linux.cc b/compiler-rt/lib/interception/interception_linux.cc index 4b27102a159c..d07f060b5b64 100644 --- a/compiler-rt/lib/interception/interception_linux.cc +++ b/compiler-rt/lib/interception/interception_linux.cc @@ -33,7 +33,7 @@ static int StrCmp(const char *s1, const char *s2) { } #endif -static void *GetFuncAddr(const char *name, uptr wrapper_addr) { +static void *GetFuncAddr(const char *name) { #if SANITIZER_NETBSD // FIXME: Find a better way to handle renames if (StrCmp(name, "sigaction")) @@ -47,18 +47,13 @@ static void *GetFuncAddr(const char *name, uptr wrapper_addr) { // want the address of the real definition, though, so look it up using // RTLD_DEFAULT. addr = dlsym(RTLD_DEFAULT, name); - - // In case `name' is not loaded, dlsym ends up finding the actual wrapper. - // We don't want to intercept the wrapper and have it point to itself. - if ((uptr)addr == wrapper_addr) - addr = nullptr; } return addr; } bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func, uptr wrapper) { - void *addr = GetFuncAddr(name, wrapper); + void *addr = GetFuncAddr(name); *ptr_to_real = (uptr)addr; return addr && (func == wrapper); } diff --git a/compiler-rt/lib/msan/msan.cc b/compiler-rt/lib/msan/msan.cc index c62e5cd4c518..d83e441e683b 100644 --- a/compiler-rt/lib/msan/msan.cc +++ b/compiler-rt/lib/msan/msan.cc @@ -403,7 +403,6 @@ void __msan_init() { AvoidCVE_2016_2143(); CacheBinaryName(); - CheckASLR(); InitializeFlags(); // Install tool-specific callbacks in sanitizer_common. @@ -412,6 +411,7 @@ void __msan_init() { __sanitizer_set_report_path(common_flags()->log_path); InitializeInterceptors(); + CheckASLR(); InitTlsSize(); InstallDeadlySignalHandlers(MsanOnDeadlySignal); InstallAtExitHandler(); // Needs __cxa_atexit interceptor. diff --git a/compiler-rt/lib/msan/msan_linux.cc b/compiler-rt/lib/msan/msan_linux.cc index 3b6e6cb85f33..056783088225 100644 --- a/compiler-rt/lib/msan/msan_linux.cc +++ b/compiler-rt/lib/msan/msan_linux.cc @@ -174,8 +174,8 @@ void InstallAtExitHandler() { // ---------------------- TSD ---------------- {{{1 -#if SANITIZER_NETBSD || SANITIZER_FREEBSD -// Thread Static Data cannot be used in early init on NetBSD and FreeBSD. +#if SANITIZER_NETBSD +// Thread Static Data cannot be used in early init on NetBSD. // Reuse the MSan TSD API for compatibility with existing code // with an alternative implementation. diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc b/compiler-rt/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc index f29226b3ee3a..1ec73827b8b1 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc @@ -24,7 +24,7 @@ struct ioctl_desc { const char *name; }; -const unsigned ioctl_table_max = 1200; +const unsigned ioctl_table_max = 1236; static ioctl_desc ioctl_table[ioctl_table_max]; static unsigned ioctl_table_size = 0; @@ -645,7 +645,7 @@ static void ioctl_table_fill() { _(SPKRTUNE, NONE, 0); _(SPKRGETVOL, WRITE, sizeof(unsigned int)); _(SPKRSETVOL, READ, sizeof(unsigned int)); -#if 0 /* WIP */ +#if defined(__x86_64__) /* Entries from file: dev/nvmm/nvmm_ioctl.h */ _(NVMM_IOC_CAPABILITY, WRITE, struct_nvmm_ioc_capability_sz); _(NVMM_IOC_MACHINE_CREATE, READWRITE, struct_nvmm_ioc_machine_create_sz); @@ -661,7 +661,11 @@ static void ioctl_table_fill() { _(NVMM_IOC_GPA_UNMAP, READ, struct_nvmm_ioc_gpa_unmap_sz); _(NVMM_IOC_HVA_MAP, READ, struct_nvmm_ioc_hva_map_sz); _(NVMM_IOC_HVA_UNMAP, READ, struct_nvmm_ioc_hva_unmap_sz); + _(NVMM_IOC_CTL, READ, struct_nvmm_ioc_ctl_sz); #endif + /* Entries from file: dev/spi/spi_io.h */ + _(SPI_IOCTL_CONFIGURE, READ, struct_spi_ioctl_configure_sz); + _(SPI_IOCTL_TRANSFER, READ, struct_spi_ioctl_transfer_sz); /* Entries from file: fs/autofs/autofs_ioctl.h */ _(AUTOFSREQUEST, WRITE, struct_autofs_daemon_request_sz); _(AUTOFSDONE, READ, struct_autofs_daemon_done_sz); @@ -895,6 +899,9 @@ static void ioctl_table_fill() { _(AUDIO_GETBUFINFO, WRITE, struct_audio_info_sz); _(AUDIO_SETCHAN, READ, sizeof(int)); _(AUDIO_GETCHAN, WRITE, sizeof(int)); + _(AUDIO_QUERYFORMAT, READWRITE, struct_audio_format_query_sz); + _(AUDIO_GETFORMAT, WRITE, struct_audio_info_sz); + _(AUDIO_SETFORMAT, READ, struct_audio_info_sz); _(AUDIO_MIXER_READ, READWRITE, struct_mixer_ctrl_sz); _(AUDIO_MIXER_WRITE, READWRITE, struct_mixer_ctrl_sz); _(AUDIO_MIXER_DEVINFO, READWRITE, struct_mixer_devinfo_sz); @@ -985,6 +992,7 @@ static void ioctl_table_fill() { _(DIOCMWEDGES, WRITE, sizeof(int)); _(DIOCGSECTORSIZE, WRITE, sizeof(unsigned int)); _(DIOCGMEDIASIZE, WRITE, sizeof(uptr)); + _(DIOCRMWEDGES, WRITE, sizeof(int)); /* Entries from file: sys/drvctlio.h */ _(DRVDETACHDEV, READ, struct_devdetachargs_sz); _(DRVRESCANBUS, READ, struct_devrescanargs_sz); @@ -1206,6 +1214,8 @@ static void ioctl_table_fill() { _(SIOCGETHERCAP, READWRITE, struct_eccapreq_sz); _(SIOCGIFINDEX, READWRITE, struct_ifreq_sz); _(SIOCSETHERCAP, READ, struct_eccapreq_sz); + _(SIOCSIFDESCR, READ, struct_ifreq_sz); + _(SIOCGIFDESCR, READWRITE, struct_ifreq_sz); _(SIOCGUMBINFO, READWRITE, struct_ifreq_sz); _(SIOCSUMBPARAM, READ, struct_ifreq_sz); _(SIOCGUMBPARAM, READWRITE, struct_ifreq_sz); @@ -1335,6 +1345,21 @@ static void ioctl_table_fill() { _(WDOGIOC_TICKLE, NONE, 0); _(WDOGIOC_GTICKLER, WRITE, sizeof(int)); _(WDOGIOC_GWDOGS, READWRITE, struct_wdog_conf_sz); + /* Entries from file: sys/kcov.h */ + _(KCOV_IOC_SETBUFSIZE, READ, sizeof(u64)); + _(KCOV_IOC_ENABLE, READ, sizeof(int)); + _(KCOV_IOC_DISABLE, NONE, 0); + /* Entries from file: sys/ipmi.h */ + _(IPMICTL_RECEIVE_MSG_TRUNC, READWRITE, struct_ipmi_recv_sz); + _(IPMICTL_RECEIVE_MSG, READWRITE, struct_ipmi_recv_sz); + _(IPMICTL_SEND_COMMAND, READ, struct_ipmi_req_sz); + _(IPMICTL_REGISTER_FOR_CMD, READ, struct_ipmi_cmdspec_sz); + _(IPMICTL_UNREGISTER_FOR_CMD, READ, struct_ipmi_cmdspec_sz); + _(IPMICTL_SET_GETS_EVENTS_CMD, READ, sizeof(int)); + _(IPMICTL_SET_MY_ADDRESS_CMD, READ, sizeof(unsigned int)); + _(IPMICTL_GET_MY_ADDRESS_CMD, WRITE, sizeof(unsigned int)); + _(IPMICTL_SET_MY_LUN_CMD, READ, sizeof(unsigned int)); + _(IPMICTL_GET_MY_LUN_CMD, WRITE, sizeof(unsigned int)); /* Entries from file: soundcard.h */ _(SNDCTL_DSP_RESET, NONE, 0); _(SNDCTL_DSP_SYNC, NONE, 0); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc index 88ab0979bb05..73960fee5be6 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc @@ -779,7 +779,11 @@ int internal_sysctl(const int *name, unsigned int namelen, void *oldp, #if SANITIZER_FREEBSD int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, const void *newp, uptr newlen) { - return sysctlbyname(sname, oldp, (size_t *)oldlenp, newp, (size_t)newlen); + static decltype(sysctlbyname) *real = nullptr; + if (!real) + real = (decltype(sysctlbyname) *)dlsym(RTLD_NEXT, "sysctlbyname"); + CHECK(real); + return real(sname, oldp, (size_t *)oldlenp, newp, (size_t)newlen); } #endif #endif @@ -2007,6 +2011,35 @@ void CheckASLR() { CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1); ReExec(); } +#elif SANITIZER_FREEBSD + int aslr_pie; + uptr len = sizeof(aslr_pie); +#if SANITIZER_WORDSIZE == 64 + if (UNLIKELY(internal_sysctlbyname("kern.elf64.aslr.pie_enable", + &aslr_pie, &len, NULL, 0) == -1)) { + // We're making things less 'dramatic' here since + // the OID is not necessarily guaranteed to be here + // just yet regarding FreeBSD release + return; + } + + if (aslr_pie > 0) { + Printf("This sanitizer is not compatible with enabled ASLR " + "and binaries compiled with PIE\n"); + Die(); + } +#endif + // there might be 32 bits compat for 64 bits + if (UNLIKELY(internal_sysctlbyname("kern.elf32.aslr.pie_enable", + &aslr_pie, &len, NULL, 0) == -1)) { + return; + } + + if (aslr_pie > 0) { + Printf("This sanitizer is not compatible with enabled ASLR " + "and binaries compiled with PIE\n"); + Die(); + } #else // Do nothing #endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc index b2fb5cb76463..87a55e51c9d0 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc @@ -62,6 +62,8 @@ #include #include #include +#include +#include #include #include #include @@ -123,9 +125,6 @@ #include #include #include -#if 0 -#include -#endif #include #include #include @@ -168,6 +167,7 @@ #include #include #include +#include #include #include #include @@ -221,6 +221,10 @@ #include #include #include + +#if defined(__x86_64__) +#include +#endif // clang-format on // Include these after system headers to avoid name clashes and ambiguities. @@ -686,6 +690,26 @@ unsigned struct_usb_config_desc_sz = sizeof(usb_config_desc); unsigned struct_usb_ctl_report_desc_sz = sizeof(usb_ctl_report_desc); unsigned struct_usb_ctl_report_sz = sizeof(usb_ctl_report); unsigned struct_usb_ctl_request_sz = sizeof(usb_ctl_request); +#if defined(__x86_64__) +unsigned struct_nvmm_ioc_capability_sz = sizeof(nvmm_ioc_capability); +unsigned struct_nvmm_ioc_machine_create_sz = sizeof(nvmm_ioc_machine_create); +unsigned struct_nvmm_ioc_machine_destroy_sz = sizeof(nvmm_ioc_machine_destroy); +unsigned struct_nvmm_ioc_machine_configure_sz = + sizeof(nvmm_ioc_machine_configure); +unsigned struct_nvmm_ioc_vcpu_create_sz = sizeof(nvmm_ioc_vcpu_create); +unsigned struct_nvmm_ioc_vcpu_destroy_sz = sizeof(nvmm_ioc_vcpu_destroy); +unsigned struct_nvmm_ioc_vcpu_setstate_sz = sizeof(nvmm_ioc_vcpu_destroy); +unsigned struct_nvmm_ioc_vcpu_getstate_sz = sizeof(nvmm_ioc_vcpu_getstate); +unsigned struct_nvmm_ioc_vcpu_inject_sz = sizeof(nvmm_ioc_vcpu_inject); +unsigned struct_nvmm_ioc_vcpu_run_sz = sizeof(nvmm_ioc_vcpu_run); +unsigned struct_nvmm_ioc_gpa_map_sz = sizeof(nvmm_ioc_gpa_map); +unsigned struct_nvmm_ioc_gpa_unmap_sz = sizeof(nvmm_ioc_gpa_unmap); +unsigned struct_nvmm_ioc_hva_map_sz = sizeof(nvmm_ioc_hva_map); +unsigned struct_nvmm_ioc_hva_unmap_sz = sizeof(nvmm_ioc_hva_unmap); +unsigned struct_nvmm_ioc_ctl_sz = sizeof(nvmm_ioc_ctl); +#endif +unsigned struct_spi_ioctl_configure_sz = sizeof(spi_ioctl_configure); +unsigned struct_spi_ioctl_transfer_sz = sizeof(spi_ioctl_transfer); unsigned struct_autofs_daemon_request_sz = sizeof(autofs_daemon_request); unsigned struct_autofs_daemon_done_sz = sizeof(autofs_daemon_done); unsigned struct_sctp_connectx_addrs_sz = sizeof(sctp_connectx_addrs); @@ -728,6 +752,9 @@ unsigned struct_vnd_user_sz = sizeof(vnd_user); unsigned struct_vt_stat_sz = sizeof(vt_stat); unsigned struct_wdog_conf_sz = sizeof(wdog_conf); unsigned struct_wdog_mode_sz = sizeof(wdog_mode); +unsigned struct_ipmi_recv_sz = sizeof(ipmi_recv); +unsigned struct_ipmi_req_sz = sizeof(ipmi_req); +unsigned struct_ipmi_cmdspec_sz = sizeof(ipmi_cmdspec); unsigned struct_wfq_conf_sz = sizeof(wfq_conf); unsigned struct_wfq_getqid_sz = sizeof(wfq_getqid); unsigned struct_wfq_getstats_sz = sizeof(wfq_getstats); @@ -813,6 +840,7 @@ unsigned struct_iscsi_wait_event_parameters_sz = unsigned struct_isp_stats_sz = sizeof(isp_stats_t); unsigned struct_lsenable_sz = sizeof(struct lsenable); unsigned struct_lsdisable_sz = sizeof(struct lsdisable); +unsigned struct_audio_format_query_sz = sizeof(audio_format_query); unsigned struct_mixer_ctrl_sz = sizeof(struct mixer_ctrl); unsigned struct_mixer_devinfo_sz = sizeof(struct mixer_devinfo); unsigned struct_mpu_command_rec_sz = sizeof(mpu_command_rec); @@ -1423,7 +1451,7 @@ unsigned IOCTL_SPKRTONE = SPKRTONE; unsigned IOCTL_SPKRTUNE = SPKRTUNE; unsigned IOCTL_SPKRGETVOL = SPKRGETVOL; unsigned IOCTL_SPKRSETVOL = SPKRSETVOL; -#if 0 /* interfaces are WIP */ +#if defined(__x86_64__) unsigned IOCTL_NVMM_IOC_CAPABILITY = NVMM_IOC_CAPABILITY; unsigned IOCTL_NVMM_IOC_MACHINE_CREATE = NVMM_IOC_MACHINE_CREATE; unsigned IOCTL_NVMM_IOC_MACHINE_DESTROY = NVMM_IOC_MACHINE_DESTROY; @@ -1438,7 +1466,10 @@ unsigned IOCTL_NVMM_IOC_GPA_MAP = NVMM_IOC_GPA_MAP; unsigned IOCTL_NVMM_IOC_GPA_UNMAP = NVMM_IOC_GPA_UNMAP; unsigned IOCTL_NVMM_IOC_HVA_MAP = NVMM_IOC_HVA_MAP; unsigned IOCTL_NVMM_IOC_HVA_UNMAP = NVMM_IOC_HVA_UNMAP; +unsigned IOCTL_NVMM_IOC_CTL = NVMM_IOC_CTL; #endif +unsigned IOCTL_SPI_IOCTL_CONFIGURE = SPI_IOCTL_CONFIGURE; +unsigned IOCTL_SPI_IOCTL_TRANSFER = SPI_IOCTL_TRANSFER; unsigned IOCTL_AUTOFSREQUEST = AUTOFSREQUEST; unsigned IOCTL_AUTOFSDONE = AUTOFSDONE; unsigned IOCTL_BIOCGBLEN = BIOCGBLEN; @@ -1656,6 +1687,9 @@ unsigned IOCTL_AUDIO_GETPROPS = AUDIO_GETPROPS; unsigned IOCTL_AUDIO_GETBUFINFO = AUDIO_GETBUFINFO; unsigned IOCTL_AUDIO_SETCHAN = AUDIO_SETCHAN; unsigned IOCTL_AUDIO_GETCHAN = AUDIO_GETCHAN; +unsigned IOCTL_AUDIO_QUERYFORMAT = AUDIO_QUERYFORMAT; +unsigned IOCTL_AUDIO_GETFORMAT = AUDIO_GETFORMAT; +unsigned IOCTL_AUDIO_SETFORMAT = AUDIO_SETFORMAT; unsigned IOCTL_AUDIO_MIXER_READ = AUDIO_MIXER_READ; unsigned IOCTL_AUDIO_MIXER_WRITE = AUDIO_MIXER_WRITE; unsigned IOCTL_AUDIO_MIXER_DEVINFO = AUDIO_MIXER_DEVINFO; @@ -1741,6 +1775,7 @@ unsigned IOCTL_DIOCTUR = DIOCTUR; unsigned IOCTL_DIOCMWEDGES = DIOCMWEDGES; unsigned IOCTL_DIOCGSECTORSIZE = DIOCGSECTORSIZE; unsigned IOCTL_DIOCGMEDIASIZE = DIOCGMEDIASIZE; +unsigned IOCTL_DIOCRMWEDGES = DIOCRMWEDGES; unsigned IOCTL_DRVDETACHDEV = DRVDETACHDEV; unsigned IOCTL_DRVRESCANBUS = DRVRESCANBUS; unsigned IOCTL_DRVCTLCOMMAND = DRVCTLCOMMAND; @@ -1945,6 +1980,8 @@ unsigned IOCTL_SIOCSLINKSTR = SIOCSLINKSTR; unsigned IOCTL_SIOCGETHERCAP = SIOCGETHERCAP; unsigned IOCTL_SIOCGIFINDEX = SIOCGIFINDEX; unsigned IOCTL_SIOCSETHERCAP = SIOCSETHERCAP; +unsigned IOCTL_SIOCSIFDESCR = SIOCSIFDESCR; +unsigned IOCTL_SIOCGIFDESCR = SIOCGIFDESCR; unsigned IOCTL_SIOCGUMBINFO = SIOCGUMBINFO; unsigned IOCTL_SIOCSUMBPARAM = SIOCSUMBPARAM; unsigned IOCTL_SIOCGUMBPARAM = SIOCGUMBPARAM; @@ -2069,6 +2106,19 @@ unsigned IOCTL_WDOGIOC_WHICH = WDOGIOC_WHICH; unsigned IOCTL_WDOGIOC_TICKLE = WDOGIOC_TICKLE; unsigned IOCTL_WDOGIOC_GTICKLER = WDOGIOC_GTICKLER; unsigned IOCTL_WDOGIOC_GWDOGS = WDOGIOC_GWDOGS; +unsigned IOCTL_KCOV_IOC_SETBUFSIZE = KCOV_IOC_SETBUFSIZE; +unsigned IOCTL_KCOV_IOC_ENABLE = KCOV_IOC_ENABLE; +unsigned IOCTL_KCOV_IOC_DISABLE = KCOV_IOC_DISABLE; +unsigned IOCTL_IPMICTL_RECEIVE_MSG_TRUNC = IPMICTL_RECEIVE_MSG_TRUNC; +unsigned IOCTL_IPMICTL_RECEIVE_MSG = IPMICTL_RECEIVE_MSG; +unsigned IOCTL_IPMICTL_SEND_COMMAND = IPMICTL_SEND_COMMAND; +unsigned IOCTL_IPMICTL_REGISTER_FOR_CMD = IPMICTL_REGISTER_FOR_CMD; +unsigned IOCTL_IPMICTL_UNREGISTER_FOR_CMD = IPMICTL_UNREGISTER_FOR_CMD; +unsigned IOCTL_IPMICTL_SET_GETS_EVENTS_CMD = IPMICTL_SET_GETS_EVENTS_CMD; +unsigned IOCTL_IPMICTL_SET_MY_ADDRESS_CMD = IPMICTL_SET_MY_ADDRESS_CMD; +unsigned IOCTL_IPMICTL_GET_MY_ADDRESS_CMD = IPMICTL_GET_MY_ADDRESS_CMD; +unsigned IOCTL_IPMICTL_SET_MY_LUN_CMD = IPMICTL_SET_MY_LUN_CMD; +unsigned IOCTL_IPMICTL_GET_MY_LUN_CMD = IPMICTL_GET_MY_LUN_CMD; unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET; unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC; unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h index add9852ec6c3..4fb3b8c0e06f 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h @@ -849,6 +849,25 @@ extern unsigned struct_usb_config_desc_sz; extern unsigned struct_usb_ctl_report_desc_sz; extern unsigned struct_usb_ctl_report_sz; extern unsigned struct_usb_ctl_request_sz; +#if defined(__x86_64__) +extern unsigned struct_nvmm_ioc_capability_sz; +extern unsigned struct_nvmm_ioc_machine_create_sz; +extern unsigned struct_nvmm_ioc_machine_destroy_sz; +extern unsigned struct_nvmm_ioc_machine_configure_sz; +extern unsigned struct_nvmm_ioc_vcpu_create_sz; +extern unsigned struct_nvmm_ioc_vcpu_destroy_sz; +extern unsigned struct_nvmm_ioc_vcpu_setstate_sz; +extern unsigned struct_nvmm_ioc_vcpu_getstate_sz; +extern unsigned struct_nvmm_ioc_vcpu_inject_sz; +extern unsigned struct_nvmm_ioc_vcpu_run_sz; +extern unsigned struct_nvmm_ioc_gpa_map_sz; +extern unsigned struct_nvmm_ioc_gpa_unmap_sz; +extern unsigned struct_nvmm_ioc_hva_map_sz; +extern unsigned struct_nvmm_ioc_hva_unmap_sz; +extern unsigned struct_nvmm_ioc_ctl_sz; +#endif +extern unsigned struct_spi_ioctl_configure_sz; +extern unsigned struct_spi_ioctl_transfer_sz; extern unsigned struct_autofs_daemon_request_sz; extern unsigned struct_autofs_daemon_done_sz; extern unsigned struct_sctp_connectx_addrs_sz; @@ -891,6 +910,9 @@ extern unsigned struct_vnd_user_sz; extern unsigned struct_vt_stat_sz; extern unsigned struct_wdog_conf_sz; extern unsigned struct_wdog_mode_sz; +extern unsigned struct_ipmi_recv_sz; +extern unsigned struct_ipmi_req_sz; +extern unsigned struct_ipmi_cmdspec_sz; extern unsigned struct_wfq_conf_sz; extern unsigned struct_wfq_getqid_sz; extern unsigned struct_wfq_getstats_sz; @@ -969,6 +991,7 @@ extern unsigned struct_iscsi_wait_event_parameters_sz; extern unsigned struct_isp_stats_sz; extern unsigned struct_lsenable_sz; extern unsigned struct_lsdisable_sz; +extern unsigned struct_audio_format_query_sz; extern unsigned struct_mixer_ctrl_sz; extern unsigned struct_mixer_devinfo_sz; extern unsigned struct_mpu_command_rec_sz; @@ -1575,7 +1598,7 @@ extern unsigned IOCTL_SPKRTONE; extern unsigned IOCTL_SPKRTUNE; extern unsigned IOCTL_SPKRGETVOL; extern unsigned IOCTL_SPKRSETVOL; -#if 0 /* interfaces are WIP */ +#if defined(__x86_64__) extern unsigned IOCTL_NVMM_IOC_CAPABILITY; extern unsigned IOCTL_NVMM_IOC_MACHINE_CREATE; extern unsigned IOCTL_NVMM_IOC_MACHINE_DESTROY; @@ -1590,6 +1613,7 @@ extern unsigned IOCTL_NVMM_IOC_GPA_MAP; extern unsigned IOCTL_NVMM_IOC_GPA_UNMAP; extern unsigned IOCTL_NVMM_IOC_HVA_MAP; extern unsigned IOCTL_NVMM_IOC_HVA_UNMAP; +extern unsigned IOCTL_NVMM_IOC_CTL; #endif extern unsigned IOCTL_AUTOFSREQUEST; extern unsigned IOCTL_AUTOFSDONE; @@ -1808,6 +1832,9 @@ extern unsigned IOCTL_AUDIO_GETPROPS; extern unsigned IOCTL_AUDIO_GETBUFINFO; extern unsigned IOCTL_AUDIO_SETCHAN; extern unsigned IOCTL_AUDIO_GETCHAN; +extern unsigned IOCTL_AUDIO_QUERYFORMAT; +extern unsigned IOCTL_AUDIO_GETFORMAT; +extern unsigned IOCTL_AUDIO_SETFORMAT; extern unsigned IOCTL_AUDIO_MIXER_READ; extern unsigned IOCTL_AUDIO_MIXER_WRITE; extern unsigned IOCTL_AUDIO_MIXER_DEVINFO; @@ -1893,6 +1920,7 @@ extern unsigned IOCTL_DIOCTUR; extern unsigned IOCTL_DIOCMWEDGES; extern unsigned IOCTL_DIOCGSECTORSIZE; extern unsigned IOCTL_DIOCGMEDIASIZE; +extern unsigned IOCTL_DIOCRMWEDGES; extern unsigned IOCTL_DRVDETACHDEV; extern unsigned IOCTL_DRVRESCANBUS; extern unsigned IOCTL_DRVCTLCOMMAND; @@ -1994,6 +2022,8 @@ extern unsigned IOCTL_SEQUENCER_TMR_TEMPO; extern unsigned IOCTL_SEQUENCER_TMR_SOURCE; extern unsigned IOCTL_SEQUENCER_TMR_METRONOME; extern unsigned IOCTL_SEQUENCER_TMR_SELECT; +extern unsigned IOCTL_SPI_IOCTL_CONFIGURE; +extern unsigned IOCTL_SPI_IOCTL_TRANSFER; extern unsigned IOCTL_MTIOCTOP; extern unsigned IOCTL_MTIOCGET; extern unsigned IOCTL_MTIOCIEOT; @@ -2097,6 +2127,8 @@ extern unsigned IOCTL_SIOCSLINKSTR; extern unsigned IOCTL_SIOCGETHERCAP; extern unsigned IOCTL_SIOCGIFINDEX; extern unsigned IOCTL_SIOCSETHERCAP; +extern unsigned IOCTL_SIOCSIFDESCR; +extern unsigned IOCTL_SIOCGIFDESCR; extern unsigned IOCTL_SIOCGUMBINFO; extern unsigned IOCTL_SIOCSUMBPARAM; extern unsigned IOCTL_SIOCGUMBPARAM; @@ -2221,6 +2253,19 @@ extern unsigned IOCTL_WDOGIOC_WHICH; extern unsigned IOCTL_WDOGIOC_TICKLE; extern unsigned IOCTL_WDOGIOC_GTICKLER; extern unsigned IOCTL_WDOGIOC_GWDOGS; +extern unsigned IOCTL_KCOV_IOC_SETBUFSIZE; +extern unsigned IOCTL_KCOV_IOC_ENABLE; +extern unsigned IOCTL_KCOV_IOC_DISABLE; +extern unsigned IOCTL_IPMICTL_RECEIVE_MSG_TRUNC; +extern unsigned IOCTL_IPMICTL_RECEIVE_MSG; +extern unsigned IOCTL_IPMICTL_SEND_COMMAND; +extern unsigned IOCTL_IPMICTL_REGISTER_FOR_CMD; +extern unsigned IOCTL_IPMICTL_UNREGISTER_FOR_CMD; +extern unsigned IOCTL_IPMICTL_SET_GETS_EVENTS_CMD; +extern unsigned IOCTL_IPMICTL_SET_MY_ADDRESS_CMD; +extern unsigned IOCTL_IPMICTL_GET_MY_ADDRESS_CMD; +extern unsigned IOCTL_IPMICTL_SET_MY_LUN_CMD; +extern unsigned IOCTL_IPMICTL_GET_MY_LUN_CMD; extern unsigned IOCTL_SNDCTL_DSP_RESET; extern unsigned IOCTL_SNDCTL_DSP_SYNC; extern unsigned IOCTL_SNDCTL_DSP_SPEED; diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl.cc index 8a2704ff0631..897679128ac3 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cc @@ -149,6 +149,7 @@ static void BackgroundThread(void *arg) { // We don't use ScopedIgnoreInterceptors, because we want ignores to be // enabled even when the thread function exits (e.g. during pthread thread // shutdown code). + cur_thread_init(); cur_thread()->ignore_interceptors++; const u64 kMs2Ns = 1000 * 1000; diff --git a/compiler-rt/test/asan/TestCases/Linux/dlopen-mixed-c-cxx.c b/compiler-rt/test/asan/TestCases/Linux/dlopen-mixed-c-cxx.c deleted file mode 100644 index 8bce907ef2e6..000000000000 --- a/compiler-rt/test/asan/TestCases/Linux/dlopen-mixed-c-cxx.c +++ /dev/null @@ -1,42 +0,0 @@ -// RUN: %clangxx_asan -xc++ -shared -fPIC -o %t.so - < %s -// RUN: %clang_asan %s -o %t.out -ldl -// RUN: ASAN_OPTIONS=verbosity=1 not %t.out %t.so 2>&1 | FileCheck %s -// -// CHECK: AddressSanitizer: failed to intercept '__cxa_throw' -// -// dlopen() can not be intercepted on Android -// UNSUPPORTED: android -#ifdef __cplusplus - -static void foo(void) { - int i = 0; - throw(i); -} - -extern "C" { -int bar(void); -}; -int bar(void) { - try { - foo(); - } catch (int i) { - return i; - } - return -1; -} - -#else - -#include -#include - -int main(int argc, char **argv) { - int (*bar)(void); - void *handle = dlopen(argv[1], RTLD_LAZY); - assert(handle); - bar = dlsym(handle, "bar"); - assert(bar); - return bar(); -} - -#endif diff --git a/compiler-rt/test/asan/TestCases/Posix/fread_fwrite.cc b/compiler-rt/test/asan/TestCases/Posix/fread_fwrite.cc index 640248860179..c0629260418a 100644 --- a/compiler-rt/test/asan/TestCases/Posix/fread_fwrite.cc +++ b/compiler-rt/test/asan/TestCases/Posix/fread_fwrite.cc @@ -1,9 +1,6 @@ // RUN: %clangxx_asan -g %s -o %t // RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-FWRITE // RUN: not %run %t 1 2>&1 | FileCheck %s --check-prefix=CHECK-FREAD -// -// On FreeBSD stack overflow error instead -// XFAIL: freebsd #include #include diff --git a/compiler-rt/test/asan/TestCases/Posix/tsd_dtor_leak.cc b/compiler-rt/test/asan/TestCases/Posix/tsd_dtor_leak.cc index 26109fe1a5f4..860f3459e5a8 100644 --- a/compiler-rt/test/asan/TestCases/Posix/tsd_dtor_leak.cc +++ b/compiler-rt/test/asan/TestCases/Posix/tsd_dtor_leak.cc @@ -3,8 +3,6 @@ // RUN: %clangxx_asan -O1 %s -pthread -o %t // RUN: %env_asan_opts=quarantine_size_mb=0 %run %t // XFAIL: x86_64-netbsd -// Assertion fails -// XFAIL: x86_64-freebsd #include #include #include diff --git a/compiler-rt/test/asan/Unit/lit.site.cfg.py.in b/compiler-rt/test/asan/Unit/lit.site.cfg.py.in index 1c59a6bad233..d1fd640e7385 100644 --- a/compiler-rt/test/asan/Unit/lit.site.cfg.py.in +++ b/compiler-rt/test/asan/Unit/lit.site.cfg.py.in @@ -1,6 +1,7 @@ @LIT_SITE_CFG_IN_HEADER@ import os +import platform # Load common config for all compiler-rt unit tests. lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/unittests/lit.common.unit.configured") @@ -10,6 +11,11 @@ def push_ld_library_path(config, new_path): (new_path, config.environment.get('LD_LIBRARY_PATH', ''))) config.environment['LD_LIBRARY_PATH'] = new_ld_library_path + if platform.system() == 'FreeBSD': + new_ld_32_library_path = os.path.pathsep.join( + (new_path, config.environment.get('LD_32_LIBRARY_PATH', ''))) + config.environment['LD_32_LIBRARY_PATH'] = new_ld_32_library_path + # Setup config name. config.name = 'AddressSanitizer-Unit' diff --git a/compiler-rt/test/asan/lit.cfg.py b/compiler-rt/test/asan/lit.cfg.py index e94a65304c45..0e21011340ef 100644 --- a/compiler-rt/test/asan/lit.cfg.py +++ b/compiler-rt/test/asan/lit.cfg.py @@ -36,6 +36,12 @@ def push_dynamic_library_lookup_path(config, new_path): (new_path, config.environment.get(dynamic_library_lookup_var, ''))) config.environment[dynamic_library_lookup_var] = new_ld_library_path + if platform.system() == 'FreeBSD': + dynamic_library_lookup_var = 'LD_32_LIBRARY_PATH' + new_ld_32_library_path = os.path.pathsep.join( + (new_path, config.environment.get(dynamic_library_lookup_var, ''))) + config.environment[dynamic_library_lookup_var] = new_ld_32_library_path + # Setup config name. config.name = 'AddressSanitizer' + config.name_suffix @@ -111,7 +117,7 @@ def build_invocation(compile_flags): config.substitutions.append( ("%clang_asan ", build_invocation(clang_asan_cflags)) ) config.substitutions.append( ("%clangxx_asan ", build_invocation(clang_asan_cxxflags)) ) if config.asan_dynamic: - if config.host_os in ['Linux', 'NetBSD', 'SunOS']: + if config.host_os in ['Linux', 'FreeBSD', 'NetBSD', 'SunOS']: shared_libasan_path = os.path.join(config.compiler_rt_libdir, "libclang_rt.asan{}.so".format(config.target_suffix)) elif config.host_os == 'Darwin': shared_libasan_path = os.path.join(config.compiler_rt_libdir, 'libclang_rt.asan_{}_dynamic.dylib'.format(config.apple_platform)) diff --git a/compiler-rt/test/msan/tzset.cc b/compiler-rt/test/msan/tzset.cc index 86805cd56c5d..05915e047e15 100644 --- a/compiler-rt/test/msan/tzset.cc +++ b/compiler-rt/test/msan/tzset.cc @@ -1,5 +1,4 @@ // RUN: %clangxx_msan -O0 %s -o %t && %run %t -// XFAIL: freebsd #include #include diff --git a/compiler-rt/test/tsan/ignored-interceptors-mmap.cc b/compiler-rt/test/tsan/ignored-interceptors-mmap.cc index bb43250a659d..bcfafa409914 100644 --- a/compiler-rt/test/tsan/ignored-interceptors-mmap.cc +++ b/compiler-rt/test/tsan/ignored-interceptors-mmap.cc @@ -1,7 +1,7 @@ // RUN: %clangxx_tsan -O0 %s -o %t // RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-RACE // RUN: %run %t ignore 2>&1 | FileCheck %s --check-prefix=CHECK-IGNORE -// XFAIL: freebsd,netbsd +// XFAIL: netbsd #include #include diff --git a/compiler-rt/test/xray/Unit/lit.site.cfg.py.in b/compiler-rt/test/xray/Unit/lit.site.cfg.py.in index 54fcc1cbd23c..54709ac70ce4 100644 --- a/compiler-rt/test/xray/Unit/lit.site.cfg.py.in +++ b/compiler-rt/test/xray/Unit/lit.site.cfg.py.in @@ -1,6 +1,7 @@ @LIT_SITE_CFG_IN_HEADER@ import os +import platform # Load common config for all compiler-rt unit tests. lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/unittests/lit.common.unit.configured") @@ -22,3 +23,10 @@ if 'LD_LIBRARY_PATH' in os.environ: config.environment['LD_LIBRARY_PATH'] = libdirs else: config.environment['LD_LIBRARY_PATH'] = config.llvm_lib_dir + +if platform.system() == 'FreeBSD': + if 'LD_32_LIBRARY_PATH' in os.environ: + libdirs = os.path.pathsep.join((config.llvm_lib_dir, os.environ['LD_32_LIBRARY_PATH'])) + config.environment['LD_32_LIBRARY_PATH'] = libdirs + else: + config.environment['LD_32_LIBRARY_PATH'] = config.llvm_lib_dir diff --git a/compiler-rt/utils/generate_netbsd_ioctls.awk b/compiler-rt/utils/generate_netbsd_ioctls.awk index 4ae6015f08d9..0986eccf3d71 100755 --- a/compiler-rt/utils/generate_netbsd_ioctls.awk +++ b/compiler-rt/utils/generate_netbsd_ioctls.awk @@ -482,6 +482,8 @@ function get_type(string) return "sizeof(u16)" } else if (string == "u_int32_t" || string == "uint32_t") { return "sizeof(u32)" + } else if (string == "u_int64_t" || string == "uint64_t") { + return "sizeof(u64)" } else if (string ~ /\*$/) { return "sizeof(uptr)" } else if (string == "off_t") { @@ -623,6 +625,10 @@ function get_type(string) return "struct_RF_ProgressInfo_sz" } else if (string == "nvlist_ref_t") { return "struct_nvlist_ref_sz" + } else if (string == "spi_ioctl_transfer_t") { + return "struct_spi_ioctl_transfer_sz" + } else if (string == "spi_ioctl_configure_t") { + return "struct_spi_ioctl_configure_sz" } else { print "Unrecognized entry: " string print "Aborting" diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt index 5df3f257294e..ddcd478b2139 100644 --- a/libcxx/CMakeLists.txt +++ b/libcxx/CMakeLists.txt @@ -27,7 +27,7 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR LIBCXX_STANDALONE_BUIL project(libcxx CXX C) set(PACKAGE_NAME libcxx) - set(PACKAGE_VERSION 9.0.0svn) + set(PACKAGE_VERSION 9.0.0) set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "llvm-bugs@lists.llvm.org") diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst index 29cee441839d..6bf62b7fa4ae 100644 --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -1,6 +1,6 @@ -======================================== -Libc++ 9.0.0 (In-Progress) Release Notes -======================================== +========================== +Libc++ 9.0.0 Release Notes +========================== .. contents:: :local: @@ -8,11 +8,6 @@ Libc++ 9.0.0 (In-Progress) Release Notes Written by the `Libc++ Team `_ -.. warning:: - - These are in-progress notes for the upcoming libc++ 9 release. - Release notes for previous releases can be found on - `the Download Page `_. Introduction ============ @@ -27,17 +22,39 @@ be downloaded from the `LLVM releases web site `_. For more information about libc++, please see the `Libc++ Web Site `_ or the `LLVM Web Site `_. -Note that if you are reading this file from a Subversion checkout or the -main Libc++ web page, this document applies to the *next* release, not -the current one. To see the release notes for a specific release, please -see the `releases page `_. What's New in Libc++ 9.0.0? =========================== -New Features ------------- - -API Changes ------------ -- ... +Fixes +----- + +* Minor fixes to ``std::chrono`` operators. +* libc++ now correctly handles Objective-C++ ARC qualifiers in ``std::is_pointer``. +* ``std::span`` general updates and fixes. +* Updates to the ``std::abs`` implementation. +* ``std::to_chars`` now adds leading zeros. +* Ensure ``std::tuple`` is trivially constructible. +* ``std::aligned_union`` now works in C++03. +* Output of nullptr to ``std::basic_ostream`` is formatted properly. + +Features +-------- + +* Implemented P0608: sane variant converting constructor. +* Added ``ssize`` function. +* Added ``front`` and ``back`` methods in ``std::span``. +* ``std::is_unbounded_array`` and ``std::is_bounded_array`` added to type traits. +* ``std::atomic`` now includes many new features and specialization including improved Freestanding support. +* Added ``std::midpoint`` and ``std::lerp`` math functions. +* Added the function ``std::is_constant_evaluated``. +* Erase-like algorithms now return size type. +* Added ``contains`` method to container types. +* ``std::swap`` is now a constant expression. + +Updates +------- + +* libc++ dropped support for GCC 4.9; we now support GCC 5.1 and above. +* libc++ added explicit support for WebAssembly System Interface (WASI). +* Progress towards full support of rvalues and variadics in C++03 mode. ``std::move`` and ``std::forward`` now both work in C++03 mode. diff --git a/libcxx/include/__locale b/libcxx/include/__locale index d382e4d8a94b..2b6982fc6810 100644 --- a/libcxx/include/__locale +++ b/libcxx/include/__locale @@ -409,7 +409,7 @@ public: static const mask xdigit = _ISxdigit; static const mask blank = _ISblank; #if defined(__mips__) - static const mask __regex_word = static_cast(_ISbit(15)); + static const mask __regex_word = static_cast(_ISbit(15)); #else static const mask __regex_word = 0x80; #endif diff --git a/libcxx/include/__threading_support b/libcxx/include/__threading_support index 589fe2096fd4..0d1f1e681f50 100644 --- a/libcxx/include/__threading_support +++ b/libcxx/include/__threading_support @@ -12,6 +12,7 @@ #include <__config> #include +#include #include #ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER @@ -22,16 +23,11 @@ # include <__external_threading> #elif !defined(_LIBCPP_HAS_NO_THREADS) -typedef ::timespec __libcpp_timespec_t; - #if defined(_LIBCPP_HAS_THREAD_API_PTHREAD) # include # include #endif -_LIBCPP_PUSH_MACROS -#include <__undef_macros> - #if defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \ defined(_LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL) || \ defined(_LIBCPP_HAS_THREAD_API_WIN32) @@ -46,8 +42,16 @@ _LIBCPP_PUSH_MACROS #define _LIBCPP_NO_THREAD_SAFETY_ANALYSIS #endif +typedef ::timespec __libcpp_timespec_t; +#endif // !defined(_LIBCPP_HAS_NO_THREADS) + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD +#if !defined(_LIBCPP_HAS_NO_THREADS) + #if defined(_LIBCPP_HAS_THREAD_API_PTHREAD) // Mutex typedef pthread_mutex_t __libcpp_mutex_t; @@ -75,7 +79,7 @@ typedef pthread_t __libcpp_thread_t; typedef pthread_key_t __libcpp_tls_key; #define _LIBCPP_TLS_DESTRUCTOR_CC -#else +#elif !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) // Mutex typedef void* __libcpp_mutex_t; #define _LIBCPP_MUTEX_INITIALIZER 0 @@ -108,8 +112,9 @@ typedef void* __libcpp_thread_t; typedef long __libcpp_tls_key; #define _LIBCPP_TLS_DESTRUCTOR_CC __stdcall -#endif +#endif // !defined(_LIBCPP_HAS_THREAD_API_PTHREAD) && !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) +#if !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) // Mutex _LIBCPP_THREAD_ABI_VISIBILITY int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m); @@ -204,6 +209,8 @@ void *__libcpp_tls_get(__libcpp_tls_key __key); _LIBCPP_THREAD_ABI_VISIBILITY int __libcpp_tls_set(__libcpp_tls_key __key, void *__p); +#endif // !defined(_LIBCPP_HAS_THREAD_API_EXTERNAL) + #if (!defined(_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL) || \ defined(_LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL)) && \ defined(_LIBCPP_HAS_THREAD_API_PTHREAD) @@ -394,10 +401,90 @@ int __libcpp_tls_set(__libcpp_tls_key __key, void *__p) #endif // !_LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL || _LIBCPP_BUILDING_THREAD_LIBRARY_EXTERNAL -_LIBCPP_END_NAMESPACE_STD +class _LIBCPP_TYPE_VIS thread; +class _LIBCPP_TYPE_VIS __thread_id; -_LIBCPP_POP_MACROS +namespace this_thread +{ + +_LIBCPP_INLINE_VISIBILITY __thread_id get_id() _NOEXCEPT; + +} // this_thread + +template<> struct hash<__thread_id>; + +class _LIBCPP_TEMPLATE_VIS __thread_id +{ + // FIXME: pthread_t is a pointer on Darwin but a long on Linux. + // NULL is the no-thread value on Darwin. Someone needs to check + // on other platforms. We assume 0 works everywhere for now. + __libcpp_thread_id __id_; + +public: + _LIBCPP_INLINE_VISIBILITY + __thread_id() _NOEXCEPT : __id_(0) {} + + friend _LIBCPP_INLINE_VISIBILITY + bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT + { // don't pass id==0 to underlying routines + if (__x.__id_ == 0) return __y.__id_ == 0; + if (__y.__id_ == 0) return false; + return __libcpp_thread_id_equal(__x.__id_, __y.__id_); + } + friend _LIBCPP_INLINE_VISIBILITY + bool operator!=(__thread_id __x, __thread_id __y) _NOEXCEPT + {return !(__x == __y);} + friend _LIBCPP_INLINE_VISIBILITY + bool operator< (__thread_id __x, __thread_id __y) _NOEXCEPT + { // id==0 is always less than any other thread_id + if (__x.__id_ == 0) return __y.__id_ != 0; + if (__y.__id_ == 0) return false; + return __libcpp_thread_id_less(__x.__id_, __y.__id_); + } + friend _LIBCPP_INLINE_VISIBILITY + bool operator<=(__thread_id __x, __thread_id __y) _NOEXCEPT + {return !(__y < __x);} + friend _LIBCPP_INLINE_VISIBILITY + bool operator> (__thread_id __x, __thread_id __y) _NOEXCEPT + {return __y < __x ;} + friend _LIBCPP_INLINE_VISIBILITY + bool operator>=(__thread_id __x, __thread_id __y) _NOEXCEPT + {return !(__x < __y);} + + _LIBCPP_INLINE_VISIBILITY + void __reset() { __id_ = 0; } + + template + friend + _LIBCPP_INLINE_VISIBILITY + basic_ostream<_CharT, _Traits>& + operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id); + +private: + _LIBCPP_INLINE_VISIBILITY + __thread_id(__libcpp_thread_id __id) : __id_(__id) {} + + friend __thread_id this_thread::get_id() _NOEXCEPT; + friend class _LIBCPP_TYPE_VIS thread; + friend struct _LIBCPP_TEMPLATE_VIS hash<__thread_id>; +}; + +namespace this_thread +{ + +inline _LIBCPP_INLINE_VISIBILITY +__thread_id +get_id() _NOEXCEPT +{ + return __libcpp_thread_get_current_id(); +} + +} // this_thread #endif // !_LIBCPP_HAS_NO_THREADS +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + #endif // _LIBCPP_THREADING_SUPPORT diff --git a/libcxx/include/mutex b/libcxx/include/mutex index 20c3ffc38b63..dca62202db11 100644 --- a/libcxx/include/mutex +++ b/libcxx/include/mutex @@ -280,7 +280,7 @@ class _LIBCPP_TYPE_VIS recursive_timed_mutex mutex __m_; condition_variable __cv_; size_t __count_; - __libcpp_thread_id __id_; + __thread_id __id_; public: recursive_timed_mutex(); ~recursive_timed_mutex(); @@ -307,9 +307,9 @@ bool recursive_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) { using namespace chrono; - __libcpp_thread_id __id = __libcpp_thread_get_current_id(); + __thread_id __id = this_thread::get_id(); unique_lock lk(__m_); - if (__libcpp_thread_id_equal(__id, __id_)) + if (__id == __id_) { if (__count_ == numeric_limits::max()) return false; diff --git a/libcxx/include/thread b/libcxx/include/thread index 3d8d2ac9ce50..0b914317b037 100644 --- a/libcxx/include/thread +++ b/libcxx/include/thread @@ -200,64 +200,6 @@ __thread_specific_ptr<_Tp>::set_pointer(pointer __p) __libcpp_tls_set(__key_, __p); } -class _LIBCPP_TYPE_VIS thread; -class _LIBCPP_TYPE_VIS __thread_id; - -namespace this_thread -{ - -_LIBCPP_INLINE_VISIBILITY __thread_id get_id() _NOEXCEPT; - -} // this_thread - -template<> struct hash<__thread_id>; - -class _LIBCPP_TEMPLATE_VIS __thread_id -{ - // FIXME: pthread_t is a pointer on Darwin but a long on Linux. - // NULL is the no-thread value on Darwin. Someone needs to check - // on other platforms. We assume 0 works everywhere for now. - __libcpp_thread_id __id_; - -public: - _LIBCPP_INLINE_VISIBILITY - __thread_id() _NOEXCEPT : __id_(0) {} - - friend _LIBCPP_INLINE_VISIBILITY - bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT - {return __libcpp_thread_id_equal(__x.__id_, __y.__id_);} - friend _LIBCPP_INLINE_VISIBILITY - bool operator!=(__thread_id __x, __thread_id __y) _NOEXCEPT - {return !(__x == __y);} - friend _LIBCPP_INLINE_VISIBILITY - bool operator< (__thread_id __x, __thread_id __y) _NOEXCEPT - {return __libcpp_thread_id_less(__x.__id_, __y.__id_);} - friend _LIBCPP_INLINE_VISIBILITY - bool operator<=(__thread_id __x, __thread_id __y) _NOEXCEPT - {return !(__y < __x);} - friend _LIBCPP_INLINE_VISIBILITY - bool operator> (__thread_id __x, __thread_id __y) _NOEXCEPT - {return __y < __x ;} - friend _LIBCPP_INLINE_VISIBILITY - bool operator>=(__thread_id __x, __thread_id __y) _NOEXCEPT - {return !(__x < __y);} - - template - friend - _LIBCPP_INLINE_VISIBILITY - basic_ostream<_CharT, _Traits>& - operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id) - {return __os << __id.__id_;} - -private: - _LIBCPP_INLINE_VISIBILITY - __thread_id(__libcpp_thread_id __id) : __id_(__id) {} - - friend __thread_id this_thread::get_id() _NOEXCEPT; - friend class _LIBCPP_TYPE_VIS thread; - friend struct _LIBCPP_TEMPLATE_VIS hash<__thread_id>; -}; - template<> struct _LIBCPP_TEMPLATE_VIS hash<__thread_id> : public unary_function<__thread_id, size_t> @@ -269,17 +211,11 @@ struct _LIBCPP_TEMPLATE_VIS hash<__thread_id> } }; -namespace this_thread -{ - -inline _LIBCPP_INLINE_VISIBILITY -__thread_id -get_id() _NOEXCEPT -{ - return __libcpp_thread_get_current_id(); -} - -} // this_thread +template +_LIBCPP_INLINE_VISIBILITY +basic_ostream<_CharT, _Traits>& +operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id) +{return __os << __id.__id_;} class _LIBCPP_TYPE_VIS thread { diff --git a/libcxx/src/mutex.cpp b/libcxx/src/mutex.cpp index 0d69d7cacfa1..ceb4980c9147 100644 --- a/libcxx/src/mutex.cpp +++ b/libcxx/src/mutex.cpp @@ -132,7 +132,7 @@ timed_mutex::unlock() _NOEXCEPT recursive_timed_mutex::recursive_timed_mutex() : __count_(0), - __id_(0) + __id_{} { } @@ -144,9 +144,9 @@ recursive_timed_mutex::~recursive_timed_mutex() void recursive_timed_mutex::lock() { - __libcpp_thread_id id = __libcpp_thread_get_current_id(); + __thread_id id = this_thread::get_id(); unique_lock lk(__m_); - if (__libcpp_thread_id_equal(id, __id_)) + if (id ==__id_) { if (__count_ == numeric_limits::max()) __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached"); @@ -162,9 +162,9 @@ recursive_timed_mutex::lock() bool recursive_timed_mutex::try_lock() _NOEXCEPT { - __libcpp_thread_id id = __libcpp_thread_get_current_id(); + __thread_id id = this_thread::get_id(); unique_lock lk(__m_, try_to_lock); - if (lk.owns_lock() && (__count_ == 0 || __libcpp_thread_id_equal(id, __id_))) + if (lk.owns_lock() && (__count_ == 0 || id == __id_)) { if (__count_ == numeric_limits::max()) return false; @@ -181,7 +181,7 @@ recursive_timed_mutex::unlock() _NOEXCEPT unique_lock lk(__m_); if (--__count_ == 0) { - __id_ = 0; + __id_.__reset(); lk.unlock(); __cv_.notify_one(); } diff --git a/libcxx/utils/google-benchmark/README.LLVM b/libcxx/utils/google-benchmark/README.LLVM index e51e2571bf62..6b81ddf873a8 100644 --- a/libcxx/utils/google-benchmark/README.LLVM +++ b/libcxx/utils/google-benchmark/README.LLVM @@ -4,3 +4,9 @@ LLVM notes This directory contains the Google Benchmark source code with some unnecessary files removed. Note that this directory is under a different license than libc++. + +Changes: +* https://github.com/google/benchmark/commit/4abdfbb802d1b514703223f5f852ce4a507d32d2 + is applied on top of + https://github.com/google/benchmark/commit/4528c76b718acc9b57956f63069c699ae21edcab + to add RISC-V timer support. diff --git a/libcxx/utils/google-benchmark/src/cycleclock.h b/libcxx/utils/google-benchmark/src/cycleclock.h index f5e37b011b9f..d5d62c4c7fe1 100644 --- a/libcxx/utils/google-benchmark/src/cycleclock.h +++ b/libcxx/utils/google-benchmark/src/cycleclock.h @@ -164,6 +164,21 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { uint64_t tsc; asm("stck %0" : "=Q"(tsc) : : "cc"); return tsc; +#elif defined(__riscv) // RISC-V + // Use RDCYCLE (and RDCYCLEH on riscv32) +#if __riscv_xlen == 32 + uint64_t cycles_low, cycles_hi0, cycles_hi1; + asm("rdcycleh %0" : "=r"(cycles_hi0)); + asm("rdcycle %0" : "=r"(cycles_lo)); + asm("rdcycleh %0" : "=r"(cycles_hi1)); + // This matches the PowerPC overflow detection, above + cycles_lo &= -static_cast(cycles_hi0 == cycles_hi1); + return (cycles_hi1 << 32) | cycles_lo; +#else + uint64_t cycles; + asm("rdcycle %0" : "=r"(cycles)); + return cycles; +#endif #else // The soft failover to a generic implementation is automatic only for ARM. // For other platforms the developer is expected to make an attempt to create diff --git a/libcxxabi/CMakeLists.txt b/libcxxabi/CMakeLists.txt index 8ca169065f48..ce69fff1370a 100644 --- a/libcxxabi/CMakeLists.txt +++ b/libcxxabi/CMakeLists.txt @@ -21,7 +21,7 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR LIBCXXABI_STANDALONE_B project(libcxxabi CXX C) set(PACKAGE_NAME libcxxabi) - set(PACKAGE_VERSION 9.0.0svn) + set(PACKAGE_VERSION 9.0.0) set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "llvm-bugs@lists.llvm.org") diff --git a/libunwind/CMakeLists.txt b/libunwind/CMakeLists.txt index b51922a48fe2..836b286523ef 100644 --- a/libunwind/CMakeLists.txt +++ b/libunwind/CMakeLists.txt @@ -83,7 +83,7 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR LIBUNWIND_STANDALONE_B endif() set(PACKAGE_NAME libunwind) - set(PACKAGE_VERSION 9.0.0svn) + set(PACKAGE_VERSION 9.0.0) set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "llvm-bugs@lists.llvm.org") diff --git a/lld/CMakeLists.txt b/lld/CMakeLists.txt index e2fbdbfbbb47..641f71c114ae 100644 --- a/lld/CMakeLists.txt +++ b/lld/CMakeLists.txt @@ -56,7 +56,6 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) include(HandleLLVMOptions) if(LLVM_INCLUDE_TESTS) - set(Python_ADDITIONAL_VERSIONS 2.7) include(FindPythonInterp) if(NOT PYTHONINTERP_FOUND) message(FATAL_ERROR diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h index 1b0e24042710..4b62cd05f4fc 100644 --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -189,6 +189,7 @@ struct Configuration { // Used for /thinlto-object-suffix-replace: std::pair thinLTOObjectSuffixReplace; + uint64_t align = 4096; uint64_t imageBase = -1; uint64_t fileAlign = 512; uint64_t stackReserve = 1024 * 1024; diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index d7af50b9318f..eb3aff1a8b76 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -36,6 +36,7 @@ #include "llvm/Option/Option.h" #include "llvm/Support/Debug.h" #include "llvm/Support/LEB128.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/TarWriter.h" @@ -184,8 +185,10 @@ void LinkerDriver::addBuffer(std::unique_ptr mb, if (wholeArchive) { std::unique_ptr file = CHECK(Archive::create(mbref), filename + ": failed to parse archive"); + Archive *archive = file.get(); + make>(std::move(file)); // take ownership - for (MemoryBufferRef m : getArchiveMembers(file.get())) + for (MemoryBufferRef m : getArchiveMembers(archive)) addArchiveBuffer(m, "", filename, 0); return; } @@ -268,13 +271,12 @@ void LinkerDriver::addArchiveBuffer(MemoryBufferRef mb, StringRef symName, } void LinkerDriver::enqueueArchiveMember(const Archive::Child &c, - StringRef symName, + const Archive::Symbol &sym, StringRef parentName) { - auto reportBufferError = [=](Error &&e, - StringRef childName) { + auto reportBufferError = [=](Error &&e, StringRef childName) { fatal("could not get the buffer for the member defining symbol " + - symName + ": " + parentName + "(" + childName + "): " + + toCOFFString(sym) + ": " + parentName + "(" + childName + "): " + toString(std::move(e))); }; @@ -285,7 +287,8 @@ void LinkerDriver::enqueueArchiveMember(const Archive::Child &c, reportBufferError(mbOrErr.takeError(), check(c.getFullName())); MemoryBufferRef mb = mbOrErr.get(); enqueueTask([=]() { - driver->addArchiveBuffer(mb, symName, parentName, offsetInArchive); + driver->addArchiveBuffer(mb, toCOFFString(sym), parentName, + offsetInArchive); }); return; } @@ -293,15 +296,16 @@ void LinkerDriver::enqueueArchiveMember(const Archive::Child &c, std::string childName = CHECK( c.getFullName(), "could not get the filename for the member defining symbol " + - symName); + toCOFFString(sym)); auto future = std::make_shared>( createFutureForFile(childName)); enqueueTask([=]() { auto mbOrErr = future->get(); if (mbOrErr.second) reportBufferError(errorCodeToError(mbOrErr.second), childName); - driver->addArchiveBuffer(takeBuffer(std::move(mbOrErr.first)), symName, - parentName, /* OffsetInArchive */ 0); + driver->addArchiveBuffer(takeBuffer(std::move(mbOrErr.first)), + toCOFFString(sym), parentName, + /*OffsetInArchive=*/0); }); } @@ -1051,6 +1055,12 @@ void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &args) { }); } +static const char *libcallRoutineNames[] = { +#define HANDLE_LIBCALL(code, name) name, +#include "llvm/IR/RuntimeLibcalls.def" +#undef HANDLE_LIBCALL +}; + void LinkerDriver::link(ArrayRef argsArr) { // Needed for LTO. InitializeAllTargetInfos(); @@ -1419,6 +1429,13 @@ void LinkerDriver::link(ArrayRef argsArr) { for (auto *arg : args.filtered(OPT_section)) parseSection(arg->getValue()); + // Handle /align + if (auto *arg = args.getLastArg(OPT_align)) { + parseNumbers(arg->getValue(), &config->align); + if (!isPowerOf2_64(config->align)) + error("/align: not a power of two: " + StringRef(arg->getValue())); + } + // Handle /aligncomm for (auto *arg : args.filtered(OPT_aligncomm)) parseAligncomm(arg->getValue()); @@ -1746,6 +1763,15 @@ void LinkerDriver::link(ArrayRef argsArr) { u->weakAlias = symtab->addUndefined(to); } + // If any inputs are bitcode files, the LTO code generator may create + // references to library functions that are not explicit in the bitcode + // file's symbol table. If any of those library functions are defined in a + // bitcode file in an archive member, we need to arrange to use LTO to + // compile those archive members by adding them to the link beforehand. + if (!BitcodeFile::instances.empty()) + for (const char *s : libcallRoutineNames) + symtab->addLibcall(s); + // Windows specific -- if __load_config_used can be resolved, resolve it. if (symtab->findUnderscore("_load_config_used")) addUndefined(mangle("_load_config_used")); diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h index 6100c3ca0c9e..01bfb02a5c33 100644 --- a/lld/COFF/Driver.h +++ b/lld/COFF/Driver.h @@ -72,7 +72,7 @@ class LinkerDriver { void parseDirectives(InputFile *file); // Used by ArchiveFile to enqueue members. - void enqueueArchiveMember(const Archive::Child &c, StringRef symName, + void enqueueArchiveMember(const Archive::Child &c, const Archive::Symbol &sym, StringRef parentName); MemoryBufferRef takeBuffer(std::unique_ptr mb); diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp index c00d5c5b494e..d02fedfd178b 100644 --- a/lld/COFF/InputFiles.cpp +++ b/lld/COFF/InputFiles.cpp @@ -85,16 +85,16 @@ void ArchiveFile::parse() { } // Returns a buffer pointing to a member file containing a given symbol. -void ArchiveFile::addMember(const Archive::Symbol *sym) { +void ArchiveFile::addMember(const Archive::Symbol &sym) { const Archive::Child &c = - CHECK(sym->getMember(), - "could not get the member for symbol " + sym->getName()); + CHECK(sym.getMember(), + "could not get the member for symbol " + toCOFFString(sym)); // Return an empty buffer if we have already returned the same buffer. if (!seen.insert(c.getChildOffset()).second) return; - driver->enqueueArchiveMember(c, sym->getName(), getName()); + driver->enqueueArchiveMember(c, sym, getName()); } std::vector getArchiveMembers(Archive *file) { diff --git a/lld/COFF/InputFiles.h b/lld/COFF/InputFiles.h index dfad9814a397..8d3a021a3789 100644 --- a/lld/COFF/InputFiles.h +++ b/lld/COFF/InputFiles.h @@ -96,7 +96,7 @@ class ArchiveFile : public InputFile { // Enqueues an archive member load for the given symbol. If we've already // enqueued a load for the same archive member, this function does nothing, // which ensures that we don't load the same member more than once. - void addMember(const Archive::Symbol *sym); + void addMember(const Archive::Symbol &sym); private: std::unique_ptr file; diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp index 0aff164ee567..3f3e6607479c 100644 --- a/lld/COFF/SymbolTable.cpp +++ b/lld/COFF/SymbolTable.cpp @@ -179,7 +179,7 @@ void SymbolTable::loadMinGWAutomaticImports() { log("Loading lazy " + l->getName() + " from " + l->file->getName() + " for automatic import"); l->pendingArchiveLoad = true; - l->file->addMember(&l->sym); + l->file->addMember(l->sym); } } @@ -363,13 +363,13 @@ Symbol *SymbolTable::addUndefined(StringRef name, InputFile *f, if (auto *l = dyn_cast(s)) { if (!s->pendingArchiveLoad) { s->pendingArchiveLoad = true; - l->file->addMember(&l->sym); + l->file->addMember(l->sym); } } return s; } -void SymbolTable::addLazy(ArchiveFile *f, const Archive::Symbol sym) { +void SymbolTable::addLazy(ArchiveFile *f, const Archive::Symbol &sym) { StringRef name = sym.getName(); Symbol *s; bool wasInserted; @@ -382,7 +382,7 @@ void SymbolTable::addLazy(ArchiveFile *f, const Archive::Symbol sym) { if (!u || u->weakAlias || s->pendingArchiveLoad) return; s->pendingArchiveLoad = true; - f->addMember(&sym); + f->addMember(sym); } void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile) { @@ -505,6 +505,18 @@ Symbol *SymbolTable::addImportThunk(StringRef name, DefinedImportData *id, return nullptr; } +void SymbolTable::addLibcall(StringRef name) { + Symbol *sym = findUnderscore(name); + if (!sym) + return; + + if (Lazy *l = dyn_cast(sym)) { + MemoryBufferRef mb = l->getMemberBuffer(); + if (identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode) + addUndefined(sym->getName()); + } +} + std::vector SymbolTable::getChunks() { std::vector res; for (ObjFile *file : ObjFile::instances) { diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h index 88f47cbe9e78..f0a7aaf35a0e 100644 --- a/lld/COFF/SymbolTable.h +++ b/lld/COFF/SymbolTable.h @@ -83,7 +83,7 @@ class SymbolTable { Symbol *addAbsolute(StringRef n, uint64_t va); Symbol *addUndefined(StringRef name, InputFile *f, bool isWeakAlias); - void addLazy(ArchiveFile *f, const Archive::Symbol sym); + void addLazy(ArchiveFile *f, const Archive::Symbol &sym); Symbol *addAbsolute(StringRef n, COFFSymbolRef s); Symbol *addRegular(InputFile *f, StringRef n, const llvm::object::coff_symbol_generic *s = nullptr, @@ -97,6 +97,7 @@ class SymbolTable { Symbol *addImportData(StringRef n, ImportFile *f); Symbol *addImportThunk(StringRef name, DefinedImportData *s, uint16_t machine); + void addLibcall(StringRef name); void reportDuplicate(Symbol *existing, InputFile *newFile); diff --git a/lld/COFF/Symbols.cpp b/lld/COFF/Symbols.cpp index 3583d4cb28c1..1af11820a7e6 100644 --- a/lld/COFF/Symbols.cpp +++ b/lld/COFF/Symbols.cpp @@ -20,18 +20,23 @@ using namespace llvm::object; using namespace lld::coff; +namespace lld { + static_assert(sizeof(SymbolUnion) <= 48, "symbols should be optimized for memory usage"); // Returns a symbol name for an error message. -std::string lld::toString(coff::Symbol &b) { +static std::string demangle(StringRef symName) { if (config->demangle) - if (Optional s = lld::demangleMSVC(b.getName())) + if (Optional s = demangleMSVC(symName)) return *s; - return b.getName(); + return symName; +} +std::string toString(coff::Symbol &b) { return demangle(b.getName()); } +std::string toCOFFString(const Archive::Symbol &b) { + return demangle(b.getName()); } -namespace lld { namespace coff { StringRef Symbol::getName() { @@ -113,5 +118,14 @@ Defined *Undefined::getWeakAlias() { return d; return nullptr; } + +MemoryBufferRef Lazy::getMemberBuffer() { + Archive::Child c = + CHECK(sym.getMember(), + "could not get the member for symbol " + toCOFFString(sym)); + return CHECK(c.getMemoryBufferRef(), + "could not get the buffer for the member defining symbol " + + toCOFFString(sym)); +} } // namespace coff } // namespace lld diff --git a/lld/COFF/Symbols.h b/lld/COFF/Symbols.h index 86cd4f585e50..78c357aa2a58 100644 --- a/lld/COFF/Symbols.h +++ b/lld/COFF/Symbols.h @@ -21,6 +21,14 @@ #include namespace lld { + +std::string toString(coff::Symbol &b); + +// There are two different ways to convert an Archive::Symbol to a string: +// One for Microsoft name mangling and one for Itanium name mangling. +// Call the functions toCOFFString and toELFString, not just toString. +std::string toCOFFString(const coff::Archive::Symbol &b); + namespace coff { using llvm::object::Archive; @@ -257,6 +265,8 @@ class Lazy : public Symbol { static bool classof(const Symbol *s) { return s->kind() == LazyKind; } + MemoryBufferRef getMemberBuffer(); + ArchiveFile *file; private: @@ -429,7 +439,6 @@ void replaceSymbol(Symbol *s, ArgT &&... arg) { } } // namespace coff -std::string toString(coff::Symbol &b); } // namespace lld #endif diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index 36ef87de4263..5736281958fa 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -626,6 +626,9 @@ void Writer::run() { writeMapFile(outputSections); + if (errorCount()) + return; + ScopedTimer t2(diskCommitTimer); if (auto e = buffer->commit()) fatal("failed to write the output file: " + toString(std::move(e))); @@ -762,6 +765,28 @@ void Writer::locateImportTables() { } } +// Return whether a SectionChunk's suffix (the dollar and any trailing +// suffix) should be removed and sorted into the main suffixless +// PartialSection. +static bool shouldStripSectionSuffix(SectionChunk *sc, StringRef name) { + // On MinGW, comdat groups are formed by putting the comdat group name + // after the '$' in the section name. For .eh_frame$, that must + // still be sorted before the .eh_frame trailer from crtend.o, thus just + // strip the section name trailer. For other sections, such as + // .tls$$ (where non-comdat .tls symbols are otherwise stored in + // ".tls$"), they must be strictly sorted after .tls. And for the + // hypothetical case of comdat .CRT$XCU, we definitely need to keep the + // suffix for sorting. Thus, to play it safe, only strip the suffix for + // the standard sections. + if (!config->mingw) + return false; + if (!sc || !sc->isCOMDAT()) + return false; + return name.startswith(".text$") || name.startswith(".data$") || + name.startswith(".rdata$") || name.startswith(".pdata$") || + name.startswith(".xdata$") || name.startswith(".eh_frame$"); +} + // Create output section objects and add them to OutputSections. void Writer::createSections() { // First, create the builtin sections. @@ -807,10 +832,7 @@ void Writer::createSections() { continue; } StringRef name = c->getSectionName(); - // On MinGW, comdat groups are formed by putting the comdat group name - // after the '$' in the section name. Such a section name suffix shouldn't - // imply separate alphabetical sorting of those section chunks though. - if (config->mingw && sc && sc->isCOMDAT()) + if (shouldStripSectionSuffix(sc, name)) name = name.split('$').first; PartialSection *pSec = createPartialSection(name, c->getOutputCharacteristics()); @@ -1076,6 +1098,13 @@ Optional Writer::createSymbol(Defined *def) { } } + // Symbols that are runtime pseudo relocations don't point to the actual + // symbol data itself (as they are imported), but points to the IAT entry + // instead. Avoid emitting them to the symbol table, as they can confuse + // debuggers. + if (def->isRuntimePseudoReloc) + return None; + StringRef name = def->getName(); if (name.size() > COFF::NameSize) { sym.Name.Offset.Zeroes = 0; @@ -1179,9 +1208,11 @@ void Writer::assignAddresses() { sizeOfHeaders += config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header); sizeOfHeaders = alignTo(sizeOfHeaders, config->fileAlign); - uint64_t rva = pageSize; // The first page is kept unmapped. fileSize = sizeOfHeaders; + // The first page is kept unmapped. + uint64_t rva = alignTo(sizeOfHeaders, config->align); + for (OutputSection *sec : outputSections) { if (sec == relocSec) addBaserels(); @@ -1211,10 +1242,10 @@ void Writer::assignAddresses() { sec->header.SizeOfRawData = rawSize; if (rawSize != 0) sec->header.PointerToRawData = fileSize; - rva += alignTo(virtualSize, pageSize); + rva += alignTo(virtualSize, config->align); fileSize += alignTo(rawSize, config->fileAlign); } - sizeOfImage = alignTo(rva, pageSize); + sizeOfImage = alignTo(rva, config->align); // Assign addresses to sections in MergeChunks. for (MergeChunk *mc : MergeChunk::instances) @@ -1283,7 +1314,7 @@ template void Writer::writeHeader() { pe->MinorLinkerVersion = 0; pe->ImageBase = config->imageBase; - pe->SectionAlignment = pageSize; + pe->SectionAlignment = config->align; pe->FileAlignment = config->fileAlign; pe->MajorImageVersion = config->majorImageVersion; pe->MinorImageVersion = config->minorImageVersion; diff --git a/lld/ELF/Arch/CAHP.cpp b/lld/ELF/Arch/CAHP.cpp new file mode 100644 index 000000000000..167fb44cf389 --- /dev/null +++ b/lld/ELF/Arch/CAHP.cpp @@ -0,0 +1,92 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "InputFiles.h" +#include "SyntheticSections.h" +#include "Target.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::support::endian; +using namespace llvm::ELF; +using namespace lld; +using namespace lld::elf; + +namespace { + +class CAHP final : public TargetInfo { +public: + CAHP(); + RelExpr getRelExpr(RelType type, const Symbol &s, + const uint8_t *loc) const override; + void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; +}; + +} // end anonymous namespace + +CAHP::CAHP() { noneRel = R_CAHP_NONE; } + +RelExpr CAHP::getRelExpr(const RelType type, const Symbol &s, + const uint8_t *loc) const { + switch (type) { + case R_CAHP_PCREL_11: + return R_PC; + + default: + return R_ABS; + } +} + +void CAHP::relocateOne(uint8_t *loc, const RelType type, + const uint64_t val) const { + switch (type) { + case R_CAHP_NONE: + break; + + case R_CAHP_16: + write16le(loc, val); + break; + + case R_CAHP_PCREL_11: { + checkInt(loc, static_cast(val), 11, type); + uint32_t insn = read16le(loc) & 0x001F; + insn |= (val << 5); + write16le(loc, insn); + break; + } + + case R_CAHP_HI6: { + uint64_t hi = (val + 0x200) >> 10; + + uint32_t insn = read16le(loc) & 0x0F3F; + uint16_t imm3_0 = (hi & 0xF) << 12; + uint16_t imm5_4 = ((hi >> 4) & 3) << 6; + insn |= imm3_0 | imm5_4; + write16le(loc, insn); + break; + } + + case R_CAHP_LO10: { + uint64_t hi = (val + 0x200) >> 10; + uint64_t lo = val - (hi << 10); + + uint32_t insn = read32le(loc) & 0xFF00FF3F; + uint32_t imm7_0 = (lo & 0xFF) << 16; + uint32_t imm9_8 = ((lo >> 8) & 3) << 6; + insn |= imm7_0 | imm9_8; + write32le(loc, insn); + break; + } + + default: + error(getErrorLocation(loc) + + "unimplemented relocation: " + toString(type)); + return; + } +} + +TargetInfo *elf::getCAHPTargetInfo() { + static CAHP target; + return ⌖ +} diff --git a/lld/ELF/Arch/PPC.cpp b/lld/ELF/Arch/PPC.cpp index 46c5891e4f8a..cf4ad4049926 100644 --- a/lld/ELF/Arch/PPC.cpp +++ b/lld/ELF/Arch/PPC.cpp @@ -190,6 +190,13 @@ bool PPC::inBranchRange(RelType type, uint64_t src, uint64_t dst) const { RelExpr PPC::getRelExpr(RelType type, const Symbol &s, const uint8_t *loc) const { switch (type) { + case R_PPC_NONE: + return R_NONE; + case R_PPC_ADDR16_HA: + case R_PPC_ADDR16_HI: + case R_PPC_ADDR16_LO: + case R_PPC_ADDR32: + return R_ABS; case R_PPC_DTPREL16: case R_PPC_DTPREL16_HA: case R_PPC_DTPREL16_HI: @@ -227,7 +234,9 @@ RelExpr PPC::getRelExpr(RelType type, const Symbol &s, case R_PPC_TPREL16_HI: return R_TLS; default: - return R_ABS; + error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + + ") against symbol " + toString(s)); + return R_NONE; } } @@ -319,7 +328,7 @@ void PPC::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { break; } default: - error(getErrorLocation(loc) + "unrecognized relocation " + toString(type)); + llvm_unreachable("unknown relocation"); } } diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp index 70d284cfad71..0f382dcd6b3c 100644 --- a/lld/ELF/Arch/PPC64.cpp +++ b/lld/ELF/Arch/PPC64.cpp @@ -532,6 +532,21 @@ void PPC64::relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const { RelExpr PPC64::getRelExpr(RelType type, const Symbol &s, const uint8_t *loc) const { switch (type) { + case R_PPC64_NONE: + return R_NONE; + case R_PPC64_ADDR16: + case R_PPC64_ADDR16_DS: + case R_PPC64_ADDR16_HA: + case R_PPC64_ADDR16_HI: + case R_PPC64_ADDR16_HIGHER: + case R_PPC64_ADDR16_HIGHERA: + case R_PPC64_ADDR16_HIGHEST: + case R_PPC64_ADDR16_HIGHESTA: + case R_PPC64_ADDR16_LO: + case R_PPC64_ADDR16_LO_DS: + case R_PPC64_ADDR32: + case R_PPC64_ADDR64: + return R_ABS; case R_PPC64_GOT16: case R_PPC64_GOT16_DS: case R_PPC64_GOT16_HA: @@ -554,6 +569,7 @@ RelExpr PPC64::getRelExpr(RelType type, const Symbol &s, return R_PPC64_CALL_PLT; case R_PPC64_REL16_LO: case R_PPC64_REL16_HA: + case R_PPC64_REL16_HI: case R_PPC64_REL32: case R_PPC64_REL64: return R_PC; @@ -607,7 +623,9 @@ RelExpr PPC64::getRelExpr(RelType type, const Symbol &s, case R_PPC64_TLS: return R_TLSIE_HINT; default: - return R_ABS; + error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + + ") against symbol " + toString(s)); + return R_NONE; } } @@ -870,7 +888,7 @@ void PPC64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { write64(loc, val - dynamicThreadPointerOffset); break; default: - error(getErrorLocation(loc) + "unrecognized relocation " + toString(type)); + llvm_unreachable("unknown relocation"); } } diff --git a/lld/ELF/CMakeLists.txt b/lld/ELF/CMakeLists.txt index 70578746483d..b34a2ed846ca 100644 --- a/lld/ELF/CMakeLists.txt +++ b/lld/ELF/CMakeLists.txt @@ -12,6 +12,7 @@ add_lld_library(lldELF Arch/AMDGPU.cpp Arch/ARM.cpp Arch/AVR.cpp + Arch/CAHP.cpp Arch/Hexagon.cpp Arch/Mips.cpp Arch/MipsArchTree.cpp diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index fbfc71d22b7e..9c7aa4db2662 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -135,6 +135,7 @@ static std::tuple parseEmulation(StringRef emul) { .Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS}) .Cases("elf32ltsmip", "elf32ltsmipn32", {ELF32LEKind, EM_MIPS}) .Case("elf32lriscv", {ELF32LEKind, EM_RISCV}) + .Case("elf32lcahp", {ELF32LEKind, EM_CAHP}) .Cases("elf32ppc", "elf32ppclinux", {ELF32BEKind, EM_PPC}) .Case("elf64btsmip", {ELF64BEKind, EM_MIPS}) .Case("elf64ltsmip", {ELF64LEKind, EM_MIPS}) @@ -1083,7 +1084,7 @@ static void setConfigs(opt::InputArgList &args) { // that. config->isRela = m == EM_AARCH64 || m == EM_AMDGPU || m == EM_HEXAGON || m == EM_PPC || m == EM_PPC64 || m == EM_RISCV || - m == EM_X86_64; + m == EM_X86_64 || m == EM_CAHP; // If the output uses REL relocations we must store the dynamic relocation // addends to the output sections. We also store addends for RELA relocations diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 98b88283cf09..f9cbf1569090 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1144,7 +1144,7 @@ void ArchiveFile::fetch(const Archive::Symbol &sym) { Archive::Child c = CHECK(sym.getMember(), toString(this) + ": could not get the member for symbol " + - sym.getName()); + toELFString(sym)); if (!seen.insert(c.getChildOffset()).second) return; @@ -1153,7 +1153,7 @@ void ArchiveFile::fetch(const Archive::Symbol &sym) { CHECK(c.getMemoryBufferRef(), toString(this) + ": could not get the buffer for the member defining symbol " + - sym.getName()); + toELFString(sym)); if (tar && c.getParent()->isThin()) tar->append(relativeToRoot(CHECK(c.getFullName(), this)), mb.getBuffer()); diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index 62c552e04828..22677303c322 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -42,6 +42,20 @@ Defined *ElfSym::relaIpltEnd; Defined *ElfSym::riscvGlobalPointer; Defined *ElfSym::tlsModuleBase; +// Returns a symbol for an error message. +static std::string demangle(StringRef symName) { + if (config->demangle) + if (Optional s = demangleItanium(symName)) + return *s; + return symName; +} +namespace lld { +std::string toString(const Symbol &b) { return demangle(b.getName()); } +std::string toELFString(const Archive::Symbol &b) { + return demangle(b.getName()); +} +} // namespace lld + static uint64_t getSymVA(const Symbol &sym, int64_t &addend) { switch (sym.kind()) { case Symbol::DefinedKind: { @@ -250,12 +264,13 @@ void Symbol::fetch() const { } MemoryBufferRef LazyArchive::getMemberBuffer() { - Archive::Child c = CHECK( - sym.getMember(), "could not get the member for symbol " + sym.getName()); + Archive::Child c = + CHECK(sym.getMember(), + "could not get the member for symbol " + toELFString(sym)); return CHECK(c.getMemoryBufferRef(), "could not get the buffer for the member defining symbol " + - sym.getName()); + toELFString(sym)); } uint8_t Symbol::computeBinding() const { @@ -331,14 +346,6 @@ void elf::maybeWarnUnorderableSymbol(const Symbol *sym) { report(": unable to order discarded symbol: "); } -// Returns a symbol for an error message. -std::string lld::toString(const Symbol &b) { - if (config->demangle) - if (Optional s = demangleItanium(b.getName())) - return *s; - return b.getName(); -} - static uint8_t getMinVisibility(uint8_t va, uint8_t vb) { if (va == STV_DEFAULT) return vb; diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index d640495b0e01..9c1eb387c2f4 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -33,7 +33,11 @@ class Undefined; } // namespace elf std::string toString(const elf::Symbol &); -std::string toString(const elf::InputFile *); + +// There are two different ways to convert an Archive::Symbol to a string: +// One for Microsoft name mangling and one for Itanium name mangling. +// Call the functions toCOFFString and toELFString, not just toString. +std::string toELFString(const elf::Archive::Symbol &); namespace elf { diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index f6d0f190d84d..35b9b8928c9f 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -3177,11 +3177,23 @@ static bool isDuplicateArmExidxSec(InputSection *prev, InputSection *cur) { // The .ARM.exidx table must be sorted in ascending order of the address of the // functions the table describes. Optionally duplicate adjacent table entries -// can be removed. At the end of the function the ExecutableSections must be +// can be removed. At the end of the function the executableSections must be // sorted in ascending order of address, Sentinel is set to the InputSection // with the highest address and any InputSections that have mergeable // .ARM.exidx table entries are removed from it. void ARMExidxSyntheticSection::finalizeContents() { + if (script->hasSectionsCommand) { + // The executableSections and exidxSections that we use to derive the + // final contents of this SyntheticSection are populated before the + // linker script assigns InputSections to OutputSections. The linker script + // SECTIONS command may have a /DISCARD/ entry that removes executable + // InputSections and their dependent .ARM.exidx section that we recorded + // earlier. + auto isDiscarded = [](const InputSection *isec) { return !isec->isLive(); }; + llvm::erase_if(executableSections, isDiscarded); + llvm::erase_if(exidxSections, isDiscarded); + } + // Sort the executable sections that may or may not have associated // .ARM.exidx sections by order of ascending address. This requires the // relative positions of InputSections to be known. diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index d07478a5178c..a2ea90d1fa6d 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -59,6 +59,8 @@ TargetInfo *elf::getTarget() { return getARMTargetInfo(); case EM_AVR: return getAVRTargetInfo(); + case EM_CAHP: + return getCAHPTargetInfo(); case EM_HEXAGON: return getHexagonTargetInfo(); case EM_MIPS: diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index effa6001f6d9..705214d53b42 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -141,6 +141,7 @@ TargetInfo *getAArch64TargetInfo(); TargetInfo *getAMDGPUTargetInfo(); TargetInfo *getARMTargetInfo(); TargetInfo *getAVRTargetInfo(); +TargetInfo *getCAHPTargetInfo(); TargetInfo *getHexagonTargetInfo(); TargetInfo *getMSP430TargetInfo(); TargetInfo *getPPC64TargetInfo(); diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index b8c8891648a4..10b171e8c0d7 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -2230,25 +2230,27 @@ template void Writer::fixSectionAlignments() { // same with its virtual address modulo the page size, so that the loader can // load executables without any address adjustment. static uint64_t computeFileOffset(OutputSection *os, uint64_t off) { - // File offsets are not significant for .bss sections. By convention, we keep - // section offsets monotonically increasing rather than setting to zero. - if (os->type == SHT_NOBITS) - return off; - - // If the section is not in a PT_LOAD, we just have to align it. - if (!os->ptLoad) - return alignTo(off, os->alignment); - // The first section in a PT_LOAD has to have congruent offset and address // module the page size. - OutputSection *first = os->ptLoad->firstSec; - if (os == first) { - uint64_t alignment = std::max(os->alignment, config->maxPageSize); + if (os->ptLoad && os->ptLoad->firstSec == os) { + uint64_t alignment = + std::max(os->ptLoad->p_align, config->maxPageSize); return alignTo(off, alignment, os->addr); } + // File offsets are not significant for .bss sections other than the first one + // in a PT_LOAD. By convention, we keep section offsets monotonically + // increasing rather than setting to zero. + if (os->type == SHT_NOBITS) + return off; + + // If the section is not in a PT_LOAD, we just have to align it. + if (!os->ptLoad) + return alignTo(off, os->alignment); + // If two sections share the same PT_LOAD the file offset is calculated // using this formula: Off2 = Off1 + (VA2 - VA1). + OutputSection *first = os->ptLoad->firstSec; return first->offset + os->addr - first->addr; } diff --git a/lld/MinGW/Driver.cpp b/lld/MinGW/Driver.cpp index 24e18aacb3c1..be1b757e45b5 100644 --- a/lld/MinGW/Driver.cpp +++ b/lld/MinGW/Driver.cpp @@ -303,6 +303,8 @@ bool mingw::link(ArrayRef argsArr, raw_ostream &diag) { add("-include:" + StringRef(a->getValue())); for (auto *a : args.filtered(OPT_undefined)) add("-includeoptional:" + StringRef(a->getValue())); + for (auto *a : args.filtered(OPT_delayload)) + add("-delayload:" + StringRef(a->getValue())); std::vector searchPaths; for (auto *a : args.filtered(OPT_L)) { diff --git a/lld/MinGW/Options.td b/lld/MinGW/Options.td index 44de98dfc90b..86400433d041 100644 --- a/lld/MinGW/Options.td +++ b/lld/MinGW/Options.td @@ -80,6 +80,8 @@ def require_defined_eq: J<"require-defined=">, Alias; def _HASH_HASH_HASH : Flag<["-"], "###">, HelpText<"Print (but do not run) the commands to run for this compilation">; def appcontainer: F<"appcontainer">, HelpText<"Set the appcontainer flag in the executable">; +def delayload: S<"delayload">, HelpText<"DLL to load only on demand">; +def delayload_eq: J<"delayload=">, Alias; def mllvm: S<"mllvm">; def pdb: S<"pdb">, HelpText<"Output PDB debug info file, chosen implicitly if the argument is empty">; def pdb_eq: J<"pdb=">, Alias; diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst index 76207fec11ac..df00e31bf971 100644 --- a/lld/docs/ReleaseNotes.rst +++ b/lld/docs/ReleaseNotes.rst @@ -5,18 +5,15 @@ lld 9.0.0 Release Notes .. contents:: :local: -.. warning:: - These are in-progress notes for the upcoming LLVM 9.0.0 release. - Release notes for previous releases can be found on - `the Download Page `_. - Introduction ============ -This document contains the release notes for the lld linker, release 9.0.0. -Here we describe the status of lld, including major improvements -from the previous release. All lld releases may be downloaded -from the `LLVM releases web site `_. +lld is a high-performance linker that supports ELF (Unix), COFF +(Windows), Mach-O (macOS), MinGW and WebAssembly. lld is +command-line-compatible with GNU linkers and Microsoft link.exe and is +significantly faster than the system default linkers. + +lld 9 has lots of feature improvements and bug fixes. Non-comprehensive list of changes in this release ================================================= @@ -27,33 +24,187 @@ ELF Improvements * ld.lld now has typo suggestions for flags: ``$ ld.lld --call-shared`` now prints ``unknown argument '--call-shared', did you mean '--call_shared'``. + (`r361518 `_) + +* ``--allow-shlib-undefined`` and ``--no-allow-shlib-undefined`` + options are added. ``--no-allow-shlib-undefined`` is the default for + executables. + (`r352826 `_) + +* ``-nmagic`` and ``-omagic`` options are fully supported. + (`r360593 `_) + +* Segment layout has changed. PT_GNU_RELRO, which was previously + placed in the middle of readable/writable PT_LOAD segments, is now + placed at the beginning of them. This change permits lld-produced + ELF files to be read correctly by GNU strip older than 2.31, which + has a bug to discard a PT_GNU_RELRO in the former layout. + +* ``-z common-page-size`` is supported. + (`r360593 `_) + +* Diagnostics messages have improved. A new flag ``--vs-diagnostics`` + alters the format of diagnostic output to enable source hyperlinks + in Microsoft Visual Studio IDE. + +* Linker script compatibility with GNU BFD linker has generally improved. + +* The clang ``--dependent-library`` form of autolinking is supported. + + This feature is added to implement the Windows-style autolinking for + Unix. On Unix, in order to use a library, you usually have to + include a header file provided by the library and then explicitly + link the library with the linker ``-l`` option. On Windows, header + files usually contain pragmas that list needed libraries. Compilers + copy that information to object files, so that linkers can + automatically link needed libraries. ``--dependent-library`` is + added for implementing that Windows semantics on Unix. + (`r360984 `_) + +* AArch64 BTI and PAC are supported. + (`r362793 `_) + +* lld now supports replacing ``JAL`` with ``JALX`` instructions in case + of MIPS-microMIPS cross-mode jumps. + (`r354311 `_) + +* lld now creates LA25 thunks for MIPS R6 code. + (`r354312 `_) + +* Put MIPS-specific .reginfo, .MIPS.options, and .MIPS.abiflags sections + into corresponding PT_MIPS_REGINFO, PT_MIPS_OPTIONS, and PT_MIPS_ABIFLAGS + segments. + +* The quality of RISC-V and PowerPC ports have greatly improved. Many + applications can now be linked by lld. PowerPC64 is now almost + production ready. + +* The Linux kernel for arm32_7, arm64, ppc64le and x86_64 can now be + linked by lld. + +* x86-64 TLSDESC is supported. + (`r361911 `_, + `r362078 `_) + +* DF_STATIC_TLS flag is set for i386 and x86-64 when needed. + (`r353293 `_, + `r353378 `_) + +* The experimental partitioning feature is added to allow a program to + be split into multiple pieces. + + The feature allows you to semi-automatically split a single program + into multiple ELF files called "partitions". Since all partitions + share the same memory address space and don't use PLT/GOT, split + programs run as fast as regular programs. + + With the mechanism, you can start a program only with a "main" + partition and load remaining partitions on-demand. For example, you + can split a web browser into a main partition and a PDF reader + sub-partition and load the PDF reader partition only when a user + tries to open a PDF file. + + See `the documentation `_ for more information. + +* If "-" is given as an output filename, lld writes the final result + to the standard output. Previously, it created a file "-" in the + current directory. + (`r351852 `_) + +* ``-z ifunc-noplt`` option is added to reduce IFunc function call + overhead in a freestanding environment such as the OS kernel. + + Functions resolved by the IFunc mechanism are usually dispatched via + PLT and thus slower than regular functions because of the cost of + indirection. With ``-z ifunc-noplt``, you can eliminate it by doing + text relocations at load-time. You need a special loader to utilize + this feature. This feature is added for the FreeBSD kernel but can + be used by any operating systems. + (`r360685 `_) + +* ``--undefined-glob`` option is added. The new option is an extension + to ``--undefined`` to take a glob pattern instead of a single symbol + name. + (`r363396 `_) -* ... COFF Improvements ----------------- * Like the ELF driver, lld-link now has typo suggestions for flags. + (`r361518 `_) + +* lld-link now correctly reports duplicate symbol errors for object + files that were compiled with ``/Gy``. + (`r352590 `_) -* lld-link now correctly reports duplicate symbol errors for obj files - that were compiled with /Gy. +* lld-link now correctly reports duplicate symbol errors when several + resource (.res) input files define resources with the same type, + name and language. This can be demoted to a warning using + ``/force:multipleres``. + (`r359829 `_) -* lld-link now correctly reports duplicate symbol errors when several res - input files define resources with the same type, name, and language. - This can be demoted to a warning using ``/force:multipleres``. +* lld-link now rejects more than one resource object input files, + matching link.exe. Previously, lld-link would silently ignore all + but one. If you hit this: Don't pass resource object files to the + linker, instead pass res files to the linker directly. Don't put + resource files in static libraries, pass them on the command line. + (`r359749 `_) * Having more than two ``/natvis:`` now works correctly; it used to not work for larger binaries before. + (`r327895 `_) * Undefined symbols are now printed only in demangled form. Pass ``/demangle:no`` to see raw symbol names instead. - -* The following flags have been added: ``/functionpadmin``, ``/swaprun:``, - ``/threads:no`` + (`r355878 `_) * Several speed and memory usage improvements. -* ... +* lld-link now supports resource object files created by GNU windres and + MS cvtres, not only llvm-cvtres. + +* The generated thunks for delayimports now share the majority of code + among thunks, significantly reducing the overhead of using delayimport. + (`r365823 `_) + +* ``IMAGE_REL_ARM{,64}_REL32`` relocations are supported. + (`r352325 `_) + +* Range extension thunks for AArch64 are now supported, so lld can + create large executables for Windows/ARM64. + (`r352929 `_) + +* The following flags have been added: + ``/functionpadmin`` (`r354716 `_), + ``/swaprun:`` (`r359192 `_), + ``/threads:no`` (`r355029 `_), + ``/filealign`` (`r361634 `_) + +WebAssembly Improvements +------------------------ + +* Imports from custom module names are supported. + (`r352828 `_) + +* Symbols that are in llvm.used are now exported by default. + (`r353364 `_) + +* Initial support for PIC and dynamic linking has landed. + (`r357022 `_) + +* wasm-ld now add ``__start_``/``__stop_`` symbols for data sections. + (`r361236 `_) + +* wasm-ld now doesn't report an error on archives without a symbol index. + (`r364338 `_) + +* The following flags have been added: + ``--emit-relocs`` (`r361635 `_), + ``--wrap`` (`r361639 `_), + ``--trace`` and ``--trace-symbol`` + (`r353264 `_). + MinGW Improvements ------------------ @@ -62,12 +213,19 @@ MinGW Improvements terminators for the sections such as .eh_frame properly, fixing DWARF exception handling with libgcc and gcc's crtend.o. -MachO Improvements ------------------- +* lld now also handles DWARF unwind info generated by GCC, when linking + with libgcc. -* Item 1. +* PDB output can be requested without manually specifying the PDB file + name, with the new option ``-pdb=`` with an empty value to the option. + (The old existing syntax ``-pdb `` was more cumbersome to use + with an empty parameter value.) -WebAssembly Improvements ------------------------- +* ``--no-insert-timestamp`` option is added as an alias to ``/timestamp:0``. + (`r353145 `_) + +* Many more GNU ld options are now supported, which e.g. allows the lld + MinGW frontend to be called by GCC. -* ... +* The following options are added: ``--exclude-all-symbols``, + ``--appcontainer``, ``--undefined`` diff --git a/lld/test/COFF/Inputs/libcall-archive.ll b/lld/test/COFF/Inputs/libcall-archive.ll new file mode 100644 index 000000000000..3f8a24df4c37 --- /dev/null +++ b/lld/test/COFF/Inputs/libcall-archive.ll @@ -0,0 +1,6 @@ +target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" +target triple = "i686-unknown-windows" + +define void @memcpy() { + ret void +} diff --git a/lld/test/COFF/Inputs/libcall-archive.s b/lld/test/COFF/Inputs/libcall-archive.s new file mode 100644 index 000000000000..487cf2009f85 --- /dev/null +++ b/lld/test/COFF/Inputs/libcall-archive.s @@ -0,0 +1,2 @@ +.globl ___sync_val_compare_and_swap_8 +___sync_val_compare_and_swap_8: diff --git a/lld/test/COFF/Inputs/mangled-symbol.s b/lld/test/COFF/Inputs/mangled-symbol.s new file mode 100644 index 000000000000..d393236768ed --- /dev/null +++ b/lld/test/COFF/Inputs/mangled-symbol.s @@ -0,0 +1,9 @@ + .text + + .def "?f@@YAHXZ" + .scl 2 + .type 32 + .endef + .global "?f@@YAHXZ" +"?f@@YAHXZ": + retq $0 diff --git a/lld/test/COFF/Inputs/tlssup.s b/lld/test/COFF/Inputs/tlssup.s new file mode 100644 index 000000000000..ca61c9dda3e9 --- /dev/null +++ b/lld/test/COFF/Inputs/tlssup.s @@ -0,0 +1,10 @@ + .section .tls,"dw" + .byte 0xaa + + .section .tls$ZZZ,"dw" + .byte 0xff + + .globl _tls_index + .data +_tls_index: + .int 0 diff --git a/lld/test/COFF/align.s b/lld/test/COFF/align.s new file mode 100644 index 000000000000..67ca349e0030 --- /dev/null +++ b/lld/test/COFF/align.s @@ -0,0 +1,45 @@ +# RUN: yaml2obj < %s > %t.obj +# RUN: lld-link /out:%t.exe /entry:main /align:32 %t.obj +# RUN: llvm-readobj --file-headers %t.exe | FileCheck %s + +# CHECK: SectionAlignment: 32 + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4096 + SectionData: 0000000000000000 + Relocations: + - VirtualAddress: 0 + SymbolName: __ImageBase + Type: IMAGE_REL_AMD64_ADDR64 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 1 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: main + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: __ImageBase + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/lld/test/COFF/autoimport-gnu-implib.s b/lld/test/COFF/autoimport-gnu-implib.s index e6e0ed207c0b..d7d4ed626e83 100644 --- a/lld/test/COFF/autoimport-gnu-implib.s +++ b/lld/test/COFF/autoimport-gnu-implib.s @@ -7,9 +7,10 @@ # RUN: llvm-ar rcs %t-implib.a %t-dabcdh.o %t-dabcds00000.o %t-dabcdt.o # RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj -# RUN: lld-link -lldmingw -out:%t.exe -entry:main %t.obj %t-implib.a -verbose +# RUN: lld-link -lldmingw -debug:symtab -out:%t.exe -entry:main %t.obj %t-implib.a -verbose # RUN: llvm-readobj --coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s +# RUN: llvm-nm %t.exe | FileCheck -check-prefix=SYMBOLS %s # IMPORTS: Import { # IMPORTS-NEXT: Name: foo.dll @@ -18,6 +19,10 @@ # IMPORTS-NEXT: Symbol: data (0) # IMPORTS-NEXT: } +# Check that the automatically imported symbol "data" is not listed in +# the symbol table. +# SYMBOLS-NOT: {{ }}data + .global main .text main: diff --git a/lld/test/COFF/autoimport-x86.s b/lld/test/COFF/autoimport-x86.s index 400cec71173e..9e0ae1ead189 100644 --- a/lld/test/COFF/autoimport-x86.s +++ b/lld/test/COFF/autoimport-x86.s @@ -5,11 +5,12 @@ # RUN: lld-link -out:%t-lib.dll -dll -entry:DllMainCRTStartup %t-lib.obj -lldmingw -implib:%t-lib.lib # RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj -# RUN: lld-link -lldmingw -out:%t.exe -entry:main %t.obj %t-lib.lib -verbose +# RUN: lld-link -lldmingw -debug:symtab -out:%t.exe -entry:main %t.obj %t-lib.lib -verbose # RUN: llvm-readobj --coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s # RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=DISASM %s # RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=CONTENTS %s +# RUN: llvm-nm %t.exe | FileCheck -check-prefix=SYMBOLS %s # IMPORTS: Import { # IMPORTS-NEXT: Name: autoimport-x86.s.tmp-lib.dll @@ -20,7 +21,7 @@ # DISASM: Disassembly of section .text: # DISASM-EMPTY: -# DISASM: .text: +# DISASM: main: # Relative offset at 0x1002 pointing at the IAT at 0x2080. # DISASM: 140001000: 8b 05 7a 10 00 00 movl 4218(%rip), %eax # DISASM: 140001006: c3 retq @@ -41,6 +42,10 @@ # CONTENTS: 140003000 80200040 01000000 00200040 01000000 # CONTENTS: 140003010 24200040 01000000 +# Check that the automatically imported symbol "variable" is not listed in +# the symbol table. +# SYMBOLS-NOT: variable + .global main .text main: diff --git a/lld/test/COFF/libcall-archive.ll b/lld/test/COFF/libcall-archive.ll new file mode 100644 index 000000000000..631503d0dd9a --- /dev/null +++ b/lld/test/COFF/libcall-archive.ll @@ -0,0 +1,22 @@ +; REQUIRES: x86 +; RUN: rm -f %t.a +; RUN: llvm-as -o %t.obj %s +; RUN: llvm-as -o %t2.obj %S/Inputs/libcall-archive.ll +; RUN: llvm-mc -filetype=obj -triple=i686-unknown-windows -o %t3.obj %S/Inputs/libcall-archive.s +; RUN: llvm-ar rcs %t.a %t2.obj %t3.obj +; RUN: lld-link -out:%t.exe -subsystem:console -entry:start -safeseh:no -lldmap:- %t.obj %t.a | FileCheck %s + +; CHECK-NOT: ___sync_val_compare_and_swap_8 +; CHECK: _start +; CHECK: _memcpy + +target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" +target triple = "i686-unknown-windows" + +define void @start(i8* %a, i8* %b) { +entry: + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a, i8* %b, i64 1024, i1 false) + ret void +} + +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture, i64, i1) diff --git a/lld/test/COFF/multiple-resource-objs.test b/lld/test/COFF/multiple-resource-objs.test index 4263c64be4d4..be5f9a280657 100644 --- a/lld/test/COFF/multiple-resource-objs.test +++ b/lld/test/COFF/multiple-resource-objs.test @@ -1,7 +1,9 @@ # RUN: llvm-cvtres /out:%t_resource.obj %S/Inputs/resource.res # RUN: llvm-cvtres /out:%t_id.obj %S/Inputs/id.res +# RUN: rm -f %t.exe # RUN: not lld-link /out:%t.exe /dll /noentry %t_id.obj %t_resource.obj 2>&1 | \ # RUN: FileCheck --check-prefix=TWOOBJ %s +# RUN: not test -f %t.exe TWOOBJ: error: {{.*}}_resource.obj: more than one resource obj file not allowed, already got {{.*}}_id.obj diff --git a/lld/test/COFF/thin-archive.s b/lld/test/COFF/thin-archive.s new file mode 100644 index 000000000000..6eb896c57da6 --- /dev/null +++ b/lld/test/COFF/thin-archive.s @@ -0,0 +1,36 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-windows-msvc -o %t.main.obj %s + +# RUN: llvm-mc -filetype=obj -triple=x86_64-windows-msvc -o %t.lib.obj \ +# RUN: %S/Inputs/mangled-symbol.s +# RUN: lld-link /lib /out:%t.lib %t.lib.obj +# RUN: lld-link /lib /llvmlibthin /out:%t_thin.lib %t.lib.obj + +# RUN: lld-link /entry:main %t.main.obj %t.lib /out:%t.exe 2>&1 | \ +# RUN: FileCheck --allow-empty %s +# RUN: lld-link /entry:main %t.main.obj %t_thin.lib /out:%t.exe 2>&1 | \ +# RUN: FileCheck --allow-empty %s + +# RUN: rm %t.lib.obj +# RUN: lld-link /entry:main %t.main.obj %t.lib /out:%t.exe 2>&1 | \ +# RUN: FileCheck --allow-empty %s +# RUN: not lld-link /entry:main %t.main.obj %t_thin.lib /out:%t.exe 2>&1 | \ +# RUN: FileCheck --check-prefix=NOOBJ %s +# RUN: not lld-link /entry:main %t.main.obj %t_thin.lib /out:%t.exe \ +# RUN: /demangle:no 2>&1 | FileCheck --check-prefix=NOOBJNODEMANGLE %s + +# CHECK-NOT: error: could not get the buffer for the member defining +# NOOBJ: error: could not get the buffer for the member defining symbol int __cdecl f(void): {{.*}}.lib({{.*}}.lib.obj): +# NOOBJNODEMANGLE: error: could not get the buffer for the member defining symbol ?f@@YAHXZ: {{.*}}.lib({{.*}}.lib.obj): + + .text + + .def main + .scl 2 + .type 32 + .endef + .global main +main: + call "?f@@YAHXZ" + retq $0 diff --git a/lld/test/COFF/tls_suffix_sorting.s b/lld/test/COFF/tls_suffix_sorting.s new file mode 100644 index 000000000000..d426ac1fe1cd --- /dev/null +++ b/lld/test/COFF/tls_suffix_sorting.s @@ -0,0 +1,27 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -triple=x86_64-windows-gnu %S/Inputs/tlssup.s -filetype=obj -o %t.tlssup.o +# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.main.o + +# RUN: lld-link -lldmingw -entry:main %t.main.o %t.tlssup.o -out:%t.exe +# RUN: llvm-objdump -s %t.exe | FileCheck %s + +# Check that .tls$$foo is sorted after the start marker (aa) and before the +# end marker (ff). + +# CHECK: Contents of section .tls: +# CHECK: 140004000 aabbff + + .text + .globl main +main: + movl _tls_index(%rip), %eax + movq %gs:88, %rcx + movq (%rcx,%rax,8), %rax + movb foo@SECREL32(%rax), %al + ret + + .section .tls$$foo,"dw" + .linkonce discard +foo: + .byte 0xbb diff --git a/lld/test/ELF/archive-thin-missing-member.s b/lld/test/ELF/archive-thin-missing-member.s index d96fbc45415b..4db1376cfaf2 100644 --- a/lld/test/ELF/archive-thin-missing-member.s +++ b/lld/test/ELF/archive-thin-missing-member.s @@ -8,17 +8,19 @@ # RUN: rm %t.o # Test error when loading symbols from missing thin archive member. -# RUN: not ld.lld %t-no-syms.a -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR1 +# RUN: not ld.lld --entry=_Z1fi %t-no-syms.a -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR1 # ERR1: {{.*}}-no-syms.a: could not get the buffer for a child of the archive: '{{.*}}.o': {{[Nn]}}o such file or directory # Test error when thin archive has symbol table but member is missing. -# RUN: not ld.lld -m elf_amd64_fbsd %t-syms.a -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR2 -# ERR2: {{.*}}-syms.a: could not get the buffer for the member defining symbol _start: '{{.*}}.o': {{[Nn]}}o such file or directory +# RUN: not ld.lld --entry=_Z1fi -m elf_amd64_fbsd %t-syms.a -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR2 +# ERR2: {{.*}}-syms.a: could not get the buffer for the member defining symbol f(int): '{{.*}}.o': {{[Nn]}}o such file or directory +# RUN: not ld.lld --entry=_Z1fi --no-demangle -m elf_amd64_fbsd %t-syms.a -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR2MANGLE +# ERR2MANGLE: {{.*}}-syms.a: could not get the buffer for the member defining symbol _Z1fi: '{{.*}}.o': {{[Nn]}}o such file or directory # Test error when thin archive is linked using --whole-archive but member is missing. -# RUN: not ld.lld --whole-archive %t-syms.a -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR3 +# RUN: not ld.lld --entry=_Z1fi --whole-archive %t-syms.a -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR3 # ERR3: {{.*}}-syms.a: could not get the buffer for a child of the archive: '{{.*}}.o': {{[Nn]}}o such file or directory -.global _start -_start: +.global _Z1fi +_Z1fi: nop diff --git a/lld/test/ELF/arm-exidx-partial-discard.s b/lld/test/ELF/arm-exidx-partial-discard.s new file mode 100644 index 000000000000..770a811c1b83 --- /dev/null +++ b/lld/test/ELF/arm-exidx-partial-discard.s @@ -0,0 +1,37 @@ +// REQUIRES: arm +// RUN: llvm-mc -filetype=obj -triple arm-gnu-linux-eabi -mcpu cortex-a7 -arm-add-build-attributes %s -o %t.o +// RUN: echo "SECTIONS { . = 0x10000; .text : { *(.text) } /DISCARD/ : { *(.exit.text) } }" > %t.script +// RUN: ld.lld -T %t.script %t.o -o %t.elf +// RUN: llvm-readobj -x .ARM.exidx --sections %t.elf | FileCheck %s + +// CHECK-NOT: .exit.text +/// Expect 2 entries both CANTUNWIND as the .ARM.exidx.exit.text +// should have been removed. +// CHECK: Hex dump of section '.ARM.exidx': +// CHECK-NEXT: 0x00010000 10000000 01000000 10000000 01000000 + +/// The /DISCARD/ is evaluated after sections have been assigned to the +/// .ARM.exidx synthetic section. We must account for the /DISCARD/ + .section .exit.text, "ax", %progbits + .globl foo + .type foo, %function +foo: + .fnstart + bx lr + .save {r7, lr} + .setfp r7, sp, #0 + .fnend + + .text + .globl _start + .type _start, %function +_start: + .fnstart + bx lr + .cantunwind + .fnend + + .section .text.__aeabi_unwind_cpp_pr0, "ax", %progbits + .global __aeabi_unwind_cpp_pr0 +__aeabi_unwind_cpp_pr0: + bx lr diff --git a/lld/test/ELF/basic-ppc64.s b/lld/test/ELF/basic-ppc64.s index cab130212b0b..d1e47464a9de 100644 --- a/lld/test/ELF/basic-ppc64.s +++ b/lld/test/ELF/basic-ppc64.s @@ -35,7 +35,7 @@ // CHECK-NEXT: Version: 1 // CHECK-NEXT: Entry: 0x10000 // CHECK-NEXT: ProgramHeaderOffset: 0x40 -// CHECK-NEXT: SectionHeaderOffset: 0x200F8 +// CHECK-NEXT: SectionHeaderOffset: 0x30098 // CHECK-NEXT: Flags [ (0x2) // CHECK-NEXT: 0x2 // CHECK-NEXT: ] @@ -178,7 +178,7 @@ // CHECK-NEXT: SHF_WRITE (0x1) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x30000 -// CHECK-NEXT: Offset: 0x20060 +// CHECK-NEXT: Offset: 0x30000 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 @@ -194,7 +194,7 @@ // CHECK-NEXT: SHF_STRINGS (0x20) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 -// CHECK-NEXT: Offset: 0x20060 +// CHECK-NEXT: Offset: 0x30000 // CHECK-NEXT: Size: 8 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 @@ -211,7 +211,7 @@ // CHECK-NEXT: Flags [ (0x0) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 -// CHECK-NEXT: Offset: 0x20068 +// CHECK-NEXT: Offset: 0x30008 // CHECK-NEXT: Size: 48 // CHECK-NEXT: Link: 10 // CHECK-NEXT: Info: 2 @@ -233,7 +233,7 @@ // CHECK-NEXT: Flags [ (0x0) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 -// CHECK-NEXT: Offset: 0x20098 +// CHECK-NEXT: Offset: 0x30038 // CHECK-NEXT: Size: 84 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 @@ -255,7 +255,7 @@ // CHECK-NEXT: Flags [ (0x0) // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 -// CHECK-NEXT: Offset: 0x200EC +// CHECK-NEXT: Offset: 0x3008C // CHECK-NEXT: Size: 10 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 diff --git a/lld/test/ELF/cahp-hi6-lo10.s b/lld/test/ELF/cahp-hi6-lo10.s new file mode 100644 index 000000000000..1611c16f8132 --- /dev/null +++ b/lld/test/ELF/cahp-hi6-lo10.s @@ -0,0 +1,32 @@ +# REQUIRES: cahp + +# RUN: llvm-mc -filetype=obj -triple=cahp %s -o %t.o + +# RUN: ld.lld %t.o --defsym foo=0 --defsym bar=42 -o %t +# RUN: llvm-objdump -d %t | FileCheck %s +# CHECK: 04 08 lui a0, 0 +# CHECK-NEXT: 03 88 00 addi a0, a0, 0 +# CHECK-NEXT: 1d 88 00 sw a0, 0(a0) +# CHECK-NEXT: 04 09 lui a1, 0 +# CHECK-NEXT: 03 99 2a addi a1, a1, 42 +# CHECK-NEXT: 1d 99 2a sw a1, 42(a1) + +# RUN: ld.lld %t.o --defsym foo=0x7fff --defsym bar=0x7dff -o %t.limits +# RUN: llvm-objdump -d %t.limits | FileCheck --check-prefix=LIMITS %s +# LIMITS: 84 08 lui a0, -32 +# LIMITS-NEXT: c3 88 ff addi a0, a0, -1 +# LIMITS-NEXT: dd 88 ff sw a0, -1(a0) +# LIMITS-NEXT: 44 f9 lui a1, 31 +# LIMITS-NEXT: 43 99 ff addi a1, a1, 511 +# LIMITS-NEXT: 5d 99 ff sw a1, 511(a1) + +.global _start + +_start: + lui a0, %hi(foo) + addi a0, a0, %lo(foo) + sw a0, %lo(foo)(a0) + lui a1, %hi(bar) + addi a1, a1, %lo(bar) + sw a1, %lo(bar)(a1) + diff --git a/lld/test/ELF/linkerscript/nobits-offset.s b/lld/test/ELF/linkerscript/nobits-offset.s index c4141487630b..051f3f99da3b 100644 --- a/lld/test/ELF/linkerscript/nobits-offset.s +++ b/lld/test/ELF/linkerscript/nobits-offset.s @@ -2,17 +2,24 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: echo "SECTIONS { \ # RUN: .sec1 (NOLOAD) : { . += 1; } \ -# RUN: .text : { *(.text) } \ +# RUN: .bss : { *(.bss) } \ # RUN: };" > %t.script # RUN: ld.lld %t.o -T %t.script -o %t -# RUN: llvm-readelf --sections %t | FileCheck %s +# RUN: llvm-readelf -S -l %t | FileCheck %s -# We used to misalign section offsets if the first section in a -# PT_LOAD was SHT_NOBITS. +## If a SHT_NOBITS section is the only section of a PT_LOAD segment, +## p_offset will be set to the sh_offset field of the section. Check we align +## sh_offset to sh_addr modulo max-page-size, so that p_vaddr=p_offset (mod +## p_align). -# CHECK: [ 2] .text PROGBITS 0000000000000010 001010 000010 00 AX 0 0 16 +# CHECK: Name Type Address Off Size ES Flg Lk Inf Al +# CHECK: .bss NOBITS 0000000000000400 001400 000001 00 WA 0 0 1024 -.global _start -_start: - nop -.p2align 4 +# CHECK: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +# CHECK: LOAD 0x001400 0x0000000000000400 0x0000000000000400 0x000000 0x000001 RW 0x1000 + +# CHECK: 00 .bss + +.bss +.p2align 10 +.byte 0 diff --git a/lld/test/ELF/nmagic.s b/lld/test/ELF/nmagic.s new file mode 100644 index 000000000000..f2feacb1bab5 --- /dev/null +++ b/lld/test/ELF/nmagic.s @@ -0,0 +1,23 @@ +# REQUIRES: x86 +# Verify that .rodata is aligned to a 8 byte boundary. + +# RUN: llvm-mc -filetype=obj -triple=i386 %s -o %t.o +# RUN: ld.lld %t.o -o %t.exe -n -Ttext 0 +# RUN: llvm-readelf --section-headers %t.exe | FileCheck %s + +# CHECK: [ 0] NULL 00000000 000000 000000 00 0 0 0 +# CHECK: [ 1] .text PROGBITS 00000000 0000d4 000001 00 AX 0 0 4 +# CHECK: [ 2] .rodata PROGBITS 00000008 0000d8 000008 00 A 0 0 8 +# CHECK: [ 3] .comment PROGBITS 00000000 0000e0 000008 01 MS 0 0 1 +# CHECK: [ 4] .symtab SYMTAB 00000000 0000e8 000020 10 6 1 4 +# CHECK: [ 5] .shstrtab STRTAB 00000000 000108 000032 00 0 0 1 +# CHECK: [ 6] .strtab STRTAB 00000000 00013a 000008 00 0 0 1 + +.globl _start +.text +_start: + ret + +.rodata +.align 8 +.quad 42 diff --git a/lld/test/ELF/nobits-offset.s b/lld/test/ELF/nobits-offset.s new file mode 100644 index 000000000000..c01047329046 --- /dev/null +++ b/lld/test/ELF/nobits-offset.s @@ -0,0 +1,21 @@ +# REQUIRES: aarch64 +# RUN: llvm-mc -filetype=obj -triple=aarch64 %s -o %t.o +# RUN: ld.lld %t.o -o %t +# RUN: llvm-readelf -S -l %t | FileCheck %s + +## If a SHT_NOBITS section is the only section of a PT_LOAD segment, +## p_offset will be set to the sh_offset field of the section. Check we align +## sh_offset to sh_addr modulo max-page-size, so that p_vaddr=p_offset (mod +## p_align). + +# CHECK: Name Type Address Off Size ES Flg Lk Inf Al +# CHECK: .bss NOBITS 0000000000210000 010000 000001 00 WA 0 0 4096 + +# CHECK: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +# CHECK: LOAD 0x010000 0x0000000000210000 0x0000000000210000 0x000000 0x000001 RW 0x10000 + +# CHECK: 02 .bss + +.bss +.p2align 12 +.byte 0 diff --git a/lld/test/ELF/ppc64-dynamic-relocations.s b/lld/test/ELF/ppc64-dynamic-relocations.s deleted file mode 100644 index 71a26137a779..000000000000 --- a/lld/test/ELF/ppc64-dynamic-relocations.s +++ /dev/null @@ -1,50 +0,0 @@ -// REQUIRES: ppc - -// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o -// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o -// RUN: ld.lld -shared %t2.o -o %t2.so -// RUN: ld.lld %t.o %t2.so -o %t -// RUN: llvm-readobj --dyn-relocations %t | FileCheck %s -// RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=DIS %s -// RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s - -// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o -// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o -// RUN: ld.lld -shared %t2.o -o %t2.so -// RUN: ld.lld %t.o %t2.so -o %t -// RUN: llvm-readobj --dyn-relocations %t | FileCheck %s -// RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=DIS %s -// RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s - - -// The dynamic relocation for foo should point to 16 bytes past the start of -// the .plt section. -// CHECK: Dynamic Relocations { -// CHECK-NEXT: 0x10030010 R_PPC64_JMP_SLOT foo 0x0 - -// There should be 2 reserved doublewords before the first entry. The dynamic -// linker will fill those in with the address of the resolver entry point and -// the dynamic object identifier. -// DIS: Idx Name Size VMA Type -// DIS: .plt 00000018 0000000010030000 BSS - -// DT_PLTGOT should point to the start of the .plt section. -// DT: 0x0000000000000003 (PLTGOT) 0x10030000 - - .text - .abiversion 2 - .globl _start - .p2align 4 - .type _start,@function -_start: -.Lfunc_begin0: -.Lfunc_gep0: - addis 2, 12, .TOC.-.Lfunc_gep0@ha - addi 2, 2, .TOC.-.Lfunc_gep0@l -.Lfunc_lep0: - .localentry _start, .Lfunc_lep0-.Lfunc_gep0 - bl foo - nop - li 0, 1 - sc - .size _start, .-.Lfunc_begin0 diff --git a/lld/test/ELF/ppc64-reloc-rel.s b/lld/test/ELF/ppc64-reloc-rel.s new file mode 100644 index 000000000000..3e3c5c94ef89 --- /dev/null +++ b/lld/test/ELF/ppc64-reloc-rel.s @@ -0,0 +1,58 @@ +# REQUIRES: ppc + +# RUN: llvm-mc -filetype=obj -triple=powerpc64le %s -o %t.o +# RUN: ld.lld %t.o --defsym=foo=rel16+0x8000 -o %t +# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s +# RUN: llvm-readobj -r %t.o | FileCheck --check-prefix=REL %s +# RUN: llvm-readelf -S %t | FileCheck --check-prefix=SEC %s +# RUN: llvm-readelf -x .eh_frame %t | FileCheck --check-prefix=HEX %s + +.section .R_PPC64_REL14,"ax",@progbits +# FIXME This does not produce a relocation + beq 1f +1: +# CHECK-LABEL: Disassembly of section .R_PPC64_REL14: +# CHECK: bt 2, .+4 + +.section .R_PPC64_REL16,"ax",@progbits +.globl rel16 +rel16: + li 3, foo-rel16-1@ha # R_PPC64_REL16_HA + li 3, foo-rel16@ha + li 4, foo-rel16+0x7fff@h # R_PPC64_REL16_HI + li 4, foo-rel16+0x8000@h + li 5, foo-rel16-1@l # R_PPC64_REL16_LO + li 5, foo-rel16@l +# CHECK-LABEL: Disassembly of section .R_PPC64_REL16: +# CHECK: li 3, 0 +# CHECK-NEXT: li 3, 1 +# CHECK-NEXT: li 4, 0 +# CHECK-NEXT: li 4, 1 +# CHECK-NEXT: li 5, 32767 +# CHECK-NEXT: li 5, -32768 + +.section .R_PPC64_REL24,"ax",@progbits + b rel16 +# CHECK-LABEL: Disassembly of section .R_PPC64_REL24: +# CHECK: b .+67108840 + +.section .REL32_AND_REL64,"ax",@progbits + .cfi_startproc + .cfi_personality 148, rel64 + nop + .cfi_endproc +rel64: + li 3, 0 +# REL: .rela.eh_frame { +# REL-NEXT: 0x12 R_PPC64_REL64 .REL32_AND_REL64 0x4 +# REL-NEXT: 0x28 R_PPC64_REL32 .REL32_AND_REL64 0x0 +# REL-NEXT: } + +# SEC: .REL32_AND_REL64 PROGBITS 0000000010010020 + +## CIE Personality Address: 0x10010020-(0x10000168+2)+4 = 0xfeba +## FDE PC Begin: 0x10010020-(0x10000178+8) = 0xfea0 +# HEX: section '.eh_frame': +# HEX-NEXT: 0x10000158 +# HEX-NEXT: 0x10000168 {{....}}bafe 00000000 +# HEX-NEXT: 0x10000178 {{[0-9a-f]+}} {{[0-9a-f]+}} a0fe0000 diff --git a/lld/test/ELF/ppc64-relocs.s b/lld/test/ELF/ppc64-relocs.s index 5e8c529e9614..8e69e08df68b 100644 --- a/lld/test/ELF/ppc64-relocs.s +++ b/lld/test/ELF/ppc64-relocs.s @@ -18,16 +18,9 @@ _start: li 3,42 sc -.section .rodata,"a",@progbits - .p2align 2 -.LJTI0_0: - .long .LBB0_2-.LJTI0_0 - -.section .toc,"aw",@progbits +.section .toc,"aw",@progbits .L1: -.quad 22, 37, 89, 47 -.LC0: - .tc .LJTI0_0[TC],.LJTI0_0 + .quad 22, 37, 89, 47 .section .R_PPC64_TOC16_LO_DS,"ax",@progbits ld 1, .L1@toc@l(2) @@ -53,91 +46,47 @@ _start: # CHECK-LABEL: Disassembly of section .R_PPC64_TOC16_HA: # CHECK: 10010018: addis 1, 2, 0 -.section .R_PPC64_REL24,"ax",@progbits - b 1f -1: - -# CHECK-LABEL: Disassembly of section .R_PPC64_REL24: -# CHECK: 1001001c: b .+4 - -.section .R_PPC64_REL14,"ax",@progbits - beq 1f -1: - -# CHECK-LABEL: Disassembly of section .R_PPC64_REL14: -# CHECK: 10010020: bt 2, .+4 - .section .R_PPC64_ADDR16_LO,"ax",@progbits li 1, .Lfoo@l # CHECK-LABEL: Disassembly of section .R_PPC64_ADDR16_LO: -# CHECK: 10010024: li 1, 0 +# CHECK: li 1, 0 .section .R_PPC64_ADDR16_HI,"ax",@progbits li 1, .Lfoo@h # CHECK-LABEL: Disassembly of section .R_PPC64_ADDR16_HI: -# CHECK: 10010028: li 1, 4097 +# CHECK: li 1, 4097 .section .R_PPC64_ADDR16_HA,"ax",@progbits li 1, .Lfoo@ha # CHECK-LABEL: Disassembly of section .R_PPC64_ADDR16_HA: -# CHECK: 1001002c: li 1, 4097 +# CHECK: li 1, 4097 .section .R_PPC64_ADDR16_HIGHER,"ax",@progbits li 1, .Lfoo@higher # CHECK-LABEL: Disassembly of section .R_PPC64_ADDR16_HIGHER: -# CHECK: 10010030: li 1, 0 +# CHECK: li 1, 0 .section .R_PPC64_ADDR16_HIGHERA,"ax",@progbits li 1, .Lfoo@highera # CHECK-LABEL: Disassembly of section .R_PPC64_ADDR16_HIGHERA: -# CHECK: 10010034: li 1, 0 +# CHECK: li 1, 0 .section .R_PPC64_ADDR16_HIGHEST,"ax",@progbits li 1, .Lfoo@highest # CHECK-LABEL: Disassembly of section .R_PPC64_ADDR16_HIGHEST: -# CHECK: 10010038: li 1, 0 +# CHECK: li 1, 0 .section .R_PPC64_ADDR16_HIGHESTA,"ax",@progbits li 1, .Lfoo@highesta # CHECK-LABEL: Disassembly of section .R_PPC64_ADDR16_HIGHESTA: -# CHECK: 1001003c: li 1, 0 - -.section .R_PPC64_REL32, "ax",@progbits - addis 5, 2, .LC0@toc@ha - ld 5, .LC0@toc@l(5) -.LBB0_2: - add 3, 3, 4 - -# DATALE: '.rodata': -# DATALE: 0x100001c8 80fe0000 - -# DATABE: '.rodata': -# DATABE: 0x100001c8 0000fe80 - -# Address of rodata + value stored at rodata entry -# should equal address of LBB0_2. -# 0x10000190 + 0xfeb4 = 0x10010044 -# CHECK-LABEL: Disassembly of section .R_PPC64_REL32: -# CHECK: 10010040: addis 5, 2, 0 -# CHECK: 10010044: ld 5, -32736(5) -# CHECK: 10010048: add 3, 3, 4 - -.section .R_PPC64_REL64, "ax",@progbits - .cfi_startproc - .cfi_personality 148, __foo - li 0, 1 - li 3, 55 - sc - .cfi_endproc -__foo: - li 3,0 +# CHECK: li 1, 0 .section .R_PPC64_TOC,"a",@progbits .quad .TOC.@tocbase @@ -150,15 +99,3 @@ __foo: # DATABE-LABEL: section '.R_PPC64_TOC': # DATABE: 00000000 10028000 - -# Check that the personality (relocated by R_PPC64_REL64) in the .eh_frame -# equals the address of __foo. -# 0x100001ea + 0xfe6e = 0x10010058 -# DATALE: section '.eh_frame': -# DATALE: 0x100001e8 {{....}}6efe - -# DATABE: section '.eh_frame': -# DATABE: 0x100001e8 {{[0-9a-f]+ [0-9a-f]+}} fe6e{{....}} - -# CHECK: __foo -# CHECK-NEXT: 10010058: li 3, 0 diff --git a/lld/test/ELF/relocation-copy-align-common.s b/lld/test/ELF/relocation-copy-align-common.s index 124064c71d14..748f84546b71 100644 --- a/lld/test/ELF/relocation-copy-align-common.s +++ b/lld/test/ELF/relocation-copy-align-common.s @@ -15,7 +15,7 @@ # CHECK-NEXT: SHF_WRITE # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x203000 -# CHECK-NEXT: Offset: 0x20B0 +# CHECK-NEXT: Offset: 0x3000 # CHECK-NEXT: Size: 16 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 diff --git a/lld/test/MinGW/driver.test b/lld/test/MinGW/driver.test index cdd802e93f4d..b8bc2ddea8a3 100644 --- a/lld/test/MinGW/driver.test +++ b/lld/test/MinGW/driver.test @@ -200,3 +200,7 @@ APPCONTAINER: -appcontainer # RUN: ld.lld -m i386pep --help 2>&1 | FileCheck -check-prefix=HELP %s # HELP: USAGE: # HELP: --enable-auto-import + +RUN: ld.lld -### -m i386pep foo.o -delayload user32.dll --delayload shell32.dll | FileCheck -check-prefix DELAYLOAD %s +RUN: ld.lld -### -m i386pep foo.o -delayload=user32.dll --delayload=shell32.dll | FileCheck -check-prefix DELAYLOAD %s +DELAYLOAD: -delayload:user32.dll -delayload:shell32.dll diff --git a/lld/test/lit.cfg.py b/lld/test/lit.cfg.py index 267f8c517858..52898a458e33 100644 --- a/lld/test/lit.cfg.py +++ b/lld/test/lit.cfg.py @@ -70,6 +70,7 @@ 'AMDGPU': 'amdgpu', 'ARM': 'arm', 'AVR': 'avr', + 'CAHP': 'cahp', 'Hexagon': 'hexagon', 'Mips': 'mips', 'MSP430': 'msp430', diff --git a/lld/test/wasm/data-layout.ll b/lld/test/wasm/data-layout.ll index 20fe30445cb7..6c060f460019 100644 --- a/lld/test/wasm/data-layout.ll +++ b/lld/test/wasm/data-layout.ll @@ -76,7 +76,7 @@ target triple = "wasm32-unknown-unknown" ; RUN: wasm-ld -no-gc-sections --allow-undefined --no-entry --shared-memory \ ; RUN: --initial-memory=131072 --max-memory=131072 -o %t_max.wasm %t.o \ -; RUN: %t.hello.o +; RUN: --active-segments %t.hello.o ; RUN: obj2yaml %t_max.wasm | FileCheck %s -check-prefix=CHECK-SHARED ; CHECK-SHARED: - Type: MEMORY diff --git a/lld/test/wasm/data-segments.ll b/lld/test/wasm/data-segments.ll index 944895a0d39c..32fb6812d3b9 100644 --- a/lld/test/wasm/data-segments.ll +++ b/lld/test/wasm/data-segments.ll @@ -2,9 +2,8 @@ ; RUN: llc -filetype=obj %s -o %t.bulk-mem.o -mattr=+bulk-memory ; RUN: llc -filetype=obj %s -o %t.atomics.bulk-mem.o -mattr=+atomics,+bulk-memory -; atomics => active segments (TODO: error) -; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 %t.atomics.o -o %t.atomics.wasm -; RUN: obj2yaml %t.atomics.wasm | FileCheck %s --check-prefixes ACTIVE,ACTIVE-TLS +; atomics => error +; RUN: not wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 %t.atomics.o -o %t.atomics.wasm 2>&1 | FileCheck %s --check-prefix ERROR ; atomics, active segments => active segments ; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 --active-segments %t.atomics.o -o %t.atomics.active.wasm @@ -25,15 +24,15 @@ ; RUN: wasm-ld -no-gc-sections --no-entry --passive-segments %t.bulk-mem.o -o %t.bulk-mem.passive.wasm ; RUN: obj2yaml %t.bulk-mem.passive.wasm | FileCheck %s --check-prefix PASSIVE -; atomics, bulk memory => active segments (TODO: passive) +; atomics, bulk memory => passive segments ; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 %t.atomics.bulk-mem.o -o %t.atomics.bulk-mem.wasm -; RUN: obj2yaml %t.atomics.bulk-mem.wasm | FileCheck %s --check-prefixes ACTIVE,ACTIVE-TLS +; RUN: obj2yaml %t.atomics.bulk-mem.wasm | FileCheck %s --check-prefixes PASSIVE,PASSIVE-TLS -; atomics, bulk memory, active segments => active segments +; atomics, bulk memory, active segments => active segments ; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 --active-segments %t.atomics.bulk-mem.o -o %t.atomics.bulk-mem.active.wasm ; RUN: obj2yaml %t.atomics.bulk-mem.active.wasm | FileCheck %s --check-prefixes ACTIVE,ACTIVE-TLS -; atomics, bulk memory, passive segments => passive segments +; atomics, bulk memory, passive segments => passive segments ; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 --passive-segments %t.atomics.bulk-mem.o -o %t.atomics.bulk-mem.passive.wasm ; RUN: obj2yaml %t.atomics.bulk-mem.passive.wasm | FileCheck %s --check-prefixes PASSIVE,PASSIVE-TLS diff --git a/lld/test/wasm/import-memory.test b/lld/test/wasm/import-memory.test index 0a64afd6ce20..e9dd972bc496 100644 --- a/lld/test/wasm/import-memory.test +++ b/lld/test/wasm/import-memory.test @@ -32,8 +32,8 @@ # CHECK-MAX-NEXT: Maximum: 0x00000005 # CHECK-MAX-NEXT: - Type: -# RUN: wasm-ld --import-memory --shared-memory --initial-memory=262144 \ -# RUN: --max-memory=327680 -o %t.max.wasm %t.start.o +# RUN: wasm-ld --import-memory --shared-memory --active-segments \ +# RUN: --initial-memory=262144 --max-memory=327680 -o %t.max.wasm %t.start.o # RUN: obj2yaml %t.max.wasm | FileCheck -check-prefix=CHECK-SHARED %s # Verify the --shared-memory flag works with imports diff --git a/lld/test/wasm/relocatable.ll b/lld/test/wasm/relocatable.ll index 67f8ac0d8bec..097adca48456 100644 --- a/lld/test/wasm/relocatable.ll +++ b/lld/test/wasm/relocatable.ll @@ -1,7 +1,12 @@ ; RUN: llc -filetype=obj %p/Inputs/hello.ll -o %t.hello.o ; RUN: llc -filetype=obj %s -o %t.o ; RUN: wasm-ld -r -o %t.wasm %t.hello.o %t.o -; RUN: obj2yaml %t.wasm | FileCheck %s +; RUN: obj2yaml %t.wasm | FileCheck %s --check-prefixes CHECK,NORMAL + +; RUN: llc -filetype=obj %p/Inputs/hello.ll -o %t.hello.bm.o -mattr=+bulk-memory +; RUN: llc -filetype=obj %s -o %t.bm.o -mattr=+bulk-memory +; RUN: wasm-ld -r -o %t.mt.wasm %t.hello.bm.o %t.bm.o --shared-memory --max-memory=131072 +; RUN: obj2yaml %t.mt.wasm | FileCheck %s --check-prefixes CHECK,SHARED target triple = "wasm32-unknown-unknown" @@ -70,13 +75,18 @@ entry: ; CHECK-NEXT: Maximum: 0x00000004 ; CHECK-NEXT: - Type: MEMORY ; CHECK-NEXT: Memories: -; CHECK-NEXT: - Initial: 0x00000001 +; NORMAL-NEXT: - Initial: 0x00000001 +; SHARED-NEXT: - Flags: [ HAS_MAX, IS_SHARED ] +; SHARED-NEXT: Initial: 0x00000001 +; SHARED-NEXT: Maximum: 0x00000002 ; CHECK-NEXT: - Type: ELEM ; CHECK-NEXT: Segments: ; CHECK-NEXT: - Offset: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 1 ; CHECK-NEXT: Functions: [ 4, 1, 2 ] +; SHARED-NEXT: - Type: DATACOUNT +; SHARED-NEXT: Count: 6 ; CHECK-NEXT: - Type: CODE ; CHECK-NEXT: Relocations: ; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_SLEB @@ -104,176 +114,176 @@ entry: ; CHECK-NEXT: - Index: 5 ; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 419C808080000B -; CHECK-NEXT: - Type: DATA -; CHECK-NEXT: Relocations: -; CHECK-NEXT: - Type: R_WASM_TABLE_INDEX_I32 -; CHECK-NEXT: Index: 3 -; CHECK-NEXT: Offset: 0x00000012 -; CHECK-NEXT: - Type: R_WASM_TABLE_INDEX_I32 -; CHECK-NEXT: Index: 4 -; CHECK-NEXT: Offset: 0x0000001B -; CHECK-NEXT: - Type: R_WASM_TABLE_INDEX_I32 -; CHECK-NEXT: Index: 5 -; CHECK-NEXT: Offset: 0x00000024 -; CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_I32 -; CHECK-NEXT: Index: 12 -; CHECK-NEXT: Offset: 0x0000002D -; CHECK-NEXT: Segments: -; CHECK-NEXT: - SectionOffset: 6 -; CHECK-NEXT: InitFlags: 0 -; CHECK-NEXT: Offset: -; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 0 -; CHECK-NEXT: Content: 68656C6C6F0A00 -; CHECK-NEXT: - SectionOffset: 18 -; CHECK-NEXT: InitFlags: 0 -; CHECK-NEXT: Offset: -; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 8 -; CHECK-NEXT: Content: '01000000' -; CHECK-NEXT: - SectionOffset: 27 -; CHECK-NEXT: InitFlags: 0 -; CHECK-NEXT: Offset: -; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 12 -; CHECK-NEXT: Content: '02000000' -; CHECK-NEXT: - SectionOffset: 36 -; CHECK-NEXT: InitFlags: 0 -; CHECK-NEXT: Offset: -; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 16 -; CHECK-NEXT: Content: '03000000' -; CHECK-NEXT: - SectionOffset: 45 -; CHECK-NEXT: InitFlags: 0 -; CHECK-NEXT: Offset: -; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 24 -; CHECK-NEXT: Content: '00000000' -; CHECK-NEXT: - SectionOffset: 54 -; CHECK-NEXT: InitFlags: 0 -; CHECK-NEXT: Offset: -; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 28 -; CHECK-NEXT: Content: '616263' -; CHECK-NEXT: - Type: CUSTOM -; CHECK-NEXT: Name: linking -; CHECK-NEXT: Version: 2 -; CHECK-NEXT: SymbolTable: -; CHECK-NEXT: - Index: 0 -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Name: hello -; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ] -; CHECK-NEXT: Function: 3 -; CHECK-NEXT: - Index: 1 -; CHECK-NEXT: Kind: DATA -; CHECK-NEXT: Name: hello_str -; CHECK-NEXT: Flags: [ ] -; CHECK-NEXT: Segment: 0 -; CHECK-NEXT: Size: 7 -; CHECK-NEXT: - Index: 2 -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Name: puts -; CHECK-NEXT: Flags: [ UNDEFINED ] -; CHECK-NEXT: Function: 0 -; CHECK-NEXT: - Index: 3 -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Name: my_func -; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ] -; CHECK-NEXT: Function: 4 -; CHECK-NEXT: - Index: 4 -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Name: foo_import -; CHECK-NEXT: Flags: [ UNDEFINED ] -; CHECK-NEXT: Function: 1 -; CHECK-NEXT: - Index: 5 -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Name: bar_import -; CHECK-NEXT: Flags: [ BINDING_WEAK, UNDEFINED ] -; CHECK-NEXT: Function: 2 -; CHECK-NEXT: - Index: 6 -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Name: func_comdat -; CHECK-NEXT: Flags: [ BINDING_WEAK ] -; CHECK-NEXT: Function: 5 -; CHECK-NEXT: - Index: 7 -; CHECK-NEXT: Kind: DATA -; CHECK-NEXT: Name: data_comdat -; CHECK-NEXT: Flags: [ BINDING_WEAK ] -; CHECK-NEXT: Segment: 5 -; CHECK-NEXT: Size: 3 -; CHECK-NEXT: - Index: 8 -; CHECK-NEXT: Kind: DATA -; CHECK-NEXT: Name: func_addr1 -; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ] -; CHECK-NEXT: Segment: 1 -; CHECK-NEXT: Size: 4 -; CHECK-NEXT: - Index: 9 -; CHECK-NEXT: Kind: DATA -; CHECK-NEXT: Name: func_addr2 -; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ] -; CHECK-NEXT: Segment: 2 -; CHECK-NEXT: Size: 4 -; CHECK-NEXT: - Index: 10 -; CHECK-NEXT: Kind: DATA -; CHECK-NEXT: Name: func_addr3 -; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ] -; CHECK-NEXT: Segment: 3 -; CHECK-NEXT: Size: 4 -; CHECK-NEXT: - Index: 11 -; CHECK-NEXT: Kind: DATA -; CHECK-NEXT: Name: data_addr1 -; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ] -; CHECK-NEXT: Segment: 4 -; CHECK-NEXT: Size: 4 -; CHECK-NEXT: - Index: 12 -; CHECK-NEXT: Kind: DATA -; CHECK-NEXT: Name: data_import -; CHECK-NEXT: Flags: [ UNDEFINED ] -; CHECK-NEXT: SegmentInfo: -; CHECK-NEXT: - Index: 0 -; CHECK-NEXT: Name: .rodata.hello_str -; CHECK-NEXT: Alignment: 0 -; CHECK-NEXT: Flags: [ ] -; CHECK-NEXT: - Index: 1 -; CHECK-NEXT: Name: .data.func_addr1 -; CHECK-NEXT: Alignment: 2 -; CHECK-NEXT: Flags: [ ] -; CHECK-NEXT: - Index: 2 -; CHECK-NEXT: Name: .data.func_addr2 -; CHECK-NEXT: Alignment: 2 -; CHECK-NEXT: Flags: [ ] -; CHECK-NEXT: - Index: 3 -; CHECK-NEXT: Name: .data.func_addr3 -; CHECK-NEXT: Alignment: 2 -; CHECK-NEXT: Flags: [ ] -; CHECK-NEXT: - Index: 4 -; CHECK-NEXT: Name: .data.data_addr1 -; CHECK-NEXT: Alignment: 3 -; CHECK-NEXT: Flags: [ ] -; CHECK-NEXT: - Index: 5 -; CHECK-NEXT: Name: .rodata.data_comdat -; CHECK-NEXT: Alignment: 0 -; CHECK-NEXT: Flags: [ ] -; CHECK-NEXT: Comdats: -; CHECK-NEXT: - Name: func_comdat -; CHECK-NEXT: Entries: -; CHECK-NEXT: - Kind: FUNCTION -; CHECK-NEXT: Index: 5 -; CHECK-NEXT: - Kind: DATA -; CHECK-NEXT: Index: 5 -; CHECK-NEXT: - Type: CUSTOM -; CHECK-NEXT: Name: name -; CHECK-NEXT: FunctionNames: -; CHECK-NEXT: - Index: 0 -; CHECK-NEXT: Name: puts -; CHECK-NEXT: - Index: 1 -; CHECK-NEXT: Name: foo_import -; CHECK-NEXT: - Index: 2 -; CHECK-NEXT: Name: bar_import -; CHECK-NEXT: - Index: 3 -; CHECK-NEXT: Name: hello -; CHECK-NEXT: - Index: 4 -; CHECK-NEXT: Name: my_func -; CHECK-NEXT: - Index: 5 -; CHECK-NEXT: Name: func_comdat -; CHECK-NEXT: ... +; NORMAL-NEXT: - Type: DATA +; NORMAL-NEXT: Relocations: +; NORMAL-NEXT: - Type: R_WASM_TABLE_INDEX_I32 +; NORMAL-NEXT: Index: 3 +; NORMAL-NEXT: Offset: 0x00000012 +; NORMAL-NEXT: - Type: R_WASM_TABLE_INDEX_I32 +; NORMAL-NEXT: Index: 4 +; NORMAL-NEXT: Offset: 0x0000001B +; NORMAL-NEXT: - Type: R_WASM_TABLE_INDEX_I32 +; NORMAL-NEXT: Index: 5 +; NORMAL-NEXT: Offset: 0x00000024 +; NORMAL-NEXT: - Type: R_WASM_MEMORY_ADDR_I32 +; NORMAL-NEXT: Index: 12 +; NORMAL-NEXT: Offset: 0x0000002D +; NORMAL-NEXT: Segments: +; NORMAL-NEXT: - SectionOffset: 6 +; NORMAL-NEXT: InitFlags: 0 +; NORMAL-NEXT: Offset: +; NORMAL-NEXT: Opcode: I32_CONST +; NORMAL-NEXT: Value: 0 +; NORMAL-NEXT: Content: 68656C6C6F0A00 +; NORMAL-NEXT: - SectionOffset: 18 +; NORMAL-NEXT: InitFlags: 0 +; NORMAL-NEXT: Offset: +; NORMAL-NEXT: Opcode: I32_CONST +; NORMAL-NEXT: Value: 8 +; NORMAL-NEXT: Content: '01000000' +; NORMAL-NEXT: - SectionOffset: 27 +; NORMAL-NEXT: InitFlags: 0 +; NORMAL-NEXT: Offset: +; NORMAL-NEXT: Opcode: I32_CONST +; NORMAL-NEXT: Value: 12 +; NORMAL-NEXT: Content: '02000000' +; NORMAL-NEXT: - SectionOffset: 36 +; NORMAL-NEXT: InitFlags: 0 +; NORMAL-NEXT: Offset: +; NORMAL-NEXT: Opcode: I32_CONST +; NORMAL-NEXT: Value: 16 +; NORMAL-NEXT: Content: '03000000' +; NORMAL-NEXT: - SectionOffset: 45 +; NORMAL-NEXT: InitFlags: 0 +; NORMAL-NEXT: Offset: +; NORMAL-NEXT: Opcode: I32_CONST +; NORMAL-NEXT: Value: 24 +; NORMAL-NEXT: Content: '00000000' +; NORMAL-NEXT: - SectionOffset: 54 +; NORMAL-NEXT: InitFlags: 0 +; NORMAL-NEXT: Offset: +; NORMAL-NEXT: Opcode: I32_CONST +; NORMAL-NEXT: Value: 28 +; NORMAL-NEXT: Content: '616263' +; NORMAL-NEXT: - Type: CUSTOM +; NORMAL-NEXT: Name: linking +; NORMAL-NEXT: Version: 2 +; NORMAL-NEXT: SymbolTable: +; NORMAL-NEXT: - Index: 0 +; NORMAL-NEXT: Kind: FUNCTION +; NORMAL-NEXT: Name: hello +; NORMAL-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; NORMAL-NEXT: Function: 3 +; NORMAL-NEXT: - Index: 1 +; NORMAL-NEXT: Kind: DATA +; NORMAL-NEXT: Name: hello_str +; NORMAL-NEXT: Flags: [ ] +; NORMAL-NEXT: Segment: 0 +; NORMAL-NEXT: Size: 7 +; NORMAL-NEXT: - Index: 2 +; NORMAL-NEXT: Kind: FUNCTION +; NORMAL-NEXT: Name: puts +; NORMAL-NEXT: Flags: [ UNDEFINED ] +; NORMAL-NEXT: Function: 0 +; NORMAL-NEXT: - Index: 3 +; NORMAL-NEXT: Kind: FUNCTION +; NORMAL-NEXT: Name: my_func +; NORMAL-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; NORMAL-NEXT: Function: 4 +; NORMAL-NEXT: - Index: 4 +; NORMAL-NEXT: Kind: FUNCTION +; NORMAL-NEXT: Name: foo_import +; NORMAL-NEXT: Flags: [ UNDEFINED ] +; NORMAL-NEXT: Function: 1 +; NORMAL-NEXT: - Index: 5 +; NORMAL-NEXT: Kind: FUNCTION +; NORMAL-NEXT: Name: bar_import +; NORMAL-NEXT: Flags: [ BINDING_WEAK, UNDEFINED ] +; NORMAL-NEXT: Function: 2 +; NORMAL-NEXT: - Index: 6 +; NORMAL-NEXT: Kind: FUNCTION +; NORMAL-NEXT: Name: func_comdat +; NORMAL-NEXT: Flags: [ BINDING_WEAK ] +; NORMAL-NEXT: Function: 5 +; NORMAL-NEXT: - Index: 7 +; NORMAL-NEXT: Kind: DATA +; NORMAL-NEXT: Name: data_comdat +; NORMAL-NEXT: Flags: [ BINDING_WEAK ] +; NORMAL-NEXT: Segment: 5 +; NORMAL-NEXT: Size: 3 +; NORMAL-NEXT: - Index: 8 +; NORMAL-NEXT: Kind: DATA +; NORMAL-NEXT: Name: func_addr1 +; NORMAL-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; NORMAL-NEXT: Segment: 1 +; NORMAL-NEXT: Size: 4 +; NORMAL-NEXT: - Index: 9 +; NORMAL-NEXT: Kind: DATA +; NORMAL-NEXT: Name: func_addr2 +; NORMAL-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; NORMAL-NEXT: Segment: 2 +; NORMAL-NEXT: Size: 4 +; NORMAL-NEXT: - Index: 10 +; NORMAL-NEXT: Kind: DATA +; NORMAL-NEXT: Name: func_addr3 +; NORMAL-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; NORMAL-NEXT: Segment: 3 +; NORMAL-NEXT: Size: 4 +; NORMAL-NEXT: - Index: 11 +; NORMAL-NEXT: Kind: DATA +; NORMAL-NEXT: Name: data_addr1 +; NORMAL-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; NORMAL-NEXT: Segment: 4 +; NORMAL-NEXT: Size: 4 +; NORMAL-NEXT: - Index: 12 +; NORMAL-NEXT: Kind: DATA +; NORMAL-NEXT: Name: data_import +; NORMAL-NEXT: Flags: [ UNDEFINED ] +; NORMAL-NEXT: SegmentInfo: +; NORMAL-NEXT: - Index: 0 +; NORMAL-NEXT: Name: .rodata.hello_str +; NORMAL-NEXT: Alignment: 0 +; NORMAL-NEXT: Flags: [ ] +; NORMAL-NEXT: - Index: 1 +; NORMAL-NEXT: Name: .data.func_addr1 +; NORMAL-NEXT: Alignment: 2 +; NORMAL-NEXT: Flags: [ ] +; NORMAL-NEXT: - Index: 2 +; NORMAL-NEXT: Name: .data.func_addr2 +; NORMAL-NEXT: Alignment: 2 +; NORMAL-NEXT: Flags: [ ] +; NORMAL-NEXT: - Index: 3 +; NORMAL-NEXT: Name: .data.func_addr3 +; NORMAL-NEXT: Alignment: 2 +; NORMAL-NEXT: Flags: [ ] +; NORMAL-NEXT: - Index: 4 +; NORMAL-NEXT: Name: .data.data_addr1 +; NORMAL-NEXT: Alignment: 3 +; NORMAL-NEXT: Flags: [ ] +; NORMAL-NEXT: - Index: 5 +; NORMAL-NEXT: Name: .rodata.data_comdat +; NORMAL-NEXT: Alignment: 0 +; NORMAL-NEXT: Flags: [ ] +; NORMAL-NEXT: Comdats: +; NORMAL-NEXT: - Name: func_comdat +; NORMAL-NEXT: Entries: +; NORMAL-NEXT: - Kind: FUNCTION +; NORMAL-NEXT: Index: 5 +; NORMAL-NEXT: - Kind: DATA +; NORMAL-NEXT: Index: 5 +; NORMAL-NEXT: - Type: CUSTOM +; NORMAL-NEXT: Name: name +; NORMAL-NEXT: FunctionNames: +; NORMAL-NEXT: - Index: 0 +; NORMAL-NEXT: Name: puts +; NORMAL-NEXT: - Index: 1 +; NORMAL-NEXT: Name: foo_import +; NORMAL-NEXT: - Index: 2 +; NORMAL-NEXT: Name: bar_import +; NORMAL-NEXT: - Index: 3 +; NORMAL-NEXT: Name: hello +; NORMAL-NEXT: - Index: 4 +; NORMAL-NEXT: Name: my_func +; NORMAL-NEXT: - Index: 5 +; NORMAL-NEXT: Name: func_comdat +; NORMAL-NEXT:... diff --git a/lld/test/wasm/shared-memory.yaml b/lld/test/wasm/shared-memory.yaml index 3538f34a4aca..57eccf152917 100644 --- a/lld/test/wasm/shared-memory.yaml +++ b/lld/test/wasm/shared-memory.yaml @@ -1,18 +1,18 @@ # RUN: yaml2obj %s -o %t1.o -# RUN: not wasm-ld --no-entry --shared-memory %t1.o -o - 2>&1 | FileCheck %s --check-prefix SHARED-NO-MAX +# RUN: not wasm-ld --no-entry --shared-memory --active-segments %t1.o -o - 2>&1 | FileCheck %s --check-prefix SHARED-NO-MAX -# RUN: not wasm-ld --no-entry --shared-memory --max-memory=100000 %t1.o -o - 2>&1 | FileCheck %s --check-prefix SHARED-UNALIGNED +# RUN: not wasm-ld --no-entry --shared-memory --active-segments --max-memory=100000 %t1.o -o - 2>&1 | FileCheck %s --check-prefix SHARED-UNALIGNED -# RUN: wasm-ld --no-entry --shared-memory --max-memory=131072 %t1.o -o - | obj2yaml | FileCheck %s --check-prefix SHARED +# RUN: wasm-ld --no-entry --shared-memory --active-segments --max-memory=131072 %t1.o -o - | obj2yaml | FileCheck %s --check-prefix SHARED # RUN: not wasm-ld --no-entry --features=atomics %t1.o -o - 2>&1 | FileCheck %s --check-prefix ATOMICS-NO-SHARED -# RUN: not wasm-ld --no-entry --features=atomics --shared-memory %t1.o -o - 2>&1 | FileCheck %s --check-prefix ATOMICS-NO-MAX +# RUN: not wasm-ld --no-entry --features=atomics --shared-memory --active-segments %t1.o -o - 2>&1 | FileCheck %s --check-prefix ATOMICS-NO-MAX -# RUN: not wasm-ld --no-entry --features=atomics --shared-memory --max-memory=100000 %t1.o -o - 2>&1 | FileCheck %s --check-prefix ATOMICS-UNALIGNED +# RUN: not wasm-ld --no-entry --features=atomics --shared-memory --active-segments --max-memory=100000 %t1.o -o - 2>&1 | FileCheck %s --check-prefix ATOMICS-UNALIGNED -# RUN: wasm-ld --no-entry --features=atomics --shared-memory --max-memory=131072 %t1.o -o - | obj2yaml | FileCheck %s --check-prefix SHARED +# RUN: wasm-ld --no-entry --features=atomics --shared-memory --active-segments --max-memory=131072 %t1.o -o - | obj2yaml | FileCheck %s --check-prefix SHARED --- !WASM diff --git a/lld/test/wasm/tls.ll b/lld/test/wasm/tls.ll index b570d4675687..e410e08656a4 100644 --- a/lld/test/wasm/tls.ll +++ b/lld/test/wasm/tls.ll @@ -2,8 +2,8 @@ target triple = "wasm32-unknown-unknown" -@tls1 = thread_local(localexec) global i32 1, align 4 @no_tls = global i32 0, align 4 +@tls1 = thread_local(localexec) global i32 1, align 4 @tls2 = thread_local(localexec) global i32 1, align 4 define i32* @tls1_addr() { @@ -44,12 +44,10 @@ define i32* @tls2_addr() { ; CHECK: - Type: CODE ; CHECK-NEXT: Functions: -; CHECK-NEXT: - Index: 0 -; CHECK-NEXT: Locals: [] -; CHECK-NEXT: Body: 0B -; CHECK-NEXT: - Index: 1 +; Skip __wasm_call_ctors and __wasm_init_memory +; CHECK: - Index: 2 ; CHECK-NEXT: Locals: [] -; CHECK-NEXT: Body: 20002401200041004108FC0800000B +; CHECK-NEXT: Body: 20002401200041004108FC0801000B ; Expected body of __wasm_init_tls: ; local.get 0 @@ -57,10 +55,10 @@ define i32* @tls2_addr() { ; local.get 0 ; i32.const 0 ; i32.const 8 -; memory.init 0, 0 +; memory.init 1, 0 ; end -; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: - Index: 3 ; CHECK-NEXT: Locals: [] ; CHECK-NEXT: Body: 2381808080004180808080006A0B @@ -70,7 +68,7 @@ define i32* @tls2_addr() { ; i32.add ; end -; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: - Index: 4 ; CHECK-NEXT: Locals: [] ; CHECK-NEXT: Body: 2381808080004184808080006A0B diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 900cd051dcfb..003dd0d30baf 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -320,9 +320,8 @@ static void readConfigs(opt::InputArgList &args) { args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); config->importMemory = args.hasArg(OPT_import_memory); config->sharedMemory = args.hasArg(OPT_shared_memory); - // TODO: Make passive segments the default with shared memory - config->passiveSegments = - args.hasFlag(OPT_passive_segments, OPT_active_segments, false); + config->passiveSegments = args.hasFlag( + OPT_passive_segments, OPT_active_segments, config->sharedMemory); config->importTable = args.hasArg(OPT_import_table); config->ltoo = args::getInteger(args, OPT_lto_O, 2); config->ltoPartitions = args::getInteger(args, OPT_lto_partitions, 1); diff --git a/lld/wasm/Options.td b/lld/wasm/Options.td index 29bd9d9ef3d1..4bce790cd576 100644 --- a/lld/wasm/Options.td +++ b/lld/wasm/Options.td @@ -144,10 +144,10 @@ def shared_memory: F<"shared-memory">, HelpText<"Use shared linear memory">; def active_segments: F<"active-segments">, - HelpText<"Force segments to be active">; + HelpText<"Force segments to be active (default with unshared memory)">; def passive_segments: F<"passive-segments">, - HelpText<"Force segments to be passive">; + HelpText<"Force segments to be passive (default with shared memory)">; def import_table: F<"import-table">, HelpText<"Import function table from the environment">; diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 4ad91ab11171..6338b6e5fa2a 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -771,9 +771,10 @@ void Writer::createInitTLSFunction() { OutputSegment *tlsSeg = nullptr; for (auto *seg : segments) { - if (seg->name == ".tdata") + if (seg->name == ".tdata") { tlsSeg = seg; - break; + break; + } } writeUleb128(os, 0, "num locals"); @@ -897,7 +898,7 @@ void Writer::run() { createCallCtorsFunction(); } - if (config->sharedMemory && !config->shared) + if (!config->relocatable && config->sharedMemory && !config->shared) createInitTLSFunction(); if (errorCount()) diff --git a/lldb/CMakeLists.txt b/lldb/CMakeLists.txt index 6b1b67258b3d..5d52f6450657 100644 --- a/lldb/CMakeLists.txt +++ b/lldb/CMakeLists.txt @@ -42,15 +42,14 @@ endif () if(CMAKE_CROSSCOMPILING AND LLDB_BUILT_STANDALONE) set(LLVM_USE_HOST_TOOLS ON) include(CrossCompile) - if (NOT LLDB_PATH_TO_NATIVE_LLVM_BUILD OR - NOT LLDB_PATH_TO_NATIVE_CLANG_BUILD) + if (NOT NATIVE_LLVM_DIR OR NOT NATIVE_Clang_DIR) message(FATAL_ERROR - "Crosscompiling standalone requires the variables LLDB_PATH_TO_NATIVE_{CLANG,LLVM}_BUILD + "Crosscompiling standalone requires the variables NATIVE_{CLANG,LLVM}_DIR for building the native lldb-tblgen used during the build process.") endif() llvm_create_cross_target(lldb NATIVE "" Release - -DLLDB_PATH_TO_LLVM_BUILD=${LLDB_PATH_TO_NATIVE_LLVM_BUILD} - -DLLDB_PATH_TO_CLANG_BUILD=${LLDB_PATH_TO_NATIVE_CLANG_BUILD}) + -DLLVM_DIR=${NATIVE_LLVM_DIR} + -DClang_DIR=${NATIVE_Clang_DIR}) endif() add_subdirectory(utils/TableGen) @@ -107,10 +106,6 @@ if(LLDB_INCLUDE_TESTS) list(APPEND LLDB_TEST_DEPS lldb-server) endif() - if(TARGET debugserver) - list(APPEND LLDB_TEST_DEPS debugserver) - endif() - if(TARGET lldb-mi) list(APPEND LLDB_TEST_DEPS lldb-mi) endif() diff --git a/lldb/cmake/modules/AddLLDB.cmake b/lldb/cmake/modules/AddLLDB.cmake index 540d01362f0d..4c99278c583b 100644 --- a/lldb/cmake/modules/AddLLDB.cmake +++ b/lldb/cmake/modules/AddLLDB.cmake @@ -276,3 +276,27 @@ function(lldb_setup_rpaths name) INSTALL_RPATH "${LIST_INSTALL_RPATH}" ) endfunction() + +function(lldb_find_system_debugserver path) + execute_process(COMMAND xcode-select -p + RESULT_VARIABLE exit_code + OUTPUT_VARIABLE xcode_dev_dir + ERROR_VARIABLE error_msg + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(exit_code) + message(WARNING "`xcode-select -p` failed:\n${error_msg}") + else() + set(subpath "LLDB.framework/Resources/debugserver") + set(path_shared "${xcode_dev_dir}/../SharedFrameworks/${subpath}") + set(path_private "${xcode_dev_dir}/Library/PrivateFrameworks/${subpath}") + + if(EXISTS ${path_shared}) + set(${path} ${path_shared} PARENT_SCOPE) + elseif(EXISTS ${path_private}) + set(${path} ${path_private} PARENT_SCOPE) + else() + message(WARNING "System debugserver requested, but not found. " + "Candidates don't exist: ${path_shared}\n${path_private}") + endif() + endif() +endfunction() diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake index ac71136dd026..0dca557601f3 100644 --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -50,6 +50,7 @@ option(LLDB_USE_SYSTEM_SIX "Use six.py shipped with system and do not install a option(LLDB_USE_ENTITLEMENTS "When codesigning, use entitlements if available" ON) option(LLDB_BUILD_FRAMEWORK "Build LLDB.framework (Darwin only)" OFF) option(LLDB_NO_INSTALL_DEFAULT_RPATH "Disable default RPATH settings in binaries" OFF) +option(LLDB_USE_SYSTEM_DEBUGSERVER "Use the system's debugserver for testing (Darwin only)." OFF) if(LLDB_BUILD_FRAMEWORK) if(NOT APPLE) @@ -139,7 +140,6 @@ function(find_python_libs_windows) PYTHONLIBS_VERSION_STRING "${python_version_str}") message(STATUS "Found Python library version ${PYTHONLIBS_VERSION_STRING}") string(REGEX REPLACE "([0-9]+)[.]([0-9]+)[.][0-9]+" "python\\1\\2" PYTHONLIBS_BASE_NAME "${PYTHONLIBS_VERSION_STRING}") - set(PYTHONLIBS_VERSION_STRING "${PYTHONLIBS_VERSION_STRING}" PARENT_SCOPE) unset(python_version_str) else() message(WARNING "Unable to find ${PYTHON_INCLUDE_DIR}/patchlevel.h, Python installation is corrupt.") @@ -174,13 +174,32 @@ function(find_python_libs_windows) return() endif() - set (PYTHON_EXECUTABLE ${PYTHON_EXE} PARENT_SCOPE) - set (PYTHON_LIBRARY ${PYTHON_LIB} PARENT_SCOPE) - set (PYTHON_DLL ${PYTHON_DLL} PARENT_SCOPE) - set (PYTHON_INCLUDE_DIR ${PYTHON_INCLUDE_DIR} PARENT_SCOPE) + # Find the version of the Python interpreter. + execute_process(COMMAND "${PYTHON_EXE}" -c + "import sys; sys.stdout.write(';'.join([str(x) for x in sys.version_info[:3]]))" + OUTPUT_VARIABLE PYTHON_VERSION_OUTPUT + RESULT_VARIABLE PYTHON_VERSION_RESULT + ERROR_QUIET) + if(NOT PYTHON_VERSION_RESULT) + string(REPLACE ";" "." PYTHON_VERSION_STRING "${PYTHON_VERSION_OUTPUT}") + list(GET PYTHON_VERSION_OUTPUT 0 PYTHON_VERSION_MAJOR) + list(GET PYTHON_VERSION_OUTPUT 1 PYTHON_VERSION_MINOR) + list(GET PYTHON_VERSION_OUTPUT 2 PYTHON_VERSION_PATCH) + endif() - message(STATUS "LLDB Found PythonExecutable: ${PYTHON_EXE}") - message(STATUS "LLDB Found PythonLibs: ${PYTHON_LIB}") + # Set the same variables as FindPythonInterp and FindPythonLibs. + set(PYTHON_EXECUTABLE ${PYTHON_EXE} PARENT_SCOPE) + set(PYTHON_LIBRARY ${PYTHON_LIB} PARENT_SCOPE) + set(PYTHON_DLL ${PYTHON_DLL} PARENT_SCOPE) + set(PYTHON_INCLUDE_DIR ${PYTHON_INCLUDE_DIR} PARENT_SCOPE) + set(PYTHONLIBS_VERSION_STRING "${PYTHONLIBS_VERSION_STRING}" PARENT_SCOPE) + set(PYTHON_VERSION_STRING ${PYTHON_VERSION_STRING} PARENT_SCOPE) + set(PYTHON_VERSION_MAJOR ${PYTHON_VERSION_MAJOR} PARENT_SCOPE) + set(PYTHON_VERSION_MINOR ${PYTHON_VERSION_MINOR} PARENT_SCOPE) + set(PYTHON_VERSION_PATCH ${PYTHON_VERSION_PATCH} PARENT_SCOPE) + + message(STATUS "LLDB Found PythonExecutable: ${PYTHON_EXECUTABLE} (${PYTHON_VERSION_STRING})") + message(STATUS "LLDB Found PythonLibs: ${PYTHON_LIB} (${PYTHONLIBS_VERSION_STRING})") message(STATUS "LLDB Found PythonDLL: ${PYTHON_DLL}") message(STATUS "LLDB Found PythonIncludeDirs: ${PYTHON_INCLUDE_DIR}") endfunction(find_python_libs_windows) @@ -198,9 +217,18 @@ if (NOT LLDB_DISABLE_PYTHON) find_package(PythonLibs REQUIRED) endif() - if (NOT PYTHON_VERSION_STRING VERSION_EQUAL PYTHONLIBS_VERSION_STRING AND - NOT CMAKE_CROSSCOMPILING) - message(FATAL_ERROR "Found incompatible Python interpreter (${PYTHON_VERSION_STRING}) and Python libraries (${PYTHONLIBS_VERSION_STRING})") + if (NOT CMAKE_CROSSCOMPILING) + string(REPLACE "." ";" pythonlibs_version_list ${PYTHONLIBS_VERSION_STRING}) + list(GET pythonlibs_version_list 0 pythonlibs_major) + list(GET pythonlibs_version_list 1 pythonlibs_minor) + + # Ignore the patch version. Some versions of macOS report a different patch + # version for the system provided interpreter and libraries. + if (NOT PYTHON_VERSION_MAJOR VERSION_EQUAL pythonlibs_major OR + NOT PYTHON_VERSION_MINOR VERSION_EQUAL pythonlibs_minor) + message(FATAL_ERROR "Found incompatible Python interpreter (${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR})" + " and Python libraries (${pythonlibs_major}.${pythonlibs_minor})") + endif() endif() if (PYTHON_INCLUDE_DIR) diff --git a/lldb/packages/Python/lldbsuite/test/expression_command/multiline-completion/Makefile b/lldb/packages/Python/lldbsuite/test/expression_command/multiline-completion/Makefile new file mode 100644 index 000000000000..f5a47fcc46cc --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/expression_command/multiline-completion/Makefile @@ -0,0 +1,3 @@ +LEVEL = ../../make +C_SOURCES := main.c +include $(LEVEL)/Makefile.rules diff --git a/lldb/packages/Python/lldbsuite/test/expression_command/multiline-completion/TestMultilineCompletion.py b/lldb/packages/Python/lldbsuite/test/expression_command/multiline-completion/TestMultilineCompletion.py new file mode 100644 index 000000000000..2d75fc471d58 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/expression_command/multiline-completion/TestMultilineCompletion.py @@ -0,0 +1,52 @@ +""" +Test completion for multiline expressions. +""" + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * + +class MultilineCompletionTest(TestBase): + + mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True + + def setUp(self): + TestBase.setUp(self) + self.source = 'main.c' + + def expect_string(self, string): + import pexpect + """This expects for "string", with timeout & EOF being test fails.""" + try: + self.child.expect_exact(string) + except pexpect.EOF: + self.fail("Got EOF waiting for '%s'" % (string)) + except pexpect.TIMEOUT: + self.fail("Timed out waiting for '%s'" % (string)) + + @expectedFailureAll( + oslist=["windows"], + bugnumber="llvm.org/pr22274: need a pexpect replacement for windows") + def test_basic_completion(self): + """Test that we can complete a simple multiline expression""" + self.build() + self.setTearDownCleanup() + + import pexpect + exe = self.getBuildArtifact("a.out") + prompt = "(lldb) " + + run_commands = ' -o "b main" -o "r"' + self.child = pexpect.spawn( + '%s %s %s %s' % + (lldbtest_config.lldbExec, self.lldbOption, run_commands, exe)) + child = self.child + + self.expect_string(prompt) + self.child.sendline("expr") + self.expect_string("terminate with an empty line to evaluate") + self.child.send("to_\t") + self.expect_string("to_complete") + + self.deletePexpectChild() diff --git a/lldb/packages/Python/lldbsuite/test/expression_command/multiline-completion/main.c b/lldb/packages/Python/lldbsuite/test/expression_command/multiline-completion/main.c new file mode 100644 index 000000000000..03350dd8299a --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/expression_command/multiline-completion/main.c @@ -0,0 +1,5 @@ +int main(int argc, char **argv) { + lldb_enable_attach(); + int to_complete = 0; + return to_complete; +} diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/exec/TestExec.py b/lldb/packages/Python/lldbsuite/test/functionalities/exec/TestExec.py index 48bd515c963d..2d6baa1a2f2d 100644 --- a/lldb/packages/Python/lldbsuite/test/functionalities/exec/TestExec.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/exec/TestExec.py @@ -18,17 +18,17 @@ class ExecTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) - @skipUnlessDarwin @expectedFailureAll(archs=['i386'], bugnumber="rdar://28656532") @expectedFailureAll(oslist=["ios", "tvos", "watchos", "bridgeos"], bugnumber="rdar://problem/34559552") # this exec test has problems on ios systems @skipIfSanitized # rdar://problem/43756823 + @skipIfWindows def test_hitting_exec (self): self.do_test(False) - @skipUnlessDarwin @expectedFailureAll(archs=['i386'], bugnumber="rdar://28656532") @expectedFailureAll(oslist=["ios", "tvos", "watchos", "bridgeos"], bugnumber="rdar://problem/34559552") # this exec test has problems on ios systems @skipIfSanitized # rdar://problem/43756823 + @skipIfWindows def test_skipping_exec (self): self.do_test(True) diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/exec/main.cpp b/lldb/packages/Python/lldbsuite/test/functionalities/exec/main.cpp index 92206b2d88ef..4475bbe4452f 100644 --- a/lldb/packages/Python/lldbsuite/test/functionalities/exec/main.cpp +++ b/lldb/packages/Python/lldbsuite/test/functionalities/exec/main.cpp @@ -1,76 +1,16 @@ -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include #include #include +#include -static void -exit_with_errno (int err, const char *prefix) -{ - if (err) - { - fprintf (stderr, - "%s%s", - prefix ? prefix : "", - strerror(err)); - exit (err); - } -} - -static pid_t -spawn_process (const char *progname, - const char **argv, - const char **envp, - int &err) -{ - pid_t pid = 0; - - const posix_spawn_file_actions_t *file_actions = NULL; - posix_spawnattr_t attr; - err = posix_spawnattr_init (&attr); - if (err) - return pid; - - short flags = POSIX_SPAWN_SETEXEC | POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; - err = posix_spawnattr_setflags (&attr, flags); - if (err == 0) - { - // Use the default signal masks - sigset_t no_signals; - sigset_t all_signals; - sigemptyset (&no_signals); - sigfillset (&all_signals); - posix_spawnattr_setsigmask(&attr, &no_signals); - posix_spawnattr_setsigdefault(&attr, &all_signals); - - err = posix_spawn (&pid, - progname, - file_actions, - &attr, - (char * const *)argv, - (char * const *)envp); - - posix_spawnattr_destroy(&attr); - } - return pid; -} - -int -main (int argc, char const **argv) -{ - char *buf = (char*) malloc (strlen (argv[0]) + 12); - strlcpy (buf, argv[0], strlen (argv[0]) + 1); - std::string directory_name (::dirname (buf)); +int main(int argc, char const **argv) { + char *buf = strdup(argv[0]); // Set breakpoint 1 here + std::string directory_name(::dirname(buf)); - std::string other_program = directory_name + "/secondprog"; - int err = 0; // Set breakpoint 1 here - spawn_process (other_program.c_str(), argv, NULL, err); - if (err) - exit_with_errno (err, "posix_spawn x86_64 error"); - return 0; + std::string other_program = directory_name + "/secondprog"; + execve(other_program.c_str(), const_cast(argv), nullptr); + perror("execve"); + abort(); } diff --git a/lldb/source/Core/IOHandler.cpp b/lldb/source/Core/IOHandler.cpp index b30308490cca..c3c722019faa 100644 --- a/lldb/source/Core/IOHandler.cpp +++ b/lldb/source/Core/IOHandler.cpp @@ -233,7 +233,7 @@ int IOHandlerDelegate::IOHandlerComplete( matches, descriptions); case Completion::Expression: { CompletionResult result; - CompletionRequest request(current_line, current_line - cursor, + CompletionRequest request(current_line, cursor - current_line, skip_first_n_matches, max_matches, result); CommandCompletions::InvokeCommonCompletionCallbacks( io_handler.GetDebugger().GetCommandInterpreter(), diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp index 7637237aa16b..c1da6f3d2575 100644 --- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -599,12 +599,9 @@ void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info, // which only copies the main thread. LLDB_LOG(log, "exec received, stop tracking all but main thread"); - for (auto i = m_threads.begin(); i != m_threads.end();) { - if ((*i)->GetID() == GetID()) - i = m_threads.erase(i); - else - ++i; - } + llvm::erase_if(m_threads, [&](std::unique_ptr &t) { + return t->GetID() != GetID(); + }); assert(m_threads.size() == 1); auto *main_thread = static_cast(m_threads[0].get()); diff --git a/lldb/source/Plugins/Process/Windows/Common/CMakeLists.txt b/lldb/source/Plugins/Process/Windows/Common/CMakeLists.txt index 68486c1d9905..1d7b8ccd49ad 100644 --- a/lldb/source/Plugins/Process/Windows/Common/CMakeLists.txt +++ b/lldb/source/Plugins/Process/Windows/Common/CMakeLists.txt @@ -7,6 +7,9 @@ add_lldb_library(lldbPluginProcessWindowsCommon PLUGIN ProcessWindowsLog.cpp RegisterContextWindows.cpp TargetThreadWindows.cpp + x64/RegisterContextWindows_x64.cpp + x86/RegisterContextWindows_x86.cpp + # TODO add support for ARM (NT) and ARM64 LINK_LIBS lldbCore @@ -20,13 +23,3 @@ add_lldb_library(lldbPluginProcessWindowsCommon PLUGIN LINK_COMPONENTS Support ) - -# TODO add support for ARM (NT) and ARM64 -# TODO build these unconditionally as we cannot do cross-debugging or WoW -if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64") - target_sources(lldbPluginProcessWindowsCommon PRIVATE - x64/RegisterContextWindows_x64.cpp) -elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i?86|X86") - target_sources(lldbPluginProcessWindowsCommon PRIVATE - x86/RegisterContextWindows_x86.cpp) -endif() diff --git a/lldb/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp b/lldb/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp index 4101aa1f1b5e..11f72c002115 100644 --- a/lldb/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.cpp @@ -6,6 +6,8 @@ // //===----------------------------------------------------------------------===// +#if defined(__x86_64__) || defined(__amd64__) || defined(_M_X64) || defined(_M_AMD64) + #include "lldb/Host/windows/HostThreadWindows.h" #include "lldb/Host/windows/windows.h" #include "lldb/Utility/RegisterValue.h" @@ -534,3 +536,5 @@ bool RegisterContextWindows_x64::WriteRegister(const RegisterInfo *reg_info, return ::SetThreadContext( wthread.GetHostThread().GetNativeThread().GetSystemHandle(), &m_context); } + +#endif // defined(__x86_64__) || defined(__amd64__) || defined(_M_X64) || defined(_M_AMD64) diff --git a/lldb/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.h b/lldb/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.h index 5f252e162934..20d2cb90ece3 100644 --- a/lldb/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.h +++ b/lldb/source/Plugins/Process/Windows/Common/x64/RegisterContextWindows_x64.h @@ -9,6 +9,8 @@ #ifndef liblldb_RegisterContextWindows_x64_H_ #define liblldb_RegisterContextWindows_x64_H_ +#if defined(__x86_64__) || defined(__amd64__) || defined(_M_X64) || defined(_M_AMD64) + #include "RegisterContextWindows.h" #include "lldb/lldb-forward.h" @@ -40,4 +42,6 @@ class RegisterContextWindows_x64 : public RegisterContextWindows { }; } +#endif // defined(__x86_64__) || defined(__amd64__) || defined(_M_X64) || defined(_M_AMD64) + #endif // #ifndef liblldb_RegisterContextWindows_x64_H_ diff --git a/lldb/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp b/lldb/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp index 0c25853e1c16..b8f7bb46181d 100644 --- a/lldb/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.cpp @@ -6,6 +6,8 @@ // //===----------------------------------------------------------------------===// +#if defined(__i386__) || defined(_M_IX86) + #include "lldb/Host/windows/HostThreadWindows.h" #include "lldb/Host/windows/windows.h" #include "lldb/Utility/RegisterValue.h" @@ -282,3 +284,5 @@ bool RegisterContextWindows_x86::ReadRegisterHelper( reg_value.SetUInt32(value); return true; } + +#endif // defined(__i386__) || defined(_M_IX86) diff --git a/lldb/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.h b/lldb/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.h index 8dca1dc995b1..6517de0bbdfc 100644 --- a/lldb/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.h +++ b/lldb/source/Plugins/Process/Windows/Common/x86/RegisterContextWindows_x86.h @@ -9,6 +9,8 @@ #ifndef liblldb_RegisterContextWindows_x86_H_ #define liblldb_RegisterContextWindows_x86_H_ +#if defined(__i386__) || defined(_M_IX86) + #include "RegisterContextWindows.h" #include "lldb/lldb-forward.h" @@ -44,4 +46,6 @@ class RegisterContextWindows_x86 : public RegisterContextWindows { }; } +#endif // defined(__i386__) || defined(_M_IX86) + #endif // #ifndef liblldb_RegisterContextWindows_x86_H_ diff --git a/lldb/test/CMakeLists.txt b/lldb/test/CMakeLists.txt index 037222e04477..00225e791526 100644 --- a/lldb/test/CMakeLists.txt +++ b/lldb/test/CMakeLists.txt @@ -74,15 +74,6 @@ if ( CMAKE_SYSTEM_NAME MATCHES "Windows" ) endif() endif() -if(LLDB_CODESIGN_IDENTITY_USED) - list(APPEND LLDB_TEST_COMMON_ARGS --codesign-identity "${LLDB_CODESIGN_IDENTITY_USED}") -endif() - -if(LLDB_BUILD_FRAMEWORK) - get_target_property(framework_target_dir liblldb LIBRARY_OUTPUT_DIRECTORY) - list(APPEND LLDB_TEST_COMMON_ARGS --framework ${framework_target_dir}/LLDB.framework) -endif() - if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Windows|Darwin") list(APPEND LLDB_TEST_COMMON_ARGS --env ARCHIVER=${CMAKE_AR} --env OBJCOPY=${CMAKE_OBJCOPY}) @@ -94,12 +85,28 @@ if (NOT "${LLDB_LIT_TOOLS_DIR}" STREQUAL "") endif() endif() -if(CMAKE_HOST_APPLE AND DEBUGSERVER_PATH) - list(APPEND LLDB_TEST_COMMON_ARGS --server ${DEBUGSERVER_PATH}) -endif() +if(CMAKE_HOST_APPLE) + if(LLDB_BUILD_FRAMEWORK) + get_target_property(framework_build_dir liblldb LIBRARY_OUTPUT_DIRECTORY) + list(APPEND LLDB_TEST_COMMON_ARGS --framework ${framework_build_dir}/LLDB.framework) + endif() + + # Use the same identity for testing + get_property(code_sign_identity_used GLOBAL PROPERTY LLDB_DEBUGSERVER_CODESIGN_IDENTITY) + if(code_sign_identity_used) + list(APPEND LLDB_TEST_COMMON_ARGS --codesign-identity "${code_sign_identity_used}") + endif() -if(SKIP_TEST_DEBUGSERVER) - list(APPEND LLDB_TEST_COMMON_ARGS --out-of-tree-debugserver) + if(LLDB_USE_SYSTEM_DEBUGSERVER) + lldb_find_system_debugserver(system_debugserver_path) + message(STATUS "LLDB tests use out-of-tree debugserver: ${system_debugserver_path}") + list(APPEND LLDB_TEST_COMMON_ARGS --out-of-tree-debugserver) + else() + set(debugserver_path ${LLVM_RUNTIME_OUTPUT_INTDIR}/debugserver) + message(STATUS "LLDB Tests use just-built debugserver: ${debugserver_path}") + list(APPEND LLDB_TEST_COMMON_ARGS --server ${debugserver_path}) + add_dependencies(lldb-test-deps debugserver) + endif() endif() set(LLDB_DOTEST_ARGS ${LLDB_TEST_COMMON_ARGS};${LLDB_TEST_USER_ARGS}) diff --git a/lldb/tools/debugserver/source/CMakeLists.txt b/lldb/tools/debugserver/source/CMakeLists.txt index cf305c9d2680..303fd28caf6c 100644 --- a/lldb/tools/debugserver/source/CMakeLists.txt +++ b/lldb/tools/debugserver/source/CMakeLists.txt @@ -6,6 +6,58 @@ include_directories(MacOSX/DarwinLog) include_directories(MacOSX) +function(check_certificate identity result_valid) + execute_process( + COMMAND security find-certificate -Z -p -c ${identity} /Library/Keychains/System.keychain + RESULT_VARIABLE exit_code OUTPUT_QUIET ERROR_QUIET) + if(exit_code) + set(${result_valid} FALSE PARENT_SCOPE) + else() + set(${result_valid} TRUE PARENT_SCOPE) + endif() +endfunction() + +function(get_debugserver_codesign_identity result) + string(CONCAT not_found_help + "This will cause failures in the test suite." + "Pass '-DLLDB_USE_SYSTEM_DEBUGSERVER=ON' to use the system one instead." + "See 'Code Signing on macOS' in the documentation." + ) + + # Explicit override: warn if unavailable + if(LLDB_CODESIGN_IDENTITY) + set(${result} ${LLDB_CODESIGN_IDENTITY} PARENT_SCOPE) + check_certificate(${LLDB_CODESIGN_IDENTITY} available) + if(NOT available AND NOT LLDB_USE_SYSTEM_DEBUGSERVER) + message(WARNING "LLDB_CODESIGN_IDENTITY not found: '${LLDB_CODESIGN_IDENTITY}' ${not_found_help}") + endif() + return() + endif() + + # Development signing identity: use if available + check_certificate(lldb_codesign available) + if(available) + set(${result} lldb_codesign PARENT_SCOPE) + return() + endif() + + if(NOT LLDB_USE_SYSTEM_DEBUGSERVER) + message(WARNING "Development code sign identiy not found: 'lldb_codesign' ${not_found_help}") + endif() + + # LLVM pendant: fallback if available + if(LLVM_CODESIGNING_IDENTITY) + check_certificate(${LLVM_CODESIGNING_IDENTITY} available) + if(available) + set(${result} ${LLVM_CODESIGNING_IDENTITY} PARENT_SCOPE) + return() + endif() + endif() + + # Ad-hoc signing: last resort + set(${result} "-" PARENT_SCOPE) +endfunction() + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -Wl,-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_SOURCE_DIR}/../resources/lldb-debugserver-Info.plist") check_cxx_compiler_flag("-Wno-gnu-zero-variadic-macro-arguments" @@ -30,132 +82,17 @@ check_library_exists(compression compression_encode_buffer "" HAVE_LIBCOMPRESSIO add_subdirectory(MacOSX) -# LLDB-specific identity, currently used for code signing debugserver. set(LLDB_CODESIGN_IDENTITY "" CACHE STRING - "Override code sign identity for debugserver and for use in tests; falls back to LLVM_CODESIGNING_IDENTITY if set or lldb_codesign otherwise (Darwin only)") - -# Determine which identity to use and store it in the separate cache entry. -# We will query it later for LLDB_TEST_COMMON_ARGS. -if(LLDB_CODESIGN_IDENTITY) - set(LLDB_CODESIGN_IDENTITY_USED ${LLDB_CODESIGN_IDENTITY} CACHE INTERNAL "" FORCE) -elseif(LLVM_CODESIGNING_IDENTITY) - set(LLDB_CODESIGN_IDENTITY_USED ${LLVM_CODESIGNING_IDENTITY} CACHE INTERNAL "" FORCE) -else() - set(LLDB_CODESIGN_IDENTITY_USED lldb_codesign CACHE INTERNAL "" FORCE) -endif() + "Identity override for debugserver; see 'Code Signing on macOS' in the documentation (Darwin only)") -# Override locally, so the identity is used for targets created in this scope. -set(LLVM_CODESIGNING_IDENTITY ${LLDB_CODESIGN_IDENTITY_USED}) - -option(LLDB_NO_DEBUGSERVER "Disable the debugserver target" OFF) -option(LLDB_USE_SYSTEM_DEBUGSERVER "Use the system's debugserver instead of building it from source (Darwin only)." OFF) +get_debugserver_codesign_identity(debugserver_codesign_identity) -# Incompatible options -if(LLDB_NO_DEBUGSERVER AND LLDB_USE_SYSTEM_DEBUGSERVER) - message(FATAL_ERROR "Inconsistent options: LLDB_NO_DEBUGSERVER and LLDB_USE_SYSTEM_DEBUGSERVER") -endif() - -# Try to locate the system debugserver. -# Subsequent feasibility checks depend on it. -if(APPLE AND CMAKE_HOST_APPLE) - execute_process( - COMMAND xcode-select -p - OUTPUT_VARIABLE xcode_dev_dir) - string(STRIP ${xcode_dev_dir} xcode_dev_dir) - - set(debugserver_rel_path "LLDB.framework/Resources/debugserver") - set(debugserver_shared "${xcode_dev_dir}/../SharedFrameworks/${debugserver_rel_path}") - set(debugserver_private "${xcode_dev_dir}/Library/PrivateFrameworks/${debugserver_rel_path}") - - if(EXISTS ${debugserver_shared}) - set(system_debugserver ${debugserver_shared}) - elseif(EXISTS ${debugserver_private}) - set(system_debugserver ${debugserver_private}) - endif() -endif() - -# Handle unavailability -if(LLDB_USE_SYSTEM_DEBUGSERVER) - if(system_debugserver) - set(use_system_debugserver ON) - elseif(APPLE AND CMAKE_HOST_APPLE) - # Binary not found on system. Keep cached variable, to try again on reconfigure. - message(SEND_ERROR - "LLDB_USE_SYSTEM_DEBUGSERVER option set, but no debugserver found in:\ - ${debugserver_shared}\ - ${debugserver_private}") - else() - # Non-Apple target platform or non-Darwin host. Reset invalid cached variable. - message(WARNING "Reverting invalid option LLDB_USE_SYSTEM_DEBUGSERVER (Darwin only)") - set(LLDB_USE_SYSTEM_DEBUGSERVER OFF CACHE BOOL "" FORCE) - endif() -elseif(NOT LLDB_NO_DEBUGSERVER) - # Default case: on Darwin we need the right code signing ID. - # See lldb/docs/code-signing.txt for details. - if(CMAKE_HOST_APPLE AND NOT LLVM_CODESIGNING_IDENTITY STREQUAL "lldb_codesign") - message(WARNING "Codesigning debugserver with identity ${LLVM_CODESIGNING_IDENTITY}. " - "The usual setup uses the \"lldb_codesign\" identity created with " - "scripts/macos-setup-codesign.sh. As a result your debugserver might " - "not be able to attach to processes.\n" - "Pass -DLLDB_CODESIGN_IDENTITY=lldb_codesign to use the development " - "signing identity.") - endif() - set(build_and_sign_debugserver ON) -endif() - -# TODO: We don't use the $ generator expression here, -# because the value of DEBUGSERVER_PATH is used to build LLDB_DOTEST_ARGS, -# which is used for configuring lldb-dotest.in, which does not have a generator -# step at the moment. -set(default_debugserver_path "${LLVM_RUNTIME_OUTPUT_INTDIR}/debugserver${CMAKE_EXECUTABLE_SUFFIX}") - -# Remember where debugserver binary goes and whether or not we have to test it. -set(DEBUGSERVER_PATH "" CACHE FILEPATH "Path to debugserver") -set(SKIP_TEST_DEBUGSERVER OFF CACHE BOOL "Building the in-tree debugserver was skipped") - -# Reset values in all cases in order to correctly support reconfigurations. -if(use_system_debugserver) - add_custom_target(debugserver - COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${system_debugserver} ${LLVM_RUNTIME_OUTPUT_INTDIR} - COMMENT "Copying the system debugserver to LLDB's binaries directory.") - - set_target_properties(debugserver PROPERTIES FOLDER "lldb libraries/debugserver") - - # Don't test debugserver itself. - # Tests that require debugserver will use the copy. - set(DEBUGSERVER_PATH ${default_debugserver_path} CACHE FILEPATH "" FORCE) - set(SKIP_TEST_DEBUGSERVER ON CACHE BOOL "" FORCE) - - message(STATUS "Copy system debugserver from: ${system_debugserver}") -elseif(build_and_sign_debugserver) - # Build, sign and test debugserver (below) - set(DEBUGSERVER_PATH ${default_debugserver_path} CACHE FILEPATH "" FORCE) - set(SKIP_TEST_DEBUGSERVER OFF CACHE BOOL "" FORCE) - - message(STATUS "lldb debugserver: ${DEBUGSERVER_PATH}") -else() - # No tests for debugserver, no tests that require it. - set(DEBUGSERVER_PATH "" CACHE FILEPATH "" FORCE) - set(SKIP_TEST_DEBUGSERVER ON CACHE BOOL "" FORCE) - - message(STATUS "lldb debugserver will not be available.") -endif() +# Override locally, so the identity is used for targets created in this scope. +set(LLVM_CODESIGNING_IDENTITY ${debugserver_codesign_identity}) -# On MacOS, debugserver needs to be codesigned when built. Check if we have -# a certificate instead of failing in the middle of the build. -if(build_and_sign_debugserver) - execute_process( - COMMAND security find-certificate -Z -p -c ${LLDB_CODESIGN_IDENTITY_USED} /Library/Keychains/System.keychain - RESULT_VARIABLE cert_return - OUTPUT_QUIET - ERROR_QUIET) - - if (cert_return) - message(FATAL_ERROR "Certificate for debugserver not found. Run scripts/macos-setup-codesign.sh or " - "use the system debugserver passing -DLLDB_USE_SYSTEM_DEBUGSERVER=ON to CMake") - endif() -endif() +# Use the same identity later in the test suite. +set_property(GLOBAL PROPERTY + LLDB_DEBUGSERVER_CODESIGN_IDENTITY ${debugserver_codesign_identity}) if(APPLE) if(IOS) @@ -190,7 +127,7 @@ if(LLDB_USE_ENTITLEMENTS) endif() endif() -if(build_and_sign_debugserver) +#if(build_and_sign_debugserver) set(generated_mach_interfaces ${CMAKE_CURRENT_BINARY_DIR}/mach_exc.h ${CMAKE_CURRENT_BINARY_DIR}/mach_excServer.c @@ -318,4 +255,4 @@ if(build_and_sign_debugserver) ${entitlements} ) endif() -endif() +#endif() diff --git a/lldb/unittests/CMakeLists.txt b/lldb/unittests/CMakeLists.txt index 311f47b1b0ec..8e6b3e7b341a 100644 --- a/lldb/unittests/CMakeLists.txt +++ b/lldb/unittests/CMakeLists.txt @@ -78,6 +78,6 @@ add_subdirectory(tools) add_subdirectory(UnwindAssembly) add_subdirectory(Utility) -if(LLDB_CAN_USE_DEBUGSERVER AND NOT SKIP_TEST_DEBUGSERVER) +if(LLDB_CAN_USE_DEBUGSERVER AND NOT LLDB_USE_SYSTEM_DEBUGSERVER) add_subdirectory(debugserver) endif() diff --git a/lldb/unittests/tools/lldb-server/CMakeLists.txt b/lldb/unittests/tools/lldb-server/CMakeLists.txt index 3bae69bfa4a1..7d52181f44b9 100644 --- a/lldb/unittests/tools/lldb-server/CMakeLists.txt +++ b/lldb/unittests/tools/lldb-server/CMakeLists.txt @@ -13,8 +13,13 @@ endfunction() add_lldb_test_executable(thread_inferior inferior/thread_inferior.cpp) add_lldb_test_executable(environment_check inferior/environment_check.cpp) -if(DEBUGSERVER_PATH) - add_definitions(-DLLDB_SERVER="${DEBUGSERVER_PATH}" -DLLDB_SERVER_IS_DEBUGSERVER=1) +if(LLDB_CAN_USE_DEBUGSERVER) + if(LLDB_USE_SYSTEM_DEBUGSERVER) + lldb_find_system_debugserver(debugserver_path) + else() + set(debugserver_path $) + endif() + add_definitions(-DLLDB_SERVER="${debugserver_path}" -DLLDB_SERVER_IS_DEBUGSERVER=1) else() add_definitions(-DLLDB_SERVER="$" -DLLDB_SERVER_IS_DEBUGSERVER=0) endif() diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt index b8eb19848bc5..15f1311ec3a6 100644 --- a/llvm/CMakeLists.txt +++ b/llvm/CMakeLists.txt @@ -25,7 +25,7 @@ if(NOT DEFINED LLVM_VERSION_PATCH) set(LLVM_VERSION_PATCH 0) endif() if(NOT DEFINED LLVM_VERSION_SUFFIX) - set(LLVM_VERSION_SUFFIX svn) + set(LLVM_VERSION_SUFFIX "") endif() if (NOT PACKAGE_VERSION) @@ -642,8 +642,6 @@ option(LLVM_ENABLE_PLUGINS "Enable plugin support" ${LLVM_ENABLE_PLUGINS_default include(HandleLLVMOptions) -# We support both Python 2 and 3. -set(Python_ADDITIONAL_VERSIONS 3.7 3.6 3.5 2.7) include(FindPythonInterp) if( NOT PYTHONINTERP_FOUND ) message(FATAL_ERROR @@ -831,6 +829,11 @@ if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") add_definitions("-D_LARGE_FILE_API") endif() +# Build with _FILE_OFFSET_BITS=64 on Solaris to match g++ >= 9. +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "SunOS") + add_definitions("-D_FILE_OFFSET_BITS=64") +endif() + # Work around a broken bfd ld behavior. When linking a binary with a # foo.so library, it will try to find any library that foo.so uses and # check its symbols. This is wasteful (the check was done when foo.so diff --git a/llvm/cmake/config-ix.cmake b/llvm/cmake/config-ix.cmake index 0218d42eb891..4c585b8fd5a2 100644 --- a/llvm/cmake/config-ix.cmake +++ b/llvm/cmake/config-ix.cmake @@ -30,6 +30,12 @@ if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX") list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D_LARGE_FILE_API") endif() +# Do checks with _FILE_OFFSET_BITS=64 on Solaris, because we will build +# with those too. +if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "SunOS") + list(APPEND CMAKE_REQUIRED_DEFINITIONS "-D_FILE_OFFSET_BITS=64") +endif() + # include checks check_include_file(dlfcn.h HAVE_DLFCN_H) check_include_file(errno.h HAVE_ERRNO_H) diff --git a/llvm/cmake/modules/LLVMInstallSymlink.cmake b/llvm/cmake/modules/LLVMInstallSymlink.cmake index 6f378f20d6ac..09fed8085c23 100644 --- a/llvm/cmake/modules/LLVMInstallSymlink.cmake +++ b/llvm/cmake/modules/LLVMInstallSymlink.cmake @@ -3,9 +3,9 @@ # See PR8397. function(install_symlink name target outdir) + set(DESTDIR $ENV{DESTDIR}) if(CMAKE_HOST_UNIX) set(LINK_OR_COPY create_symlink) - set(DESTDIR $ENV{DESTDIR}) else() set(LINK_OR_COPY copy) endif() diff --git a/llvm/docs/GettingStarted.rst b/llvm/docs/GettingStarted.rst index 742c7b96bc89..5f95095c7191 100644 --- a/llvm/docs/GettingStarted.rst +++ b/llvm/docs/GettingStarted.rst @@ -598,6 +598,11 @@ used by people developing LLVM. | CMAKE_INSTALL_PREFIX | Specifies the install directory to target when | | | running the install action of the build files. | +-------------------------+----------------------------------------------------+ +| PYTHON_EXECUTABLE | Forces CMake to use a specific Python version by | +| | passing a path to a Python interpreter. By default | +| | the Python version of the interpreter in your PATH | +| | is used. | ++-------------------------+----------------------------------------------------+ | LLVM_TARGETS_TO_BUILD | A semicolon delimited list controlling which | | | targets will be built and linked into llvm. | | | The default list is defined as | diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst index ebf2c8db7baf..6ef3ff90e836 100644 --- a/llvm/docs/ReleaseNotes.rst +++ b/llvm/docs/ReleaseNotes.rst @@ -5,12 +5,6 @@ LLVM 9.0.0 Release Notes .. contents:: :local: -.. warning:: - These are in-progress notes for the upcoming LLVM 9 release. - Release notes for previous releases can be found on - `the Download Page `_. - - Introduction ============ @@ -26,38 +20,130 @@ have questions or comments, the `LLVM Developer's Mailing List `_ is a good place to send them. -Note that if you are reading this file from a Subversion checkout or the main -LLVM web page, this document applies to the *next* release, not the current -one. To see the release notes for a specific release, please see the `releases -page `_. + +Known Issues +============ + +These are issues that couldn't be fixed before the release. See the bug reports +for the latest status. + +* `PR40547 `_ Clang gets miscompiled by GCC 9. + Non-comprehensive list of changes in this release ================================================= -.. NOTE - For small 1-3 sentence descriptions, just add an entry at the end of - this list. If your description won't fit comfortably in one bullet - point (e.g. maybe you would like to give an example of the - functionality, or simply have a lot to talk about), see the `NOTE` below - for adding a new subsection. + +* Two new extension points, namely ``EP_FullLinkTimeOptimizationEarly`` and + ``EP_FullLinkTimeOptimizationLast`` are available for plugins to specialize + the legacy pass manager full LTO pipeline. + +* ``llvm-objcopy/llvm-strip`` got support for COFF object files/executables, + supporting the most common copying/stripping options. + +* The CMake parameter ``CLANG_ANALYZER_ENABLE_Z3_SOLVER`` has been replaced by + ``LLVM_ENABLE_Z3_SOLVER``. + +* The RISCV target is no longer "experimental" (see + `Changes to the RISCV Target`_ below for more details). + +* The ORCv1 JIT API has been deprecated. Please see + `Transitioning from ORCv1 to ORCv2 `_. + +* Support for target-independent hardware loops in IR has been added, with + PowerPC and Arm implementations. + + +Noteworthy optimizations +------------------------ + +* LLVM will now remove stores to constant memory (since this is a + contradiction) under the assumption the code in question must be dead. This + has proven to be problematic for some C/C++ code bases which expect to be + able to cast away 'const'. This is (and has always been) undefined + behavior, but up until now had not been actively utilized for optimization + purposes in this exact way. For more information, please see: + `bug 42763 `_ and + `post commit discussion `_. * The optimizer will now convert calls to ``memcmp`` into a calls to ``bcmp`` in some circumstances. Users who are building freestanding code (not depending on the platform's libc) without specifying ``-ffreestanding`` may need to either pass ``-fno-builtin-bcmp``, or provide a ``bcmp`` function. -* Two new extension points, namely ``EP_FullLinkTimeOptimizationEarly`` and - ``EP_FullLinkTimeOptimizationLast`` are available for plugins to specialize - the legacy pass manager full LTO pipeline. +* LLVM will now pattern match wide scalar values stored by a succession of + narrow stores. For example, Clang will compile the following function that + writes a 32-bit value in big-endian order in a portable manner: + + .. code-block:: c + + void write32be(unsigned char *dst, uint32_t x) { + dst[0] = x >> 24; + dst[1] = x >> 16; + dst[2] = x >> 8; + dst[3] = x >> 0; + } + + into the x86_64 code below: + + .. code-block:: asm + + write32be: + bswap esi + mov dword ptr [rdi], esi + ret + + (The corresponding read patterns have been matched since LLVM 5.) + +* LLVM will now omit range checks for jump tables when lowering switches with + unreachable default destination. For example, the switch dispatch in the C++ + code below + + .. code-block:: c + + int g(int); + enum e { A, B, C, D, E }; + int f(e x, int y, int z) { + switch(x) { + case A: return g(y); + case B: return g(z); + case C: return g(y+z); + case D: return g(x-z); + case E: return g(x+z); + } + } + + will result in the following x86_64 machine code when compiled with Clang. + This is because falling off the end of a non-void function is undefined + behaviour in C++, and the end of the function therefore being treated as + unreachable: -.. NOTE - If you would like to document a larger change, then you can add a - subsection about it right here. You can copy the following boilerplate - and un-indent it (the indentation causes it to be inside this comment). + .. code-block:: asm - Special New Feature - ------------------- + _Z1f1eii: + mov eax, edi + jmp qword ptr [8*rax + .LJTI0_0] + + +* LLVM can now sink similar instructions to a common successor block also when + the instructions have no uses, such as calls to void functions. This allows + code such as + + .. code-block:: c + + void g(int); + enum e { A, B, C, D }; + void f(e x, int y, int z) { + switch(x) { + case A: g(6); break; + case B: g(3); break; + case C: g(9); break; + case D: g(2); break; + } + } + + to be optimized to a single call to ``g``, with the argument loaded from a + lookup table. - Makes programs 10x faster by doing Special New Thing. Changes to the LLVM IR ---------------------- @@ -86,61 +172,121 @@ Changes to building LLVM * Building LLVM with Visual Studio now requires version 2017 or later. +Changes to the AArch64 Backend +------------------------------ + +* Assembly-level support was added for: Scalable Vector Extension 2 (SVE2) and + Memory Tagging Extensions (MTE). + Changes to the ARM Backend -------------------------- - During this release ... +* Assembly-level support was added for the Armv8.1-M architecture, including + the M-Profile Vector Extension (MVE). + +* A pipeline model was added for Cortex-M4. This pipeline model is also used to + tune for cores where this gives a benefit too: Cortex-M3, SC300, Cortex-M33 + and Cortex-M35P. + +* Code generation support for M-profile low-overhead loops. Changes to the MIPS Target -------------------------- - During this release ... +* Support for ``.cplocal`` assembler directive. + +* Support for ``sge``, ``sgeu``, ``sgt``, ``sgtu`` pseudo instructions. + +* Support for ``o`` inline asm constraint. + +* Improved support of GlobalISel instruction selection framework. + This feature is still in experimental state for MIPS targets though. + +* Various code-gen improvements, related to improved and fixed instruction + selection and encoding and floating-point registers allocation. + +* Complete P5600 scheduling model. Changes to the PowerPC Target ----------------------------- - During this release ... +* Improved handling of TOC pointer spills for indirect calls -Changes to the X86 Target -------------------------- +* Improve precision of square root reciprocal estimate - During this release ... +* Enabled MachinePipeliner support for P9 with ``-ppc-enable-pipeliner``. -Changes to the AMDGPU Target ------------------------------ +* MMX/SSE/SSE2 intrinsics headers have been ported to PowerPC using Altivec. -* Function call support is now enabled by default +* Machine verification failures cleaned, EXPENSIVE_CHECKS will run + MachineVerification by default now. -* Improved support for 96-bit loads and stores +* PowerPC scheduling enhancements, with customized PPC specific scheduler + strategy. -* DPP combiner pass is now enabled by default +* Inner most loop now always align to 32 bytes. -* Support for gfx10 +* Enhancements of hardware loops interaction with LSR. -Changes to the AVR Target +* New builtins added, eg: ``__builtin_setrnd``. + +* Various codegen improvements for both scalar and vector code + +* Various new exploitations and bug fixes, e.g: exploited P9 ``maddld``. + + +Changes to the SystemZ Target ----------------------------- - During this release ... +* Support for the arch13 architecture has been added. When using the + ``-march=arch13`` option, the compiler will generate code making use of + new instructions introduced with the vector enhancement facility 2 + and the miscellaneous instruction extension facility 2. + The ``-mtune=arch13`` option enables arch13 specific instruction + scheduling and tuning without making use of new instructions. -Changes to the WebAssembly Target ---------------------------------- +* Builtins for the new vector instructions have been added and can be + enabled using the ``-mzvector`` option. Support for these builtins + is indicated by the compiler predefining the ``__VEC__`` macro to + the value ``10303``. - During this release ... +* The compiler now supports and automatically generates alignment hints + on vector load and store instructions. +* Various code-gen improvements, in particular related to improved + instruction selection and register allocation. -Changes to the OCaml bindings ------------------------------ +Changes to the X86 Target +------------------------- +* Fixed a bug in generating DWARF unwind information for 32 bit MinGW +Changes to the AMDGPU Target +---------------------------- -Changes to the C API --------------------- +* Function call support is now enabled by default +* Improved support for 96-bit loads and stores + +* DPP combiner pass is now enabled by default + +* Support for gfx10 + + +Changes to the RISCV Target +--------------------------- + +The RISCV target is no longer "experimental"! It's now built by default, +rather than needing to be enabled with ``LLVM_EXPERIMENTAL_TARGETS_TO_BUILD``. + +The backend has full codegen support for the RV32I and RV64I base RISC-V +instruction set variants, with the MAFDC standard extensions. We support the +hard and soft-float ABIs for these targets. Testing has been performed with +both Linux and bare-metal targets, including the compilation of a large corpus +of Linux applications (through buildroot). -Changes to the DAG infrastructure ---------------------------------- Changes to LLDB =============== @@ -156,7 +302,66 @@ Changes to LLDB External Open Source Projects Using LLVM 9 ========================================== -* A project... +Mull - Mutation Testing tool for C and C++ +------------------------------------------ + +`Mull `_ is an LLVM-based tool for +mutation testing with a strong focus on C and C++ languages. + +Portable Computing Language (pocl) +---------------------------------- + +In addition to producing an easily portable open source OpenCL +implementation, another major goal of `pocl `_ +is improving performance portability of OpenCL programs with +compiler optimizations, reducing the need for target-dependent manual +optimizations. An important part of pocl is a set of LLVM passes used to +statically parallelize multiple work-items with the kernel compiler, even in +the presence of work-group barriers. This enables static parallelization of +the fine-grained static concurrency in the work groups in multiple ways. + +TTA-based Co-design Environment (TCE) +------------------------------------- + +`TCE `_ is an open source toolset for designing customized +processors based on the Transport Triggered Architecture (TTA). +The toolset provides a complete co-design flow from C/C++ +programs down to synthesizable VHDL/Verilog and parallel program binaries. +Processor customization points include register files, function units, +supported operations, and the interconnection network. + +TCE uses Clang and LLVM for C/C++/OpenCL C language support, target independent +optimizations and also for parts of code generation. It generates new +LLVM-based code generators "on the fly" for the designed TTA processors and +loads them in to the compiler backend as runtime libraries to avoid +per-target recompilation of larger parts of the compiler chain. + + +Zig Programming Language +------------------------ + +`Zig `_ is a system programming language intended to be +an alternative to C. It provides high level features such as generics, compile +time function execution, and partial evaluation, while exposing low level LLVM +IR features such as aliases and intrinsics. Zig uses Clang to provide automatic +import of .h symbols, including inline functions and simple macros. Zig uses +LLD combined with lazily building compiler-rt to provide out-of-the-box +cross-compiling for all supported targets. + + +LDC - the LLVM-based D compiler +------------------------------- + +`D `_ is a language with C-like syntax and static typing. It +pragmatically combines efficiency, control, and modeling power, with safety and +programmer productivity. D supports powerful concepts like Compile-Time Function +Execution (CTFE) and Template Meta-Programming, provides an innovative approach +to concurrency and offers many classical paradigms. + +`LDC `_ uses the frontend from the reference compiler +combined with LLVM as backend to produce efficient native code. LDC targets +x86/x86_64 systems like Linux, OS X, FreeBSD and Windows and also Linux on ARM +and PowerPC (32/64 bit). Ports to other architectures are underway. Additional Information diff --git a/llvm/docs/index.rst b/llvm/docs/index.rst index cf1476789047..02779ff4534f 100644 --- a/llvm/docs/index.rst +++ b/llvm/docs/index.rst @@ -1,11 +1,6 @@ Overview ======== -.. warning:: - - If you are using a released version of LLVM, see `the download page - `_ to find your documentation. - The LLVM compiler infrastructure supports a wide range of projects, from industrial strength compilers to specialized JIT applications to small research projects. diff --git a/llvm/include/llvm/ADT/Triple.h b/llvm/include/llvm/ADT/Triple.h index edeb31efab80..3777be27ac6a 100644 --- a/llvm/include/llvm/ADT/Triple.h +++ b/llvm/include/llvm/ADT/Triple.h @@ -54,6 +54,7 @@ class Triple { avr, // AVR: Atmel AVR microcontroller bpfel, // eBPF or extended BPF or 64-bit BPF (little endian) bpfeb, // eBPF or extended BPF or 64-bit BPF (big endian) + cahp, hexagon, // Hexagon: hexagon mips, // MIPS: mips, mipsallegrex, mipsr6 mipsel, // MIPSEL: mipsel, mipsallegrexe, mipsr6el diff --git a/llvm/include/llvm/Analysis/AliasAnalysis.h b/llvm/include/llvm/Analysis/AliasAnalysis.h index 948341554f23..282142f51bb3 100644 --- a/llvm/include/llvm/Analysis/AliasAnalysis.h +++ b/llvm/include/llvm/Analysis/AliasAnalysis.h @@ -949,7 +949,7 @@ template class AAResultBase { /// A pointer to the AAResults object that this AAResult is /// aggregated within. May be null if not aggregated. - AAResults *AAR; + AAResults *AAR = nullptr; /// Helper to dispatch calls back through the derived type. DerivedT &derived() { return static_cast(*this); } diff --git a/llvm/include/llvm/Analysis/InstructionSimplify.h b/llvm/include/llvm/Analysis/InstructionSimplify.h index 054ffca7215e..c36ad4c50df9 100644 --- a/llvm/include/llvm/Analysis/InstructionSimplify.h +++ b/llvm/include/llvm/Analysis/InstructionSimplify.h @@ -31,6 +31,7 @@ #ifndef LLVM_ANALYSIS_INSTRUCTIONSIMPLIFY_H #define LLVM_ANALYSIS_INSTRUCTIONSIMPLIFY_H +#include "llvm/ADT/SetVector.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Operator.h" #include "llvm/IR/User.h" @@ -263,12 +264,14 @@ Value *SimplifyInstruction(Instruction *I, const SimplifyQuery &Q, /// This first performs a normal RAUW of I with SimpleV. It then recursively /// attempts to simplify those users updated by the operation. The 'I' /// instruction must not be equal to the simplified value 'SimpleV'. +/// If UnsimplifiedUsers is provided, instructions that could not be simplified +/// are added to it. /// /// The function returns true if any simplifications were performed. -bool replaceAndRecursivelySimplify(Instruction *I, Value *SimpleV, - const TargetLibraryInfo *TLI = nullptr, - const DominatorTree *DT = nullptr, - AssumptionCache *AC = nullptr); +bool replaceAndRecursivelySimplify( + Instruction *I, Value *SimpleV, const TargetLibraryInfo *TLI = nullptr, + const DominatorTree *DT = nullptr, AssumptionCache *AC = nullptr, + SmallSetVector *UnsimplifiedUsers = nullptr); /// Recursively attempt to simplify an instruction. /// diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h index 2bd711137845..e1fa610d9d31 100644 --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -311,6 +311,8 @@ enum { EM_RISCV = 243, // RISC-V EM_LANAI = 244, // Lanai 32-bit processor EM_BPF = 247, // Linux kernel bpf virtual machine + + EM_CAHP = 246, }; // Object file classes. @@ -611,6 +613,11 @@ enum { #include "ELFRelocs/Hexagon.def" }; +// ELF Relocation type for CAHP. +enum { +#include "ELFRelocs/CAHP.def" +}; + // ELF Relocation type for Lanai. enum { #include "ELFRelocs/Lanai.def" diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/CAHP.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/CAHP.def new file mode 100644 index 000000000000..61ad6d07d5aa --- /dev/null +++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/CAHP.def @@ -0,0 +1,9 @@ +#ifndef ELF_RELOC +#error "ELF_RELOC must be defined" +#endif + +ELF_RELOC(R_CAHP_NONE, 0) +ELF_RELOC(R_CAHP_16, 1) +ELF_RELOC(R_CAHP_HI6, 2) +ELF_RELOC(R_CAHP_LO10, 3) +ELF_RELOC(R_CAHP_PCREL_11, 4) diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h index 12a970847021..45a598c898c8 100644 --- a/llvm/include/llvm/CodeGen/SelectionDAG.h +++ b/llvm/include/llvm/CodeGen/SelectionDAG.h @@ -269,7 +269,13 @@ class SelectionDAG { using CallSiteInfo = MachineFunction::CallSiteInfo; using CallSiteInfoImpl = MachineFunction::CallSiteInfoImpl; - DenseMap SDCallSiteInfo; + + struct CallSiteDbgInfo { + CallSiteInfo CSInfo; + MDNode *HeapAllocSite = nullptr; + }; + + DenseMap SDCallSiteDbgInfo; uint16_t NextPersistentId = 0; @@ -1664,16 +1670,28 @@ class SelectionDAG { } void addCallSiteInfo(const SDNode *CallNode, CallSiteInfoImpl &&CallInfo) { - SDCallSiteInfo[CallNode] = std::move(CallInfo); + SDCallSiteDbgInfo[CallNode].CSInfo = std::move(CallInfo); } CallSiteInfo getSDCallSiteInfo(const SDNode *CallNode) { - auto I = SDCallSiteInfo.find(CallNode); - if (I != SDCallSiteInfo.end()) - return std::move(I->second); + auto I = SDCallSiteDbgInfo.find(CallNode); + if (I != SDCallSiteDbgInfo.end()) + return std::move(I->second).CSInfo; return CallSiteInfo(); } + void addHeapAllocSite(const SDNode *Node, MDNode *MD) { + SDCallSiteDbgInfo[Node].HeapAllocSite = MD; + } + + /// Return the HeapAllocSite type associated with the SDNode, if it exists. + MDNode *getHeapAllocSite(const SDNode *Node) { + auto It = SDCallSiteDbgInfo.find(Node); + if (It == SDCallSiteDbgInfo.end()) + return nullptr; + return It->second.HeapAllocSite; + } + private: void InsertNode(SDNode *N); bool RemoveNodeFromCSEMaps(SDNode *N); diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h index d5cca60bb1b2..ca7548cd8d6f 100644 --- a/llvm/include/llvm/CodeGen/TargetLowering.h +++ b/llvm/include/llvm/CodeGen/TargetLowering.h @@ -3665,6 +3665,7 @@ class TargetLowering : public TargetLoweringBase { C_Register, // Constraint represents specific register(s). C_RegisterClass, // Constraint represents any of register(s) in class. C_Memory, // Memory constraint. + C_Immediate, // Requires an immediate. C_Other, // Something else. C_Unknown // Unsupported constraint. }; diff --git a/llvm/include/llvm/ExecutionEngine/Orc/LambdaResolver.h b/llvm/include/llvm/ExecutionEngine/Orc/LambdaResolver.h index 855e31b33549..84cbc53b73a5 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/LambdaResolver.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/LambdaResolver.h @@ -16,6 +16,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ExecutionEngine/JITSymbol.h" +#include "llvm/ExecutionEngine/OrcV1Deprecation.h" #include namespace llvm { diff --git a/llvm/include/llvm/IR/InlineAsm.h b/llvm/include/llvm/IR/InlineAsm.h index 2aac807623a9..72d8ad1501ae 100644 --- a/llvm/include/llvm/IR/InlineAsm.h +++ b/llvm/include/llvm/IR/InlineAsm.h @@ -244,6 +244,7 @@ class InlineAsm final : public Value { Constraint_m, Constraint_o, Constraint_v, + Constraint_A, Constraint_Q, Constraint_R, Constraint_S, diff --git a/llvm/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h index 215ce45c7b75..6773664104a3 100644 --- a/llvm/include/llvm/IR/Instructions.h +++ b/llvm/include/llvm/IR/Instructions.h @@ -3938,6 +3938,9 @@ class CallBrInst : public CallBase { ArrayRef IndirectDests, ArrayRef Args, ArrayRef Bundles, const Twine &NameStr); + /// Should the Indirect Destinations change, scan + update the Arg list. + void updateArgBlockAddresses(unsigned i, BasicBlock *B); + /// Compute the number of operands to allocate. static int ComputeNumOperands(int NumArgs, int NumIndirectDests, int NumBundleInputs = 0) { @@ -4075,7 +4078,7 @@ class CallBrInst : public CallBase { return cast(*(&Op<-1>() - getNumIndirectDests() - 1)); } BasicBlock *getIndirectDest(unsigned i) const { - return cast(*(&Op<-1>() - getNumIndirectDests() + i)); + return cast_or_null(*(&Op<-1>() - getNumIndirectDests() + i)); } SmallVector getIndirectDests() const { SmallVector IndirectDests; @@ -4087,6 +4090,7 @@ class CallBrInst : public CallBase { *(&Op<-1>() - getNumIndirectDests() - 1) = reinterpret_cast(B); } void setIndirectDest(unsigned i, BasicBlock *B) { + updateArgBlockAddresses(i, B); *(&Op<-1>() - getNumIndirectDests() + i) = reinterpret_cast(B); } @@ -4096,11 +4100,10 @@ class CallBrInst : public CallBase { return i == 0 ? getDefaultDest() : getIndirectDest(i - 1); } - void setSuccessor(unsigned idx, BasicBlock *NewSucc) { - assert(idx < getNumIndirectDests() + 1 && + void setSuccessor(unsigned i, BasicBlock *NewSucc) { + assert(i < getNumIndirectDests() + 1 && "Successor # out of range for callbr!"); - *(&Op<-1>() - getNumIndirectDests() -1 + idx) = - reinterpret_cast(NewSucc); + return i == 0 ? setDefaultDest(NewSucc) : setIndirectDest(i - 1, NewSucc); } unsigned getNumSuccessors() const { return getNumIndirectDests() + 1; } diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h index 5c2124cc0d15..c40cd7c2c257 100644 --- a/llvm/include/llvm/MC/MCContext.h +++ b/llvm/include/llvm/MC/MCContext.h @@ -112,6 +112,9 @@ namespace llvm { /// number of section symbols with the same name). StringMap UsedNames; + /// Keeps track of labels that are used in inline assembly. + SymbolTable InlineAsmUsedLabelNames; + /// The next ID to dole out to an unnamed assembler temporary symbol with /// a given prefix. StringMap NextID; @@ -377,6 +380,16 @@ namespace llvm { /// APIs. const SymbolTable &getSymbols() const { return Symbols; } + /// isInlineAsmLabel - Return true if the name is a label referenced in + /// inline assembly. + MCSymbol *getInlineAsmLabel(StringRef Name) const { + return InlineAsmUsedLabelNames.lookup(Name); + } + + /// registerInlineAsmLabel - Records that the name is a label referenced in + /// inline assembly. + void registerInlineAsmLabel(MCSymbol *Sym); + /// @} /// \name Section Management diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h index 86c015efd704..990982e90a29 100644 --- a/llvm/include/llvm/Object/ELFObjectFile.h +++ b/llvm/include/llvm/Object/ELFObjectFile.h @@ -1059,6 +1059,8 @@ StringRef ELFObjectFile::getFileFormatName() const { return (IsLittleEndian ? "ELF32-arm-little" : "ELF32-arm-big"); case ELF::EM_AVR: return "ELF32-avr"; + case ELF::EM_CAHP: + return "ELF32-cahp"; case ELF::EM_HEXAGON: return "ELF32-hexagon"; case ELF::EM_LANAI: @@ -1124,6 +1126,8 @@ template Triple::ArchType ELFObjectFile::getArch() const { return Triple::arm; case ELF::EM_AVR: return Triple::avr; + case ELF::EM_CAHP: + return Triple::cahp; case ELF::EM_HEXAGON: return Triple::hexagon; case ELF::EM_LANAI: diff --git a/llvm/include/llvm/Support/AArch64TargetParser.def b/llvm/include/llvm/Support/AArch64TargetParser.def index e152f383b3ec..5cdf190a9f19 100644 --- a/llvm/include/llvm/Support/AArch64TargetParser.def +++ b/llvm/include/llvm/Support/AArch64TargetParser.def @@ -50,35 +50,35 @@ AARCH64_ARCH("armv8.5-a", ARMV8_5A, "8.5-A", "v8.5a", #define AARCH64_ARCH_EXT_NAME(NAME, ID, FEATURE, NEGFEATURE) #endif // FIXME: This would be nicer were it tablegen -AARCH64_ARCH_EXT_NAME("invalid", AArch64::AEK_INVALID, nullptr, nullptr) -AARCH64_ARCH_EXT_NAME("none", AArch64::AEK_NONE, nullptr, nullptr) -AARCH64_ARCH_EXT_NAME("crc", AArch64::AEK_CRC, "+crc", "-crc") -AARCH64_ARCH_EXT_NAME("lse", AArch64::AEK_LSE, "+lse", "-lse") -AARCH64_ARCH_EXT_NAME("rdm", AArch64::AEK_RDM, "+rdm", "-rdm") -AARCH64_ARCH_EXT_NAME("crypto", AArch64::AEK_CRYPTO, "+crypto","-crypto") -AARCH64_ARCH_EXT_NAME("sm4", AArch64::AEK_SM4, "+sm4", "-sm4") -AARCH64_ARCH_EXT_NAME("sha3", AArch64::AEK_SHA3, "+sha3", "-sha3") -AARCH64_ARCH_EXT_NAME("sha2", AArch64::AEK_SHA2, "+sha2", "-sha2") -AARCH64_ARCH_EXT_NAME("aes", AArch64::AEK_AES, "+aes", "-aes") -AARCH64_ARCH_EXT_NAME("dotprod", AArch64::AEK_DOTPROD, "+dotprod","-dotprod") -AARCH64_ARCH_EXT_NAME("fp", AArch64::AEK_FP, "+fp-armv8", "-fp-armv8") -AARCH64_ARCH_EXT_NAME("simd", AArch64::AEK_SIMD, "+neon", "-neon") -AARCH64_ARCH_EXT_NAME("fp16", AArch64::AEK_FP16, "+fullfp16", "-fullfp16") -AARCH64_ARCH_EXT_NAME("fp16fml", AArch64::AEK_FP16FML, "+fp16fml", "-fp16fml") -AARCH64_ARCH_EXT_NAME("profile", AArch64::AEK_PROFILE, "+spe", "-spe") -AARCH64_ARCH_EXT_NAME("ras", AArch64::AEK_RAS, "+ras", "-ras") -AARCH64_ARCH_EXT_NAME("sve", AArch64::AEK_SVE, "+sve", "-sve") -AARCH64_ARCH_EXT_NAME("sve2", AArch64::AEK_SVE2, "+sve2", "-sve2") -AARCH64_ARCH_EXT_NAME("sve2-aes", AArch64::AEK_SVE2AES, "+sve2-aes", "-sve2-aes") -AARCH64_ARCH_EXT_NAME("sve2-sm4", AArch64::AEK_SVE2SM4, "+sve2-sm4", "-sve2-sm4") -AARCH64_ARCH_EXT_NAME("sve2-sha3", AArch64::AEK_SVE2SHA3, "+sve2-sha3", "-sve2-sha3") -AARCH64_ARCH_EXT_NAME("bitperm", AArch64::AEK_BITPERM, "+bitperm", "-bitperm") -AARCH64_ARCH_EXT_NAME("rcpc", AArch64::AEK_RCPC, "+rcpc", "-rcpc") -AARCH64_ARCH_EXT_NAME("rng", AArch64::AEK_RAND, "+rand", "-rand") -AARCH64_ARCH_EXT_NAME("memtag", AArch64::AEK_MTE, "+mte", "-mte") -AARCH64_ARCH_EXT_NAME("ssbs", AArch64::AEK_SSBS, "+ssbs", "-ssbs") -AARCH64_ARCH_EXT_NAME("sb", AArch64::AEK_SB, "+sb", "-sb") -AARCH64_ARCH_EXT_NAME("predres", AArch64::AEK_PREDRES, "+predres", "-predres") +AARCH64_ARCH_EXT_NAME("invalid", AArch64::AEK_INVALID, nullptr, nullptr) +AARCH64_ARCH_EXT_NAME("none", AArch64::AEK_NONE, nullptr, nullptr) +AARCH64_ARCH_EXT_NAME("crc", AArch64::AEK_CRC, "+crc", "-crc") +AARCH64_ARCH_EXT_NAME("lse", AArch64::AEK_LSE, "+lse", "-lse") +AARCH64_ARCH_EXT_NAME("rdm", AArch64::AEK_RDM, "+rdm", "-rdm") +AARCH64_ARCH_EXT_NAME("crypto", AArch64::AEK_CRYPTO, "+crypto","-crypto") +AARCH64_ARCH_EXT_NAME("sm4", AArch64::AEK_SM4, "+sm4", "-sm4") +AARCH64_ARCH_EXT_NAME("sha3", AArch64::AEK_SHA3, "+sha3", "-sha3") +AARCH64_ARCH_EXT_NAME("sha2", AArch64::AEK_SHA2, "+sha2", "-sha2") +AARCH64_ARCH_EXT_NAME("aes", AArch64::AEK_AES, "+aes", "-aes") +AARCH64_ARCH_EXT_NAME("dotprod", AArch64::AEK_DOTPROD, "+dotprod","-dotprod") +AARCH64_ARCH_EXT_NAME("fp", AArch64::AEK_FP, "+fp-armv8", "-fp-armv8") +AARCH64_ARCH_EXT_NAME("simd", AArch64::AEK_SIMD, "+neon", "-neon") +AARCH64_ARCH_EXT_NAME("fp16", AArch64::AEK_FP16, "+fullfp16", "-fullfp16") +AARCH64_ARCH_EXT_NAME("fp16fml", AArch64::AEK_FP16FML, "+fp16fml", "-fp16fml") +AARCH64_ARCH_EXT_NAME("profile", AArch64::AEK_PROFILE, "+spe", "-spe") +AARCH64_ARCH_EXT_NAME("ras", AArch64::AEK_RAS, "+ras", "-ras") +AARCH64_ARCH_EXT_NAME("sve", AArch64::AEK_SVE, "+sve", "-sve") +AARCH64_ARCH_EXT_NAME("sve2", AArch64::AEK_SVE2, "+sve2", "-sve2") +AARCH64_ARCH_EXT_NAME("sve2-aes", AArch64::AEK_SVE2AES, "+sve2-aes", "-sve2-aes") +AARCH64_ARCH_EXT_NAME("sve2-sm4", AArch64::AEK_SVE2SM4, "+sve2-sm4", "-sve2-sm4") +AARCH64_ARCH_EXT_NAME("sve2-sha3", AArch64::AEK_SVE2SHA3, "+sve2-sha3", "-sve2-sha3") +AARCH64_ARCH_EXT_NAME("sve2-bitperm", AArch64::AEK_SVE2BITPERM, "+sve2-bitperm", "-sve2-bitperm") +AARCH64_ARCH_EXT_NAME("rcpc", AArch64::AEK_RCPC, "+rcpc", "-rcpc") +AARCH64_ARCH_EXT_NAME("rng", AArch64::AEK_RAND, "+rand", "-rand") +AARCH64_ARCH_EXT_NAME("memtag", AArch64::AEK_MTE, "+mte", "-mte") +AARCH64_ARCH_EXT_NAME("ssbs", AArch64::AEK_SSBS, "+ssbs", "-ssbs") +AARCH64_ARCH_EXT_NAME("sb", AArch64::AEK_SB, "+sb", "-sb") +AARCH64_ARCH_EXT_NAME("predres", AArch64::AEK_PREDRES, "+predres", "-predres") #undef AARCH64_ARCH_EXT_NAME #ifndef AARCH64_CPU_NAME diff --git a/llvm/include/llvm/Support/AArch64TargetParser.h b/llvm/include/llvm/Support/AArch64TargetParser.h index 965d38535e74..a2d2cf32d715 100644 --- a/llvm/include/llvm/Support/AArch64TargetParser.h +++ b/llvm/include/llvm/Support/AArch64TargetParser.h @@ -53,7 +53,7 @@ enum ArchExtKind : unsigned { AEK_SVE2AES = 1 << 24, AEK_SVE2SM4 = 1 << 25, AEK_SVE2SHA3 = 1 << 26, - AEK_BITPERM = 1 << 27, + AEK_SVE2BITPERM = 1 << 27, }; enum class ArchKind { diff --git a/llvm/include/llvm/Support/ARMTargetParser.h b/llvm/include/llvm/Support/ARMTargetParser.h index 4b9070dea596..02d4c975129f 100644 --- a/llvm/include/llvm/Support/ARMTargetParser.h +++ b/llvm/include/llvm/Support/ARMTargetParser.h @@ -39,19 +39,13 @@ enum ArchExtKind : unsigned { AEK_DSP = 1 << 10, AEK_FP16 = 1 << 11, AEK_RAS = 1 << 12, - AEK_SVE = 1 << 13, - AEK_DOTPROD = 1 << 14, - AEK_SHA2 = 1 << 15, - AEK_AES = 1 << 16, - AEK_FP16FML = 1 << 17, - AEK_SB = 1 << 18, - AEK_SVE2 = 1 << 19, - AEK_SVE2AES = 1 << 20, - AEK_SVE2SM4 = 1 << 21, - AEK_SVE2SHA3 = 1 << 22, - AEK_BITPERM = 1 << 23, - AEK_FP_DP = 1 << 24, - AEK_LOB = 1 << 25, + AEK_DOTPROD = 1 << 13, + AEK_SHA2 = 1 << 14, + AEK_AES = 1 << 15, + AEK_FP16FML = 1 << 16, + AEK_SB = 1 << 17, + AEK_FP_DP = 1 << 18, + AEK_LOB = 1 << 19, // Unsupported extensions. AEK_OS = 0x8000000, AEK_IWMMXT = 0x10000000, diff --git a/llvm/include/llvm/Transforms/Utils/BypassSlowDivision.h b/llvm/include/llvm/Transforms/Utils/BypassSlowDivision.h index 471055921fa8..994b6ec9c229 100644 --- a/llvm/include/llvm/Transforms/Utils/BypassSlowDivision.h +++ b/llvm/include/llvm/Transforms/Utils/BypassSlowDivision.h @@ -19,6 +19,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMapInfo.h" +#include "llvm/IR/ValueHandle.h" #include namespace llvm { @@ -28,8 +29,8 @@ class Value; struct DivRemMapKey { bool SignedOp; - Value *Dividend; - Value *Divisor; + AssertingVH Dividend; + AssertingVH Divisor; DivRemMapKey(bool InSignedOp, Value *InDividend, Value *InDivisor) : SignedOp(InSignedOp), Dividend(InDividend), Divisor(InDivisor) {} @@ -50,8 +51,10 @@ template <> struct DenseMapInfo { } static unsigned getHashValue(const DivRemMapKey &Val) { - return (unsigned)(reinterpret_cast(Val.Dividend) ^ - reinterpret_cast(Val.Divisor)) ^ + return (unsigned)(reinterpret_cast( + static_cast(Val.Dividend)) ^ + reinterpret_cast( + static_cast(Val.Divisor))) ^ (unsigned)Val.SignedOp; } }; diff --git a/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h b/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h index b144006e2628..d7c1c2738ffe 100644 --- a/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h +++ b/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h @@ -452,8 +452,8 @@ class LoopVectorizationLegality { /// Holds the widest induction type encountered. Type *WidestIndTy = nullptr; - /// Allowed outside users. This holds the induction and reduction - /// vars which can be accessed from outside the loop. + /// Allowed outside users. This holds the variables that can be accessed from + /// outside the loop. SmallPtrSet AllowedExit; /// Can we assume the absence of NaNs. diff --git a/llvm/include/llvm/module.modulemap b/llvm/include/llvm/module.modulemap index 9c4668e1473c..7138ef5a283e 100644 --- a/llvm/include/llvm/module.modulemap +++ b/llvm/include/llvm/module.modulemap @@ -61,6 +61,7 @@ module LLVM_BinaryFormat { textual header "BinaryFormat/ELFRelocs/ARC.def" textual header "BinaryFormat/ELFRelocs/AVR.def" textual header "BinaryFormat/ELFRelocs/BPF.def" + textual header "BinaryFormat/ELFRelocs/CAHP.def" textual header "BinaryFormat/ELFRelocs/Hexagon.def" textual header "BinaryFormat/ELFRelocs/i386.def" textual header "BinaryFormat/ELFRelocs/Lanai.def" diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index e34bf6f4e43f..941a68c5e6fd 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -5221,14 +5221,16 @@ Value *llvm::SimplifyInstruction(Instruction *I, const SimplifyQuery &SQ, /// If we have a pre-simplified value in 'SimpleV', that is forcibly used to /// replace the instruction 'I'. Otherwise, we simply add 'I' to the list of /// instructions to process and attempt to simplify it using -/// InstructionSimplify. +/// InstructionSimplify. Recursively visited users which could not be +/// simplified themselves are to the optional UnsimplifiedUsers set for +/// further processing by the caller. /// /// This routine returns 'true' only when *it* simplifies something. The passed /// in simplified value does not count toward this. -static bool replaceAndRecursivelySimplifyImpl(Instruction *I, Value *SimpleV, - const TargetLibraryInfo *TLI, - const DominatorTree *DT, - AssumptionCache *AC) { +static bool replaceAndRecursivelySimplifyImpl( + Instruction *I, Value *SimpleV, const TargetLibraryInfo *TLI, + const DominatorTree *DT, AssumptionCache *AC, + SmallSetVector *UnsimplifiedUsers = nullptr) { bool Simplified = false; SmallSetVector Worklist; const DataLayout &DL = I->getModule()->getDataLayout(); @@ -5258,8 +5260,11 @@ static bool replaceAndRecursivelySimplifyImpl(Instruction *I, Value *SimpleV, // See if this instruction simplifies. SimpleV = SimplifyInstruction(I, {DL, TLI, DT, AC}); - if (!SimpleV) + if (!SimpleV) { + if (UnsimplifiedUsers) + UnsimplifiedUsers->insert(I); continue; + } Simplified = true; @@ -5285,16 +5290,17 @@ bool llvm::recursivelySimplifyInstruction(Instruction *I, const TargetLibraryInfo *TLI, const DominatorTree *DT, AssumptionCache *AC) { - return replaceAndRecursivelySimplifyImpl(I, nullptr, TLI, DT, AC); + return replaceAndRecursivelySimplifyImpl(I, nullptr, TLI, DT, AC, nullptr); } -bool llvm::replaceAndRecursivelySimplify(Instruction *I, Value *SimpleV, - const TargetLibraryInfo *TLI, - const DominatorTree *DT, - AssumptionCache *AC) { +bool llvm::replaceAndRecursivelySimplify( + Instruction *I, Value *SimpleV, const TargetLibraryInfo *TLI, + const DominatorTree *DT, AssumptionCache *AC, + SmallSetVector *UnsimplifiedUsers) { assert(I != SimpleV && "replaceAndRecursivelySimplify(X,X) is not valid!"); assert(SimpleV && "Must provide a simplified value."); - return replaceAndRecursivelySimplifyImpl(I, SimpleV, TLI, DT, AC); + return replaceAndRecursivelySimplifyImpl(I, SimpleV, TLI, DT, AC, + UnsimplifiedUsers); } namespace llvm { diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp index 7721e996aca5..5e49fec9c053 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp @@ -432,6 +432,7 @@ static void EmitGCCInlineAsmStr(const char *AsmStr, const MachineInstr *MI, const BlockAddress *BA = MI->getOperand(OpNo).getBlockAddress(); MCSymbol *Sym = AP->GetBlockAddressSymbol(BA); Sym->print(OS, AP->MAI); + MMI->getContext().registerInlineAsmLabel(Sym); } else if (MI->getOperand(OpNo).isMBB()) { const MCSymbol *Sym = MI->getOperand(OpNo).getMBB()->getSymbol(); Sym->print(OS, AP->MAI); diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp index 52b4bbea012b..e6f2aa9ef930 100644 --- a/llvm/lib/CodeGen/CodeGenPrepare.cpp +++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -1682,10 +1682,11 @@ static bool OptimizeExtractBits(BinaryOperator *ShiftI, ConstantInt *CI, TheUse = InsertedShift; } - // If we removed all uses, nuke the shift. + // If we removed all uses, or there are none, nuke the shift. if (ShiftI->use_empty()) { salvageDebugInfo(*ShiftI); ShiftI->eraseFromParent(); + MadeChange = true; } return MadeChange; diff --git a/llvm/lib/CodeGen/IfConversion.cpp b/llvm/lib/CodeGen/IfConversion.cpp index b17a253fe23f..af556e2c856e 100644 --- a/llvm/lib/CodeGen/IfConversion.cpp +++ b/llvm/lib/CodeGen/IfConversion.cpp @@ -912,6 +912,12 @@ void IfConverter::AnalyzeBranches(BBInfo &BBI) { BBI.BrCond.clear(); BBI.IsBrAnalyzable = !TII->analyzeBranch(*BBI.BB, BBI.TrueBB, BBI.FalseBB, BBI.BrCond); + if (!BBI.IsBrAnalyzable) { + BBI.TrueBB = nullptr; + BBI.FalseBB = nullptr; + BBI.BrCond.clear(); + } + SmallVector RevCond(BBI.BrCond.begin(), BBI.BrCond.end()); BBI.IsBrReversible = (RevCond.size() == 0) || !TII->reverseBranchCondition(RevCond); @@ -1758,9 +1764,15 @@ bool IfConverter::IfConvertDiamondCommon( if (!BBI1->IsBrAnalyzable) verifySameBranchInstructions(&MBB1, &MBB2); #endif - BBI1->NonPredSize -= TII->removeBranch(*BBI1->BB); - // Remove duplicated instructions. + // Remove duplicated instructions from the tail of MBB1: any branch + // instructions, and the common instructions counted by NumDups2. DI1 = MBB1.end(); + while (DI1 != MBB1.begin()) { + MachineBasicBlock::iterator Prev = std::prev(DI1); + if (!Prev->isBranch() && !Prev->isDebugInstr()) + break; + DI1 = Prev; + } for (unsigned i = 0; i != NumDups2; ) { // NumDups2 only counted non-dbg_value instructions, so this won't // run off the head of the list. diff --git a/llvm/lib/CodeGen/LiveDebugValues.cpp b/llvm/lib/CodeGen/LiveDebugValues.cpp index a669e64692b9..05e994c9eb51 100644 --- a/llvm/lib/CodeGen/LiveDebugValues.cpp +++ b/llvm/lib/CodeGen/LiveDebugValues.cpp @@ -691,9 +691,17 @@ void LiveDebugValues::insertTransferDebugPair( "No register supplied when handling a restore of a debug value"); MachineFunction *MF = MI.getMF(); DIBuilder DIB(*const_cast(MF->getFunction()).getParent()); + + const DIExpression *NewExpr; + if (auto Fragment = DebugInstr->getDebugExpression()->getFragmentInfo()) + NewExpr = *DIExpression::createFragmentExpression(DIB.createExpression(), + Fragment->OffsetInBits, Fragment->SizeInBits); + else + NewExpr = DIB.createExpression(); + NewDebugInstr = BuildMI(*MF, DebugInstr->getDebugLoc(), DebugInstr->getDesc(), false, - NewReg, DebugInstr->getDebugVariable(), DIB.createExpression()); + NewReg, DebugInstr->getDebugVariable(), NewExpr); VarLoc VL(*NewDebugInstr, LS); ProcessVarLoc(VL, NewDebugInstr); LLVM_DEBUG(dbgs() << "Creating DBG_VALUE inst for register restore: "; @@ -848,9 +856,14 @@ void LiveDebugValues::transferSpillOrRestoreInst(MachineInstr &MI, << "\n"); } // Check if the register or spill location is the location of a debug value. + // FIXME: Don't create a spill transfer if there is a complex expression, + // because we currently cannot recover the original expression on restore. for (unsigned ID : OpenRanges.getVarLocs()) { + const MachineInstr *DebugInstr = &VarLocIDs[ID].MI; + if (TKind == TransferKind::TransferSpill && - VarLocIDs[ID].isDescribedByReg() == Reg) { + VarLocIDs[ID].isDescribedByReg() == Reg && + !DebugInstr->getDebugExpression()->isComplex()) { LLVM_DEBUG(dbgs() << "Spilling Register " << printReg(Reg, TRI) << '(' << VarLocIDs[ID].Var.getVar()->getName() << ")\n"); } else if (TKind == TransferKind::TransferRestore && diff --git a/llvm/lib/CodeGen/MachineCSE.cpp b/llvm/lib/CodeGen/MachineCSE.cpp index 2df6d40d9293..a5af5cb72df9 100644 --- a/llvm/lib/CodeGen/MachineCSE.cpp +++ b/llvm/lib/CodeGen/MachineCSE.cpp @@ -21,6 +21,7 @@ #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/CFG.h" #include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineBlockFrequencyInfo.h" #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionPass.h" @@ -66,6 +67,7 @@ namespace { AliasAnalysis *AA; MachineDominatorTree *DT; MachineRegisterInfo *MRI; + MachineBlockFrequencyInfo *MBFI; public: static char ID; // Pass identification @@ -83,6 +85,8 @@ namespace { AU.addPreservedID(MachineLoopInfoID); AU.addRequired(); AU.addPreserved(); + AU.addRequired(); + AU.addPreserved(); } void releaseMemory() override { @@ -133,6 +137,11 @@ namespace { bool isPRECandidate(MachineInstr *MI); bool ProcessBlockPRE(MachineDominatorTree *MDT, MachineBasicBlock *MBB); bool PerformSimplePRE(MachineDominatorTree *DT); + /// Heuristics to see if it's beneficial to move common computations of MBB + /// and MBB1 to CandidateBB. + bool isBeneficalToHoistInto(MachineBasicBlock *CandidateBB, + MachineBasicBlock *MBB, + MachineBasicBlock *MBB1); }; } // end anonymous namespace @@ -802,6 +811,9 @@ bool MachineCSE::ProcessBlockPRE(MachineDominatorTree *DT, if (!CMBB->isLegalToHoistInto()) continue; + if (!isBeneficalToHoistInto(CMBB, MBB, MBB1)) + continue; + // Two instrs are partial redundant if their basic blocks are reachable // from one to another but one doesn't dominate another. if (CMBB != MBB1) { @@ -854,6 +866,18 @@ bool MachineCSE::PerformSimplePRE(MachineDominatorTree *DT) { return Changed; } +bool MachineCSE::isBeneficalToHoistInto(MachineBasicBlock *CandidateBB, + MachineBasicBlock *MBB, + MachineBasicBlock *MBB1) { + if (CandidateBB->getParent()->getFunction().hasMinSize()) + return true; + assert(DT->dominates(CandidateBB, MBB) && "CandidateBB should dominate MBB"); + assert(DT->dominates(CandidateBB, MBB1) && + "CandidateBB should dominate MBB1"); + return MBFI->getBlockFreq(CandidateBB) <= + MBFI->getBlockFreq(MBB) + MBFI->getBlockFreq(MBB1); +} + bool MachineCSE::runOnMachineFunction(MachineFunction &MF) { if (skipFunction(MF.getFunction())) return false; @@ -863,6 +887,7 @@ bool MachineCSE::runOnMachineFunction(MachineFunction &MF) { MRI = &MF.getRegInfo(); AA = &getAnalysis().getAAResults(); DT = &getAnalysis(); + MBFI = &getAnalysis(); LookAheadLimit = TII->getMachineCSELookAheadLimit(); bool ChangedPRE, ChangedCSE; ChangedPRE = PerformSimplePRE(DT); diff --git a/llvm/lib/CodeGen/MachineModuleInfo.cpp b/llvm/lib/CodeGen/MachineModuleInfo.cpp index aadcd7319799..2e720018262c 100644 --- a/llvm/lib/CodeGen/MachineModuleInfo.cpp +++ b/llvm/lib/CodeGen/MachineModuleInfo.cpp @@ -121,7 +121,7 @@ ArrayRef MMIAddrLabelMap::getAddrLabelSymbolToEmit(BasicBlock *BB) { BBCallbacks.back().setMap(this); Entry.Index = BBCallbacks.size() - 1; Entry.Fn = BB->getParent(); - Entry.Symbols.push_back(Context.createTempSymbol()); + Entry.Symbols.push_back(Context.createTempSymbol(!BB->hasAddressTaken())); return Entry.Symbols; } diff --git a/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp b/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp index 568c6191e512..e09f2e760f55 100644 --- a/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp @@ -909,6 +909,12 @@ EmitSchedule(MachineBasicBlock::iterator &InsertPos) { // Remember the source order of the inserted instruction. if (HasDbg) ProcessSourceNode(N, DAG, Emitter, VRBaseMap, Orders, Seen, NewInsn); + + if (MDNode *MD = DAG->getHeapAllocSite(N)) { + if (NewInsn && NewInsn->isCall()) + MF.addCodeViewHeapAllocSite(NewInsn, MD); + } + GluedNodes.pop_back(); } auto NewInsn = @@ -917,6 +923,10 @@ EmitSchedule(MachineBasicBlock::iterator &InsertPos) { if (HasDbg) ProcessSourceNode(SU->getNode(), DAG, Emitter, VRBaseMap, Orders, Seen, NewInsn); + if (MDNode *MD = DAG->getHeapAllocSite(SU->getNode())) { + if (NewInsn && NewInsn->isCall()) + MF.addCodeViewHeapAllocSite(NewInsn, MD); + } } // Insert all the dbg_values which have not already been inserted in source diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 5852e693fa9f..6b0245dfd380 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -1084,6 +1084,7 @@ void SelectionDAG::clear() { ExternalSymbols.clear(); TargetExternalSymbols.clear(); MCSymbols.clear(); + SDCallSiteDbgInfo.clear(); std::fill(CondCodeNodes.begin(), CondCodeNodes.end(), static_cast(nullptr)); std::fill(ValueTypeNodes.begin(), ValueTypeNodes.end(), diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index e818dd27c05e..4120a401b696 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -1810,7 +1810,7 @@ void SelectionDAGBuilder::visitRet(const ReturnInst &I) { // offsets to its parts don't wrap either. SDValue Ptr = DAG.getObjectPtrOffset(getCurSDLoc(), RetPtr, Offsets[i]); - SDValue Val = RetOp.getValue(i); + SDValue Val = RetOp.getValue(RetOp.getResNo() + i); if (MemVTs[i] != ValueVTs[i]) Val = DAG.getPtrExtOrTrunc(Val, getCurSDLoc(), MemVTs[i]); Chains[i] = DAG.getStore(Chain, getCurSDLoc(), Val, @@ -8021,6 +8021,14 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { // Compute the constraint code and ConstraintType to use. TLI.ComputeConstraintToUse(T, SDValue()); + if (T.ConstraintType == TargetLowering::C_Immediate && + OpInfo.CallOperand && !isa(OpInfo.CallOperand)) + // We've delayed emitting a diagnostic like the "n" constraint because + // inlining could cause an integer showing up. + return emitInlineAsmError( + CS, "constraint '" + Twine(T.ConstraintCode) + "' expects an " + "integer constant expression"); + ExtraInfo.update(T); } @@ -8105,7 +8113,8 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { switch (OpInfo.Type) { case InlineAsm::isOutput: if (OpInfo.ConstraintType == TargetLowering::C_Memory || - (OpInfo.ConstraintType == TargetLowering::C_Other && + ((OpInfo.ConstraintType == TargetLowering::C_Immediate || + OpInfo.ConstraintType == TargetLowering::C_Other) && OpInfo.isIndirect)) { unsigned ConstraintID = TLI.getInlineAsmMemConstraint(OpInfo.ConstraintCode); @@ -8119,13 +8128,14 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { MVT::i32)); AsmNodeOperands.push_back(OpInfo.CallOperand); break; - } else if ((OpInfo.ConstraintType == TargetLowering::C_Other && + } else if (((OpInfo.ConstraintType == TargetLowering::C_Immediate || + OpInfo.ConstraintType == TargetLowering::C_Other) && !OpInfo.isIndirect) || OpInfo.ConstraintType == TargetLowering::C_Register || OpInfo.ConstraintType == TargetLowering::C_RegisterClass) { // Otherwise, this outputs to a register (directly for C_Register / - // C_RegisterClass, and a target-defined fashion for C_Other). Find a - // register that we can use. + // C_RegisterClass, and a target-defined fashion for + // C_Immediate/C_Other). Find a register that we can use. if (OpInfo.AssignedRegs.Regs.empty()) { emitInlineAsmError( CS, "couldn't allocate output register for constraint '" + @@ -8205,15 +8215,24 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { } // Treat indirect 'X' constraint as memory. - if (OpInfo.ConstraintType == TargetLowering::C_Other && + if ((OpInfo.ConstraintType == TargetLowering::C_Immediate || + OpInfo.ConstraintType == TargetLowering::C_Other) && OpInfo.isIndirect) OpInfo.ConstraintType = TargetLowering::C_Memory; - if (OpInfo.ConstraintType == TargetLowering::C_Other) { + if (OpInfo.ConstraintType == TargetLowering::C_Immediate || + OpInfo.ConstraintType == TargetLowering::C_Other) { std::vector Ops; TLI.LowerAsmOperandForConstraint(InOperandVal, OpInfo.ConstraintCode, Ops, DAG); if (Ops.empty()) { + if (OpInfo.ConstraintType == TargetLowering::C_Immediate) + if (isa(InOperandVal)) { + emitInlineAsmError(CS, "value out of range for constraint '" + + Twine(OpInfo.ConstraintCode) + "'"); + return; + } + emitInlineAsmError(CS, "invalid operand for inline asm constraint '" + Twine(OpInfo.ConstraintCode) + "'"); return; @@ -8250,7 +8269,8 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { } assert((OpInfo.ConstraintType == TargetLowering::C_RegisterClass || - OpInfo.ConstraintType == TargetLowering::C_Register) && + OpInfo.ConstraintType == TargetLowering::C_Register || + OpInfo.ConstraintType == TargetLowering::C_Immediate) && "Unknown constraint type!"); // TODO: Support this. @@ -8356,6 +8376,7 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { Val = OpInfo.AssignedRegs.getCopyFromRegs( DAG, FuncInfo, getCurSDLoc(), Chain, &Flag, CS.getInstruction()); break; + case TargetLowering::C_Immediate: case TargetLowering::C_Other: Val = TLI.LowerAsmOutputForConstraint(Chain, Flag, getCurSDLoc(), OpInfo, DAG); diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index b260cd91d468..2d90dcba12b6 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -3567,15 +3567,17 @@ TargetLowering::getConstraintType(StringRef Constraint) const { if (S == 1) { switch (Constraint[0]) { default: break; - case 'r': return C_RegisterClass; + case 'r': + return C_RegisterClass; case 'm': // memory case 'o': // offsetable case 'V': // not offsetable return C_Memory; - case 'i': // Simple Integer or Relocatable Constant case 'n': // Simple Integer case 'E': // Floating Point Constant case 'F': // Floating Point Constant + return C_Immediate; + case 'i': // Simple Integer or Relocatable Constant case 's': // Relocatable Constant case 'p': // Address. case 'X': // Allow ANY value. @@ -3950,6 +3952,7 @@ TargetLowering::ParseConstraints(const DataLayout &DL, /// Return an integer indicating how general CT is. static unsigned getConstraintGenerality(TargetLowering::ConstraintType CT) { switch (CT) { + case TargetLowering::C_Immediate: case TargetLowering::C_Other: case TargetLowering::C_Unknown: return 0; @@ -4069,11 +4072,12 @@ static void ChooseConstraint(TargetLowering::AsmOperandInfo &OpInfo, TargetLowering::ConstraintType CType = TLI.getConstraintType(OpInfo.Codes[i]); - // If this is an 'other' constraint, see if the operand is valid for it. - // For example, on X86 we might have an 'rI' constraint. If the operand - // is an integer in the range [0..31] we want to use I (saving a load - // of a register), otherwise we must use 'r'. - if (CType == TargetLowering::C_Other && Op.getNode()) { + // If this is an 'other' or 'immediate' constraint, see if the operand is + // valid for it. For example, on X86 we might have an 'rI' constraint. If + // the operand is an integer in the range [0..31] we want to use I (saving a + // load of a register), otherwise we must use 'r'. + if ((CType == TargetLowering::C_Other || + CType == TargetLowering::C_Immediate) && Op.getNode()) { assert(OpInfo.Codes[i].size() == 1 && "Unhandled multi-letter 'other' constraint"); std::vector ResultOps; diff --git a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt index 2c1a772da372..d65dc877bf8b 100644 --- a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt +++ b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt @@ -33,4 +33,5 @@ target_link_libraries(LLVMOrcJIT PRIVATE LLVMBitReader LLVMBitWriter + LLVMPasses ) diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp index 310935b5213a..af9ba7b3ca69 100644 --- a/llvm/lib/IR/Core.cpp +++ b/llvm/lib/IR/Core.cpp @@ -140,7 +140,16 @@ unsigned LLVMGetLastEnumAttributeKind(void) { LLVMAttributeRef LLVMCreateEnumAttribute(LLVMContextRef C, unsigned KindID, uint64_t Val) { - return wrap(Attribute::get(*unwrap(C), (Attribute::AttrKind)KindID, Val)); + auto &Ctx = *unwrap(C); + auto AttrKind = (Attribute::AttrKind)KindID; + + if (AttrKind == Attribute::AttrKind::ByVal) { + // After r362128, byval attributes need to have a type attribute. Provide a + // NULL one until a proper API is added for this. + return wrap(Attribute::getWithByValType(Ctx, NULL)); + } else { + return wrap(Attribute::get(Ctx, AttrKind, Val)); + } } unsigned LLVMGetEnumAttributeKind(LLVMAttributeRef A) { diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp index 2e7cad103c12..90cb2c26e082 100644 --- a/llvm/lib/IR/Instructions.cpp +++ b/llvm/lib/IR/Instructions.cpp @@ -822,6 +822,17 @@ void CallBrInst::init(FunctionType *FTy, Value *Fn, BasicBlock *Fallthrough, setName(NameStr); } +void CallBrInst::updateArgBlockAddresses(unsigned i, BasicBlock *B) { + assert(getNumIndirectDests() > i && "IndirectDest # out of range for callbr"); + if (BasicBlock *OldBB = getIndirectDest(i)) { + BlockAddress *Old = BlockAddress::get(OldBB); + BlockAddress *New = BlockAddress::get(B); + for (unsigned ArgNo = 0, e = getNumArgOperands(); ArgNo != e; ++ArgNo) + if (dyn_cast(getArgOperand(ArgNo)) == Old) + setArgOperand(ArgNo, New); + } +} + CallBrInst::CallBrInst(const CallBrInst &CBI) : CallBase(CBI.Attrs, CBI.FTy, CBI.getType(), Instruction::CallBr, OperandTraits::op_end(this) - CBI.getNumOperands(), diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp index 0dc2e2d37caf..6f9efec36361 100644 --- a/llvm/lib/MC/MCContext.cpp +++ b/llvm/lib/MC/MCContext.cpp @@ -61,6 +61,7 @@ MCContext::MCContext(const MCAsmInfo *mai, const MCRegisterInfo *mri, bool DoAutoReset) : SrcMgr(mgr), InlineSrcMgr(nullptr), MAI(mai), MRI(mri), MOFI(mofi), Symbols(Allocator), UsedNames(Allocator), + InlineAsmUsedLabelNames(Allocator), CurrentDwarfLoc(0, 0, 0, DWARF2_FLAG_IS_STMT, 0, 0), AutoReset(DoAutoReset) { SecureLogFile = AsSecureLogFileName; @@ -90,6 +91,7 @@ void MCContext::reset() { XCOFFAllocator.DestroyAll(); MCSubtargetAllocator.DestroyAll(); + InlineAsmUsedLabelNames.clear(); UsedNames.clear(); Symbols.clear(); Allocator.Reset(); @@ -272,6 +274,10 @@ void MCContext::setSymbolValue(MCStreamer &Streamer, Streamer.EmitAssignment(Symbol, MCConstantExpr::create(Val, *this)); } +void MCContext::registerInlineAsmLabel(MCSymbol *Sym) { + InlineAsmUsedLabelNames[Sym->getName()] = Sym; +} + //===----------------------------------------------------------------------===// // Section Management //===----------------------------------------------------------------------===// diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp index 084f6a7a2e14..c2cbca2177be 100644 --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -1142,7 +1142,9 @@ bool AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { } } - MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName); + MCSymbol *Sym = getContext().getInlineAsmLabel(SymbolName); + if (!Sym) + Sym = getContext().getOrCreateSymbol(SymbolName); // If this is an absolute variable reference, substitute it now to preserve // semantics in the face of reassignment. diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp index 8660b1a64bdd..0b9b03797f33 100644 --- a/llvm/lib/Object/ELF.cpp +++ b/llvm/lib/Object/ELF.cpp @@ -73,6 +73,13 @@ StringRef llvm::object::getELFRelocationTypeName(uint32_t Machine, break; } break; + case ELF::EM_CAHP: + switch (Type) { +#include "llvm/BinaryFormat/ELFRelocs/CAHP.def" + default: + break; + } + break; case ELF::EM_HEXAGON: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/Hexagon.def" diff --git a/llvm/lib/Object/RelocationResolver.cpp b/llvm/lib/Object/RelocationResolver.cpp index 0a243f32e12c..41a0ac7fbd10 100644 --- a/llvm/lib/Object/RelocationResolver.cpp +++ b/llvm/lib/Object/RelocationResolver.cpp @@ -90,9 +90,9 @@ static bool supportsBPF(uint64_t Type) { static uint64_t resolveBPF(RelocationRef R, uint64_t S, uint64_t A) { switch (R.getType()) { case ELF::R_BPF_64_32: - return S & 0xFFFFFFFF; + return (S + A) & 0xFFFFFFFF; case ELF::R_BPF_64_64: - return S; + return S + A; default: llvm_unreachable("Invalid relocation type"); } diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp index 7497154c757d..a80792fa1cd6 100644 --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -216,6 +216,7 @@ void ScalarEnumerationTraits::enumeration( ECase(EM_RISCV); ECase(EM_LANAI); ECase(EM_BPF); + ECase(EM_CAHP); #undef ECase } @@ -662,6 +663,9 @@ void ScalarEnumerationTraits::enumeration( case ELF::EM_RISCV: #include "llvm/BinaryFormat/ELFRelocs/RISCV.def" break; + case ELF::EM_CAHP: +#include "llvm/BinaryFormat/ELFRelocs/CAHP.def" + break; case ELF::EM_LANAI: #include "llvm/BinaryFormat/ELFRelocs/Lanai.def" break; diff --git a/llvm/lib/Support/AArch64TargetParser.cpp b/llvm/lib/Support/AArch64TargetParser.cpp index df4caa1f07fd..6f1d6d50eee2 100644 --- a/llvm/lib/Support/AArch64TargetParser.cpp +++ b/llvm/lib/Support/AArch64TargetParser.cpp @@ -96,8 +96,8 @@ bool AArch64::getExtensionFeatures(unsigned Extensions, Features.push_back("+sve2-sm4"); if (Extensions & AEK_SVE2SHA3) Features.push_back("+sve2-sha3"); - if (Extensions & AEK_BITPERM) - Features.push_back("+bitperm"); + if (Extensions & AEK_SVE2BITPERM) + Features.push_back("+sve2-bitperm"); if (Extensions & AEK_RCPC) Features.push_back("+rcpc"); diff --git a/llvm/lib/Support/Triple.cpp b/llvm/lib/Support/Triple.cpp index d419463e6a5e..1759f5eef0f4 100644 --- a/llvm/lib/Support/Triple.cpp +++ b/llvm/lib/Support/Triple.cpp @@ -29,6 +29,7 @@ StringRef Triple::getArchTypeName(ArchType Kind) { case avr: return "avr"; case bpfel: return "bpfel"; case bpfeb: return "bpfeb"; + case cahp: return "cahp"; case hexagon: return "hexagon"; case mips: return "mips"; case mipsel: return "mipsel"; @@ -144,6 +145,8 @@ StringRef Triple::getArchTypePrefix(ArchType Kind) { case riscv32: case riscv64: return "riscv"; + + case cahp: return "cahp"; } } @@ -315,6 +318,7 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { .Case("wasm64", wasm64) .Case("renderscript32", renderscript32) .Case("renderscript64", renderscript64) + .Case("cahp", cahp) .Default(UnknownArch); } @@ -443,6 +447,7 @@ static Triple::ArchType parseArch(StringRef ArchName) { .Case("wasm64", Triple::wasm64) .Case("renderscript32", Triple::renderscript32) .Case("renderscript64", Triple::renderscript64) + .Case("cahp", Triple::cahp) .Default(Triple::UnknownArch); // Some architectures require special parsing logic just to compute the @@ -670,6 +675,7 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) { case Triple::avr: case Triple::bpfeb: case Triple::bpfel: + case Triple::cahp: case Triple::hexagon: case Triple::lanai: case Triple::hsail: @@ -1231,6 +1237,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { return 0; case llvm::Triple::avr: + case llvm::Triple::cahp: case llvm::Triple::msp430: return 16; @@ -1309,6 +1316,7 @@ Triple Triple::get32BitArchVariant() const { case Triple::avr: case Triple::bpfel: case Triple::bpfeb: + case Triple::cahp: case Triple::msp430: case Triple::systemz: case Triple::ppc64le: @@ -1371,6 +1379,7 @@ Triple Triple::get64BitArchVariant() const { case Triple::UnknownArch: case Triple::arc: case Triple::avr: + case Triple::cahp: case Triple::hexagon: case Triple::kalimba: case Triple::lanai: @@ -1440,6 +1449,7 @@ Triple Triple::getBigEndianArchVariant() const { case Triple::amdil64: case Triple::amdil: case Triple::avr: + case Triple::cahp: case Triple::hexagon: case Triple::hsail64: case Triple::hsail: @@ -1525,6 +1535,7 @@ bool Triple::isLittleEndian() const { case Triple::arm: case Triple::avr: case Triple::bpfel: + case Triple::cahp: case Triple::hexagon: case Triple::hsail64: case Triple::hsail: diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc index e80880c6b3cb..27c8a1bc9b74 100644 --- a/llvm/lib/Support/Unix/Path.inc +++ b/llvm/lib/Support/Unix/Path.inc @@ -1200,7 +1200,7 @@ namespace fs { /// implementation. std::error_code copy_file(const Twine &From, const Twine &To) { uint32_t Flag = COPYFILE_DATA; -#if __has_builtin(__builtin_available) +#if __has_builtin(__builtin_available) && defined(COPYFILE_CLONE) if (__builtin_available(macos 10.12, *)) { bool IsSymlink; if (std::error_code Error = is_symlink_file(From, IsSymlink)) diff --git a/llvm/lib/Target/AArch64/AArch64.td b/llvm/lib/Target/AArch64/AArch64.td index e39c6995e367..f54db0aa03b2 100644 --- a/llvm/lib/Target/AArch64/AArch64.td +++ b/llvm/lib/Target/AArch64/AArch64.td @@ -115,7 +115,7 @@ def FeatureSVE2SM4 : SubtargetFeature<"sve2-sm4", "HasSVE2SM4", "true", def FeatureSVE2SHA3 : SubtargetFeature<"sve2-sha3", "HasSVE2SHA3", "true", "Enable SHA3 SVE2 instructions", [FeatureSVE2, FeatureSHA3]>; -def FeatureSVE2BitPerm : SubtargetFeature<"bitperm", "HasSVE2BitPerm", "true", +def FeatureSVE2BitPerm : SubtargetFeature<"sve2-bitperm", "HasSVE2BitPerm", "true", "Enable bit permutation SVE2 instructions", [FeatureSVE2]>; def FeatureZCRegMove : SubtargetFeature<"zcm", "HasZeroCycleRegMove", "true", diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index 7becc99fb5c7..03923878fd51 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -606,6 +606,10 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM, MaxStoresPerMemmoveOptSize = MaxStoresPerMemmove = 4; + MaxLoadsPerMemcmpOptSize = 4; + MaxLoadsPerMemcmp = Subtarget->requiresStrictAlign() + ? MaxLoadsPerMemcmpOptSize : 8; + setStackPointerRegisterToSaveRestore(AArch64::SP); setSchedulingPreference(Sched::Hybrid); @@ -5661,8 +5665,6 @@ AArch64TargetLowering::getConstraintType(StringRef Constraint) const { switch (Constraint[0]) { default: break; - case 'z': - return C_Other; case 'x': case 'w': return C_RegisterClass; @@ -5670,6 +5672,16 @@ AArch64TargetLowering::getConstraintType(StringRef Constraint) const { // currently handle addresses it is the same as 'r'. case 'Q': return C_Memory; + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'Y': + case 'Z': + return C_Immediate; + case 'z': case 'S': // A symbolic address return C_Other; } @@ -10567,7 +10579,7 @@ static SDValue performPostLD1Combine(SDNode *N, // are predecessors to each other or the Vector. SmallPtrSet Visited; SmallVector Worklist; - Visited.insert(N); + Visited.insert(Addr.getNode()); Worklist.push_back(User); Worklist.push_back(LD); Worklist.push_back(Vector.getNode()); @@ -11983,6 +11995,14 @@ bool AArch64TargetLowering::isMaskAndCmp0FoldingBeneficial( return Mask->getValue().isPowerOf2(); } +bool AArch64TargetLowering::shouldExpandShift(SelectionDAG &DAG, + SDNode *N) const { + if (DAG.getMachineFunction().getFunction().hasMinSize() && + !Subtarget->isTargetWindows()) + return false; + return true; +} + void AArch64TargetLowering::initializeSplitCSR(MachineBasicBlock *Entry) const { // Update IsSplitCSR in AArch64unctionInfo. AArch64FunctionInfo *AFI = Entry->getParent()->getInfo(); diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h index 4421c31f65c9..86f313933d85 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h @@ -480,11 +480,7 @@ class AArch64TargetLowering : public TargetLowering { return VT.getSizeInBits() >= 64; // vector 'bic' } - bool shouldExpandShift(SelectionDAG &DAG, SDNode *N) const override { - if (DAG.getMachineFunction().getFunction().hasMinSize()) - return false; - return true; - } + bool shouldExpandShift(SelectionDAG &DAG, SDNode *N) const override; bool shouldTransformSignedTruncationCheck(EVT XVT, unsigned KeptBits) const override { diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp index 215e96a82d0e..fa9e5d808c4f 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp @@ -32,6 +32,7 @@ #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/GlobalValue.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/Support/Casting.h" @@ -1928,6 +1929,17 @@ bool AArch64InstrInfo::isCandidateToMergeOrPair(const MachineInstr &MI) const { if (isLdStPairSuppressed(MI)) return false; + // Do not pair any callee-save store/reload instructions in the + // prologue/epilogue if the CFI information encoded the operations as separate + // instructions, as that will cause the size of the actual prologue to mismatch + // with the prologue size recorded in the Windows CFI. + const MCAsmInfo *MAI = MI.getMF()->getTarget().getMCAsmInfo(); + bool NeedsWinCFI = MAI->usesWindowsCFI() && + MI.getMF()->getFunction().needsUnwindTableEntry(); + if (NeedsWinCFI && (MI.getFlag(MachineInstr::FrameSetup) || + MI.getFlag(MachineInstr::FrameDestroy))) + return false; + // On some CPUs quad load/store pairs are slower than two single load/stores. if (Subtarget.isPaired128Slow()) { switch (MI.getOpcode()) { diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index eed53f36d574..020035c7f6c3 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -116,7 +116,7 @@ def HasSVE2SM4 : Predicate<"Subtarget->hasSVE2SM4()">, def HasSVE2SHA3 : Predicate<"Subtarget->hasSVE2SHA3()">, AssemblerPredicate<"FeatureSVE2SHA3", "sve2-sha3">; def HasSVE2BitPerm : Predicate<"Subtarget->hasSVE2BitPerm()">, - AssemblerPredicate<"FeatureSVE2BitPerm", "bitperm">; + AssemblerPredicate<"FeatureSVE2BitPerm", "sve2-bitperm">; def HasRCPC : Predicate<"Subtarget->hasRCPC()">, AssemblerPredicate<"FeatureRCPC", "rcpc">; def HasAltNZCV : Predicate<"Subtarget->hasAlternativeNZCV()">, diff --git a/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td b/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td index 79ab42f4c080..8e1ff999bd57 100644 --- a/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td @@ -1164,6 +1164,13 @@ let Predicates = [HasSVE2] in { defm SQRSHLR_ZPmZ : sve2_int_arith_pred<0b011100, "sqrshlr">; defm UQRSHLR_ZPmZ : sve2_int_arith_pred<0b011110, "uqrshlr">; + // SVE2 predicated shifts + defm SQSHL_ZPmI : sve_int_bin_pred_shift_imm_left< 0b0110, "sqshl">; + defm UQSHL_ZPmI : sve_int_bin_pred_shift_imm_left< 0b0111, "uqshl">; + defm SRSHR_ZPmI : sve_int_bin_pred_shift_imm_right<0b1100, "srshr">; + defm URSHR_ZPmI : sve_int_bin_pred_shift_imm_right<0b1101, "urshr">; + defm SQSHLU_ZPmI : sve_int_bin_pred_shift_imm_left< 0b1111, "sqshlu">; + // SVE2 integer add/subtract long defm SADDLB_ZZZ : sve2_wide_int_arith_long<0b00000, "saddlb">; defm SADDLT_ZZZ : sve2_wide_int_arith_long<0b00001, "saddlt">; @@ -1199,14 +1206,14 @@ let Predicates = [HasSVE2] in { defm PMULLT_ZZZ : sve2_pmul_long<0b1, "pmullt">; // SVE2 bitwise shift and insert - defm SRI_ZZI : sve2_int_bin_cons_shift_imm_right<0b0, "sri">; - defm SLI_ZZI : sve2_int_bin_cons_shift_imm_left< 0b1, "sli">; + defm SRI_ZZI : sve2_int_bin_shift_imm_right<0b0, "sri">; + defm SLI_ZZI : sve2_int_bin_shift_imm_left< 0b1, "sli">; // SVE2 bitwise shift right and accumulate - defm SSRA_ZZI : sve2_int_bin_accum_cons_shift_imm_right<0b00, "ssra">; - defm USRA_ZZI : sve2_int_bin_accum_cons_shift_imm_right<0b01, "usra">; - defm SRSRA_ZZI : sve2_int_bin_accum_cons_shift_imm_right<0b10, "srsra">; - defm URSRA_ZZI : sve2_int_bin_accum_cons_shift_imm_right<0b11, "ursra">; + defm SSRA_ZZI : sve2_int_bin_accum_shift_imm_right<0b00, "ssra">; + defm USRA_ZZI : sve2_int_bin_accum_shift_imm_right<0b01, "usra">; + defm SRSRA_ZZI : sve2_int_bin_accum_shift_imm_right<0b10, "srsra">; + defm URSRA_ZZI : sve2_int_bin_accum_shift_imm_right<0b11, "ursra">; // SVE2 complex integer add defm CADD_ZZI : sve2_int_cadd<0b0, "cadd">; @@ -1228,41 +1235,47 @@ let Predicates = [HasSVE2] in { defm SBCLB_ZZZ : sve2_int_addsub_long_carry<0b10, "sbclb">; defm SBCLT_ZZZ : sve2_int_addsub_long_carry<0b11, "sbclt">; - // SVE2 bitwise shift right narrow - defm SQSHRUNB_ZZI : sve2_int_bin_cons_shift_imm_right_narrow<0b0000, "sqshrunb">; - defm SQSHRUNT_ZZI : sve2_int_bin_cons_shift_imm_right_narrow<0b0001, "sqshrunt">; - defm SQRSHRUNB_ZZI : sve2_int_bin_cons_shift_imm_right_narrow<0b0010, "sqrshrunb">; - defm SQRSHRUNT_ZZI : sve2_int_bin_cons_shift_imm_right_narrow<0b0011, "sqrshrunt">; - defm SHRNB_ZZI : sve2_int_bin_cons_shift_imm_right_narrow<0b0100, "shrnb">; - defm SHRNT_ZZI : sve2_int_bin_cons_shift_imm_right_narrow<0b0101, "shrnt">; - defm RSHRNB_ZZI : sve2_int_bin_cons_shift_imm_right_narrow<0b0110, "rshrnb">; - defm RSHRNT_ZZI : sve2_int_bin_cons_shift_imm_right_narrow<0b0111, "rshrnt">; - defm SQSHRNB_ZZI : sve2_int_bin_cons_shift_imm_right_narrow<0b1000, "sqshrnb">; - defm SQSHRNT_ZZI : sve2_int_bin_cons_shift_imm_right_narrow<0b1001, "sqshrnt">; - defm SQRSHRNB_ZZI : sve2_int_bin_cons_shift_imm_right_narrow<0b1010, "sqrshrnb">; - defm SQRSHRNT_ZZI : sve2_int_bin_cons_shift_imm_right_narrow<0b1011, "sqrshrnt">; - defm UQSHRNB_ZZI : sve2_int_bin_cons_shift_imm_right_narrow<0b1100, "uqshrnb">; - defm UQSHRNT_ZZI : sve2_int_bin_cons_shift_imm_right_narrow<0b1101, "uqshrnt">; - defm UQRSHRNB_ZZI : sve2_int_bin_cons_shift_imm_right_narrow<0b1110, "uqrshrnb">; - defm UQRSHRNT_ZZI : sve2_int_bin_cons_shift_imm_right_narrow<0b1111, "uqrshrnt">; - - // SVE2 integer add/subtract narrow high part - defm ADDHNB_ZZZ : sve2_int_addsub_narrow_high<0b000, "addhnb">; - defm ADDHNT_ZZZ : sve2_int_addsub_narrow_high<0b001, "addhnt">; - defm RADDHNB_ZZZ : sve2_int_addsub_narrow_high<0b010, "raddhnb">; - defm RADDHNT_ZZZ : sve2_int_addsub_narrow_high<0b011, "raddhnt">; - defm SUBHNB_ZZZ : sve2_int_addsub_narrow_high<0b100, "subhnb">; - defm SUBHNT_ZZZ : sve2_int_addsub_narrow_high<0b101, "subhnt">; - defm RSUBHNB_ZZZ : sve2_int_addsub_narrow_high<0b110, "rsubhnb">; - defm RSUBHNT_ZZZ : sve2_int_addsub_narrow_high<0b111, "rsubhnt">; - - // SVE2 saturating extract narrow - defm SQXTNB_ZZ : sve2_int_sat_extract_narrow<0b000, "sqxtnb">; - defm SQXTNT_ZZ : sve2_int_sat_extract_narrow<0b001, "sqxtnt">; - defm UQXTNB_ZZ : sve2_int_sat_extract_narrow<0b010, "uqxtnb">; - defm UQXTNT_ZZ : sve2_int_sat_extract_narrow<0b011, "uqxtnt">; - defm SQXTUNB_ZZ : sve2_int_sat_extract_narrow<0b100, "sqxtunb">; - defm SQXTUNT_ZZ : sve2_int_sat_extract_narrow<0b101, "sqxtunt">; + // SVE2 bitwise shift right narrow (bottom) + defm SQSHRUNB_ZZI : sve2_int_bin_shift_imm_right_narrow_bottom<0b000, "sqshrunb">; + defm SQRSHRUNB_ZZI : sve2_int_bin_shift_imm_right_narrow_bottom<0b001, "sqrshrunb">; + defm SHRNB_ZZI : sve2_int_bin_shift_imm_right_narrow_bottom<0b010, "shrnb">; + defm RSHRNB_ZZI : sve2_int_bin_shift_imm_right_narrow_bottom<0b011, "rshrnb">; + defm SQSHRNB_ZZI : sve2_int_bin_shift_imm_right_narrow_bottom<0b100, "sqshrnb">; + defm SQRSHRNB_ZZI : sve2_int_bin_shift_imm_right_narrow_bottom<0b101, "sqrshrnb">; + defm UQSHRNB_ZZI : sve2_int_bin_shift_imm_right_narrow_bottom<0b110, "uqshrnb">; + defm UQRSHRNB_ZZI : sve2_int_bin_shift_imm_right_narrow_bottom<0b111, "uqrshrnb">; + + // SVE2 bitwise shift right narrow (top) + defm SQSHRUNT_ZZI : sve2_int_bin_shift_imm_right_narrow_top<0b000, "sqshrunt">; + defm SQRSHRUNT_ZZI : sve2_int_bin_shift_imm_right_narrow_top<0b001, "sqrshrunt">; + defm SHRNT_ZZI : sve2_int_bin_shift_imm_right_narrow_top<0b010, "shrnt">; + defm RSHRNT_ZZI : sve2_int_bin_shift_imm_right_narrow_top<0b011, "rshrnt">; + defm SQSHRNT_ZZI : sve2_int_bin_shift_imm_right_narrow_top<0b100, "sqshrnt">; + defm SQRSHRNT_ZZI : sve2_int_bin_shift_imm_right_narrow_top<0b101, "sqrshrnt">; + defm UQSHRNT_ZZI : sve2_int_bin_shift_imm_right_narrow_top<0b110, "uqshrnt">; + defm UQRSHRNT_ZZI : sve2_int_bin_shift_imm_right_narrow_top<0b111, "uqrshrnt">; + + // SVE2 integer add/subtract narrow high part (bottom) + defm ADDHNB_ZZZ : sve2_int_addsub_narrow_high_bottom<0b00, "addhnb">; + defm RADDHNB_ZZZ : sve2_int_addsub_narrow_high_bottom<0b01, "raddhnb">; + defm SUBHNB_ZZZ : sve2_int_addsub_narrow_high_bottom<0b10, "subhnb">; + defm RSUBHNB_ZZZ : sve2_int_addsub_narrow_high_bottom<0b11, "rsubhnb">; + + // SVE2 integer add/subtract narrow high part (top) + defm ADDHNT_ZZZ : sve2_int_addsub_narrow_high_top<0b00, "addhnt">; + defm RADDHNT_ZZZ : sve2_int_addsub_narrow_high_top<0b01, "raddhnt">; + defm SUBHNT_ZZZ : sve2_int_addsub_narrow_high_top<0b10, "subhnt">; + defm RSUBHNT_ZZZ : sve2_int_addsub_narrow_high_top<0b11, "rsubhnt">; + + // SVE2 saturating extract narrow (bottom) + defm SQXTNB_ZZ : sve2_int_sat_extract_narrow_bottom<0b00, "sqxtnb">; + defm UQXTNB_ZZ : sve2_int_sat_extract_narrow_bottom<0b01, "uqxtnb">; + defm SQXTUNB_ZZ : sve2_int_sat_extract_narrow_bottom<0b10, "sqxtunb">; + + // SVE2 saturating extract narrow (top) + defm SQXTNT_ZZ : sve2_int_sat_extract_narrow_top<0b00, "sqxtnt">; + defm UQXTNT_ZZ : sve2_int_sat_extract_narrow_top<0b01, "uqxtnt">; + defm SQXTUNT_ZZ : sve2_int_sat_extract_narrow_top<0b10, "sqxtunt">; // SVE2 character match defm MATCH_PPzZZ : sve2_char_match<0b0, "match">; @@ -1289,10 +1302,14 @@ let Predicates = [HasSVE2] in { // SVE2 histogram generation (vector) defm HISTCNT_ZPzZZ : sve2_hist_gen_vector<"histcnt">; + // SVE2 floating-point base 2 logarithm as integer + defm FLOGB_ZPmZ : sve2_fp_flogb<"flogb">; + // SVE2 floating-point convert precision defm FCVTXNT_ZPmZ : sve2_fp_convert_down_odd_rounding<"fcvtxnt">; defm FCVTNT_ZPmZ : sve2_fp_convert_down_narrow<"fcvtnt">; defm FCVTLT_ZPmZ : sve2_fp_convert_up_long<"fcvtlt">; + def FCVTX_ZPmZ_DtoS : sve_fp_2op_p_zd<0b0001010, "fcvtx", ZPR64, ZPR32, ElementSizeD>; // SVE2 floating-point pairwise operations defm FADDP_ZPmZZ : sve2_fp_pairwise_pred<0b000, "faddp">; @@ -1321,58 +1338,45 @@ let Predicates = [HasSVE2] in { def BSL2N_ZZZZ_D : sve2_int_bitwise_ternary_op_d<0b101, "bsl2n">; def NBSL_ZZZZ_D : sve2_int_bitwise_ternary_op_d<0b111, "nbsl">; - // sve_int_rotate_imm + // SVE2 bitwise xor and rotate right by immediate defm XAR_ZZZI : sve2_int_rotate_right_imm<"xar">; // SVE2 extract vector (immediate offset, constructive) def EXT_ZZI_B : sve2_int_perm_extract_i_cons<"ext">; - // SVE floating-point convert precision - def FCVTX_ZPmZ_DtoS : sve_fp_2op_p_zd<0b0001010, "fcvtx", ZPR64, ZPR32, ElementSizeD>; - - // SVE floating-point convert to integer - defm FLOGB_ZPmZ : sve2_fp_flogb<"flogb">; - - // Non-temporal contiguous loads (vector + register) - defm LDNT1SB_ZZR_S : sve2_mem_cldnt_vs<0b00000, "ldnt1sb", Z_s, ZPR32>; - defm LDNT1B_ZZR_S : sve2_mem_cldnt_vs<0b00001, "ldnt1b", Z_s, ZPR32>; - defm LDNT1SH_ZZR_S : sve2_mem_cldnt_vs<0b00100, "ldnt1sh", Z_s, ZPR32>; - defm LDNT1H_ZZR_S : sve2_mem_cldnt_vs<0b00101, "ldnt1h", Z_s, ZPR32>; - defm LDNT1W_ZZR_S : sve2_mem_cldnt_vs<0b01001, "ldnt1w", Z_s, ZPR32>; - - defm LDNT1SB_ZZR_D : sve2_mem_cldnt_vs<0b10000, "ldnt1sb", Z_d, ZPR64>; - defm LDNT1B_ZZR_D : sve2_mem_cldnt_vs<0b10010, "ldnt1b", Z_d, ZPR64>; - defm LDNT1SH_ZZR_D : sve2_mem_cldnt_vs<0b10100, "ldnt1sh", Z_d, ZPR64>; - defm LDNT1H_ZZR_D : sve2_mem_cldnt_vs<0b10110, "ldnt1h", Z_d, ZPR64>; - defm LDNT1SW_ZZR_D : sve2_mem_cldnt_vs<0b11000, "ldnt1sw", Z_d, ZPR64>; - defm LDNT1W_ZZR_D : sve2_mem_cldnt_vs<0b11010, "ldnt1w", Z_d, ZPR64>; - defm LDNT1D_ZZR_D : sve2_mem_cldnt_vs<0b11110, "ldnt1d", Z_d, ZPR64>; + // SVE2 non-temporal gather loads + defm LDNT1SB_ZZR_S : sve2_mem_gldnt_vs<0b00000, "ldnt1sb", Z_s, ZPR32>; + defm LDNT1B_ZZR_S : sve2_mem_gldnt_vs<0b00001, "ldnt1b", Z_s, ZPR32>; + defm LDNT1SH_ZZR_S : sve2_mem_gldnt_vs<0b00100, "ldnt1sh", Z_s, ZPR32>; + defm LDNT1H_ZZR_S : sve2_mem_gldnt_vs<0b00101, "ldnt1h", Z_s, ZPR32>; + defm LDNT1W_ZZR_S : sve2_mem_gldnt_vs<0b01001, "ldnt1w", Z_s, ZPR32>; + + defm LDNT1SB_ZZR_D : sve2_mem_gldnt_vs<0b10000, "ldnt1sb", Z_d, ZPR64>; + defm LDNT1B_ZZR_D : sve2_mem_gldnt_vs<0b10010, "ldnt1b", Z_d, ZPR64>; + defm LDNT1SH_ZZR_D : sve2_mem_gldnt_vs<0b10100, "ldnt1sh", Z_d, ZPR64>; + defm LDNT1H_ZZR_D : sve2_mem_gldnt_vs<0b10110, "ldnt1h", Z_d, ZPR64>; + defm LDNT1SW_ZZR_D : sve2_mem_gldnt_vs<0b11000, "ldnt1sw", Z_d, ZPR64>; + defm LDNT1W_ZZR_D : sve2_mem_gldnt_vs<0b11010, "ldnt1w", Z_d, ZPR64>; + defm LDNT1D_ZZR_D : sve2_mem_gldnt_vs<0b11110, "ldnt1d", Z_d, ZPR64>; // SVE2 vector splice (constructive) defm SPLICE_ZPZZ : sve2_int_perm_splice_cons<"splice">; - // Predicated shifts - defm SQSHL_ZPmI : sve_int_bin_pred_shift_imm_left< 0b0110, "sqshl">; - defm UQSHL_ZPmI : sve_int_bin_pred_shift_imm_left< 0b0111, "uqshl">; - defm SRSHR_ZPmI : sve_int_bin_pred_shift_imm_right<0b1100, "srshr">; - defm URSHR_ZPmI : sve_int_bin_pred_shift_imm_right<0b1101, "urshr">; - defm SQSHLU_ZPmI : sve_int_bin_pred_shift_imm_left< 0b1111, "sqshlu">; - - // Non-temporal contiguous stores (vector + register) - defm STNT1B_ZZR_S : sve2_mem_cstnt_vs<0b001, "stnt1b", Z_s, ZPR32>; - defm STNT1H_ZZR_S : sve2_mem_cstnt_vs<0b011, "stnt1h", Z_s, ZPR32>; - defm STNT1W_ZZR_S : sve2_mem_cstnt_vs<0b101, "stnt1w", Z_s, ZPR32>; + // SVE2 non-temporal scatter stores + defm STNT1B_ZZR_S : sve2_mem_sstnt_vs<0b001, "stnt1b", Z_s, ZPR32>; + defm STNT1H_ZZR_S : sve2_mem_sstnt_vs<0b011, "stnt1h", Z_s, ZPR32>; + defm STNT1W_ZZR_S : sve2_mem_sstnt_vs<0b101, "stnt1w", Z_s, ZPR32>; - defm STNT1B_ZZR_D : sve2_mem_cstnt_vs<0b000, "stnt1b", Z_d, ZPR64>; - defm STNT1H_ZZR_D : sve2_mem_cstnt_vs<0b010, "stnt1h", Z_d, ZPR64>; - defm STNT1W_ZZR_D : sve2_mem_cstnt_vs<0b100, "stnt1w", Z_d, ZPR64>; - defm STNT1D_ZZR_D : sve2_mem_cstnt_vs<0b110, "stnt1d", Z_d, ZPR64>; + defm STNT1B_ZZR_D : sve2_mem_sstnt_vs<0b000, "stnt1b", Z_d, ZPR64>; + defm STNT1H_ZZR_D : sve2_mem_sstnt_vs<0b010, "stnt1h", Z_d, ZPR64>; + defm STNT1W_ZZR_D : sve2_mem_sstnt_vs<0b100, "stnt1w", Z_d, ZPR64>; + defm STNT1D_ZZR_D : sve2_mem_sstnt_vs<0b110, "stnt1d", Z_d, ZPR64>; - // SVE table lookup (three sources) + // SVE2 table lookup (three sources) defm TBL_ZZZZ : sve2_int_perm_tbl<"tbl">; defm TBX_ZZZ : sve2_int_perm_tbx<"tbx">; - // SVE integer compare scalar count and limit + // SVE2 integer compare scalar count and limit defm WHILEGE_PWW : sve_int_while4_rr<0b000, "whilege">; defm WHILEGT_PWW : sve_int_while4_rr<0b001, "whilegt">; defm WHILEHS_PWW : sve_int_while4_rr<0b100, "whilehs">; @@ -1383,7 +1387,7 @@ let Predicates = [HasSVE2] in { defm WHILEHS_PXX : sve_int_while8_rr<0b100, "whilehs">; defm WHILEHI_PXX : sve_int_while8_rr<0b101, "whilehi">; - // SVE pointer conflict compare + // SVE2 pointer conflict compare defm WHILEWR_PXX : sve2_int_while_rr<0b0, "whilewr">; defm WHILERW_PXX : sve2_int_while_rr<0b1, "whilerw">; } diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp index a4b78f2a7d6b..301bf72d5239 100644 --- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp @@ -618,6 +618,19 @@ int AArch64TTIImpl::getCmpSelInstrCost(unsigned Opcode, Type *ValTy, return BaseT::getCmpSelInstrCost(Opcode, ValTy, CondTy, I); } +AArch64TTIImpl::TTI::MemCmpExpansionOptions +AArch64TTIImpl::enableMemCmpExpansion(bool OptSize, bool IsZeroCmp) const { + TTI::MemCmpExpansionOptions Options; + Options.AllowOverlappingLoads = !ST->requiresStrictAlign(); + Options.MaxNumLoads = TLI->getMaxExpandSizeMemcmp(OptSize); + Options.NumLoadsPerBlock = Options.MaxNumLoads; + // TODO: Though vector loads usually perform well on AArch64, in some targets + // they may wake up the FP unit, which raises the power consumption. Perhaps + // they could be used with no holds barred (-O3). + Options.LoadSizes = {8, 4, 2, 1}; + return Options; +} + int AArch64TTIImpl::getMemoryOpCost(unsigned Opcode, Type *Ty, unsigned Alignment, unsigned AddressSpace, const Instruction *I) { diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.h b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.h index 10c15a139b4c..95cda63b0174 100644 --- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.h +++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.h @@ -130,6 +130,9 @@ class AArch64TTIImpl : public BasicTTIImplBase { int getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy, const Instruction *I = nullptr); + TTI::MemCmpExpansionOptions enableMemCmpExpansion(bool OptSize, + bool IsZeroCmp) const; + int getMemoryOpCost(unsigned Opcode, Type *Src, unsigned Alignment, unsigned AddressSpace, const Instruction *I = nullptr); diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index f4c55d48d215..09b42811f786 100644 --- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -2840,7 +2840,7 @@ static const struct Extension { {"sve2-aes", {AArch64::FeatureSVE2AES}}, {"sve2-sm4", {AArch64::FeatureSVE2SM4}}, {"sve2-sha3", {AArch64::FeatureSVE2SHA3}}, - {"bitperm", {AArch64::FeatureSVE2BitPerm}}, + {"sve2-bitperm", {AArch64::FeatureSVE2BitPerm}}, // FIXME: Unsupported extensions {"pan", {}}, {"lor", {}}, diff --git a/llvm/lib/Target/AArch64/SVEInstrFormats.td b/llvm/lib/Target/AArch64/SVEInstrFormats.td index 808e59467081..dfd6c576e99b 100644 --- a/llvm/lib/Target/AArch64/SVEInstrFormats.td +++ b/llvm/lib/Target/AArch64/SVEInstrFormats.td @@ -403,12 +403,12 @@ multiclass sve_int_count_r_x64 opc, string asm> { } class sve_int_count_v sz8_64, bits<5> opc, string asm, - ZPRRegOp zprty> -: I<(outs zprty:$Zdn), (ins zprty:$_Zdn, PPRAny:$Pg), - asm, "\t$Zdn, $Pg", + ZPRRegOp zprty, PPRRegOp pprty> +: I<(outs zprty:$Zdn), (ins zprty:$_Zdn, pprty:$Pm), + asm, "\t$Zdn, $Pm", "", []>, Sched<[]> { - bits<4> Pg; + bits<4> Pm; bits<5> Zdn; let Inst{31-24} = 0b00100101; let Inst{23-22} = sz8_64; @@ -416,7 +416,7 @@ class sve_int_count_v sz8_64, bits<5> opc, string asm, let Inst{18-16} = opc{4-2}; let Inst{15-11} = 0b10000; let Inst{10-9} = opc{1-0}; - let Inst{8-5} = Pg; + let Inst{8-5} = Pm; let Inst{4-0} = Zdn; let Constraints = "$Zdn = $_Zdn"; @@ -425,9 +425,16 @@ class sve_int_count_v sz8_64, bits<5> opc, string asm, } multiclass sve_int_count_v opc, string asm> { - def _H : sve_int_count_v<0b01, opc, asm, ZPR16>; - def _S : sve_int_count_v<0b10, opc, asm, ZPR32>; - def _D : sve_int_count_v<0b11, opc, asm, ZPR64>; + def _H : sve_int_count_v<0b01, opc, asm, ZPR16, PPR16>; + def _S : sve_int_count_v<0b10, opc, asm, ZPR32, PPR32>; + def _D : sve_int_count_v<0b11, opc, asm, ZPR64, PPR64>; + + def : InstAlias(NAME # "_H") ZPR16:$Zdn, PPRAny:$Pm), 0>; + def : InstAlias(NAME # "_S") ZPR32:$Zdn, PPRAny:$Pm), 0>; + def : InstAlias(NAME # "_D") ZPR64:$Zdn, PPRAny:$Pm), 0>; } class sve_int_pcount_pred sz8_64, bits<4> opc, string asm, @@ -744,7 +751,7 @@ multiclass sve2_int_perm_tbl { } class sve2_int_perm_tbx sz8_64, string asm, ZPRRegOp zprty> -: I<(outs zprty:$Zd), (ins zprty:$Zn, zprty:$Zm), +: I<(outs zprty:$Zd), (ins zprty:$_Zd, zprty:$Zn, zprty:$Zm), asm, "\t$Zd, $Zn, $Zm", "", []>, Sched<[]> { @@ -758,6 +765,8 @@ class sve2_int_perm_tbx sz8_64, string asm, ZPRRegOp zprty> let Inst{15-10} = 0b001011; let Inst{9-5} = Zn; let Inst{4-0} = Zd; + + let Constraints = "$Zd = $_Zd"; } multiclass sve2_int_perm_tbx { @@ -1489,7 +1498,7 @@ multiclass sve_fp_fcadd { class sve2_fp_convert_precision opc, string asm, ZPRRegOp zprty1, ZPRRegOp zprty2> -: I<(outs zprty1:$Zd), (ins PPR3bAny:$Pg, zprty2:$Zn), +: I<(outs zprty1:$Zd), (ins zprty1:$_Zd, PPR3bAny:$Pg, zprty2:$Zn), asm, "\t$Zd, $Pg/m, $Zn", "", []>, Sched<[]> { @@ -1504,6 +1513,8 @@ class sve2_fp_convert_precision opc, string asm, let Inst{12-10} = Pg; let Inst{9-5} = Zn; let Inst{4-0} = Zd; + + let Constraints = "$Zd = $_Zd"; } multiclass sve2_fp_convert_down_narrow { @@ -2399,21 +2410,40 @@ multiclass sve2_misc_bitwise opc, string asm> { def _D : sve2_misc<0b11, opc, asm, ZPR64, ZPR64>; } -multiclass sve2_bitwise_xor_interleaved { - let DestructiveInstType = Destructive, ElementSize = ElementSizeNone in { - def _B : sve2_misc<0b00, { 0b010, opc }, asm, ZPR8, ZPR8>; - def _H : sve2_misc<0b01, { 0b010, opc }, asm, ZPR16, ZPR16>; - def _S : sve2_misc<0b10, { 0b010, opc }, asm, ZPR32, ZPR32>; - def _D : sve2_misc<0b11, { 0b010, opc }, asm, ZPR64, ZPR64>; - } -} - multiclass sve2_misc_int_addsub_long_interleaved opc, string asm> { def _H : sve2_misc<0b01, { 0b00, opc }, asm, ZPR16, ZPR8>; def _S : sve2_misc<0b10, { 0b00, opc }, asm, ZPR32, ZPR16>; def _D : sve2_misc<0b11, { 0b00, opc }, asm, ZPR64, ZPR32>; } +class sve2_bitwise_xor_interleaved sz, bits<1> opc, string asm, + ZPRRegOp zprty1, ZPRRegOp zprty2> +: I<(outs zprty1:$Zd), (ins zprty1:$_Zd, zprty2:$Zn, zprty2:$Zm), + asm, "\t$Zd, $Zn, $Zm", "", []>, Sched<[]> { + bits<5> Zd; + bits<5> Zn; + bits<5> Zm; + let Inst{31-24} = 0b01000101; + let Inst{23-22} = sz; + let Inst{21} = 0b0; + let Inst{20-16} = Zm; + let Inst{15-11} = 0b10010; + let Inst{10} = opc; + let Inst{9-5} = Zn; + let Inst{4-0} = Zd; + + let Constraints = "$Zd = $_Zd"; + let DestructiveInstType = Destructive; + let ElementSize = ElementSizeNone; +} + +multiclass sve2_bitwise_xor_interleaved { + def _B : sve2_bitwise_xor_interleaved<0b00, opc, asm, ZPR8, ZPR8>; + def _H : sve2_bitwise_xor_interleaved<0b01, opc, asm, ZPR16, ZPR16>; + def _S : sve2_bitwise_xor_interleaved<0b10, opc, asm, ZPR32, ZPR32>; + def _D : sve2_bitwise_xor_interleaved<0b11, opc, asm, ZPR64, ZPR64>; +} + class sve2_bitwise_shift_left_long tsz8_64, bits<2> opc, string asm, ZPRRegOp zprty1, ZPRRegOp zprty2, Operand immtype> @@ -2451,9 +2481,9 @@ multiclass sve2_bitwise_shift_left_long opc, string asm> { // SVE2 Accumulate Group //===----------------------------------------------------------------------===// -class sve2_int_bin_cons_shift_imm tsz8_64, bit opc, string asm, - ZPRRegOp zprty, Operand immtype> -: I<(outs zprty:$Zd), (ins zprty:$Zn, immtype:$imm), +class sve2_int_bin_shift_imm tsz8_64, bit opc, string asm, + ZPRRegOp zprty, Operand immtype> +: I<(outs zprty:$Zd), (ins zprty:$_Zd, zprty:$Zn, immtype:$imm), asm, "\t$Zd, $Zn, $imm", "", []>, Sched<[]> { bits<5> Zd; @@ -2468,38 +2498,40 @@ class sve2_int_bin_cons_shift_imm tsz8_64, bit opc, string asm, let Inst{10} = opc; let Inst{9-5} = Zn; let Inst{4-0} = Zd; + + let Constraints = "$Zd = $_Zd"; } -multiclass sve2_int_bin_cons_shift_imm_left { - def _B : sve2_int_bin_cons_shift_imm<{0,0,0,1}, opc, asm, ZPR8, vecshiftL8>; - def _H : sve2_int_bin_cons_shift_imm<{0,0,1,?}, opc, asm, ZPR16, vecshiftL16> { +multiclass sve2_int_bin_shift_imm_left { + def _B : sve2_int_bin_shift_imm<{0,0,0,1}, opc, asm, ZPR8, vecshiftL8>; + def _H : sve2_int_bin_shift_imm<{0,0,1,?}, opc, asm, ZPR16, vecshiftL16> { let Inst{19} = imm{3}; } - def _S : sve2_int_bin_cons_shift_imm<{0,1,?,?}, opc, asm, ZPR32, vecshiftL32> { + def _S : sve2_int_bin_shift_imm<{0,1,?,?}, opc, asm, ZPR32, vecshiftL32> { let Inst{20-19} = imm{4-3}; } - def _D : sve2_int_bin_cons_shift_imm<{1,?,?,?}, opc, asm, ZPR64, vecshiftL64> { + def _D : sve2_int_bin_shift_imm<{1,?,?,?}, opc, asm, ZPR64, vecshiftL64> { let Inst{22} = imm{5}; let Inst{20-19} = imm{4-3}; } } -multiclass sve2_int_bin_cons_shift_imm_right { - def _B : sve2_int_bin_cons_shift_imm<{0,0,0,1}, opc, asm, ZPR8, vecshiftR8>; - def _H : sve2_int_bin_cons_shift_imm<{0,0,1,?}, opc, asm, ZPR16, vecshiftR16> { +multiclass sve2_int_bin_shift_imm_right { + def _B : sve2_int_bin_shift_imm<{0,0,0,1}, opc, asm, ZPR8, vecshiftR8>; + def _H : sve2_int_bin_shift_imm<{0,0,1,?}, opc, asm, ZPR16, vecshiftR16> { let Inst{19} = imm{3}; } - def _S : sve2_int_bin_cons_shift_imm<{0,1,?,?}, opc, asm, ZPR32, vecshiftR32> { + def _S : sve2_int_bin_shift_imm<{0,1,?,?}, opc, asm, ZPR32, vecshiftR32> { let Inst{20-19} = imm{4-3}; } - def _D : sve2_int_bin_cons_shift_imm<{1,?,?,?}, opc, asm, ZPR64, vecshiftR64> { + def _D : sve2_int_bin_shift_imm<{1,?,?,?}, opc, asm, ZPR64, vecshiftR64> { let Inst{22} = imm{5}; let Inst{20-19} = imm{4-3}; } } -class sve2_int_bin_accum_cons_shift_imm tsz8_64, bits<2> opc, string asm, - ZPRRegOp zprty, Operand immtype> +class sve2_int_bin_accum_shift_imm tsz8_64, bits<2> opc, string asm, + ZPRRegOp zprty, Operand immtype> : I<(outs zprty:$Zda), (ins zprty:$_Zda, zprty:$Zn, immtype:$imm), asm, "\t$Zda, $Zn, $imm", "", []>, Sched<[]> { @@ -2521,15 +2553,15 @@ class sve2_int_bin_accum_cons_shift_imm tsz8_64, bits<2> opc, string asm let ElementSize = ElementSizeNone; } -multiclass sve2_int_bin_accum_cons_shift_imm_right opc, string asm> { - def _B : sve2_int_bin_accum_cons_shift_imm<{0,0,0,1}, opc, asm, ZPR8, vecshiftR8>; - def _H : sve2_int_bin_accum_cons_shift_imm<{0,0,1,?}, opc, asm, ZPR16, vecshiftR16> { +multiclass sve2_int_bin_accum_shift_imm_right opc, string asm> { + def _B : sve2_int_bin_accum_shift_imm<{0,0,0,1}, opc, asm, ZPR8, vecshiftR8>; + def _H : sve2_int_bin_accum_shift_imm<{0,0,1,?}, opc, asm, ZPR16, vecshiftR16> { let Inst{19} = imm{3}; } - def _S : sve2_int_bin_accum_cons_shift_imm<{0,1,?,?}, opc, asm, ZPR32, vecshiftR32> { + def _S : sve2_int_bin_accum_shift_imm<{0,1,?,?}, opc, asm, ZPR32, vecshiftR32> { let Inst{20-19} = imm{4-3}; } - def _D : sve2_int_bin_accum_cons_shift_imm<{1,?,?,?}, opc, asm, ZPR64, vecshiftR64> { + def _D : sve2_int_bin_accum_shift_imm<{1,?,?,?}, opc, asm, ZPR64, vecshiftR64> { let Inst{22} = imm{5}; let Inst{20-19} = imm{4-3}; } @@ -2607,9 +2639,9 @@ multiclass sve2_int_addsub_long_carry opc, string asm> { // SVE2 Narrowing Group //===----------------------------------------------------------------------===// -class sve2_int_bin_cons_shift_imm_narrow tsz8_64, bits<4> opc, - string asm, ZPRRegOp zprty1, - ZPRRegOp zprty2, Operand immtype> +class sve2_int_bin_shift_imm_narrow_bottom tsz8_64, bits<3> opc, + string asm, ZPRRegOp zprty1, + ZPRRegOp zprty2, Operand immtype> : I<(outs zprty1:$Zd), (ins zprty2:$Zn, immtype:$imm), asm, "\t$Zd, $Zn, $imm", "", []>, Sched<[]> { @@ -2622,26 +2654,63 @@ class sve2_int_bin_cons_shift_imm_narrow tsz8_64, bits<4> opc, let Inst{20-19} = tsz8_64{1-0}; let Inst{18-16} = imm{2-0}; // imm3 let Inst{15-14} = 0b00; - let Inst{13-10} = opc; + let Inst{13-11} = opc; + let Inst{10} = 0b0; + let Inst{9-5} = Zn; + let Inst{4-0} = Zd; +} + +multiclass sve2_int_bin_shift_imm_right_narrow_bottom opc, string asm> { + def _B : sve2_int_bin_shift_imm_narrow_bottom<{0,0,1}, opc, asm, ZPR8, ZPR16, + vecshiftR8>; + def _H : sve2_int_bin_shift_imm_narrow_bottom<{0,1,?}, opc, asm, ZPR16, ZPR32, + vecshiftR16> { + let Inst{19} = imm{3}; + } + def _S : sve2_int_bin_shift_imm_narrow_bottom<{1,?,?}, opc, asm, ZPR32, ZPR64, + vecshiftR32> { + let Inst{20-19} = imm{4-3}; + } +} + +class sve2_int_bin_shift_imm_narrow_top tsz8_64, bits<3> opc, + string asm, ZPRRegOp zprty1, + ZPRRegOp zprty2, Operand immtype> +: I<(outs zprty1:$Zd), (ins zprty1:$_Zd, zprty2:$Zn, immtype:$imm), + asm, "\t$Zd, $Zn, $imm", + "", []>, Sched<[]> { + bits<5> Zd; + bits<5> Zn; + bits<5> imm; + let Inst{31-23} = 0b010001010; + let Inst{22} = tsz8_64{2}; + let Inst{21} = 0b1; + let Inst{20-19} = tsz8_64{1-0}; + let Inst{18-16} = imm{2-0}; // imm3 + let Inst{15-14} = 0b00; + let Inst{13-11} = opc; + let Inst{10} = 0b1; let Inst{9-5} = Zn; let Inst{4-0} = Zd; + + let Constraints = "$Zd = $_Zd"; } -multiclass sve2_int_bin_cons_shift_imm_right_narrow opc, string asm> { - def _B : sve2_int_bin_cons_shift_imm_narrow<{0,0,1}, opc, asm, ZPR8, ZPR16, - vecshiftR8>; - def _H : sve2_int_bin_cons_shift_imm_narrow<{0,1,?}, opc, asm, ZPR16, ZPR32, - vecshiftR16> { +multiclass sve2_int_bin_shift_imm_right_narrow_top opc, string asm> { + def _B : sve2_int_bin_shift_imm_narrow_top<{0,0,1}, opc, asm, ZPR8, ZPR16, + vecshiftR8>; + def _H : sve2_int_bin_shift_imm_narrow_top<{0,1,?}, opc, asm, ZPR16, ZPR32, + vecshiftR16> { let Inst{19} = imm{3}; } - def _S : sve2_int_bin_cons_shift_imm_narrow<{1,?,?}, opc, asm, ZPR32, ZPR64, - vecshiftR32> { + def _S : sve2_int_bin_shift_imm_narrow_top<{1,?,?}, opc, asm, ZPR32, ZPR64, + vecshiftR32> { let Inst{20-19} = imm{4-3}; } } -class sve2_int_addsub_narrow_high sz, bits<3> opc, string asm, - ZPRRegOp zprty1, ZPRRegOp zprty2> +class sve2_int_addsub_narrow_high_bottom sz, bits<2> opc, string asm, + ZPRRegOp zprty1, ZPRRegOp zprty2> : I<(outs zprty1:$Zd), (ins zprty2:$Zn, zprty2:$Zm), asm, "\t$Zd, $Zn, $Zm", "", []>, Sched<[]> { bits<5> Zd; @@ -2652,19 +2721,46 @@ class sve2_int_addsub_narrow_high sz, bits<3> opc, string asm, let Inst{21} = 0b1; let Inst{20-16} = Zm; let Inst{15-13} = 0b011; - let Inst{12-10} = opc; // S, R, T + let Inst{12-11} = opc; // S, R + let Inst{10} = 0b0; // Top + let Inst{9-5} = Zn; + let Inst{4-0} = Zd; +} + +multiclass sve2_int_addsub_narrow_high_bottom opc, string asm> { + def _B : sve2_int_addsub_narrow_high_bottom<0b01, opc, asm, ZPR8, ZPR16>; + def _H : sve2_int_addsub_narrow_high_bottom<0b10, opc, asm, ZPR16, ZPR32>; + def _S : sve2_int_addsub_narrow_high_bottom<0b11, opc, asm, ZPR32, ZPR64>; +} + +class sve2_int_addsub_narrow_high_top sz, bits<2> opc, string asm, + ZPRRegOp zprty1, ZPRRegOp zprty2> +: I<(outs zprty1:$Zd), (ins zprty1:$_Zd, zprty2:$Zn, zprty2:$Zm), + asm, "\t$Zd, $Zn, $Zm", "", []>, Sched<[]> { + bits<5> Zd; + bits<5> Zn; + bits<5> Zm; + let Inst{31-24} = 0b01000101; + let Inst{23-22} = sz; + let Inst{21} = 0b1; + let Inst{20-16} = Zm; + let Inst{15-13} = 0b011; + let Inst{12-11} = opc; // S, R + let Inst{10} = 0b1; // Top let Inst{9-5} = Zn; let Inst{4-0} = Zd; + + let Constraints = "$Zd = $_Zd"; } -multiclass sve2_int_addsub_narrow_high opc, string asm> { - def _B : sve2_int_addsub_narrow_high<0b01, opc, asm, ZPR8, ZPR16>; - def _H : sve2_int_addsub_narrow_high<0b10, opc, asm, ZPR16, ZPR32>; - def _S : sve2_int_addsub_narrow_high<0b11, opc, asm, ZPR32, ZPR64>; +multiclass sve2_int_addsub_narrow_high_top opc, string asm> { + def _B : sve2_int_addsub_narrow_high_top<0b01, opc, asm, ZPR8, ZPR16>; + def _H : sve2_int_addsub_narrow_high_top<0b10, opc, asm, ZPR16, ZPR32>; + def _S : sve2_int_addsub_narrow_high_top<0b11, opc, asm, ZPR32, ZPR64>; } -class sve2_int_sat_extract_narrow tsz8_64, bits<3> opc, string asm, - ZPRRegOp zprty1, ZPRRegOp zprty2> +class sve2_int_sat_extract_narrow_bottom tsz8_64, bits<2> opc, string asm, + ZPRRegOp zprty1, ZPRRegOp zprty2> : I<(outs zprty1:$Zd), (ins zprty2:$Zn), asm, "\t$Zd, $Zn", "", []>, Sched<[]> { bits<5> Zd; @@ -2674,15 +2770,41 @@ class sve2_int_sat_extract_narrow tsz8_64, bits<3> opc, string asm, let Inst{21} = 0b1; let Inst{20-19} = tsz8_64{1-0}; let Inst{18-13} = 0b000010; - let Inst{12-10} = opc; + let Inst{12-11} = opc; + let Inst{10} = 0b0; + let Inst{9-5} = Zn; + let Inst{4-0} = Zd; +} + +multiclass sve2_int_sat_extract_narrow_bottom opc, string asm> { + def _B : sve2_int_sat_extract_narrow_bottom<0b001, opc, asm, ZPR8, ZPR16>; + def _H : sve2_int_sat_extract_narrow_bottom<0b010, opc, asm, ZPR16, ZPR32>; + def _S : sve2_int_sat_extract_narrow_bottom<0b100, opc, asm, ZPR32, ZPR64>; +} + +class sve2_int_sat_extract_narrow_top tsz8_64, bits<2> opc, string asm, + ZPRRegOp zprty1, ZPRRegOp zprty2> +: I<(outs zprty1:$Zd), (ins zprty1:$_Zd, zprty2:$Zn), + asm, "\t$Zd, $Zn", "", []>, Sched<[]> { + bits<5> Zd; + bits<5> Zn; + let Inst{31-23} = 0b010001010; + let Inst{22} = tsz8_64{2}; + let Inst{21} = 0b1; + let Inst{20-19} = tsz8_64{1-0}; + let Inst{18-13} = 0b000010; + let Inst{12-11} = opc; + let Inst{10} = 0b1; let Inst{9-5} = Zn; let Inst{4-0} = Zd; + + let Constraints = "$Zd = $_Zd"; } -multiclass sve2_int_sat_extract_narrow opc, string asm> { - def _B : sve2_int_sat_extract_narrow<0b001, opc, asm, ZPR8, ZPR16>; - def _H : sve2_int_sat_extract_narrow<0b010, opc, asm, ZPR16, ZPR32>; - def _S : sve2_int_sat_extract_narrow<0b100, opc, asm, ZPR32, ZPR64>; +multiclass sve2_int_sat_extract_narrow_top opc, string asm> { + def _B : sve2_int_sat_extract_narrow_top<0b001, opc, asm, ZPR8, ZPR16>; + def _H : sve2_int_sat_extract_narrow_top<0b010, opc, asm, ZPR16, ZPR32>; + def _S : sve2_int_sat_extract_narrow_top<0b100, opc, asm, ZPR32, ZPR64>; } //===----------------------------------------------------------------------===// @@ -3886,9 +4008,9 @@ multiclass sve_mem_cstnt_ss msz, string asm, RegisterOperand listty, (!cast(NAME) zprty:$Zt, PPR3bAny:$Pg, GPR64sp:$Rn, gprty:$Rm), 0>; } -class sve2_mem_cstnt_vs_base opc, dag iops, string asm, - RegisterOperand VecList> -: I<(outs VecList:$Zt), iops, +class sve2_mem_sstnt_vs_base opc, string asm, + RegisterOperand listty, ZPRRegOp zprty> +: I<(outs), (ins listty:$Zt, PPR3bAny:$Pg, zprty:$Zn, GPR64:$Rm), asm, "\t$Zt, $Pg, [$Zn, $Rm]", "", []>, Sched<[]> { @@ -3908,17 +4030,14 @@ class sve2_mem_cstnt_vs_base opc, dag iops, string asm, let mayStore = 1; } -multiclass sve2_mem_cstnt_vs opc, string asm, +multiclass sve2_mem_sstnt_vs opc, string asm, RegisterOperand listty, ZPRRegOp zprty> { - def _REAL : sve2_mem_cstnt_vs_base; + def _REAL : sve2_mem_sstnt_vs_base; def : InstAlias(NAME # _REAL) zprty:$Zt, PPR3bAny:$Pg, zprty:$Zn, GPR64:$Rm), 0>; def : InstAlias(NAME # _REAL) zprty:$Zt, PPR3bAny:$Pg, zprty:$Zn, XZR), 0>; - def : InstAlias(NAME # _REAL) listty:$Zt, PPR3bAny:$Pg, zprty:$Zn, GPR64:$Rm), 0>; def : InstAlias(NAME # _REAL) listty:$Zt, PPR3bAny:$Pg, zprty:$Zn, XZR), 1>; } @@ -5094,7 +5213,7 @@ multiclass sve_mem_p_fill { (!cast(NAME) PPRAny:$Pt, GPR64sp:$Rn, 0), 1>; } -class sve2_mem_cldnt_vs_base opc, dag iops, string asm, +class sve2_mem_gldnt_vs_base opc, dag iops, string asm, RegisterOperand VecList> : I<(outs VecList:$Zt), iops, asm, "\t$Zt, $Pg/z, [$Zn, $Rm]", @@ -5119,17 +5238,15 @@ class sve2_mem_cldnt_vs_base opc, dag iops, string asm, let mayLoad = 1; } -multiclass sve2_mem_cldnt_vs opc, string asm, +multiclass sve2_mem_gldnt_vs opc, string asm, RegisterOperand listty, ZPRRegOp zprty> { - def _REAL : sve2_mem_cldnt_vs_base; def : InstAlias(NAME # _REAL) zprty:$Zt, PPR3bAny:$Pg, zprty:$Zn, GPR64:$Rm), 0>; def : InstAlias(NAME # _REAL) zprty:$Zt, PPR3bAny:$Pg, zprty:$Zn, XZR), 0>; - def : InstAlias(NAME # _REAL) listty:$Zt, PPR3bAny:$Pg, zprty:$Zn, GPR64:$Rm), 0>; def : InstAlias(NAME # _REAL) listty:$Zt, PPR3bAny:$Pg, zprty:$Zn, XZR), 1>; } diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp index 18bb9bf3eccc..d390c9e237e6 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -14369,7 +14369,8 @@ const char *ARMTargetLowering::LowerXConstraint(EVT ConstraintVT) const { /// constraint it is for this target. ARMTargetLowering::ConstraintType ARMTargetLowering::getConstraintType(StringRef Constraint) const { - if (Constraint.size() == 1) { + unsigned S = Constraint.size(); + if (S == 1) { switch (Constraint[0]) { default: break; case 'l': return C_RegisterClass; @@ -14377,12 +14378,12 @@ ARMTargetLowering::getConstraintType(StringRef Constraint) const { case 'h': return C_RegisterClass; case 'x': return C_RegisterClass; case 't': return C_RegisterClass; - case 'j': return C_Other; // Constant for movw. - // An address with a single base register. Due to the way we - // currently handle addresses it is the same as an 'r' memory constraint. + case 'j': return C_Immediate; // Constant for movw. + // An address with a single base register. Due to the way we + // currently handle addresses it is the same as an 'r' memory constraint. case 'Q': return C_Memory; } - } else if (Constraint.size() == 2) { + } else if (S == 2) { switch (Constraint[0]) { default: break; case 'T': return C_RegisterClass; diff --git a/llvm/lib/Target/ARM/ARMInstrThumb.td b/llvm/lib/Target/ARM/ARMInstrThumb.td index cfeb13c6acb6..fa266c41080c 100644 --- a/llvm/lib/Target/ARM/ARMInstrThumb.td +++ b/llvm/lib/Target/ARM/ARMInstrThumb.td @@ -592,6 +592,7 @@ let isBranch = 1, isTerminator = 1, isBarrier = 1 in { [(ARMbrjt tGPR:$target, tjumptable:$jt)]>, Sched<[WriteBrTbl]> { let Size = 2; + let isNotDuplicable = 1; list Predicates = [IsThumb, IsThumb1Only]; } } @@ -1465,7 +1466,7 @@ def tLEApcrelJT : tPseudoInst<(outs tGPR:$Rd), // Thumb-1 doesn't have the TBB or TBH instructions, but we can synthesize them // and make use of the same compressed jump table format as Thumb-2. let Size = 2, isBranch = 1, isTerminator = 1, isBarrier = 1, - isIndirectBranch = 1 in { + isIndirectBranch = 1, isNotDuplicable = 1 in { def tTBB_JT : tPseudoInst<(outs), (ins tGPRwithpc:$base, tGPR:$index, i32imm:$jt, i32imm:$pclbl), 0, IIC_Br, []>, Sched<[WriteBr]>; diff --git a/llvm/lib/Target/AVR/AVRISelLowering.cpp b/llvm/lib/Target/AVR/AVRISelLowering.cpp index b6ba5f22fafb..f159beee9730 100644 --- a/llvm/lib/Target/AVR/AVRISelLowering.cpp +++ b/llvm/lib/Target/AVR/AVRISelLowering.cpp @@ -1689,6 +1689,8 @@ AVRTargetLowering::getConstraintType(StringRef Constraint) const { if (Constraint.size() == 1) { // See http://www.nongnu.org/avr-libc/user-manual/inline_asm.html switch (Constraint[0]) { + default: + break; case 'a': // Simple upper registers case 'b': // Base pointer registers pairs case 'd': // Upper register @@ -1715,9 +1717,7 @@ AVRTargetLowering::getConstraintType(StringRef Constraint) const { case 'O': // Integer constant (Range: 8, 16, 24) case 'P': // Integer constant (Range: 1) case 'R': // Integer constant (Range: -6 to 5)x - return C_Other; - default: - break; + return C_Immediate; } } diff --git a/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp b/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp index 51d4cbc8a429..509484b71544 100644 --- a/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp +++ b/llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp @@ -116,9 +116,8 @@ class BPFAbstractMemberAccess final : public ModulePass { void replaceWithGEP(std::vector &CallList, uint32_t NumOfZerosIndex, uint32_t DIIndex); - Value *computeBaseAndAccessStr(CallInst *Call, std::string &AccessStr, - std::string &AccessKey, uint32_t Kind, - MDNode *&TypeMeta); + Value *computeBaseAndAccessKey(CallInst *Call, std::string &AccessKey, + uint32_t Kind, MDNode *&TypeMeta); bool getAccessIndex(const Value *IndexValue, uint64_t &AccessIndex); bool transformGEPChain(Module &M, CallInst *Call, uint32_t Kind); }; @@ -340,8 +339,7 @@ bool BPFAbstractMemberAccess::getAccessIndex(const Value *IndexValue, /// Compute the base of the whole preserve_*_access_index chains, i.e., the base /// pointer of the first preserve_*_access_index call, and construct the access /// string, which will be the name of a global variable. -Value *BPFAbstractMemberAccess::computeBaseAndAccessStr(CallInst *Call, - std::string &AccessStr, +Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call, std::string &AccessKey, uint32_t Kind, MDNode *&TypeMeta) { @@ -392,16 +390,16 @@ Value *BPFAbstractMemberAccess::computeBaseAndAccessStr(CallInst *Call, if (!LastTypeName.size() || AccessIndices.size() > TypeNameIndex + 2) return nullptr; - // Construct the type string AccessStr. + // Construct the type string AccessKey. for (unsigned I = 0; I < AccessIndices.size(); ++I) - AccessStr = std::to_string(AccessIndices[I]) + ":" + AccessStr; + AccessKey = std::to_string(AccessIndices[I]) + ":" + AccessKey; if (TypeNameIndex == AccessIndices.size() - 1) - AccessStr = "0:" + AccessStr; + AccessKey = "0:" + AccessKey; // Access key is the type name + access string, uniquely identifying // one kernel memory access. - AccessKey = LastTypeName + ":" + AccessStr; + AccessKey = LastTypeName + ":" + AccessKey; return Base; } @@ -410,10 +408,10 @@ Value *BPFAbstractMemberAccess::computeBaseAndAccessStr(CallInst *Call, /// transformation to a chain of relocable GEPs. bool BPFAbstractMemberAccess::transformGEPChain(Module &M, CallInst *Call, uint32_t Kind) { - std::string AccessStr, AccessKey; + std::string AccessKey; MDNode *TypeMeta = nullptr; Value *Base = - computeBaseAndAccessStr(Call, AccessStr, AccessKey, Kind, TypeMeta); + computeBaseAndAccessKey(Call, AccessKey, Kind, TypeMeta); if (!Base) return false; @@ -432,7 +430,7 @@ bool BPFAbstractMemberAccess::transformGEPChain(Module &M, CallInst *Call, if (GEPGlobals.find(AccessKey) == GEPGlobals.end()) { GV = new GlobalVariable(M, Type::getInt64Ty(BB->getContext()), false, - GlobalVariable::ExternalLinkage, NULL, AccessStr); + GlobalVariable::ExternalLinkage, NULL, AccessKey); GV->addAttribute(BPFCoreSharedInfo::AmaAttr); // Set the metadata (debuginfo types) for the global. if (TypeMeta) diff --git a/llvm/lib/Target/BPF/BTFDebug.cpp b/llvm/lib/Target/BPF/BTFDebug.cpp index fa35c6619e21..5c542e739088 100644 --- a/llvm/lib/Target/BPF/BTFDebug.cpp +++ b/llvm/lib/Target/BPF/BTFDebug.cpp @@ -30,6 +30,18 @@ static const char *BTFKindStr[] = { #include "BTF.def" }; +static const DIType * stripQualifiers(const DIType *Ty) { + while (const auto *DTy = dyn_cast(Ty)) { + unsigned Tag = DTy->getTag(); + if (Tag != dwarf::DW_TAG_typedef && Tag != dwarf::DW_TAG_const_type && + Tag != dwarf::DW_TAG_volatile_type && Tag != dwarf::DW_TAG_restrict_type) + break; + Ty = DTy->getBaseType(); + } + + return Ty; +} + /// Emit a BTF common type. void BTFTypeBase::emitType(MCStreamer &OS) { OS.AddComment(std::string(BTFKindStr[Kind]) + "(id = " + std::to_string(Id) + @@ -184,9 +196,9 @@ void BTFTypeEnum::emitType(MCStreamer &OS) { } } -BTFTypeArray::BTFTypeArray(uint32_t ElemTypeId, uint32_t ElemSize, - uint32_t NumElems) - : ElemSize(ElemSize) { +BTFTypeArray::BTFTypeArray(const DIType *Ty, uint32_t ElemTypeId, + uint32_t ElemSize, uint32_t NumElems) + : ElemTyNoQual(Ty), ElemSize(ElemSize) { Kind = BTF::BTF_KIND_ARRAY; BTFType.NameOff = 0; BTFType.Info = Kind << 24; @@ -207,6 +219,9 @@ void BTFTypeArray::completeType(BTFDebug &BDebug) { // created during initial type traversal. Just // retrieve that type id. ArrayInfo.IndexType = BDebug.getArrayIndexTypeId(); + + ElemTypeNoQual = ElemTyNoQual ? BDebug.getTypeId(ElemTyNoQual) + : ArrayInfo.ElemType; } void BTFTypeArray::emitType(MCStreamer &OS) { @@ -218,7 +233,7 @@ void BTFTypeArray::emitType(MCStreamer &OS) { void BTFTypeArray::getLocInfo(uint32_t Loc, uint32_t &LocOffset, uint32_t &ElementTypeId) { - ElementTypeId = ArrayInfo.ElemType; + ElementTypeId = ElemTypeNoQual; LocOffset = Loc * ElemSize; } @@ -251,7 +266,9 @@ void BTFTypeStruct::completeType(BTFDebug &BDebug) { } else { BTFMember.Offset = DDTy->getOffsetInBits(); } - BTFMember.Type = BDebug.getTypeId(DDTy->getBaseType()); + const auto *BaseTy = DDTy->getBaseType(); + BTFMember.Type = BDebug.getTypeId(BaseTy); + MemberTypeNoQual.push_back(BDebug.getTypeId(stripQualifiers(BaseTy))); Members.push_back(BTFMember); } } @@ -270,7 +287,7 @@ std::string BTFTypeStruct::getName() { return STy->getName(); } void BTFTypeStruct::getMemberInfo(uint32_t Loc, uint32_t &MemberOffset, uint32_t &MemberType) { - MemberType = Members[Loc].Type; + MemberType = MemberTypeNoQual[Loc]; MemberOffset = HasBitField ? Members[Loc].Offset & 0xffffff : Members[Loc].Offset; } @@ -492,10 +509,13 @@ void BTFDebug::visitArrayType(const DICompositeType *CTy, uint32_t &TypeId) { uint32_t ElemTypeId, ElemSize; const DIType *ElemType = CTy->getBaseType(); visitTypeEntry(ElemType, ElemTypeId, false, false); + + // Strip qualifiers from element type to get accurate element size. + ElemType = stripQualifiers(ElemType); ElemSize = ElemType->getSizeInBits() >> 3; if (!CTy->getSizeInBits()) { - auto TypeEntry = llvm::make_unique(ElemTypeId, 0, 0); + auto TypeEntry = llvm::make_unique(ElemType, ElemTypeId, 0, 0); ArrayTypes.push_back(TypeEntry.get()); ElemTypeId = addType(std::move(TypeEntry), CTy); } else { @@ -507,9 +527,11 @@ void BTFDebug::visitArrayType(const DICompositeType *CTy, uint32_t &TypeId) { const DISubrange *SR = cast(Element); auto *CI = SR->getCount().dyn_cast(); int64_t Count = CI->getSExtValue(); + const DIType *ArrayElemTy = (I == 0) ? ElemType : nullptr; auto TypeEntry = - llvm::make_unique(ElemTypeId, ElemSize, Count); + llvm::make_unique(ArrayElemTy, ElemTypeId, + ElemSize, Count); ArrayTypes.push_back(TypeEntry.get()); if (I == 0) ElemTypeId = addType(std::move(TypeEntry), CTy); @@ -1006,19 +1028,20 @@ void BTFDebug::generateOffsetReloc(const MachineInstr *MI, unsigned RootId = populateStructType(RootTy); setTypeFromId(RootId, &PrevStructType, &PrevArrayType); unsigned RootTySize = PrevStructType->getStructSize(); + StringRef IndexPattern = AccessPattern.substr(AccessPattern.find_first_of(':') + 1); BTFOffsetReloc OffsetReloc; OffsetReloc.Label = ORSym; - OffsetReloc.OffsetNameOff = addString(AccessPattern.drop_back()); + OffsetReloc.OffsetNameOff = addString(IndexPattern.drop_back()); OffsetReloc.TypeID = RootId; uint32_t Start = 0, End = 0, Offset = 0; bool FirstAccess = true; - for (auto C : AccessPattern) { + for (auto C : IndexPattern) { if (C != ':') { End++; } else { - std::string SubStr = AccessPattern.substr(Start, End - Start); + std::string SubStr = IndexPattern.substr(Start, End - Start); int Loc = std::stoi(SubStr); if (FirstAccess) { @@ -1038,12 +1061,15 @@ void BTFDebug::generateOffsetReloc(const MachineInstr *MI, Offset += LocOffset; PrevArrayType = nullptr; setTypeFromId(ElementTypeId, &PrevStructType, &PrevArrayType); + } else { + llvm_unreachable("Internal Error: BTF offset relocation type traversal error"); } + Start = End + 1; End = Start; } } - AccessOffsets[RootTy->getName().str() + ":" + AccessPattern.str()] = Offset; + AccessOffsets[AccessPattern.str()] = Offset; OffsetRelocTable[SecNameOff].push_back(OffsetReloc); } @@ -1227,7 +1253,7 @@ bool BTFDebug::InstLower(const MachineInstr *MI, MCInst &OutMI) { MDNode *MDN = GVar->getMetadata(LLVMContext::MD_preserve_access_index); DIType *Ty = dyn_cast(MDN); std::string TypeName = Ty->getName(); - int64_t Imm = AccessOffsets[TypeName + ":" + GVar->getName().str()]; + int64_t Imm = AccessOffsets[GVar->getName().str()]; // Emit "mov ri, " for abstract member accesses. OutMI.setOpcode(BPF::MOV_ri); diff --git a/llvm/lib/Target/BPF/BTFDebug.h b/llvm/lib/Target/BPF/BTFDebug.h index 6c0cdde17d9b..e210d18f941e 100644 --- a/llvm/lib/Target/BPF/BTFDebug.h +++ b/llvm/lib/Target/BPF/BTFDebug.h @@ -104,11 +104,14 @@ class BTFTypeEnum : public BTFTypeBase { /// Handle array type. class BTFTypeArray : public BTFTypeBase { + const DIType *ElemTyNoQual; uint32_t ElemSize; struct BTF::BTFArray ArrayInfo; + uint32_t ElemTypeNoQual; public: - BTFTypeArray(uint32_t ElemTypeId, uint32_t ElemSize, uint32_t NumElems); + BTFTypeArray(const DIType *Ty, uint32_t ElemTypeId, + uint32_t ElemSize, uint32_t NumElems); uint32_t getSize() { return BTFTypeBase::getSize() + BTF::BTFArraySize; } void completeType(BTFDebug &BDebug); void emitType(MCStreamer &OS); @@ -120,6 +123,7 @@ class BTFTypeStruct : public BTFTypeBase { const DICompositeType *STy; bool HasBitField; std::vector Members; + std::vector MemberTypeNoQual; public: BTFTypeStruct(const DICompositeType *STy, bool IsStruct, bool HasBitField, diff --git a/llvm/lib/Target/CAHP/AsmParser/CAHPAsmParser.cpp b/llvm/lib/Target/CAHP/AsmParser/CAHPAsmParser.cpp new file mode 100644 index 000000000000..8f93e54c42db --- /dev/null +++ b/llvm/lib/Target/CAHP/AsmParser/CAHPAsmParser.cpp @@ -0,0 +1,628 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "MCTargetDesc/CAHPMCExpr.h" +#include "MCTargetDesc/CAHPMCTargetDesc.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCParser/MCTargetAsmParser.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +namespace { +struct CAHPOperand; + +class CAHPAsmParser : public MCTargetAsmParser { + SMLoc getLoc() const { return getParser().getTok().getLoc(); } + + bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo, + int64_t Lower, int64_t Upper, Twine Msg); + + bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, MCStreamer &Out, + uint64_t &ErrorInfo, + bool MatchingInlineAsm) override; + + bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; + + bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) override; + + bool ParseDirective(AsmToken DirectiveID) override; + +// Auto-generated instruction matching functions +#define GET_ASSEMBLER_HEADER +#include "CAHPGenAsmMatcher.inc" + + OperandMatchResultTy parseImmediate(OperandVector &Operands); + OperandMatchResultTy parseRegister(OperandVector &Operands); + OperandMatchResultTy parseMemOpBaseReg(OperandVector &Operands); + OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands); + + bool parseOperand(OperandVector &Operands); + +public: + enum CAHPMatchResultTy { + Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY, +#define GET_OPERAND_DIAGNOSTIC_TYPES +#include "CAHPGenAsmMatcher.inc" +#undef GET_OPERAND_DIAGNOSTIC_TYPES + }; + + static bool classifySymbolRef(const MCExpr *Expr, + CAHPMCExpr::VariantKind &Kind, int64_t &Addend); + + CAHPAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser, + const MCInstrInfo &MII, const MCTargetOptions &Options) + : MCTargetAsmParser(Options, STI, MII) { + setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); + } +}; + +/// CAHPOperand - Instances of this class represent a parsed machine +/// instruction +struct CAHPOperand : public MCParsedAsmOperand { + + enum KindTy { + Token, + Register, + Immediate, + } Kind; + + struct RegOp { + unsigned RegNum; + }; + + struct ImmOp { + const MCExpr *Val; + }; + + SMLoc StartLoc, EndLoc; + union { + StringRef Tok; + RegOp Reg; + ImmOp Imm; + }; + + CAHPOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} + +public: + CAHPOperand(const CAHPOperand &o) : MCParsedAsmOperand() { + Kind = o.Kind; + StartLoc = o.StartLoc; + EndLoc = o.EndLoc; + switch (Kind) { + case Register: + Reg = o.Reg; + break; + case Immediate: + Imm = o.Imm; + break; + case Token: + Tok = o.Tok; + break; + } + } + + bool isToken() const override { return Kind == Token; } + bool isReg() const override { return Kind == Register; } + bool isImm() const override { return Kind == Immediate; } + bool isMem() const override { return false; } + + bool evaluateConstantImm(int64_t &Imm, CAHPMCExpr::VariantKind &VK) const { + const MCExpr *Val = getImm(); + bool Ret = false; + if (auto *RE = dyn_cast(Val)) { + Ret = RE->evaluateAsConstant(Imm); + VK = RE->getKind(); + } else if (auto CE = dyn_cast(Val)) { + Ret = true; + VK = CAHPMCExpr::VK_CAHP_None; + Imm = CE->getValue(); + } + return Ret; + } + + // True if operand is a symbol with no modifiers, or a constant with no + // modifiers and pred(Op) is true. + template bool isBareImm(Pred pred) const { + if (!isImm()) + return false; + + CAHPMCExpr::VariantKind VK; + int64_t Imm; + bool IsValid; + + bool IsConstantImm = evaluateConstantImm(Imm, VK); + if (IsConstantImm) + IsValid = pred(Imm); + else + IsValid = CAHPAsmParser::classifySymbolRef(getImm(), VK, Imm); + + return IsValid && VK == CAHPMCExpr::VK_CAHP_None; + } + + int64_t getConstantImm() const { + const MCExpr *Val = getImm(); + return static_cast(Val)->getValue(); + } + + bool isUImm4() const { return isBareImm(isUInt<4>); } + + bool isSImm6() const { + if (!isImm()) + return false; + + CAHPMCExpr::VariantKind VK; + int64_t Imm; + bool IsValid; + + bool IsConstantImm = evaluateConstantImm(Imm, VK); + if (IsConstantImm) + IsValid = isInt<6>(Imm); + else + IsValid = CAHPAsmParser::classifySymbolRef(getImm(), VK, Imm); + + return IsValid && ((IsConstantImm && VK == CAHPMCExpr::VK_CAHP_None) || + VK == CAHPMCExpr::VK_CAHP_HI); + } + + bool isSImm10() const { + if (!isImm()) + return false; + + CAHPMCExpr::VariantKind VK; + int64_t Imm; + bool IsValid; + + bool IsConstantImm = evaluateConstantImm(Imm, VK); + if (IsConstantImm) + IsValid = isInt<10>(Imm); + else + IsValid = CAHPAsmParser::classifySymbolRef(getImm(), VK, Imm); + + return IsValid && ((IsConstantImm && VK == CAHPMCExpr::VK_CAHP_None) || + VK == CAHPMCExpr::VK_CAHP_LO); + } + + bool isBareSImm10() const { return isBareImm(isInt<10>); } + + bool isSImm11() const { return isBareImm(isInt<11>); } + + bool isUImm7Lsb0() const { return isBareImm(isShiftedUInt<6, 1>); } + + bool isSImm11Lsb0() const { return isBareImm(isShiftedInt<10, 1>); } + + /// getStartLoc - Gets location of the first token of this operand + SMLoc getStartLoc() const override { return StartLoc; } + /// getEndLoc - Gets location of the last token of this operand + SMLoc getEndLoc() const override { return EndLoc; } + + unsigned getReg() const override { + assert(Kind == Register && "Invalid type access!"); + return Reg.RegNum; + } + + const MCExpr *getImm() const { + assert(Kind == Immediate && "Invalid type access!"); + return Imm.Val; + } + + StringRef getToken() const { + assert(Kind == Token && "Invalid type access!"); + return Tok; + } + + void print(raw_ostream &OS) const override { + switch (Kind) { + case Immediate: + OS << *getImm(); + break; + case Register: + OS << ""; + break; + case Token: + OS << "'" << getToken() << "'"; + break; + } + } + + static std::unique_ptr createToken(StringRef Str, SMLoc S) { + auto Op = make_unique(Token); + Op->Tok = Str; + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } + + static std::unique_ptr createReg(unsigned RegNo, SMLoc S, + SMLoc E) { + auto Op = make_unique(Register); + Op->Reg.RegNum = RegNo; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + static std::unique_ptr createImm(const MCExpr *Val, SMLoc S, + SMLoc E) { + auto Op = make_unique(Immediate); + Op->Imm.Val = Val; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + + void addExpr(MCInst &Inst, const MCExpr *Expr) const { + assert(Expr && "Expr shouldn't be null!"); + + int64_t Imm = 0; + bool IsConstant = false; + if (auto *RE = dyn_cast(Expr)) { + IsConstant = RE->evaluateAsConstant(Imm); + } else if (auto *CE = dyn_cast(Expr)) { + IsConstant = true; + Imm = CE->getValue(); + } + + if (IsConstant) + Inst.addOperand(MCOperand::createImm(Imm)); + else + Inst.addOperand(MCOperand::createExpr(Expr)); + } + + // Used by the TableGen Code + void addRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getReg())); + } + + void addImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addExpr(Inst, getImm()); + } +}; +} // end anonymous namespace. + +#define GET_REGISTER_MATCHER +#define GET_MATCHER_IMPLEMENTATION +#include "CAHPGenAsmMatcher.inc" + +bool CAHPAsmParser::generateImmOutOfRangeError( + OperandVector &Operands, uint64_t ErrorInfo, int64_t Lower, int64_t Upper, + Twine Msg = "immediate must be an integer in the range") { + SMLoc ErrorLoc = ((CAHPOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error(ErrorLoc, Msg + " [" + Twine(Lower) + ", " + Twine(Upper) + "]"); +} + +bool CAHPAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, + OperandVector &Operands, + MCStreamer &Out, + uint64_t &ErrorInfo, + bool MatchingInlineAsm) { + MCInst Inst; + + unsigned Res = + MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm); + switch (Res) { + default: + break; + case Match_Success: + Inst.setLoc(IDLoc); + Out.EmitInstruction(Inst, getSTI()); + return false; + case Match_MissingFeature: + return Error(IDLoc, "instruction use requires an option to be enabled"); + case Match_MnemonicFail: + return Error(IDLoc, "unrecognized instruction mnemonic"); + case Match_InvalidOperand: { + SMLoc ErrorLoc = IDLoc; + if (ErrorInfo != ~0U) { + if (ErrorInfo >= Operands.size()) + return Error(ErrorLoc, "too few operands for instruction"); + + ErrorLoc = ((CAHPOperand &)*Operands[ErrorInfo]).getStartLoc(); + if (ErrorLoc == SMLoc()) + ErrorLoc = IDLoc; + } + return Error(ErrorLoc, "invalid operand for instruction"); + } + } + + CAHPOperand &Operand = (CAHPOperand &)*Operands[ErrorInfo]; + if (!Operand.isImm()) + return Error(Operand.getStartLoc(), "invalid operand for instruction"); + + switch (Res) { +#define CASE_MATCH_INVALID_SIMM(nbits) \ + case Match_InvalidSImm##nbits: \ + return generateImmOutOfRangeError( \ + Operands, ErrorInfo, -(1 << (nbits - 1)), (1 << (nbits - 1)) - 1); +#define CASE_MATCH_INVALID_UIMM(nbits) \ + case Match_InvalidUImm##nbits: \ + return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << nbits) - 1); +#define CASE_MATCH_INVALID_SIMM_LSB0(nbits) \ + case Match_InvalidSImm##nbits##Lsb0: \ + return generateImmOutOfRangeError( \ + Operands, ErrorInfo, -(1 << (nbits - 1)), (1 << (nbits - 1)) - 2, \ + "immediate must be a multiple of 2 bytes in the range"); +#define CASE_MATCH_INVALID_UIMM_LSB0(nbits) \ + case Match_InvalidUImm##nbits##Lsb0: \ + return generateImmOutOfRangeError( \ + Operands, ErrorInfo, 0, (1 << nbits) - 2, \ + "immediate must be a multiple of 2 bytes in the range"); + + CASE_MATCH_INVALID_UIMM(4); + CASE_MATCH_INVALID_SIMM(11); + CASE_MATCH_INVALID_UIMM_LSB0(7); + + case Match_InvalidSImm6: + return generateImmOutOfRangeError( + Operands, ErrorInfo, -(1 << 5), (1 << 5) - 1, + "operand must be a symbol with %hi modifier or an integer in " + "the range"); + + case Match_InvalidSImm10: + return generateImmOutOfRangeError( + Operands, ErrorInfo, -(1 << 9), (1 << 9) - 1, + "operand must be a symbol with %lo modifier or an integer in " + "the range"); + } + + llvm_unreachable("Unknown match type detected!"); +} + +bool CAHPAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, + SMLoc &EndLoc) { + const AsmToken &Tok = getParser().getTok(); + StartLoc = Tok.getLoc(); + EndLoc = Tok.getEndLoc(); + RegNo = 0; + StringRef Name = getLexer().getTok().getIdentifier(); + + if (!MatchRegisterName(Name) || !MatchRegisterAltName(Name)) { + getParser().Lex(); // Eat identifier token. + return false; + } + + return Error(StartLoc, "invalid register name"); +} + +OperandMatchResultTy CAHPAsmParser::parseRegister(OperandVector &Operands) { + SMLoc S = getLoc(); + SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); + + switch (getLexer().getKind()) { + default: + return MatchOperand_NoMatch; + case AsmToken::Identifier: + StringRef Name = getLexer().getTok().getIdentifier(); + unsigned RegNo = MatchRegisterName(Name); + if (RegNo == 0) { + RegNo = MatchRegisterAltName(Name); + if (RegNo == 0) + return MatchOperand_NoMatch; + } + getLexer().Lex(); + Operands.push_back(CAHPOperand::createReg(RegNo, S, E)); + } + return MatchOperand_Success; +} + +OperandMatchResultTy CAHPAsmParser::parseImmediate(OperandVector &Operands) { + SMLoc S = getLoc(); + SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); + const MCExpr *Res; + + switch (getLexer().getKind()) { + default: + return MatchOperand_NoMatch; + + case AsmToken::LParen: + case AsmToken::Minus: + case AsmToken::Plus: + case AsmToken::Integer: + case AsmToken::String: + if (getParser().parseExpression(Res)) + return MatchOperand_ParseFail; + break; + + case AsmToken::Identifier: { + StringRef Identifier; + if (getParser().parseIdentifier(Identifier)) + return MatchOperand_ParseFail; + MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); + Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + break; + } + + case AsmToken::Percent: { + return parseOperandWithModifier(Operands); + } + } + + Operands.push_back(CAHPOperand::createImm(Res, S, E)); + return MatchOperand_Success; +} + +OperandMatchResultTy +CAHPAsmParser::parseOperandWithModifier(OperandVector &Operands) { + SMLoc S = getLoc(); + SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); + + if (getLexer().getKind() != AsmToken::Percent) { + Error(getLoc(), "expected '%' for operand modifier"); + return MatchOperand_ParseFail; + } + + getParser().Lex(); // Eat '%' + + if (getLexer().getKind() != AsmToken::Identifier) { + Error(getLoc(), "expected valid identifier for operand modifier"); + return MatchOperand_ParseFail; + } + StringRef Identifier = getParser().getTok().getIdentifier(); + CAHPMCExpr::VariantKind VK = CAHPMCExpr::getVariantKindForName(Identifier); + if (VK == CAHPMCExpr::VK_CAHP_Invalid) { + Error(getLoc(), "unrecognized operand modifier"); + return MatchOperand_ParseFail; + } + + getParser().Lex(); // Eat the identifier + if (getLexer().getKind() != AsmToken::LParen) { + Error(getLoc(), "expected '('"); + return MatchOperand_ParseFail; + } + getParser().Lex(); // Eat '(' + + const MCExpr *SubExpr; + if (getParser().parseParenExpression(SubExpr, E)) { + return MatchOperand_ParseFail; + } + + const MCExpr *ModExpr = CAHPMCExpr::create(SubExpr, VK, getContext()); + Operands.push_back(CAHPOperand::createImm(ModExpr, S, E)); + return MatchOperand_Success; +} + +OperandMatchResultTy CAHPAsmParser::parseMemOpBaseReg(OperandVector &Operands) { + if (getLexer().isNot(AsmToken::LParen)) { + Error(getLoc(), "expected '('"); + return MatchOperand_ParseFail; + } + + getParser().Lex(); // Eat '(' + Operands.push_back(CAHPOperand::createToken("(", getLoc())); + + if (parseRegister(Operands) != MatchOperand_Success) { + Error(getLoc(), "expected register"); + return MatchOperand_ParseFail; + } + + if (getLexer().isNot(AsmToken::RParen)) { + Error(getLoc(), "expected ')'"); + return MatchOperand_ParseFail; + } + + getParser().Lex(); // Eat ')' + Operands.push_back(CAHPOperand::createToken(")", getLoc())); + + return MatchOperand_Success; +} + +/// Looks at a token type and creates the relevant operand +/// from this information, adding to Operands. +/// If operand was parsed, returns false, else true. +bool CAHPAsmParser::parseOperand(OperandVector &Operands) { + // Attempt to parse token as register + if (parseRegister(Operands) == MatchOperand_Success) + return false; + + // Attempt to parse token as an immediate + if (parseImmediate(Operands) == MatchOperand_Success) { + // Parse memory base register if present + if (getLexer().is(AsmToken::LParen)) + return parseMemOpBaseReg(Operands) != MatchOperand_Success; + return false; + } + + // Finally we have exhausted all options and must declare defeat. + Error(getLoc(), "unknown operand"); + return true; +} + +bool CAHPAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands) { + // First operand is token for instruction + Operands.push_back(CAHPOperand::createToken(Name, NameLoc)); + + // If there are no more operands, then finish + if (getLexer().is(AsmToken::EndOfStatement)) + return false; + + // Parse first operand + if (parseOperand(Operands)) + return true; + + // Parse until end of statement, consuming commas between operands + while (getLexer().is(AsmToken::Comma)) { + // Consume comma token + getLexer().Lex(); + + // Parse next operand + if (parseOperand(Operands)) + return true; + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + SMLoc Loc = getLexer().getLoc(); + getParser().eatToEndOfStatement(); + return Error(Loc, "unexpected token"); + } + + getParser().Lex(); // Consume the EndOfStatement. + return false; +} + +bool CAHPAsmParser::classifySymbolRef(const MCExpr *Expr, + CAHPMCExpr::VariantKind &Kind, + int64_t &Addend) { + Kind = CAHPMCExpr::VK_CAHP_None; + Addend = 0; + + if (const CAHPMCExpr *RE = dyn_cast(Expr)) { + Kind = RE->getKind(); + Expr = RE->getSubExpr(); + } + + // It's a simple symbol reference or constant with no addend. + if (isa(Expr) || isa(Expr)) + return true; + + const MCBinaryExpr *BE = dyn_cast(Expr); + if (!BE) + return false; + + if (!isa(BE->getLHS())) + return false; + + if (BE->getOpcode() != MCBinaryExpr::Add && + BE->getOpcode() != MCBinaryExpr::Sub) + return false; + + // We are able to support the subtraction of two symbol references + if (BE->getOpcode() == MCBinaryExpr::Sub && + isa(BE->getRHS())) + return true; + + // See if the addend is is a constant, otherwise there's more going + // on here than we can deal with. + auto AddendExpr = dyn_cast(BE->getRHS()); + if (!AddendExpr) + return false; + + Addend = AddendExpr->getValue(); + if (BE->getOpcode() == MCBinaryExpr::Sub) + Addend = -Addend; + + // It's some symbol reference + a constant addend + return Kind != CAHPMCExpr::VK_CAHP_Invalid; +} + +bool CAHPAsmParser::ParseDirective(AsmToken DirectiveID) { return true; } + +extern "C" void LLVMInitializeCAHPAsmParser() { + RegisterMCAsmParser X(getTheCAHPTarget()); +} diff --git a/llvm/lib/Target/CAHP/AsmParser/CMakeLists.txt b/llvm/lib/Target/CAHP/AsmParser/CMakeLists.txt new file mode 100644 index 000000000000..3675ebe04bfb --- /dev/null +++ b/llvm/lib/Target/CAHP/AsmParser/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_library(LLVMCAHPAsmParser + CAHPAsmParser.cpp + ) diff --git a/llvm/lib/Target/CAHP/AsmParser/LLVMBuild.txt b/llvm/lib/Target/CAHP/AsmParser/LLVMBuild.txt new file mode 100644 index 000000000000..ffa9ef3e7e06 --- /dev/null +++ b/llvm/lib/Target/CAHP/AsmParser/LLVMBuild.txt @@ -0,0 +1,10 @@ +; This file is copied and modified from The LLVM Compiler Infrastructure, which +; is distributed under the Apache License v2.0 with LLVM Exceptions (see +; LICENSE.TXT for details). This file is licensed under the same license. + +[component_0] +type = Library +name = CAHPAsmParser +parent = CAHP +required_libraries = MC MCParser CAHPDesc CAHPInfo Support +add_to_library_groups = CAHP diff --git a/llvm/lib/Target/CAHP/CAHP.h b/llvm/lib/Target/CAHP/CAHP.h new file mode 100644 index 000000000000..2bec5865ee19 --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHP.h @@ -0,0 +1,27 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#ifndef LLVM_LIB_TARGET_CAHP_CAHP_H +#define LLVM_LIB_TARGET_CAHP_CAHP_H + +#include "MCTargetDesc/CAHPBaseInfo.h" + +namespace llvm { +class AsmPrinter; +class CAHPTargetMachine; +class FunctionPass; +class MCInst; +class MCOperand; +class MachineInstr; +class MachineOperand; + +void LowerCAHPMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI, + const AsmPrinter &AP); +bool LowerCAHPMachineOperandToMCOperand(const MachineOperand &MO, + MCOperand &MCOp, const AsmPrinter &AP); + +FunctionPass *createCAHPISelDag(CAHPTargetMachine &TM); +} // namespace llvm + +#endif diff --git a/llvm/lib/Target/CAHP/CAHP.td b/llvm/lib/Target/CAHP/CAHP.td new file mode 100644 index 000000000000..c06a00ec9ae4 --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHP.td @@ -0,0 +1,45 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +include "llvm/Target/Target.td" + +//===----------------------------------------------------------------------===// +// Register file, calling conventions, instruction descriptions. +//===----------------------------------------------------------------------===// + +include "CAHPSchedule.td" +include "CAHPRegisterInfo.td" +include "CAHPCallingConv.td" +include "CAHPInstrInfo.td" + +//===----------------------------------------------------------------------===// +// CAHP processors supported. +//===----------------------------------------------------------------------===// + +def : ProcessorModel<"generic", NoSchedModel, []>; +def : ProcessorModel<"emerald", EmeraldModel, []>; + +//===----------------------------------------------------------------------===// +// Define the CAHP target. +//===----------------------------------------------------------------------===// + +def CAHPInstrInfo : InstrInfo { + let guessInstructionProperties = 0; +} + +def CAHPAsmParser : AsmParser { + // Use alternative names of registers when emitting. + let ShouldEmitMatchRegisterAltName = 1; +} + +def CAHPAsmWriter : AsmWriter { + int PassSubtarget = 1; +} + +def CAHP : Target { + let InstructionSet = CAHPInstrInfo; + let AssemblyParsers = [CAHPAsmParser]; + let AssemblyWriters = [CAHPAsmWriter]; + let AllowRegisterRenaming = 1; +} diff --git a/llvm/lib/Target/CAHP/CAHPAsmPrinter.cpp b/llvm/lib/Target/CAHP/CAHPAsmPrinter.cpp new file mode 100644 index 000000000000..25811b6e4c66 --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHPAsmPrinter.cpp @@ -0,0 +1,107 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "CAHP.h" +#include "CAHPTargetMachine.h" +#include "InstPrinter/CAHPInstPrinter.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +#define DEBUG_TYPE "asm-printer" + +namespace { +class CAHPAsmPrinter : public AsmPrinter { +public: + explicit CAHPAsmPrinter(TargetMachine &TM, + std::unique_ptr Streamer) + : AsmPrinter(TM, std::move(Streamer)) {} + + StringRef getPassName() const override { return "CAHP Assembly Printer"; } + + void EmitInstruction(const MachineInstr *MI) override; + + bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + const char *ExtraCode, raw_ostream &OS) override; + bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, + const char *ExtraCode, raw_ostream &OS) override; + + // TableGen'erated function. + bool emitPseudoExpansionLowering(MCStreamer &OutStreamer, + const MachineInstr *MI); +}; +} // namespace + +// Simple pseudo-instructions have their lowering (with expansion to real +// instructions) auto-generated. +#include "CAHPGenMCPseudoLowering.inc" + +#define GEN_COMPRESS_INSTR +#include "CAHPGenCompressInstEmitter.inc" + +void CAHPAsmPrinter::EmitInstruction(const MachineInstr *MI) { + // Do any auto-generated pseudo lowerings. + if (emitPseudoExpansionLowering(*OutStreamer, MI)) + return; + + MCInst TmpInst, CInst; + LowerCAHPMachineInstrToMCInst(MI, TmpInst, *this); + bool Res = compressInst(CInst, TmpInst, *TM.getMCSubtargetInfo(), + OutStreamer->getContext()); + EmitToStreamer(*OutStreamer, Res ? CInst : TmpInst); +} + +bool CAHPAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + const char *ExtraCode, raw_ostream &OS) { + // First try the generic code, which knows about modifiers like 'c' and 'n'. + if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS)) + return false; + + if (!ExtraCode) { + const MachineOperand &MO = MI->getOperand(OpNo); + switch (MO.getType()) { + case MachineOperand::MO_Immediate: + OS << MO.getImm(); + return false; + case MachineOperand::MO_Register: + OS << CAHPInstPrinter::getRegisterName(MO.getReg()); + return false; + default: + break; + } + } + + return true; +} + +bool CAHPAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, + unsigned OpNo, const char *ExtraCode, + raw_ostream &OS) { + if (!ExtraCode) { + const MachineOperand &MO = MI->getOperand(OpNo); + // For now, we only support register memory operands in registers and + // assume there is no addend + if (!MO.isReg()) + return true; + + OS << "0(" << CAHPInstPrinter::getRegisterName(MO.getReg()) << ")"; + return false; + } + + return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS); +} + +// Force static initialization. +extern "C" void LLVMInitializeCAHPAsmPrinter() { + RegisterAsmPrinter X(getTheCAHPTarget()); +} diff --git a/llvm/lib/Target/CAHP/CAHPCallingConv.td b/llvm/lib/Target/CAHP/CAHPCallingConv.td new file mode 100644 index 000000000000..c57a85fd7083 --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHPCallingConv.td @@ -0,0 +1,22 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +// CAHP 16-bit C return-value convention. +def RetCC_CAHP : CallingConv<[ + CCIfType<[i16], CCAssignToReg<[X8, X9]>> +]>; + +// CAHP 16-bit C Calling convention. +def CC_CAHP : CallingConv<[ + // Promote i8 args to i16 + CCIfType<[i8], CCPromoteToType>, + + // All arguments get passed in integer registers if there is space. + CCIfType<[i16], CCAssignToReg<[ X8, X9, X10, X11, X12, X13 ]>>, + + // Could be assigned to the stack in 8-byte aligned units, but unsupported + CCAssignToStack<2, 2> // The slot's size, the stack alignment +]>; + +def CSR : CalleeSavedRegs<(add X0, X2, X3, X4, X5, X6, X7)>; diff --git a/llvm/lib/Target/CAHP/CAHPFrameLowering.cpp b/llvm/lib/Target/CAHP/CAHPFrameLowering.cpp new file mode 100644 index 000000000000..270a97c8ed6c --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHPFrameLowering.cpp @@ -0,0 +1,215 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "CAHPFrameLowering.h" +#include "CAHPSubtarget.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/RegisterScavenging.h" + +using namespace llvm; + +// hasFP - Return true if the specified function should have a dedicated frame +// pointer register. This is true if the function has variable sized allocas or +// if frame pointer elimination is disabled. +bool CAHPFrameLowering::hasFP(const MachineFunction &MF) const { + const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); + const MachineFrameInfo &MFI = MF.getFrameInfo(); + + return MF.getTarget().Options.DisableFramePointerElim(MF) || + RegInfo->needsStackRealignment(MF) || MFI.hasVarSizedObjects() || + MFI.isFrameAddressTaken(); +} + +// Determines the size of the frame and maximum call frame size. +void CAHPFrameLowering::determineFrameLayout(MachineFunction &MF) const { + MachineFrameInfo &MFI = MF.getFrameInfo(); + const CAHPRegisterInfo *RI = STI.getRegisterInfo(); + + // Get the number of bytes to allocate from the FrameInfo. + uint64_t FrameSize = MFI.getStackSize(); + + // Get the alignment. + uint64_t StackAlign = RI->needsStackRealignment(MF) ? MFI.getMaxAlignment() + : getStackAlignment(); + + // Make sure the frame is aligned. + FrameSize = alignTo(FrameSize, StackAlign); + + // Update frame info. + MFI.setStackSize(FrameSize); +} + +// Build a MI to compute "DestReg = SrcReg + Val" +void CAHPFrameLowering::adjustReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + const DebugLoc &DL, unsigned DestReg, + unsigned SrcReg, int64_t Val, + MachineInstr::MIFlag Flag) const { + if (DestReg == SrcReg && Val == 0) + return; + + MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo(); + const CAHPInstrInfo *TII = STI.getInstrInfo(); + + if (isInt<10>(Val)) { + BuildMI(MBB, MBBI, DL, TII->get(CAHP::ADDI), DestReg) + .addReg(SrcReg) + .addImm(Val) + .setMIFlag(Flag); + } else if (isInt<16>(Val)) { + unsigned Opc = CAHP::ADD; + bool isSub = Val < 0; + if (isSub) { + Val = -Val; + Opc = CAHP::SUB; + } + + unsigned ScratchReg = MRI.createVirtualRegister(&CAHP::GPRRegClass); + TII->movImm16(MBB, MBBI, DL, ScratchReg, Val, Flag); + BuildMI(MBB, MBBI, DL, TII->get(Opc), DestReg) + .addReg(SrcReg) + .addReg(ScratchReg) + .setMIFlag(Flag); + } else { + report_fatal_error("adjustReg cannot yet handle adjustments >16 bits"); + } +} + +// Returns the register used to hold the frame pointer. +static unsigned getFPReg() { return CAHP::X2; } + +// Returns the register used to hold the stack pointer. +static unsigned getSPReg() { return CAHP::X1; } + +void CAHPFrameLowering::emitPrologue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported"); + + MachineFrameInfo &MFI = MF.getFrameInfo(); + MachineBasicBlock::iterator MBBI = MBB.begin(); + + unsigned FPReg = getFPReg(); + unsigned SPReg = getSPReg(); + + // Debug location must be unknown since the first debug location is used + // to determine the end of the prologue. + DebugLoc DL; + + // Determine the correct frame layout + determineFrameLayout(MF); + + // FIXME (note copied from Lanai/RISCV): This appears to be overallocating. + // Needs investigation. Get the number of bytes to allocate from the + // FrameInfo. + uint64_t StackSize = MFI.getStackSize(); + + // Early exit if there is no need to allocate on the stack + if (StackSize == 0 && !MFI.adjustsStack()) + return; + + // Allocate space on the stack if necessary. + adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup); + + // The frame pointer is callee-saved, and code has been generated for us to + // save it to the stack. We need to skip over the storing of callee-saved + // registers as the frame pointer must be modified after it has been saved + // to the stack, not before. + // FIXME: assumes exactly one instruction is used to save each callee-saved + // register. + const std::vector &CSI = MFI.getCalleeSavedInfo(); + std::advance(MBBI, CSI.size()); + + // Generate new FP. + if (hasFP(MF)) + adjustReg(MBB, MBBI, DL, FPReg, SPReg, StackSize, MachineInstr::FrameSetup); +} + +void CAHPFrameLowering::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); + const CAHPRegisterInfo *RI = STI.getRegisterInfo(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + DebugLoc DL = MBBI->getDebugLoc(); + unsigned FPReg = getFPReg(); + unsigned SPReg = getSPReg(); + + // Skip to before the restores of callee-saved registers + // FIXME: assumes exactly one instruction is used to restore each + // callee-saved register. + MachineBasicBlock::iterator LastFrameDestroy = MBBI; + std::advance(LastFrameDestroy, -MFI.getCalleeSavedInfo().size()); + + uint64_t StackSize = MFI.getStackSize(); + + // Restore the stack pointer using the value of the frame pointer. Only + // necessary if the stack pointer was modified, meaning the stack size is + // unknown. + if (RI->needsStackRealignment(MF) || MFI.hasVarSizedObjects()) { + assert(hasFP(MF) && "frame pointer should not have been eliminated"); + adjustReg(MBB, LastFrameDestroy, DL, SPReg, FPReg, -StackSize, + MachineInstr::FrameDestroy); + } + + // Deallocate stack + adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy); +} + +int CAHPFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI, + unsigned &FrameReg) const { + const MachineFrameInfo &MFI = MF.getFrameInfo(); + const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo(); + + // Callee-saved registers should be referenced relative to the stack + // pointer (positive offset), otherwise use the frame pointer (negative + // offset). + const std::vector &CSI = MFI.getCalleeSavedInfo(); + int MinCSFI = 0; + int MaxCSFI = -1; + + int Offset = MFI.getObjectOffset(FI) - getOffsetOfLocalArea() + + MFI.getOffsetAdjustment(); + + if (CSI.size()) { + MinCSFI = CSI[0].getFrameIdx(); + MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); + } + + FrameReg = RI->getFrameRegister(MF); + + // If the frame index points to a callee-saved register or no frame pointer is + // used in the MachineFunction, then make the Offset relative to the stack + // pointer. + if ((FI >= MinCSFI && FI <= MaxCSFI) || !hasFP(MF)) { + FrameReg = CAHP::X1; // X1 is SP. + Offset += MF.getFrameInfo().getStackSize(); + } + return Offset; +} + +void CAHPFrameLowering::determineCalleeSaves(MachineFunction &MF, + BitVector &SavedRegs, + RegScavenger *RS) const { + TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); + // Unconditionally spill RA and FP only if the function uses a frame + // pointer. + if (hasFP(MF)) { + SavedRegs.set(CAHP::X0); + SavedRegs.set(CAHP::X2); + } +} + +void CAHPFrameLowering::processFunctionBeforeFrameFinalized( + MachineFunction &MF, RegScavenger *RS) const { + const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + const TargetRegisterClass *RC = &CAHP::GPRRegClass; + if (!isInt<9>(MFI.estimateStackSize(MF))) { + int RegScavFI = MFI.CreateStackObject( + RegInfo->getSpillSize(*RC), RegInfo->getSpillAlignment(*RC), false); + RS->addScavengingFrameIndex(RegScavFI); + } +} diff --git a/llvm/lib/Target/CAHP/CAHPFrameLowering.h b/llvm/lib/Target/CAHP/CAHPFrameLowering.h new file mode 100644 index 000000000000..611d3beb714d --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHPFrameLowering.h @@ -0,0 +1,50 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#ifndef LLVM_LIB_TARGET_CAHP_CAHPFRAMELOWERING_H +#define LLVM_LIB_TARGET_CAHP_CAHPFRAMELOWERING_H + +#include "llvm/CodeGen/TargetFrameLowering.h" + +namespace llvm { +class CAHPSubtarget; + +class CAHPFrameLowering : public TargetFrameLowering { +private: + const CAHPSubtarget &STI; + + void determineFrameLayout(MachineFunction &MF) const; + void adjustReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + const DebugLoc &DL, unsigned DestReg, unsigned SrcReg, + int64_t Val, MachineInstr::MIFlag Flag) const; + +public: + explicit CAHPFrameLowering(const CAHPSubtarget &STI) + : TargetFrameLowering(StackGrowsDown, + /*StackAlignment=*/2, + /*LocalAreaOffset=*/0), + STI(STI) {} + + void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override; + + int getFrameIndexReference(const MachineFunction &MF, int FI, + unsigned &FrameReg) const override; + + void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, + RegScavenger *RS) const override; + + void processFunctionBeforeFrameFinalized(MachineFunction &MF, + RegScavenger *RS) const override; + + bool hasFP(const MachineFunction &MF) const override; + + MachineBasicBlock::iterator + eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI) const override { + return MBB.erase(MI); + } +}; +} // namespace llvm +#endif diff --git a/llvm/lib/Target/CAHP/CAHPISelDAGToDAG.cpp b/llvm/lib/Target/CAHP/CAHPISelDAGToDAG.cpp new file mode 100644 index 000000000000..2160502e73ca --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHPISelDAGToDAG.cpp @@ -0,0 +1,90 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "CAHP.h" +#include "CAHPTargetMachine.h" +#include "MCTargetDesc/CAHPMCTargetDesc.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +#define DEBUG_TYPE "cahp-isel" + +// CAHP-specific code to select CAHP machine instructions for +// SelectionDAG operations. +namespace { +class CAHPDAGToDAGISel final : public SelectionDAGISel { +public: + explicit CAHPDAGToDAGISel(CAHPTargetMachine &TargetMachine) + : SelectionDAGISel(TargetMachine) {} + + StringRef getPassName() const override { + return "CAHP DAG->DAG Pattern Instruction Selection"; + } + + void Select(SDNode *Node) override; + + bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, + std::vector &OutOps) override; + + bool SelectAddrFI(SDValue Addr, SDValue &Base); + + // Include the pieces autogenerated from the target description. +#include "CAHPGenDAGISel.inc" +}; +} // namespace + +void CAHPDAGToDAGISel::Select(SDNode *Node) { + // If we have a custom node, we have already selected + if (Node->isMachineOpcode()) { + LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n"); + Node->setNodeId(-1); + return; + } + + if (Node->getOpcode() == ISD::FrameIndex) { + SDLoc DL(Node); + SDValue Imm = CurDAG->getTargetConstant(0, DL, MVT::i16); + int FI = dyn_cast(Node)->getIndex(); + EVT VT = Node->getValueType(0); + SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT); + ReplaceNode(Node, CurDAG->getMachineNode(CAHP::ADDI, DL, VT, TFI, Imm)); + return; + } + + // Select the default instruction. + SelectCode(Node); +} + +bool CAHPDAGToDAGISel::SelectInlineAsmMemoryOperand( + const SDValue &Op, unsigned ConstraintID, std::vector &OutOps) { + switch (ConstraintID) { + case InlineAsm::Constraint_i: + case InlineAsm::Constraint_m: + // We just support simple memory operands that have a single address + // operand and need no special handling. + OutOps.push_back(Op); + return false; + default: + break; + } + + return true; +} + +bool CAHPDAGToDAGISel::SelectAddrFI(SDValue Addr, SDValue &Base) { + if (auto FIN = dyn_cast(Addr)) { + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i16); + return true; + } + return false; +} + +// This pass converts a legalized DAG into a CAHP-specific DAG, ready +// for instruction scheduling. +FunctionPass *llvm::createCAHPISelDag(CAHPTargetMachine &TM) { + return new CAHPDAGToDAGISel(TM); +} diff --git a/llvm/lib/Target/CAHP/CAHPISelLowering.cpp b/llvm/lib/Target/CAHP/CAHPISelLowering.cpp new file mode 100644 index 000000000000..9fcd69146f46 --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHPISelLowering.cpp @@ -0,0 +1,626 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "CAHPISelLowering.h" +#include "CAHP.h" +#include "CAHPRegisterInfo.h" +#include "CAHPSubtarget.h" +#include "CAHPTargetMachine.h" +#include "MCTargetDesc/CAHPBaseInfo.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#define DEBUG_TYPE "cahp-lower" + +CAHPTargetLowering::CAHPTargetLowering(const TargetMachine &TM, + const CAHPSubtarget &STI) + : TargetLowering(TM), Subtarget(STI) { + + // Set up the register classes. + addRegisterClass(MVT::i16, &CAHP::GPRRegClass); + + // Compute derived properties from the register classes. + computeRegisterProperties(STI.getRegisterInfo()); + + setStackPointerRegisterToSaveRestore(CAHP::X1); + + for (auto N : {ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}) + setLoadExtAction(N, MVT::i16, MVT::i1, Promote); + + // TODO: add all necessary setOperationAction calls. + setOperationAction(ISD::GlobalAddress, MVT::i16, Custom); + setOperationAction(ISD::BRCOND, MVT::Other, Expand); + setOperationAction(ISD::BR_CC, MVT::i16, Custom); + setOperationAction(ISD::BR_JT, MVT::Other, Expand); + setOperationAction(ISD::SELECT, MVT::i16, Custom); + setOperationAction(ISD::SELECT_CC, MVT::i16, Expand); + setOperationAction(ISD::SETCC, MVT::i16, Expand); + for (auto VT : {MVT::i1, MVT::i8}) + setOperationAction(ISD::SIGN_EXTEND_INREG, VT, Expand); + + setOperationAction(ISD::MUL, MVT::i16, Expand); + setOperationAction(ISD::SMUL_LOHI, MVT::i16, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i16, Expand); + setOperationAction(ISD::MULHS, MVT::i16, Expand); + setOperationAction(ISD::MULHU, MVT::i16, Expand); + + setOperationAction(ISD::SREM, MVT::i16, Expand); + setOperationAction(ISD::SDIVREM, MVT::i16, Expand); + setOperationAction(ISD::SDIV, MVT::i16, Expand); + setOperationAction(ISD::UREM, MVT::i16, Expand); + setOperationAction(ISD::UDIVREM, MVT::i16, Expand); + setOperationAction(ISD::UDIV, MVT::i16, Expand); + + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i16, Expand); + setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); + setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); + + setBooleanContents(ZeroOrOneBooleanContent); + + // Function alignments (log2). + setMinFunctionAlignment(0); + setPrefFunctionAlignment(0); + + // Effectively disable jump table generation. + setMinimumJumpTableEntries(INT_MAX); +} + +// Changes the condition code and swaps operands if necessary, so the SetCC +// operation matches one of the comparisons supported directly in the CAHP +// ISA. +static void normalizeSetCC(SDValue &LHS, SDValue &RHS, ISD::CondCode &CC) { + switch (CC) { + default: + break; + case ISD::SETGT: + case ISD::SETGE: + case ISD::SETUGT: + case ISD::SETUGE: + CC = ISD::getSetCCSwappedOperands(CC); + std::swap(LHS, RHS); + break; + } +} + +// Return the CAHP branch opcode that matches the given DAG integer +// condition code. The CondCode must be one of those supported by the CAHP +// ISA (see normalizeSetCC). +static unsigned getBranchOpcodeForIntCondCode(ISD::CondCode CC) { + switch (CC) { + default: + llvm_unreachable("Unsupported CondCode"); + case ISD::SETEQ: + return CAHP::BEQ; + case ISD::SETNE: + return CAHP::BNE; + case ISD::SETLT: + return CAHP::BLT; + case ISD::SETLE: + return CAHP::BLE; + case ISD::SETULT: + return CAHP::BLTU; + case ISD::SETULE: + return CAHP::BLEU; + } +} + +SDValue CAHPTargetLowering::LowerOperation(SDValue Op, + SelectionDAG &DAG) const { + switch (Op.getOpcode()) { + default: + report_fatal_error("unimplemented operand"); + + case ISD::BR_CC: + return LowerBR_CC(Op, DAG); + + case ISD::GlobalAddress: + return LowerGlobalAddress(Op, DAG); + + case ISD::SELECT: + return LowerSELECT(Op, DAG); + + case ISD::FRAMEADDR: + return LowerFRAMEADDR(Op, DAG); + + case ISD::RETURNADDR: + return LowerRETURNADDR(Op, DAG); + } +} + +SDValue CAHPTargetLowering::LowerGlobalAddress(SDValue Op, + SelectionDAG &DAG) const { + SDLoc DL(Op); + EVT Ty = Op.getValueType(); + GlobalAddressSDNode *N = cast(Op); + const GlobalValue *GV = N->getGlobal(); + int64_t Offset = N->getOffset(); + + if (isPositionIndependent()) + report_fatal_error("Unable to LowerGlobalAddress"); + + SDValue GAHi = DAG.getTargetGlobalAddress(GV, DL, Ty, Offset, CAHPII::MO_HI); + SDValue GALo = DAG.getTargetGlobalAddress(GV, DL, Ty, Offset, CAHPII::MO_LO); + SDValue MNHi = SDValue(DAG.getMachineNode(CAHP::LUI, DL, Ty, GAHi), 0); + SDValue MNLo = SDValue(DAG.getMachineNode(CAHP::ADDI, DL, Ty, MNHi, GALo), 0); + return MNLo; +} + +SDValue CAHPTargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const { + SDValue CondV = Op.getOperand(0); + SDValue TrueV = Op.getOperand(1); + SDValue FalseV = Op.getOperand(2); + SDLoc DL(Op); + + // (select (setcc lhs, rhs, cc), truev, falsev) + // -> (cahpisd::select_cc lhs, rhs, cc, truev, falsev) + if (Op.getSimpleValueType() == MVT::i16 && CondV.getOpcode() == ISD::SETCC && + CondV.getOperand(0).getSimpleValueType() == MVT::i16) { + SDValue LHS = CondV.getOperand(0); + SDValue RHS = CondV.getOperand(1); + auto CC = cast(CondV.getOperand(2)); + ISD::CondCode CCVal = CC->get(); + + normalizeSetCC(LHS, RHS, CCVal); + + SDValue TargetCC = DAG.getConstant(CCVal, DL, MVT::i16); + SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue); + SDValue Ops[] = {LHS, RHS, TargetCC, TrueV, FalseV}; + return DAG.getNode(CAHPISD::SELECT_CC, DL, VTs, Ops); + } + + // Otherwise: + // (select condv, truev, falsev) + // -> (cahpisd::select_cc condv, zero, setne, truev, falsev) + SDValue Zero = DAG.getConstant(0, DL, MVT::i16); + SDValue SetNE = DAG.getConstant(ISD::SETNE, DL, MVT::i16); + + SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue); + SDValue Ops[] = {CondV, Zero, SetNE, TrueV, FalseV}; + + return DAG.getNode(CAHPISD::SELECT_CC, DL, VTs, Ops); +} + +SDValue CAHPTargetLowering::LowerFRAMEADDR(SDValue Op, + SelectionDAG &DAG) const { + const CAHPRegisterInfo &RI = *Subtarget.getRegisterInfo(); + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + MFI.setFrameAddressIsTaken(true); + unsigned FrameReg = RI.getFrameRegister(MF); + + EVT VT = Op.getValueType(); + SDLoc DL(Op); + SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, VT); + unsigned Depth = cast(Op.getOperand(0))->getZExtValue(); + while (Depth--) { + int Offset = -4; + SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr, + DAG.getIntPtrConstant(Offset, DL)); + FrameAddr = + DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo()); + } + return FrameAddr; +} + +SDValue CAHPTargetLowering::LowerRETURNADDR(SDValue Op, + SelectionDAG &DAG) const { + const CAHPRegisterInfo &RI = *Subtarget.getRegisterInfo(); + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + MFI.setReturnAddressIsTaken(true); + + if (verifyReturnAddressArgumentIsConstant(Op, DAG)) + return SDValue(); + + EVT VT = Op.getValueType(); + SDLoc DL(Op); + unsigned Depth = cast(Op.getOperand(0))->getZExtValue(); + if (Depth) { + int Off = -2; + SDValue FrameAddr = LowerFRAMEADDR(Op, DAG); + SDValue Offset = DAG.getConstant(Off, DL, VT); + return DAG.getLoad(VT, DL, DAG.getEntryNode(), + DAG.getNode(ISD::ADD, DL, VT, FrameAddr, Offset), + MachinePointerInfo()); + } + + // Return the value of the return address register, marking it an implicit + // live-in. + unsigned Reg = MF.addLiveIn(RI.getRARegister(), &CAHP::GPRRegClass); + return DAG.getCopyFromReg(DAG.getEntryNode(), DL, Reg, MVT::i16); +} + +MachineBasicBlock * +CAHPTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, + MachineBasicBlock *BB) const { + const TargetInstrInfo &TII = *BB->getParent()->getSubtarget().getInstrInfo(); + DebugLoc DL = MI.getDebugLoc(); + + assert(MI.getOpcode() == CAHP::Select_GPR_Using_CC_GPR && + "Unexpected instr type to insert"); + + // To "insert" a SELECT instruction, we actually have to insert the triangle + // control-flow pattern. The incoming instruction knows the destination vreg + // to set, the condition code register to branch on, the true/false values to + // select between, and the condcode to use to select the appropriate branch. + // + // We produce the following control flow: + // HeadMBB + // | \ + // | IfFalseMBB + // | / + // TailMBB + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator I = ++BB->getIterator(); + + MachineBasicBlock *HeadMBB = BB; + MachineFunction *F = BB->getParent(); + MachineBasicBlock *TailMBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *IfFalseMBB = F->CreateMachineBasicBlock(LLVM_BB); + + F->insert(I, IfFalseMBB); + F->insert(I, TailMBB); + // Move all remaining instructions to TailMBB. + TailMBB->splice(TailMBB->begin(), HeadMBB, + std::next(MachineBasicBlock::iterator(MI)), HeadMBB->end()); + // Update machine-CFG edges by transferring all successors of the current + // block to the new block which will contain the Phi node for the select. + TailMBB->transferSuccessorsAndUpdatePHIs(HeadMBB); + // Set the successors for HeadMBB. + HeadMBB->addSuccessor(IfFalseMBB); + HeadMBB->addSuccessor(TailMBB); + + // Insert appropriate branch. + unsigned LHS = MI.getOperand(1).getReg(); + unsigned RHS = MI.getOperand(2).getReg(); + auto CC = static_cast(MI.getOperand(3).getImm()); + unsigned Opcode = getBranchOpcodeForIntCondCode(CC); + + BuildMI(HeadMBB, DL, TII.get(Opcode)).addReg(LHS).addReg(RHS).addMBB(TailMBB); + + // IfFalseMBB just falls through to TailMBB. + IfFalseMBB->addSuccessor(TailMBB); + + // %Result = phi [ %TrueValue, HeadMBB ], [ %FalseValue, IfFalseMBB ] + BuildMI(*TailMBB, TailMBB->begin(), DL, TII.get(CAHP::PHI), + MI.getOperand(0).getReg()) + .addReg(MI.getOperand(4).getReg()) + .addMBB(HeadMBB) + .addReg(MI.getOperand(5).getReg()) + .addMBB(IfFalseMBB); + + MI.eraseFromParent(); // The pseudo instruction is gone now. + return TailMBB; +} + +SDValue CAHPTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const { + SDValue Chain = Op.getOperand(0); + SDValue Cond = Op.getOperand(1); + SDValue LHS = Op.getOperand(2); + SDValue RHS = Op.getOperand(3); + SDValue Dest = Op.getOperand(4); + SDLoc DL(Op); + + ISD::CondCode CC = cast(Cond)->get(); + normalizeSetCC(LHS, RHS, CC); + + // Create new SelectionDAG nodes + return DAG.getNode(CAHPISD::BR_CC, DL, Op.getValueType(), Chain, LHS, RHS, + DAG.getConstant(CC, DL, MVT::i16), Dest); +} + +// Calling Convention Implementation. +#include "CAHPGenCallingConv.inc" + +// Transform physical registers into virtual registers. +SDValue CAHPTargetLowering::LowerFormalArguments( + SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Ins, const SDLoc &DL, + SelectionDAG &DAG, SmallVectorImpl &InVals) const { + + switch (CallConv) { + default: + report_fatal_error("Unsupported calling convention"); + case CallingConv::C: + case CallingConv::Fast: + break; + } + + MachineFunction &MF = DAG.getMachineFunction(); + MachineRegisterInfo &RegInfo = MF.getRegInfo(); + + if (IsVarArg) + report_fatal_error("VarArg not supported"); + + // Assign locations to all of the incoming arguments. + SmallVector ArgLocs; + CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); + CCInfo.AnalyzeFormalArguments(Ins, CC_CAHP); + + for (auto &VA : ArgLocs) { + SDValue ArgVal; + if (VA.isRegLoc()) { + // Arguments passed in registers. + EVT RegVT = VA.getLocVT(); + if (RegVT != MVT::i16) { + LLVM_DEBUG(dbgs() << "LowerFormalArguments Unhandled argument type: " + << RegVT.getEVTString() << "\n"); + report_fatal_error("unhandled argument type"); + } + const unsigned VReg = RegInfo.createVirtualRegister(&CAHP::GPRRegClass); + RegInfo.addLiveIn(VA.getLocReg(), VReg); + ArgVal = DAG.getCopyFromReg(Chain, DL, VReg, RegVT); + } else { + assert(VA.isMemLoc()); + assert(VA.getValVT() == MVT::i16); + assert(VA.getLocVT() == MVT::i16); + + // Create the frame index object for this incoming parameter. + int FI = + MF.getFrameInfo().CreateFixedObject(2, VA.getLocMemOffset(), true); + + // Create the SelectionDAG nodes corresponding to a load from this + // parameter. + SDValue FIN = DAG.getFrameIndex(FI, MVT::i16); + ArgVal = DAG.getLoad( + VA.getLocVT(), DL, Chain, FIN, + MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI)); + } + + InVals.push_back(ArgVal); + } + return Chain; +} + +// Lower a call to a callseq_start + CALL + callseq_end chain, and add input +// and output parameter nodes. +SDValue CAHPTargetLowering::LowerCall(CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const { + SelectionDAG &DAG = CLI.DAG; + SDLoc &DL = CLI.DL; + SmallVectorImpl &Outs = CLI.Outs; + SmallVectorImpl &OutVals = CLI.OutVals; + SmallVectorImpl &Ins = CLI.Ins; + SDValue Chain = CLI.Chain; + SDValue Callee = CLI.Callee; + CLI.IsTailCall = false; + CallingConv::ID CallConv = CLI.CallConv; + bool IsVarArg = CLI.IsVarArg; + EVT PtrVT = getPointerTy(DAG.getDataLayout()); + + if (IsVarArg) { + report_fatal_error("LowerCall with varargs not implemented"); + } + + MachineFunction &MF = DAG.getMachineFunction(); + + // Analyze the operands of the call, assigning locations to each operand. + SmallVector ArgLocs; + CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); + ArgCCInfo.AnalyzeCallOperands(Outs, CC_CAHP); + + // Get a count of how many bytes are to be pushed on the stack. + unsigned NumBytes = ArgCCInfo.getNextStackOffset(); + + // Create local copies for byval args + SmallVector ByValArgs; + for (unsigned i = 0, e = Outs.size(); i != e; ++i) { + ISD::ArgFlagsTy Flags = Outs[i].Flags; + if (!Flags.isByVal()) + continue; + + SDValue Arg = OutVals[i]; + unsigned Size = Flags.getByValSize(); + unsigned Align = Flags.getByValAlign(); + + int FI = MF.getFrameInfo().CreateStackObject(Size, Align, + /*isSillSlot=*/false); + SDValue FIPtr = DAG.getFrameIndex(FI, MVT::i16); + SDValue SizeNode = DAG.getConstant(Size, DL, MVT::i16); + + Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Align, + /*IsVolatile=*/false, + /*AlwaysInline=*/false, CLI.IsTailCall, + MachinePointerInfo(), MachinePointerInfo()); + ByValArgs.push_back(FIPtr); + } + + Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL); + + // Copy argument values to their designated locations. + SmallVector, 8> RegsToPass; + SmallVector MemOpChains; + SDValue StackPtr; + for (unsigned I = 0, J = 0, E = ArgLocs.size(); I != E; ++I) { + CCValAssign &VA = ArgLocs[I]; + SDValue ArgValue = OutVals[I]; + ISD::ArgFlagsTy Flags = Outs[I].Flags; + + // Promote the value if needed. + // For now, only handle fully promoted arguments. + switch (VA.getLocInfo()) { + case CCValAssign::Full: + break; + default: + llvm_unreachable("Unknown loc info!"); + } + + if (Flags.isByVal()) + ArgValue = ByValArgs[J++]; + + if (VA.isRegLoc()) { + // Queue up the argument copies and emit them at the end. + RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue)); + } else { + assert(VA.isMemLoc() && "Argument not register or memory"); + + if (!StackPtr.getNode()) + StackPtr = DAG.getCopyFromReg(Chain, DL, CAHP::X1, MVT::i16); + + SDValue Address = + DAG.getNode(ISD::ADD, DL, MVT::i16, StackPtr, + DAG.getIntPtrConstant(VA.getLocMemOffset(), DL)); + + MemOpChains.push_back( + DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo())); + } + } + + // Transform all store nodes into one single node because all store nodes are + // independent of each other. + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains); + + SDValue Glue; + + // Build a sequence of copy-to-reg nodes, chained and glued together. + for (auto &Reg : RegsToPass) { + Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue); + Glue = Chain.getValue(1); + } + + if (GlobalAddressSDNode *S = dyn_cast(Callee)) + Callee = DAG.getTargetGlobalAddress(S->getGlobal(), DL, PtrVT, 0, 0); + else if (ExternalSymbolSDNode *S = dyn_cast(Callee)) + Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, 0); + + // The first call operand is the chain and the second is the target address. + SmallVector Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + + // Add argument registers to the end of the list so that they are + // known live into the call. + for (auto &Reg : RegsToPass) + Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType())); + + // Add a register mask operand representing the call-preserved registers. + const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); + const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv); + assert(Mask && "Missing call preserved mask for calling convention"); + Ops.push_back(DAG.getRegisterMask(Mask)); + + // Glue the call to the argument copies, if any. + if (Glue.getNode()) + Ops.push_back(Glue); + + // Emit the call. + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); + Chain = DAG.getNode(CAHPISD::CALL, DL, NodeTys, Ops); + Glue = Chain.getValue(1); + + // Mark the end of the call, which is glued to the call itself. + Chain = DAG.getCALLSEQ_END(Chain, DAG.getConstant(NumBytes, DL, PtrVT, true), + DAG.getConstant(0, DL, PtrVT, true), Glue, DL); + Glue = Chain.getValue(1); + + // Assign locations to each value returned by this call. + SmallVector RVLocs; + CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext()); + RetCCInfo.AnalyzeCallResult(Ins, RetCC_CAHP); + + // Copy all of the result registers out of their specified physreg. + for (auto &VA : RVLocs) { + // Copy the value out, gluing the copy to the end of the call sequence. + SDValue RetValue = + DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue); + Chain = RetValue.getValue(1); + Glue = RetValue.getValue(2); + + InVals.push_back(Chain.getValue(0)); + } + + return Chain; +} + +SDValue +CAHPTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, + bool IsVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, + const SDLoc &DL, SelectionDAG &DAG) const { + if (IsVarArg) { + report_fatal_error("VarArg not supported"); + } + + // Stores the assignment of the return value to a location. + SmallVector RVLocs; + + // Info about the registers and stack slot. + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, + *DAG.getContext()); + + CCInfo.AnalyzeReturn(Outs, RetCC_CAHP); + + SDValue Flag; + SmallVector RetOps(1, Chain); + + // Copy the result values into the output registers. + for (unsigned i = 0, e = RVLocs.size(); i < e; ++i) { + CCValAssign &VA = RVLocs[i]; + assert(VA.isRegLoc() && "Can only return in registers!"); + + Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), OutVals[i], Flag); + + // Guarantee that all emitted copies are stuck together. + Flag = Chain.getValue(1); + RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); + } + + RetOps[0] = Chain; // Update chain. + + // Add the flag if we have it. + if (Flag.getNode()) { + RetOps.push_back(Flag); + } + + return DAG.getNode(CAHPISD::RET_FLAG, DL, MVT::Other, RetOps); +} + +const char *CAHPTargetLowering::getTargetNodeName(unsigned Opcode) const { + switch ((CAHPISD::NodeType)Opcode) { + case CAHPISD::FIRST_NUMBER: + break; + case CAHPISD::BR_CC: + return "CAHPISD::BR_CC"; + case CAHPISD::CALL: + return "CAHPISD::CALL"; + case CAHPISD::SELECT_CC: + return "CAHPISD::SELECT_CC"; + case CAHPISD::RET_FLAG: + return "CAHPISD::RET_FLAG"; + } + return nullptr; +} + +std::pair +CAHPTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, + StringRef Constraint, + MVT VT) const { + // First, see if this is a constraint that directly corresponds to a + // CAHP register class. + if (Constraint.size() == 1) { + switch (Constraint[0]) { + case 'r': + return std::make_pair(0U, &CAHP::GPRRegClass); + default: + break; + } + } + + return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); +} diff --git a/llvm/lib/Target/CAHP/CAHPISelLowering.h b/llvm/lib/Target/CAHP/CAHPISelLowering.h new file mode 100644 index 000000000000..b4f01243ad3d --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHPISelLowering.h @@ -0,0 +1,73 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#ifndef LLVM_LIB_TARGET_CAHP_CAHPISELLOWERING_H +#define LLVM_LIB_TARGET_CAHP_CAHPISELLOWERING_H + +#include "CAHP.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/CodeGen/TargetLowering.h" + +namespace llvm { +class CAHPSubtarget; +namespace CAHPISD { +enum NodeType : unsigned { + FIRST_NUMBER = ISD::BUILTIN_OP_END, + + BR_CC, + CALL, + SELECT_CC, + RET_FLAG, +}; +} + +class CAHPTargetLowering : public TargetLowering { +private: + const CAHPSubtarget &Subtarget; + +public: + explicit CAHPTargetLowering(const TargetMachine &TM, + const CAHPSubtarget &STI); + + // Provide custom lowering hooks for some operations. + SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; + + // This method returns the name of a target specific DAG node. + const char *getTargetNodeName(unsigned Opcode) const override; + + MachineBasicBlock * + EmitInstrWithCustomInserter(MachineInstr &MI, + MachineBasicBlock *BB) const override; + + std::pair + getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, + StringRef Constraint, MVT VT) const override; + +private: + // Lower incoming arguments, copy physregs into vregs + SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, + bool IsVarArg, + const SmallVectorImpl &Ins, + const SDLoc &DL, SelectionDAG &DAG, + SmallVectorImpl &InVals) const override; + SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Outs, + const SmallVectorImpl &OutVals, const SDLoc &DL, + SelectionDAG &DAG) const override; + SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const override; + bool shouldConvertConstantLoadToIntImm(const APInt &Imm, + Type *Ty) const override { + return true; + } + + SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSELECT(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const; +}; +} // namespace llvm + +#endif diff --git a/llvm/lib/Target/CAHP/CAHPInstrFormats.td b/llvm/lib/Target/CAHP/CAHPInstrFormats.td new file mode 100644 index 000000000000..2f44d82607a2 --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHPInstrFormats.td @@ -0,0 +1,229 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +class CAHPInst pattern = []> +: Instruction { + // SoftFail is a field the disassembler can use to provide a way for + // instructions to not match without killing the whole decode process. It is + // mainly used for ARM, but Tablegen expects this field to exist or it fails + // to build the decode table. + bits<32> SoftFail = 0; + + let Namespace = "CAHP"; + + dag OutOperandList = outs; + dag InOperandList = ins; + + let AsmString = opcodestr # "\t" # argstr; + + // Matching patterns used when converting SelectionDAG into MachineDAG. + let Pattern = pattern; +} + +// 16-bit instruction format. +class CAHPInst16 pattern = []> +: CAHPInst { + let Size = 2; + bits<16> Inst; +} + +// 24-bit instruction format. +class CAHPInst24 pattern = []> +: CAHPInst { + let Size = 3; + bits<24> Inst; +} + +// Pseudo instructions +class Pseudo pattern> +: CAHPInst { + let isPseudo = 1; + let isCodeGenOnly = 1; +} + +class Pseudo16 pattern> +: Pseudo { + let Size = 2; +} + +class Pseudo24 pattern> +: Pseudo { + let Size = 3; +} + +// 24-bit M-instruction format. +class CAHPInst24MLoad opcode, dag outs, dag ins, string opcodestr, string argstr> +: CAHPInst24, Sched<[WriteLDST]> { + bits<4> rd; + bits<4> rs; + bits<10> imm; + + let Inst{23-16} = imm{7-0}; + let Inst{15-12} = rs; + let Inst{11-8} = rd; + let Inst{7-6} = imm{9-8}; + let Inst{5-0} = opcode; +} + +class CAHPInst24MLoadI opcode, dag outs, dag ins, string opcodestr, string argstr> +: CAHPInst24, Sched<[WriteALU]> { + bits<4> rd; + bits<4> rs; + bits<10> imm; + + let Inst{23-16} = imm{7-0}; + let Inst{15-12} = rs; + let Inst{11-8} = rd; + let Inst{7-6} = imm{9-8}; + let Inst{5-0} = opcode; +} + +class CAHPInst24MStore opcode, dag outs, dag ins, string opcodestr, string argstr> +: CAHPInst24, Sched<[WriteLDST]> { + bits<4> rs; + bits<4> rd; + bits<10> imm; + + let Inst{23-16} = imm{7-0}; + let Inst{15-12} = rd; + let Inst{11-8} = rs; + let Inst{7-6} = imm{9-8}; + let Inst{5-0} = opcode; +} + +// 24-bit R-instruction format. +class CAHPInst24R opcode, dag outs, dag ins, string opcodestr, string argstr> +: CAHPInst24, Sched<[WriteALU]> { + bits<4> rd; + bits<4> rs1; + bits<4> rs2; + + let Inst{23-20} = 0; + let Inst{19-16} = rs2; + let Inst{15-12} = rs1; + let Inst{11-8} = rd; + let Inst{7-0} = opcode; +} + +// 24-bit I-instruction format for 10bit immediate. +class CAHPInst24I_10 opcode, dag outs, dag ins, string opcodestr, string argstr> +: CAHPInst24, Sched<[WriteALU]> { + bits<4> rd; + bits<4> rs1; + bits<10> imm; + + let Inst{23-16} = imm{7-0}; + let Inst{15-12} = rs1; + let Inst{11-8} = rd; + let Inst{7-6} = imm{9-8}; + let Inst{5-0} = opcode; +} + +// 24-bit I-instruction format for 4bit immediate. +class CAHPInst24I_4 opcode, dag outs, dag ins, string opcodestr, string argstr> +: CAHPInst24, Sched<[WriteALU]> { + bits<4> rd; + bits<4> rs1; + bits<4> imm; + + let Inst{23-20} = 0; + let Inst{19-16} = imm{3-0}; + let Inst{15-12} = rs1; + let Inst{11-8} = rd; + let Inst{7-6} = 0; + let Inst{5-0} = opcode; +} + +// 24-bit J-instruction format. +class CAHPInst24J opcode, dag ins, string opcodestr, string argstr> +: CAHPInst24<(outs), ins, opcodestr, argstr> { + bits<4> rs1; + bits<4> rs2; + bits<10> imm; + + let Inst{23-16} = imm{7-0}; + let Inst{15-12} = rs1; + let Inst{11-8} = rs2; + let Inst{7-6} = imm{9-8}; + let Inst{5-0} = opcode; +} + +// 16-bit M-instruction format. +class CAHPInst16MLoad opcode, dag outs, dag ins, string opcodestr, string argstr> +: CAHPInst16, Sched<[WriteLDST]> { + bits<4> rd; + + let Inst{11-8} = rd; + let Inst{5-0} = opcode; +} + +class CAHPInst16MLoadI opcode, dag outs, dag ins, string opcodestr, string argstr> +: CAHPInst16, Sched<[WriteALU]> { + bits<4> rd; + + let Inst{11-8} = rd; + let Inst{5-0} = opcode; +} + +class CAHPInst16MStore opcode, dag outs, dag ins, string opcodestr, string argstr> +: CAHPInst16, Sched<[WriteLDST]> { + bits<4> rs; + + let Inst{11-8} = rs; + let Inst{5-0} = opcode; +} + +// 16-bit R-instruction format. +class CAHPInst16R opcode, dag outs, dag ins, string opcodestr, string argstr> +: CAHPInst16, Sched<[WriteALU]> { + bits<4> rd; + bits<4> rs; + + let Inst{15-12} = rs; + let Inst{11-8} = rd; + let Inst{7-0} = opcode; +} + +// 16-bit I-instruction format for 6bit immediate. +class CAHPInst16I_6 opcode, dag outs, dag ins, string opcodestr, string argstr> +: CAHPInst16, Sched<[WriteALU]> { + bits<4> rd; + bits<6> imm; + + let Inst{15-12} = imm{3-0}; + let Inst{11-8} = rd; + let Inst{7-6} = imm{5-4}; + let Inst{5-0} = opcode; +} + +// 16-bit I-instruction format for 4bit immediate. +class CAHPInst16I_4 opcode, dag outs, dag ins, string opcodestr, string argstr> +: CAHPInst16, Sched<[WriteALU]> { + bits<4> rd; + bits<4> imm; + + let Inst{15-12} = imm{3-0}; + let Inst{11-8} = rd; + let Inst{7-6} = 0; + let Inst{5-0} = opcode; +} + +// 16-bit J-instruction format. +class CAHPInst16JR opcode, dag ins, string opcodestr, string argstr> +: CAHPInst16<(outs), ins, opcodestr, argstr> { + bits<4> rs; + + let Inst{15-12} = 0; + let Inst{11-8} = rs; + let Inst{7-5} = 0; + let Inst{4-0} = opcode; +} + +class CAHPInst16JI opcode, dag ins, string opcodestr, string argstr> +: CAHPInst16<(outs), ins, opcodestr, argstr> { + bits<11> imm; + + let Inst{15-5} = imm; + let Inst{4-0} = opcode; +} diff --git a/llvm/lib/Target/CAHP/CAHPInstrInfo.cpp b/llvm/lib/Target/CAHP/CAHPInstrInfo.cpp new file mode 100644 index 000000000000..344de59e9d99 --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHPInstrInfo.cpp @@ -0,0 +1,323 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "CAHPInstrInfo.h" +#include "CAHP.h" +#include "CAHPSubtarget.h" +#include "CAHPTargetMachine.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" + +#define GET_INSTRINFO_CTOR_DTOR +#include "CAHPGenInstrInfo.inc" + +using namespace llvm; + +CAHPInstrInfo::CAHPInstrInfo() + : CAHPGenInstrInfo(CAHP::ADJCALLSTACKDOWN, CAHP::ADJCALLSTACKUP) {} + +void CAHPInstrInfo::copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + const DebugLoc &DL, unsigned DstReg, + unsigned SrcReg, bool KillSrc) const { + assert(CAHP::GPRRegClass.contains(DstReg, SrcReg) && + "Impossible reg-to-reg copy"); + + BuildMI(MBB, MBBI, DL, get(CAHP::MOV), DstReg).addReg(SrcReg); +} + +void CAHPInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned SrcReg, bool IsKill, int FI, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + DebugLoc DL; + if (I != MBB.end()) + DL = I->getDebugLoc(); + + if (!CAHP::GPRRegClass.hasSubClassEq(RC)) + llvm_unreachable("Can't store this register to stack slot"); + + BuildMI(MBB, I, DL, get(CAHP::SW)).addReg(SrcReg).addFrameIndex(FI).addImm(0); +} + +void CAHPInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + unsigned DstReg, int FI, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + DebugLoc DL; + if (I != MBB.end()) + DL = I->getDebugLoc(); + + if (!CAHP::GPRRegClass.hasSubClassEq(RC)) + llvm_unreachable("Can't load this register from stack slot"); + + BuildMI(MBB, I, DL, get(CAHP::LW), DstReg).addFrameIndex(FI).addImm(0); +} + +void CAHPInstrInfo::movImm16(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI, + const DebugLoc &DL, unsigned DstReg, uint64_t Val, + MachineInstr::MIFlag Flag) const { + assert(isInt<16>(Val) && "Can only materialize 16-bit constants"); + + // TODO: If the value can be materialized using only one instruction, only + // insert a single instruction. + + uint64_t Hi6 = ((Val + 0x200) >> 10) & 0x3f; + uint64_t Lo10 = SignExtend64<10>(Val); + BuildMI(MBB, MBBI, DL, get(CAHP::LUI), DstReg).addImm(Hi6).setMIFlag(Flag); + BuildMI(MBB, MBBI, DL, get(CAHP::ADDI), DstReg) + .addReg(DstReg) + .addImm(Lo10) + .setMIFlag(Flag); +} + +// The contents of values added to Cond are not examined outside of +// CAHPInstrInfo, giving us flexibility in what to push to it. For CAHP, we +// push BranchOpcode, Reg1, Reg2. +static void parseCondBranch(MachineInstr &LastInst, MachineBasicBlock *&Target, + SmallVectorImpl &Cond) { + // Block ends with fall-through condbranch. + assert(LastInst.getDesc().isConditionalBranch() && + "Unknown conditional branch"); + Target = LastInst.getOperand(2).getMBB(); + Cond.push_back(MachineOperand::CreateImm(LastInst.getOpcode())); + Cond.push_back(LastInst.getOperand(0)); + Cond.push_back(LastInst.getOperand(1)); +} + +bool CAHPInstrInfo::analyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl &Cond, + bool AllowModify) const { + TBB = FBB = nullptr; + Cond.clear(); + + // If the block has no terminators, it just falls into the block after it. + MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); + if (I == MBB.end() || !isUnpredicatedTerminator(*I)) + return false; + + // Count the number of terminators and find the first unconditional or + // indirect branch. + MachineBasicBlock::iterator FirstUncondOrIndirectBr = MBB.end(); + int NumTerminators = 0; + for (auto J = I.getReverse(); J != MBB.rend() && isUnpredicatedTerminator(*J); + J++) { + NumTerminators++; + if (J->getDesc().isUnconditionalBranch() || + J->getDesc().isIndirectBranch()) { + FirstUncondOrIndirectBr = J.getReverse(); + } + } + + // If AllowModify is true, we can erase any terminators after + // FirstUncondOrIndirectBR. + if (AllowModify && FirstUncondOrIndirectBr != MBB.end()) { + while (std::next(FirstUncondOrIndirectBr) != MBB.end()) { + std::next(FirstUncondOrIndirectBr)->eraseFromParent(); + NumTerminators--; + } + I = FirstUncondOrIndirectBr; + } + + // We can't handle blocks that end in an indirect branch. + if (I->getDesc().isIndirectBranch()) + return true; + + // We can't handle blocks with more than 2 terminators. + if (NumTerminators > 2) + return true; + + // Handle a single unconditional branch. + if (NumTerminators == 1 && I->getDesc().isUnconditionalBranch()) { + TBB = I->getOperand(0).getMBB(); + return false; + } + + // Handle a single conditional branch. + if (NumTerminators == 1 && I->getDesc().isConditionalBranch()) { + parseCondBranch(*I, TBB, Cond); + return false; + } + + // Handle a conditional branch followed by an unconditional branch. + if (NumTerminators == 2 && std::prev(I)->getDesc().isConditionalBranch() && + I->getDesc().isUnconditionalBranch()) { + parseCondBranch(*std::prev(I), TBB, Cond); + FBB = I->getOperand(0).getMBB(); + return false; + } + + // Otherwise, we can't handle this. + return true; +} + +unsigned CAHPInstrInfo::removeBranch(MachineBasicBlock &MBB, + int *BytesRemoved) const { + if (BytesRemoved) + *BytesRemoved = 0; + + MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); + if (I == MBB.end()) + return 0; + + if (!I->getDesc().isUnconditionalBranch() && + !I->getDesc().isConditionalBranch()) + return 0; + + // Remove the branch. + I->eraseFromParent(); + if (BytesRemoved) + *BytesRemoved += getInstSizeInBytes(*I); + + I = MBB.end(); + + if (I == MBB.begin()) + return 1; + --I; + if (!I->getDesc().isConditionalBranch()) + return 1; + + // Remove the branch. + I->eraseFromParent(); + if (BytesRemoved) + *BytesRemoved += getInstSizeInBytes(*I); + return 2; +} + +// Inserts a branch into the end of the specific MachineBasicBlock, returning +// the number of instructions inserted. +unsigned CAHPInstrInfo::insertBranch( + MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, + ArrayRef Cond, const DebugLoc &DL, int *BytesAdded) const { + if (BytesAdded) + *BytesAdded = 0; + + // Shouldn't be a fall through. + assert(TBB && "InsertBranch must not be told to insert a fallthrough"); + assert((Cond.size() == 3 || Cond.size() == 0) && + "CAHP branch conditions have two components!"); + + // Unconditional branch. + if (Cond.empty()) { + MachineInstr &MI = *BuildMI(&MBB, DL, get(CAHP::JS)).addMBB(TBB); + if (BytesAdded) + *BytesAdded = getInstSizeInBytes(MI); + return 1; + } + + // Either a one or two-way conditional branch. + unsigned Opc = Cond[0].getImm(); + MachineInstr &CondMI = + *BuildMI(&MBB, DL, get(Opc)).add(Cond[1]).add(Cond[2]).addMBB(TBB); + if (BytesAdded) + *BytesAdded += getInstSizeInBytes(CondMI); + + // One-way conditional branch. + if (!FBB) + return 1; + + // Two-way conditional branch. + MachineInstr &MI = *BuildMI(&MBB, DL, get(CAHP::JS)).addMBB(FBB); + if (BytesAdded) + *BytesAdded += getInstSizeInBytes(MI); + return 2; +} + +bool CAHPInstrInfo::reverseBranchCondition( + SmallVectorImpl &Cond) const { + assert((Cond.size() == 3) && "Invalid branch condition!"); + + bool ShouldSwap = false; + switch (Cond[0].getImm()) { + case CAHP::BEQ: + Cond[0].setImm(CAHP::BNE); + break; + case CAHP::BNE: + Cond[0].setImm(CAHP::BEQ); + break; + case CAHP::BLT: + Cond[0].setImm(CAHP::BLE); + ShouldSwap = true; + break; + case CAHP::BLE: + Cond[0].setImm(CAHP::BLT); + ShouldSwap = true; + break; + case CAHP::BLTU: + Cond[0].setImm(CAHP::BLEU); + ShouldSwap = true; + break; + case CAHP::BLEU: + Cond[0].setImm(CAHP::BLTU); + ShouldSwap = true; + break; + } + + if (ShouldSwap) { + using std::swap; + swap(Cond[1], Cond[2]); + } + + return false; +} + +MachineBasicBlock * +CAHPInstrInfo::getBranchDestBlock(const MachineInstr &MI) const { + assert(MI.getDesc().isBranch() && "Unexpected opcode!"); + // The branch target is always the last operand. + int NumOp = MI.getNumExplicitOperands(); + return MI.getOperand(NumOp - 1).getMBB(); +} + +bool CAHPInstrInfo::isBranchOffsetInRange(unsigned BranchOp, + int64_t BrOffset) const { + switch (BranchOp) { + default: + llvm_unreachable("Unexpected opcode!"); + + case CAHP::BEQ: + case CAHP::BNE: + case CAHP::BLT: + case CAHP::BLE: + case CAHP::BLTU: + case CAHP::BLEU: + return isInt<10>(BrOffset); + + case CAHP::JSAL: + case CAHP::JS: + return isInt<11>(BrOffset); + } +} + +unsigned CAHPInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { + unsigned Opcode = MI.getOpcode(); + + switch (Opcode) { + default: + return get(Opcode).getSize(); + + case TargetOpcode::EH_LABEL: + case TargetOpcode::IMPLICIT_DEF: + case TargetOpcode::KILL: + case TargetOpcode::DBG_VALUE: + return 0; + + case TargetOpcode::INLINEASM: { + const MachineFunction &MF = *MI.getParent()->getParent(); + const auto &TM = static_cast(MF.getTarget()); + return getInlineAsmLength(MI.getOperand(0).getSymbolName(), + *TM.getMCAsmInfo()); + } + } +} diff --git a/llvm/lib/Target/CAHP/CAHPInstrInfo.h b/llvm/lib/Target/CAHP/CAHPInstrInfo.h new file mode 100644 index 000000000000..2ae849da637d --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHPInstrInfo.h @@ -0,0 +1,63 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#ifndef LLVM_LIB_TARGET_CAHP_CAHPINSTRINFO_H +#define LLVM_LIB_TARGET_CAHP_CAHPINSTRINFO_H + +#include "CAHPRegisterInfo.h" +#include "llvm/CodeGen/TargetInstrInfo.h" + +#define GET_INSTRINFO_HEADER +#include "CAHPGenInstrInfo.inc" + +namespace llvm { + +class CAHPInstrInfo : public CAHPGenInstrInfo { + +public: + CAHPInstrInfo(); + + void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + const DebugLoc &DL, unsigned DstReg, unsigned SrcReg, + bool KillSrc) const override; + void storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, unsigned SrcReg, + bool IsKill, int FI, const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const override; + void loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, unsigned DstReg, + int FI, const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const override; + + // Materializes the given int16 Val into DstReg. + void movImm16(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, + const DebugLoc &DL, unsigned DstReg, uint64_t Val, + MachineInstr::MIFlag Flag = MachineInstr::NoFlags) const; + + bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl &Cond, + bool AllowModify) const override; + + unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, ArrayRef Cond, + const DebugLoc &dl, + int *BytesAdded = nullptr) const override; + + unsigned removeBranch(MachineBasicBlock &MBB, + int *BytesRemoved = nullptr) const override; + + bool + reverseBranchCondition(SmallVectorImpl &Cond) const override; + + unsigned getInstSizeInBytes(const MachineInstr &MI) const override; + + bool isBranchOffsetInRange(unsigned BranchOpc, + int64_t BrOffset) const override; + + MachineBasicBlock *getBranchDestBlock(const MachineInstr &MI) const override; +}; +} // namespace llvm + +#endif diff --git a/llvm/lib/Target/CAHP/CAHPInstrInfo.td b/llvm/lib/Target/CAHP/CAHPInstrInfo.td new file mode 100644 index 000000000000..227119dfd751 --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHPInstrInfo.td @@ -0,0 +1,496 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +include "CAHPInstrFormats.td" + +def SDT_CAHPCall : SDTypeProfile<0, -1, [SDTCisVT<0, i16>]>; +def SDT_CAHPCallSeqStart : SDCallSeqStart<[SDTCisVT<0, i16>, SDTCisVT<1, i16>]>; +def SDT_CAHPCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i16>, SDTCisVT<1, i16>]>; +def SDT_CAHPSelectCC : SDTypeProfile<1, 5, [SDTCisSameAs<1, 2>, + SDTCisSameAs<0, 4>, + SDTCisSameAs<4, 5>]>; +def SDT_CAHPBrCC : SDTypeProfile<0, 4, [SDTCisSameAs<0, 1>, + SDTCisVT<3, OtherVT>]>; + +def BrCC : SDNode<"CAHPISD::BR_CC", SDT_CAHPBrCC, + [SDNPHasChain, SDNPOutGlue, SDNPInGlue]>; +def Call : SDNode<"CAHPISD::CALL", SDT_CAHPCall, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, + SDNPVariadic]>; +def CallSeqStart : SDNode<"ISD::CALLSEQ_START", SDT_CAHPCallSeqStart, + [SDNPHasChain, SDNPOutGlue]>; +def CallSeqEnd : SDNode<"ISD::CALLSEQ_END", SDT_CAHPCallSeqEnd, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; +def RetFlag : SDNode<"CAHPISD::RET_FLAG", SDTNone, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; +def SelectCC : SDNode<"CAHPISD::SELECT_CC", SDT_CAHPSelectCC, + [SDNPInGlue]>; + +class ImmAsmOperand : AsmOperandClass { + let Name = prefix # "Imm" # width # suffix; + let RenderMethod = "addImmOperands"; + let DiagnosticType = "Invalid" # Name; +} + +class SImmAsmOperand + : ImmAsmOperand<"S", width, suffix> { +} + +class UImmAsmOperand + : ImmAsmOperand<"U", width, suffix> { +} + +def uimm4 : Operand, ImmLeaf(Imm);}]> { + let ParserMatchClass = UImmAsmOperand<4>; + let DecoderMethod = "decodeUImmOperand<4>"; + let EncoderMethod = "getImmOpValue"; + let MCOperandPredicate = [{ + int64_t Imm; + if (!MCOp.evaluateAsConstantImm(Imm)) + return false; + return isUInt<4>(Imm); + }]; +} + +def simm6 : Operand, ImmLeaf(Imm);}]> { + let ParserMatchClass = SImmAsmOperand<6>; + let DecoderMethod = "decodeSImmOperand<6>"; + let EncoderMethod = "getImmOpValue"; + let MCOperandPredicate = [{ + int64_t Imm; + if (!MCOp.evaluateAsConstantImm(Imm)) + return false; + return isInt<6>(Imm); + }]; +} + +def simm10 : Operand, ImmLeaf(Imm);}]> { + let ParserMatchClass = SImmAsmOperand<10>; + let DecoderMethod = "decodeSImmOperand<10>"; + let EncoderMethod = "getImmOpValue"; + let MCOperandPredicate = [{ + int64_t Imm; + if (!MCOp.evaluateAsConstantImm(Imm)) + return false; + return isInt<10>(Imm); + }]; +} + +def simm10_branch : Operand { + let ParserMatchClass = ImmAsmOperand<"BareS", 10, "">; + let DecoderMethod = "decodeSImmOperand<10>"; + let EncoderMethod = "getImmOpValue"; +} + +def simm11 : Operand, ImmLeaf(Imm);}]> { + let ParserMatchClass = SImmAsmOperand<11>; + let DecoderMethod = "decodeSImmOperand<11>"; + let EncoderMethod = "getImmOpValue"; +} + +def simm11_branch : Operand { + let ParserMatchClass = SImmAsmOperand<11>; + let DecoderMethod = "decodeSImmOperand<11>"; + let EncoderMethod = "getImmOpValue"; +} + +def uimm7_lsb0 : Operand { + let ParserMatchClass = UImmAsmOperand<7, "Lsb0">; + let DecoderMethod = "decodeUImmOperand<7>"; + let EncoderMethod = "getImmOpValue"; + let MCOperandPredicate = [{ + int64_t Imm; + if (!MCOp.evaluateAsConstantImm(Imm)) + return false; + return isShiftedUInt<6, 1>(Imm); + }]; +} + +// Standalone (codegen-only) immleaf patterns. +def simm16 : ImmLeaf(Imm);}]>; +def simm16hi6 : ImmLeaf(Imm);}]>; + +// Extract least significant 10 bits from an immediate value and sign extend +// them. +def LO10Sext : SDNodeXFormgetTargetConstant(SignExtend64<10>(N->getZExtValue()), + SDLoc(N), N->getValueType(0)); +}]>; + +// Extract the most significant 6 bits from an immediate value. Add 1 if bit +// 9 is 1, to compensate for the low 10 bits in the matching immediate addi +// or ld/st being negative. +def HI6 : SDNodeXFormgetTargetConstant(((N->getZExtValue()+0x200) >> 10) & 0x3f, + SDLoc(N), N->getValueType(0)); +}]>; + +// Addressing modes. +// Necessary because a frameindex can't be matched directly in a pattern. +def AddrFI : ComplexPattern; + +def IsOrAdd: PatFrag<(ops node:$A, node:$B), (or node:$A, node:$B), [{ + return isOrEquivalentToAdd(N); +}]>; + +// Conditional code predicates - used for pattern matching for jump instructions +def CC_EQ : PatLeaf<(i16 imm), + [{return (N->getZExtValue() == ISD::SETEQ);}]>; +def CC_NE : PatLeaf<(i16 imm), + [{return (N->getZExtValue() == ISD::SETNE);}]>; +def CC_GE : PatLeaf<(i16 imm), + [{return (N->getZExtValue() == ISD::SETGE);}]>; +def CC_GT : PatLeaf<(i16 imm), + [{return (N->getZExtValue() == ISD::SETGT);}]>; +def CC_GTU : PatLeaf<(i16 imm), + [{return (N->getZExtValue() == ISD::SETUGT);}]>; +def CC_GEU : PatLeaf<(i16 imm), + [{return (N->getZExtValue() == ISD::SETUGE);}]>; +def CC_LE : PatLeaf<(i16 imm), + [{return (N->getZExtValue() == ISD::SETLE);}]>; +def CC_LT : PatLeaf<(i16 imm), + [{return (N->getZExtValue() == ISD::SETLT);}]>; +def CC_LTU : PatLeaf<(i16 imm), + [{return (N->getZExtValue() == ISD::SETULT);}]>; +def CC_LEU : PatLeaf<(i16 imm), + [{return (N->getZExtValue() == ISD::SETULE);}]>; + +// 24-bit M-instructions. + +let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in { + def LW : CAHPInst24MLoad <0b010101, (outs GPR:$rd), (ins GPR:$rs, simm10:$imm), + "lw", "$rd, ${imm}(${rs})">; + def LB : CAHPInst24MLoad <0b100101, (outs GPR:$rd), (ins GPR:$rs, simm10:$imm), + "lb", "$rd, ${imm}(${rs})">; + def LBU : CAHPInst24MLoad <0b000101, (outs GPR:$rd), (ins GPR:$rs, simm10:$imm), + "lbu", "$rd, ${imm}(${rs})">; +} + +let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in { + def SW : CAHPInst24MStore<0b011101, (outs), (ins GPR:$rs, GPR:$rd, simm10:$imm), + "sw", "$rs, ${imm}(${rd})">; + def SB : CAHPInst24MStore<0b001101, (outs), (ins GPR:$rs, GPR:$rd, simm10:$imm), + "sb", "$rs, ${imm}(${rd})">; +} + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isMoveImm = 1 in +def LI : CAHPInst24MLoadI <0b110101, (outs GPR:$rd), (ins simm10:$imm), + "li", "$rd, $imm"> { + let rs = 0; +} + +// 24-bit R-instructions. + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in { + let isCommutable = 1 in { + def ADD : CAHPInst24R<0b00000001, (outs GPR:$rd), (ins GPR:$rs1, GPR:$rs2), + "add", "$rd, $rs1, $rs2">; + def AND : CAHPInst24R<0b00010001, (outs GPR:$rd), (ins GPR:$rs1, GPR:$rs2), + "and", "$rd, $rs1, $rs2">; + def XOR : CAHPInst24R<0b00011001, (outs GPR:$rd), (ins GPR:$rs1, GPR:$rs2), + "xor", "$rd, $rs1, $rs2">; + def OR : CAHPInst24R<0b00100001, (outs GPR:$rd), (ins GPR:$rs1, GPR:$rs2), + "or", "$rd, $rs1, $rs2">; + } + + def SUB : CAHPInst24R<0b00001001, (outs GPR:$rd), (ins GPR:$rs1, GPR:$rs2), + "sub", "$rd, $rs1, $rs2">; + def LSL : CAHPInst24R<0b00101001, (outs GPR:$rd), (ins GPR:$rs1, GPR:$rs2), + "lsl", "$rd, $rs1, $rs2">; + def LSR : CAHPInst24R<0b00110001, (outs GPR:$rd), (ins GPR:$rs1, GPR:$rs2), + "lsr", "$rd, $rs1, $rs2">; + def ASR : CAHPInst24R<0b00111001, (outs GPR:$rd), (ins GPR:$rs1, GPR:$rs2), + "asr", "$rd, $rs1, $rs2">; +} + +// 24-bit I-instructions. + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in { + def ADDI : CAHPInst24I_10<0b000011, (outs GPR:$rd), (ins GPR:$rs1, simm10:$imm), + "addi", "$rd, $rs1, $imm">; + def ANDI : CAHPInst24I_10<0b010011, (outs GPR:$rd), (ins GPR:$rs1, simm10:$imm), + "andi", "$rd, $rs1, $imm">; + def XORI : CAHPInst24I_10<0b011011, (outs GPR:$rd), (ins GPR:$rs1, simm10:$imm), + "xori", "$rd, $rs1, $imm">; + def ORI : CAHPInst24I_10<0b100011, (outs GPR:$rd), (ins GPR:$rs1, simm10:$imm), + "ori", "$rd, $rs1, $imm">; + def LSLI : CAHPInst24I_4 <0b101011, (outs GPR:$rd), (ins GPR:$rs1, uimm4:$imm), + "lsli", "$rd, $rs1, $imm">; + def LSRI : CAHPInst24I_4 <0b110011, (outs GPR:$rd), (ins GPR:$rs1, uimm4:$imm), + "lsri", "$rd, $rs1, $imm">; + def ASRI : CAHPInst24I_4 <0b111011, (outs GPR:$rd), (ins GPR:$rs1, uimm4:$imm), + "asri", "$rd, $rs1, $imm">; +} + +// 24-bit J-instructions. + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, + isBranch = 1, isTerminator = 1 in { + def BEQ : CAHPInst24J<0b001111, (ins GPR:$rs1, GPR:$rs2, simm10_branch:$imm), + "beq", "$rs1, $rs2, $imm">; + def BNE : CAHPInst24J<0b101111, (ins GPR:$rs1, GPR:$rs2, simm10_branch:$imm), + "bne", "$rs1, $rs2, $imm">; + def BLT : CAHPInst24J<0b110111, (ins GPR:$rs1, GPR:$rs2, simm10_branch:$imm), + "blt", "$rs1, $rs2, $imm">; + def BLTU : CAHPInst24J<0b010111, (ins GPR:$rs1, GPR:$rs2, simm10_branch:$imm), + "bltu", "$rs1, $rs2, $imm">; + def BLE : CAHPInst24J<0b111111, (ins GPR:$rs1, GPR:$rs2, simm10_branch:$imm), + "ble", "$rs1, $rs2, $imm">; + def BLEU : CAHPInst24J<0b011111, (ins GPR:$rs1, GPR:$rs2, simm10_branch:$imm), + "bleu", "$rs1, $rs2, $imm">; +} + +// 16-bit M-instructions. + +let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in +def LWSP : CAHPInst16MLoad <0b010100, (outs GPR:$rd), (ins SP:$rs, uimm7_lsb0:$imm), + "lwsp", "$rd, ${imm}(${rs})"> { + bits<7> imm; + let Inst{15-12} = imm{4-1}; + let Inst{7-6} = imm{6-5}; +} + +let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in +def SWSP : CAHPInst16MStore<0b011100, (outs), (ins GPR:$rs, SP:$rd, uimm7_lsb0:$imm), + "swsp", "$rs, ${imm}(${rd})"> { + bits<7> imm; + let Inst{15-12} = imm{4-1}; + let Inst{7-6} = imm{6-5}; +} + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isMoveImm = 1 in +def LSI : CAHPInst16MLoadI <0b110100, (outs GPR:$rd), (ins simm6:$imm), + "lsi", "$rd, $imm"> { + bits<6> imm; + let Inst{15-12} = imm{3-0}; + let Inst{7-6} = imm{5-4}; +} + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isMoveImm = 1 in +def LUI : CAHPInst16MLoadI <0b000100, (outs GPR:$rd), (ins simm6:$imm), + "lui", "$rd, $imm"> { + bits<6> imm; + let Inst{15-12} = imm{3-0}; + let Inst{7-6} = imm{5-4}; +} + +// 16-bit R-instructions. + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isMoveReg = 1 in +def MOV : CAHPInst16R<0b11000000, (outs GPR:$rd), (ins GPR:$rs), + "mov", "$rd, $rs">; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, + Constraints = "$rd = $rd_w" in { + let isCommutable = 1 in { + def ADD2 : CAHPInst16R<0b10000000, (outs GPR:$rd_w), (ins GPR:$rd, GPR:$rs), + "add2", "$rd, $rs">; + def AND2 : CAHPInst16R<0b10010000, (outs GPR:$rd_w), (ins GPR:$rd, GPR:$rs), + "and2", "$rd, $rs">; + def XOR2 : CAHPInst16R<0b10011000, (outs GPR:$rd_w), (ins GPR:$rd, GPR:$rs), + "xor2", "$rd, $rs">; + def OR2 : CAHPInst16R<0b10100000, (outs GPR:$rd_w), (ins GPR:$rd, GPR:$rs), + "or2", "$rd, $rs">; + } + + def SUB2 : CAHPInst16R<0b10001000, (outs GPR:$rd_w), (ins GPR:$rd, GPR:$rs), + "sub2", "$rd, $rs">; + def LSL2 : CAHPInst16R<0b10101000, (outs GPR:$rd_w), (ins GPR:$rd, GPR:$rs), + "lsl2", "$rd, $rs">; + def LSR2 : CAHPInst16R<0b10110000, (outs GPR:$rd_w), (ins GPR:$rd, GPR:$rs), + "lsr2", "$rd, $rs">; + def ASR2 : CAHPInst16R<0b10111000, (outs GPR:$rd_w), (ins GPR:$rd, GPR:$rs), + "asr2", "$rd, $rs">; +} + +// 16-bit I-instructions. + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, + Constraints = "$rd = $rd_w" in { + def LSLI2 : CAHPInst16I_4<0b101010, (outs GPR:$rd_w), (ins GPR:$rd, uimm4:$imm), + "lsli2", "$rd, $imm">; + def LSRI2 : CAHPInst16I_4<0b110010, (outs GPR:$rd_w), (ins GPR:$rd, uimm4:$imm), + "lsri2", "$rd, $imm">; + def ASRI2 : CAHPInst16I_4<0b111010, (outs GPR:$rd_w), (ins GPR:$rd, uimm4:$imm), + "asri2", "$rd, $imm">; + def ADDI2 : CAHPInst16I_6<0b000010, (outs GPR:$rd_w), (ins GPR:$rd, simm6:$imm), + "addi2", "$rd, $imm">; + def ANDI2 : CAHPInst16I_6<0b010010, (outs GPR:$rd_w), (ins GPR:$rd, simm6:$imm), + "andi2", "$rd, $imm">; +} + +// 16-bit J-instructions. + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in { + let isCall = 1, Defs = [/* RA */ X0] in + def JALR : CAHPInst16JR<0b10110, (ins GPR:$rs), "jalr", "$rs">; + + let isBranch = 1, isBarrier = 1, isTerminator = 1, isIndirectBranch = 1 in + def JR : CAHPInst16JR<0b00110, (ins GPR:$rs), "jr", "$rs">; + + let isBranch = 1, isTerminator = 1, isBarrier = 1 in + def JS : CAHPInst16JI<0b01110, (ins simm11_branch:$imm), "js", "$imm">; + + let isCall = 1, Defs = [/* RA */ X0] in + def JSAL : CAHPInst16JI<0b11110, (ins simm11:$imm), "jsal", "$imm">; +} + +// Others. + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in +def NOP : CAHPInst16<(outs), (ins), "nop", ""> { + let Inst = 0; +} + +let isBarrier = 1, isReturn = 1, isTerminator = 1 in +def PseudoRET : Pseudo<(outs), (ins), [(RetFlag)]>, + PseudoInstExpansion<(JR X0)>; + +// Pessimistically assume the stack pointer will be clobbered +let Defs = [/* SP */ X1], Uses = [/* SP */ X1] in { +def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i16imm:$amt1, i16imm:$amt2), + [(CallSeqStart timm:$amt1, timm:$amt2)]>; +def ADJCALLSTACKUP : Pseudo<(outs), (ins i16imm:$amt1, i16imm:$amt2), + [(CallSeqEnd timm:$amt1, timm:$amt2)]>; +} // Defs = [X1], Uses = [X1] + +let usesCustomInserter = 1 in +def Select_GPR_Using_CC_GPR + : Pseudo<(outs GPR:$dst), + (ins GPR:$lhs, GPR:$rhs, i16imm:$imm, GPR:$src, GPR:$src2), + [(set i16:$dst, (SelectCC GPR:$lhs, GPR:$rhs, + (i16 imm:$imm), GPR:$src, GPR:$src2))]>; + +let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCodeGenOnly = 0 in +def PseudoHLT : Pseudo16<(outs), (ins), []> { + let AsmString = "hlt"; +} + +// Codegen patterns. + +/// FrameIndex calculations +def : Pat<(add (i16 AddrFI:$Rs), simm10:$imm), + (ADDI (i16 AddrFI:$Rs), simm10:$imm)>; +def : Pat<(IsOrAdd (i16 AddrFI:$Rs), simm10:$imm), + (ADDI (i16 AddrFI:$Rs), simm10:$imm)>; + +def : Pat<(simm6:$imm), (LSI simm6:$imm)>; +def : Pat<(simm10:$imm), (LI simm10:$imm)>; +def : Pat<(simm16hi6:$imm), (LUI (HI6 imm:$imm))>; +def : Pat<(simm16:$imm), (ADDI (LUI (HI6 imm:$imm)), (LO10Sext imm:$imm))>; + +multiclass LdPat { + def : Pat<(LoadOp GPR:$rs1), (Inst GPR:$rs1, 0)>; + def : Pat<(LoadOp AddrFI:$rs1), (LW AddrFI:$rs1, 0)>; + def : Pat<(LoadOp (add GPR:$rs1, simm10:$imm)), + (Inst GPR:$rs1, simm10:$imm)>; + def : Pat<(LoadOp (add AddrFI:$rs1, simm10:$imm)), + (Inst AddrFI:$rs1, simm10:$imm)>; + def : Pat<(LoadOp (IsOrAdd AddrFI:$rs1, simm10:$imm)), + (Inst AddrFI:$rs1, simm10:$imm)>; +} +defm : LdPat; +defm : LdPat; +defm : LdPat; +defm : LdPat; + +multiclass StPat { + def : Pat<(StoreOp GPR:$rs, GPR:$rd), (Inst GPR:$rs, GPR:$rd, 0)>; + def : Pat<(StoreOp GPR:$rs, AddrFI:$rd), (Inst GPR:$rs, AddrFI:$rd, 0)>; + def : Pat<(StoreOp GPR:$rs, (add GPR:$rd, simm10:$imm)), + (Inst GPR:$rs, GPR:$rd, simm10:$imm)>; + def : Pat<(StoreOp GPR:$rs, (add AddrFI:$rd, simm10:$imm)), + (Inst GPR:$rs, AddrFI:$rd, simm10:$imm)>; + def : Pat<(StoreOp GPR:$rs, (IsOrAdd AddrFI:$rd, simm10:$imm)), + (Inst GPR:$rs, AddrFI:$rd, simm10:$imm)>; +} +defm : StPat; +defm : StPat; + +def : Pat<(add GPR:$rs1, GPR:$rs2), (ADD GPR:$rs1, GPR:$rs2)>; +def : Pat<(sub GPR:$rs1, GPR:$rs2), (SUB GPR:$rs1, GPR:$rs2)>; +def : Pat<(and GPR:$rs1, GPR:$rs2), (AND GPR:$rs1, GPR:$rs2)>; +def : Pat<(xor GPR:$rs1, GPR:$rs2), (XOR GPR:$rs1, GPR:$rs2)>; +def : Pat<(or GPR:$rs1, GPR:$rs2), (OR GPR:$rs1, GPR:$rs2)>; +def : Pat<(shl GPR:$rs1, GPR:$rs2), (LSL GPR:$rs1, GPR:$rs2)>; +def : Pat<(srl GPR:$rs1, GPR:$rs2), (LSR GPR:$rs1, GPR:$rs2)>; +def : Pat<(sra GPR:$rs1, GPR:$rs2), (ASR GPR:$rs1, GPR:$rs2)>; + +def : Pat<(add GPR:$rs1, simm10:$imm), (ADDI GPR:$rs1, simm10:$imm)>; +def : Pat<(and GPR:$rs1, simm10:$imm), (ANDI GPR:$rs1, simm10:$imm)>; +def : Pat<(xor GPR:$rs1, simm10:$imm), (XORI GPR:$rs1, simm10:$imm)>; +def : Pat<(or GPR:$rs1, simm10:$imm), (ORI GPR:$rs1, simm10:$imm)>; +def : Pat<(shl GPR:$rs1, uimm4:$imm), (LSLI GPR:$rs1, uimm4:$imm)>; +def : Pat<(srl GPR:$rs1, uimm4:$imm), (LSRI GPR:$rs1, uimm4:$imm)>; +def : Pat<(sra GPR:$rs1, uimm4:$imm), (ASRI GPR:$rs1, uimm4:$imm)>; + +// Match `(brcond (CondOp ..), ..)` and lower to the appropriate CAHP branch +// instruction. +class BccPat + : Pat<(BrCC GPR:$rs1, GPR:$rs2, Cond, bb:$imm), + (Inst GPR:$rs1, GPR:$rs2, simm10_branch:$imm)>; +def : BccPat; +def : BccPat; +def : BccPat; +def : BccPat; +def : BccPat; +def : BccPat; + +class BccSwapPat + : Pat<(BrCC GPR:$rs1, GPR:$rs2, Cond, bb:$imm), + (Inst GPR:$rs2, GPR:$rs1, bb:$imm)>; +// Condition codes that don't have matching CAHP branch instructions, but +// are trivially supported by swapping the two input operands +def : BccSwapPat; +def : BccSwapPat; +def : BccSwapPat; +def : BccSwapPat; + +// An extra pattern is needed for a brcond without a setcc (i.e. where the +// condition was calculated elsewhere). +def : Pat<(brcond GPR:$cond, bb:$imm), (BNE GPR:$cond, (LSI 0), bb:$imm)>; + +def : Pat<(br bb:$imm), (JS simm11_branch:$imm)>; +def : Pat<(Call GPR:$rs), (JALR GPR:$rs)>; +def : Pat<(Call tglobaladdr:$dst), (JSAL tglobaladdr:$dst)>; +def : Pat<(Call texternalsym:$dst), (JSAL texternalsym:$dst)>; + +// Compress patterns + +class CompressPat { + dag Input = input; + dag Output = output; + list Predicates = []; +} + +multiclass CompPatRRRComm { + def : CompressPat<(Inst24 GPR:$rs1, GPR:$rs1, GPR:$rs2), + (Inst16 GPR:$rs1, GPR:$rs2)>; + def : CompressPat<(Inst24 GPR:$rs1, GPR:$rs2, GPR:$rs1), + (Inst16 GPR:$rs1, GPR:$rs2)>; +} +defm : CompPatRRRComm; +defm : CompPatRRRComm; +defm : CompPatRRRComm; +defm : CompPatRRRComm; + +class CompPatRRRNonComm + : CompressPat<(Inst24 GPR:$rs1, GPR:$rs1, GPR:$rs2), + (Inst16 GPR:$rs1, GPR:$rs2)> { +} +def : CompPatRRRNonComm; +def : CompPatRRRNonComm; +def : CompPatRRRNonComm; +def : CompPatRRRNonComm; + +def : CompressPat<(LSLI GPR:$rs1, GPR:$rs1, uimm4:$imm), (LSLI2 GPR:$rs1, uimm4:$imm)>; +def : CompressPat<(LSRI GPR:$rs1, GPR:$rs1, uimm4:$imm), (LSRI2 GPR:$rs1, uimm4:$imm)>; +def : CompressPat<(ASRI GPR:$rs1, GPR:$rs1, uimm4:$imm), (ASRI2 GPR:$rs1, uimm4:$imm)>; +def : CompressPat<(ADDI GPR:$rs1, GPR:$rs1, simm6:$imm), (ADDI2 GPR:$rs1, simm6:$imm)>; +def : CompressPat<(ANDI GPR:$rs1, GPR:$rs1, simm6:$imm), (ANDI2 GPR:$rs1, simm6:$imm)>; + +def : CompressPat<(LW GPR:$rd, SP:$rs, uimm7_lsb0:$imm), + (LWSP GPR:$rd, SP:$rs, uimm7_lsb0:$imm)>; +def : CompressPat<(SW GPR:$rd, SP:$rs, uimm7_lsb0:$imm), + (SWSP GPR:$rd, SP:$rs, uimm7_lsb0:$imm)>; diff --git a/llvm/lib/Target/CAHP/CAHPMCInstLower.cpp b/llvm/lib/Target/CAHP/CAHPMCInstLower.cpp new file mode 100644 index 000000000000..a26f5fc3b88f --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHPMCInstLower.cpp @@ -0,0 +1,101 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "CAHP.h" +#include "MCTargetDesc/CAHPBaseInfo.h" +#include "MCTargetDesc/CAHPMCExpr.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +static MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym, + const AsmPrinter &AP) { + MCContext &Ctx = AP.OutContext; + CAHPMCExpr::VariantKind Kind; + + switch (MO.getTargetFlags()) { + default: + llvm_unreachable("Unknown target flag on GV operand"); + case CAHPII::MO_None: + Kind = CAHPMCExpr::VK_CAHP_None; + break; + case CAHPII::MO_LO: + Kind = CAHPMCExpr::VK_CAHP_LO; + break; + case CAHPII::MO_HI: + Kind = CAHPMCExpr::VK_CAHP_HI; + break; + } + + const MCExpr *ME = + MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx); + + if (!MO.isJTI() && MO.getOffset()) + ME = MCBinaryExpr::createAdd( + ME, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx); + + if (Kind != CAHPMCExpr::VK_CAHP_None) + ME = CAHPMCExpr::create(ME, Kind, Ctx); + return MCOperand::createExpr(ME); +} + +bool llvm::LowerCAHPMachineOperandToMCOperand(const MachineOperand &MO, + MCOperand &MCOp, + const AsmPrinter &AP) { + switch (MO.getType()) { + default: + report_fatal_error("LowerCAHPMachineInstrToMCInst: unknown operand type"); + + case MachineOperand::MO_Register: + // Ignore all implicit register operands. + if (MO.isImplicit()) + return false; + MCOp = MCOperand::createReg(MO.getReg()); + break; + + case MachineOperand::MO_RegisterMask: + // Regmasks are like implicit defs. + return false; + + case MachineOperand::MO_Immediate: + MCOp = MCOperand::createImm(MO.getImm()); + break; + + case MachineOperand::MO_MachineBasicBlock: + MCOp = MCOperand::createExpr( + MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), AP.OutContext)); + break; + + case MachineOperand::MO_GlobalAddress: + MCOp = LowerSymbolOperand(MO, AP.getSymbol(MO.getGlobal()), AP); + break; + + case MachineOperand::MO_ExternalSymbol: + MCOp = LowerSymbolOperand( + MO, AP.GetExternalSymbolSymbol(MO.getSymbolName()), AP); + break; + } + + return true; +} + +void llvm::LowerCAHPMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI, + const AsmPrinter &AP) { + OutMI.setOpcode(MI->getOpcode()); + + for (const MachineOperand &MO : MI->operands()) { + MCOperand MCOp; + LowerCAHPMachineOperandToMCOperand(MO, MCOp, AP); + if (LowerCAHPMachineOperandToMCOperand(MO, MCOp, AP)) + OutMI.addOperand(MCOp); + } +} diff --git a/llvm/lib/Target/CAHP/CAHPRegisterInfo.cpp b/llvm/lib/Target/CAHP/CAHPRegisterInfo.cpp new file mode 100644 index 000000000000..492b55d7387c --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHPRegisterInfo.cpp @@ -0,0 +1,89 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "CAHPRegisterInfo.h" +#include "CAHP.h" +#include "CAHPSubtarget.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/CodeGen/TargetFrameLowering.h" +#include "llvm/CodeGen/TargetInstrInfo.h" +#include "llvm/Support/ErrorHandling.h" + +#define GET_REGINFO_TARGET_DESC +#include "CAHPGenRegisterInfo.inc" + +using namespace llvm; + +CAHPRegisterInfo::CAHPRegisterInfo(unsigned HwMode) + : CAHPGenRegisterInfo(/* RA */ CAHP::X0, /*DwarfFlavour*/ 0, + /*EHFlavor*/ 0, + /*PC*/ 0, HwMode) {} + +const MCPhysReg * +CAHPRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { + return CSR_SaveList; +} + +BitVector CAHPRegisterInfo::getReservedRegs(const MachineFunction &MF) const { + BitVector Reserved(getNumRegs()); + + // Use markSuperRegs to ensure any register aliases are also reserved + markSuperRegs(Reserved, CAHP::X0); // ra + markSuperRegs(Reserved, CAHP::X1); // sp + markSuperRegs(Reserved, CAHP::X2); // fp + assert(checkAllSuperRegsMarked(Reserved)); + return Reserved; +} + +void CAHPRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, unsigned FIOperandNum, + RegScavenger *RS) const { + assert(SPAdj == 0 && "Unexpected non-zero SPAdj value"); + + MachineInstr &MI = *II; + MachineFunction &MF = *MI.getParent()->getParent(); + MachineRegisterInfo &MRI = MF.getRegInfo(); + const CAHPInstrInfo *TII = MF.getSubtarget().getInstrInfo(); + DebugLoc DL = MI.getDebugLoc(); + + int FrameIndex = MI.getOperand(FIOperandNum).getIndex(); + unsigned FrameReg; + int Offset = + getFrameLowering(MF)->getFrameIndexReference(MF, FrameIndex, FrameReg) + + MI.getOperand(FIOperandNum + 1).getImm(); + + if (!isInt<16>(Offset)) + report_fatal_error( + "Frame offsets outside of the signed 16-bit range not supported"); + + MachineBasicBlock &MBB = *MI.getParent(); + + if (!isInt<10>(Offset)) { + unsigned ScratchReg = MRI.createVirtualRegister(&CAHP::GPRRegClass); + TII->movImm16(MBB, II, DL, ScratchReg, Offset); + BuildMI(MBB, II, DL, TII->get(CAHP::ADD), ScratchReg) + .addReg(ScratchReg) + .addReg(FrameReg); + Offset = 0; + FrameReg = ScratchReg; + } + + MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false); + MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); +} + +Register CAHPRegisterInfo::getFrameRegister(const MachineFunction &MF) const { + const TargetFrameLowering *TFI = getFrameLowering(MF); + // Return FP if any, SP otherwise. + return TFI->hasFP(MF) ? CAHP::X2 /* FP */ : CAHP::X1 /* SP */; +} + +const uint32_t * +CAHPRegisterInfo::getCallPreservedMask(const MachineFunction & /*MF*/, + CallingConv::ID /*CC*/) const { + return CSR_RegMask; +} diff --git a/llvm/lib/Target/CAHP/CAHPRegisterInfo.h b/llvm/lib/Target/CAHP/CAHPRegisterInfo.h new file mode 100644 index 000000000000..e5e95f3f7431 --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHPRegisterInfo.h @@ -0,0 +1,46 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#ifndef LLVM_LIB_TARGET_CAHP_CAHPREGISTERINFO_H +#define LLVM_LIB_TARGET_CAHP_CAHPREGISTERINFO_H + +#include "llvm/CodeGen/TargetRegisterInfo.h" + +#define GET_REGINFO_HEADER +#include "CAHPGenRegisterInfo.inc" + +namespace llvm { + +struct CAHPRegisterInfo : public CAHPGenRegisterInfo { + + CAHPRegisterInfo(unsigned HwMode); + + const uint32_t *getCallPreservedMask(const MachineFunction &MF, + CallingConv::ID) const override; + + const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override; + + BitVector getReservedRegs(const MachineFunction &MF) const override; + + void eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj, + unsigned FIOperandNum, + RegScavenger *RS = nullptr) const override; + + Register getFrameRegister(const MachineFunction &MF) const override; + + bool requiresRegisterScavenging(const MachineFunction &MF) const override { + return true; + } + + bool requiresFrameIndexScavenging(const MachineFunction &MF) const override { + return true; + } + + bool trackLivenessAfterRegAlloc(const MachineFunction &) const override { + return true; + } +}; +} // namespace llvm + +#endif diff --git a/llvm/lib/Target/CAHP/CAHPRegisterInfo.td b/llvm/lib/Target/CAHP/CAHPRegisterInfo.td new file mode 100644 index 000000000000..25d30c245f3e --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHPRegisterInfo.td @@ -0,0 +1,41 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +let Namespace = "CAHP" in { + def ABIRegAltName : RegAltNameIndex; + + class CAHPReg Enc, string n, list alt = []> : Register { + let HWEncoding{3-0} = Enc; + let AltNames = alt; + let RegAltNameIndices = [ABIRegAltName]; + } +} // Namespace = "CAHP" + +// Integer registers +def X0 : CAHPReg<0, "x0", ["ra"]>, DwarfRegNum<[0]>; +def X1 : CAHPReg<1, "x1", ["sp"]>, DwarfRegNum<[1]>; +def X2 : CAHPReg<2, "x2", ["fp"]>, DwarfRegNum<[2]>; +def X3 : CAHPReg<3, "x3", ["s0"]>, DwarfRegNum<[3]>; +def X4 : CAHPReg<4, "x4", ["s1"]>, DwarfRegNum<[4]>; +def X5 : CAHPReg<5, "x5", ["s2"]>, DwarfRegNum<[5]>; +def X6 : CAHPReg<6, "x6", ["s3"]>, DwarfRegNum<[6]>; +def X7 : CAHPReg<7, "x7", ["s4"]>, DwarfRegNum<[7]>; +def X8 : CAHPReg<8, "x8", ["a0"]>, DwarfRegNum<[8]>; +def X9 : CAHPReg<9, "x9", ["a1"]>, DwarfRegNum<[9]>; +def X10 : CAHPReg<10,"x10", ["a2"]>, DwarfRegNum<[10]>; +def X11 : CAHPReg<11,"x11", ["a3"]>, DwarfRegNum<[11]>; +def X12 : CAHPReg<12,"x12", ["a4"]>, DwarfRegNum<[12]>; +def X13 : CAHPReg<13,"x13", ["a5"]>, DwarfRegNum<[13]>; +def X14 : CAHPReg<14,"x14", ["t0"]>, DwarfRegNum<[14]>; +def X15 : CAHPReg<15,"x15", ["t1"]>, DwarfRegNum<[15]>; + +// General Purpose Registers. +// The order of registers represents the preferred allocation sequence. +// Registers are listed in the order caller-save, callee-save, specials. +def GPR : RegisterClass<"CAHP", [i16], 16, (add + X8, X9, X10, X11, X12, X13, X14, X15, X3, X4, X5, X6, X7, X0, X1, X2 + )>; + +// For instructions like lwsp and swsp, which accept only the stack pointer as operand. +def SP : RegisterClass<"CAHP", [i16], 16, (add X1)>; diff --git a/llvm/lib/Target/CAHP/CAHPSchedule.td b/llvm/lib/Target/CAHP/CAHPSchedule.td new file mode 100644 index 000000000000..e5eb14dfa852 --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHPSchedule.td @@ -0,0 +1,23 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +def WriteALU : SchedWrite; +def WriteLDST : SchedWrite; + +def EmeraldModel : SchedMachineModel { + let MicroOpBufferSize = 0; + let IssueWidth = 2; + let LoadLatency = 2; + let MispredictPenalty = 2; + let CompleteModel = 0; + let PostRAScheduler = 1; +} + +def EmeraldALU : ProcResource<2> { let BufferSize = 0; } +def EmeraldLdSt : ProcResource<1> { let BufferSize = 0; } + +let SchedModel = EmeraldModel in { + def : WriteRes { let Latency = 3; } + def : WriteRes { let Latency = 3; } +} diff --git a/llvm/lib/Target/CAHP/CAHPSubtarget.cpp b/llvm/lib/Target/CAHP/CAHPSubtarget.cpp new file mode 100644 index 000000000000..e78e8414e049 --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHPSubtarget.cpp @@ -0,0 +1,34 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "CAHPSubtarget.h" +#include "CAHP.h" +#include "CAHPFrameLowering.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +#define DEBUG_TYPE "cahp-subtarget" + +#define GET_SUBTARGETINFO_TARGET_DESC +#define GET_SUBTARGETINFO_CTOR +#include "CAHPGenSubtargetInfo.inc" + +void CAHPSubtarget::anchor() {} + +CAHPSubtarget &CAHPSubtarget::initializeSubtargetDependencies(StringRef CPU, + StringRef FS) { + // Determine default and user-specified characteristics + std::string CPUName = CPU; + if (CPUName.empty()) + CPUName = "generic"; + ParseSubtargetFeatures(CPUName, FS); + return *this; +} + +CAHPSubtarget::CAHPSubtarget(const Triple &TT, const std::string &CPU, + const std::string &FS, const TargetMachine &TM) + : CAHPGenSubtargetInfo(TT, CPU, FS), + FrameLowering(initializeSubtargetDependencies(CPU, FS)), InstrInfo(), + RegInfo(getHwMode()), TLInfo(TM, *this) {} diff --git a/llvm/lib/Target/CAHP/CAHPSubtarget.h b/llvm/lib/Target/CAHP/CAHPSubtarget.h new file mode 100644 index 000000000000..670a762db1e7 --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHPSubtarget.h @@ -0,0 +1,59 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#ifndef LLVM_LIB_TARGET_CAHP_CAHPSUBTARGET_H +#define LLVM_LIB_TARGET_CAHP_CAHPSUBTARGET_H + +#include "CAHPFrameLowering.h" +#include "CAHPISelLowering.h" +#include "CAHPInstrInfo.h" +#include "llvm/CodeGen/SelectionDAGTargetInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/Target/TargetMachine.h" + +#define GET_SUBTARGETINFO_HEADER +#include "CAHPGenSubtargetInfo.inc" + +namespace llvm { +class StringRef; + +class CAHPSubtarget : public CAHPGenSubtargetInfo { + virtual void anchor(); + CAHPFrameLowering FrameLowering; + CAHPInstrInfo InstrInfo; + CAHPRegisterInfo RegInfo; + CAHPTargetLowering TLInfo; + SelectionDAGTargetInfo TSInfo; + + /// Initializes using the passed in CPU and feature strings so that we can + /// use initializer lists for subtarget initialization. + CAHPSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS); + +public: + // Initializes the data members to match that of the specified triple. + CAHPSubtarget(const Triple &TT, const std::string &CPU, const std::string &FS, + const TargetMachine &TM); + + // Parses features string setting specified subtarget options. The + // definition of this function is auto-generated by tblgen. + void ParseSubtargetFeatures(StringRef CPU, StringRef FS); + + const CAHPFrameLowering *getFrameLowering() const override { + return &FrameLowering; + } + const CAHPInstrInfo *getInstrInfo() const override { return &InstrInfo; } + const CAHPRegisterInfo *getRegisterInfo() const override { return &RegInfo; } + const CAHPTargetLowering *getTargetLowering() const override { + return &TLInfo; + } + const SelectionDAGTargetInfo *getSelectionDAGInfo() const override { + return &TSInfo; + } + + bool enableMachineScheduler() const override { return true; } +}; +} // namespace llvm + +#endif diff --git a/llvm/lib/Target/CAHP/CAHPTargetMachine.cpp b/llvm/lib/Target/CAHP/CAHPTargetMachine.cpp new file mode 100644 index 000000000000..08b90f2ac02c --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHPTargetMachine.cpp @@ -0,0 +1,75 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "CAHPTargetMachine.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Target/TargetOptions.h" +using namespace llvm; + +extern "C" void LLVMInitializeCAHPTarget() { + RegisterTargetMachine X(getTheCAHPTarget()); +} + +static std::string computeDataLayout(const Triple &TT) { + return "e" // Little endian + "-m:e" // ELF name manging + "-p:16:16" // 16-bit pointers, 16 bit aligned + "-i16:16" // 16 bit integers, 16 bit aligned + "-n16" // 16 bit native integer width + "-S16"; // 16 bit natural stack alignment +} + +static Reloc::Model getEffectiveRelocModel(const Triple &TT, + Optional RM) { + if (!RM.hasValue()) + return Reloc::Static; + return *RM; +} + +CAHPTargetMachine::CAHPTargetMachine(const Target &T, const Triple &TT, + StringRef CPU, StringRef FS, + const TargetOptions &Options, + Optional RM, + Optional CM, + CodeGenOpt::Level OL, bool JIT) + : LLVMTargetMachine(T, computeDataLayout(TT), TT, CPU, FS, Options, + getEffectiveRelocModel(TT, RM), + getEffectiveCodeModel(CM, CodeModel::Small), OL), + TLOF(make_unique()), + Subtarget(TT, CPU, FS, *this) { + initAsmInfo(); +} + +namespace { +class CAHPPassConfig : public TargetPassConfig { +public: + CAHPPassConfig(CAHPTargetMachine &TM, PassManagerBase &PM) + : TargetPassConfig(TM, PM) {} + + CAHPTargetMachine &getCAHPTargetMachine() const { + return getTM(); + } + + bool addInstSelector() override; + void addPreEmitPass() override; +}; +} // namespace + +TargetPassConfig *CAHPTargetMachine::createPassConfig(PassManagerBase &PM) { + return new CAHPPassConfig(*this, PM); +} + +bool CAHPPassConfig::addInstSelector() { + addPass(createCAHPISelDag(getCAHPTargetMachine())); + + return false; +} + +void CAHPPassConfig::addPreEmitPass() { addPass(&BranchRelaxationPassID); } diff --git a/llvm/lib/Target/CAHP/CAHPTargetMachine.h b/llvm/lib/Target/CAHP/CAHPTargetMachine.h new file mode 100644 index 000000000000..67ca7694f54c --- /dev/null +++ b/llvm/lib/Target/CAHP/CAHPTargetMachine.h @@ -0,0 +1,37 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#ifndef LLVM_LIB_TARGET_CAHP_CAHPTARGETMACHINE_H +#define LLVM_LIB_TARGET_CAHP_CAHPTARGETMACHINE_H + +#include "CAHPSubtarget.h" +#include "MCTargetDesc/CAHPMCTargetDesc.h" +#include "llvm/CodeGen/SelectionDAGTargetInfo.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/Target/TargetMachine.h" + +namespace llvm { +class CAHPTargetMachine : public LLVMTargetMachine { + std::unique_ptr TLOF; + CAHPSubtarget Subtarget; + +public: + CAHPTargetMachine(const Target &T, const Triple &TT, StringRef CPU, + StringRef FS, const TargetOptions &Options, + Optional RM, Optional CM, + CodeGenOpt::Level OL, bool JIT); + + const CAHPSubtarget *getSubtargetImpl(const Function &) const override { + return &Subtarget; + } + + TargetPassConfig *createPassConfig(PassManagerBase &PM) override; + + TargetLoweringObjectFile *getObjFileLowering() const override { + return TLOF.get(); + } +}; +} // namespace llvm + +#endif diff --git a/llvm/lib/Target/CAHP/CMakeLists.txt b/llvm/lib/Target/CAHP/CMakeLists.txt new file mode 100644 index 000000000000..d20b6916cbc0 --- /dev/null +++ b/llvm/lib/Target/CAHP/CMakeLists.txt @@ -0,0 +1,32 @@ +set(LLVM_TARGET_DEFINITIONS CAHP.td) + +tablegen(LLVM CAHPGenAsmMatcher.inc -gen-asm-matcher) +tablegen(LLVM CAHPGenAsmWriter.inc -gen-asm-writer) +tablegen(LLVM CAHPGenCompressInstEmitter.inc -gen-cahp-compress-inst-emitter) +tablegen(LLVM CAHPGenCallingConv.inc -gen-callingconv) +tablegen(LLVM CAHPGenDAGISel.inc -gen-dag-isel) +tablegen(LLVM CAHPGenDisassemblerTables.inc -gen-disassembler) +tablegen(LLVM CAHPGenInstrInfo.inc -gen-instr-info) +tablegen(LLVM CAHPGenMCCodeEmitter.inc -gen-emitter) +tablegen(LLVM CAHPGenMCPseudoLowering.inc -gen-pseudo-lowering) +tablegen(LLVM CAHPGenRegisterInfo.inc -gen-register-info) +tablegen(LLVM CAHPGenSubtargetInfo.inc -gen-subtarget) + +add_public_tablegen_target(CAHPCommonTableGen) + +add_llvm_target(CAHPCodeGen + CAHPAsmPrinter.cpp + CAHPFrameLowering.cpp + CAHPISelDAGToDAG.cpp + CAHPISelLowering.cpp + CAHPInstrInfo.cpp + CAHPMCInstLower.cpp + CAHPRegisterInfo.cpp + CAHPSubtarget.cpp + CAHPTargetMachine.cpp + ) +add_subdirectory(AsmParser) +add_subdirectory(Disassembler) +add_subdirectory(InstPrinter) +add_subdirectory(MCTargetDesc) +add_subdirectory(TargetInfo) diff --git a/llvm/lib/Target/CAHP/Disassembler/CAHPDisassembler.cpp b/llvm/lib/Target/CAHP/Disassembler/CAHPDisassembler.cpp new file mode 100644 index 000000000000..be300ece8244 --- /dev/null +++ b/llvm/lib/Target/CAHP/Disassembler/CAHPDisassembler.cpp @@ -0,0 +1,126 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "MCTargetDesc/CAHPMCTargetDesc.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDisassembler/MCDisassembler.h" +#include "llvm/MC/MCFixedLenDisassembler.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +#define DEBUG_TYPE "cahp-disassembler" + +typedef MCDisassembler::DecodeStatus DecodeStatus; + +namespace { +class CAHPDisassembler : public MCDisassembler { + +public: + CAHPDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx) + : MCDisassembler(STI, Ctx) {} + + DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, + ArrayRef Bytes, uint64_t Address, + raw_ostream &VStream, + raw_ostream &CStream) const override; +}; +} // end anonymous namespace + +static MCDisassembler *createCAHPDisassembler(const Target &T, + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new CAHPDisassembler(STI, Ctx); +} + +extern "C" void LLVMInitializeCAHPDisassembler() { + TargetRegistry::RegisterMCDisassembler(getTheCAHPTarget(), + createCAHPDisassembler); +} + +static const unsigned GPRDecoderTable[] = { + CAHP::X0, CAHP::X1, CAHP::X2, CAHP::X3, CAHP::X4, CAHP::X5, + CAHP::X6, CAHP::X7, CAHP::X8, CAHP::X9, CAHP::X10, CAHP::X11, + CAHP::X12, CAHP::X13, CAHP::X14, CAHP::X15}; + +static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint64_t RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > sizeof(GPRDecoderTable)) + return MCDisassembler::Fail; + + unsigned Reg = GPRDecoderTable[RegNo]; + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + +// Add implied SP operand for instructions lwsp/swsp. The SP operand isn't +// explicitly encoded in the instruction. +static void addImplySP(MCInst &Inst, int64_t Address, const void *Decoder) { + if (Inst.getOpcode() == CAHP::LWSP || Inst.getOpcode() == CAHP::SWSP) + DecodeGPRRegisterClass(Inst, /* SP */ 1, Address, Decoder); +} + +template +static DecodeStatus decodeUImmOperand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt(Imm) && "Invalid immediate"); + addImplySP(Inst, Address, Decoder); + Inst.addOperand(MCOperand::createImm(Imm)); + return MCDisassembler::Success; +} + +template +static DecodeStatus decodeSImmOperand(MCInst &Inst, uint64_t Imm, + int64_t Address, const void *Decoder) { + assert(isUInt(Imm) && "Invalid immediate"); + // Sign-extend the number in the bottom N bits of Imm + Inst.addOperand(MCOperand::createImm(SignExtend64(Imm))); + return MCDisassembler::Success; +} + +#include "CAHPGenDisassemblerTables.inc" + +DecodeStatus CAHPDisassembler::getInstruction(MCInst &MI, uint64_t &Size, + ArrayRef Bytes, + uint64_t Address, raw_ostream &OS, + raw_ostream &CS) const { + if (Bytes.size() < 2) { + Size = 0; + return MCDisassembler::Fail; + } + + uint32_t Inst; + DecodeStatus Result; + + uint8_t is24bitInst = Bytes[0] & 1; + + if (is24bitInst) { + if (Bytes.size() < 3) { + Size = 0; + return MCDisassembler::Fail; + } + + Inst = Bytes[0] | (Bytes[1] << 8) | (Bytes[2] << 16); + LLVM_DEBUG(dbgs() << "Trying CAHP 24bit table :\n"); + Result = decodeInstruction(DecoderTable24, MI, Inst, Address, this, STI); + Size = 3; + } else { + if (Bytes.size() < 2) { + Size = 0; + return MCDisassembler::Fail; + } + Inst = support::endian::read16le(Bytes.data()); + LLVM_DEBUG(dbgs() << "Trying CAHP 16bit table :\n"); + Result = decodeInstruction(DecoderTable16, MI, Inst, Address, this, STI); + Size = 2; + } + + return Result; +} diff --git a/llvm/lib/Target/CAHP/Disassembler/CMakeLists.txt b/llvm/lib/Target/CAHP/Disassembler/CMakeLists.txt new file mode 100644 index 000000000000..da9b68775796 --- /dev/null +++ b/llvm/lib/Target/CAHP/Disassembler/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_library(LLVMCAHPDisassembler + CAHPDisassembler.cpp + ) diff --git a/llvm/lib/Target/CAHP/Disassembler/LLVMBuild.txt b/llvm/lib/Target/CAHP/Disassembler/LLVMBuild.txt new file mode 100644 index 000000000000..f155874d28d4 --- /dev/null +++ b/llvm/lib/Target/CAHP/Disassembler/LLVMBuild.txt @@ -0,0 +1,10 @@ +; This file is copied and modified from The LLVM Compiler Infrastructure, which +; is distributed under the Apache License v2.0 with LLVM Exceptions (see +; LICENSE.TXT for details). This file is licensed under the same license. + +[component_0] +type = Library +name = CAHPDisassembler +parent = CAHP +required_libraries = MCDisassembler CAHPInfo Support +add_to_library_groups = CAHP diff --git a/llvm/lib/Target/CAHP/InstPrinter/CAHPInstPrinter.cpp b/llvm/lib/Target/CAHP/InstPrinter/CAHPInstPrinter.cpp new file mode 100644 index 000000000000..f8990b7c3c97 --- /dev/null +++ b/llvm/lib/Target/CAHP/InstPrinter/CAHPInstPrinter.cpp @@ -0,0 +1,48 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "CAHPInstPrinter.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" +using namespace llvm; + +#define DEBUG_TYPE "asm-printer" + +// Include the auto-generated portion of the assembly writer. +#include "CAHPGenAsmWriter.inc" + +void CAHPInstPrinter::printInst(const MCInst *MI, raw_ostream &O, + StringRef Annot, const MCSubtargetInfo &STI) { + printInstruction(MI, STI, O); + printAnnotation(O, Annot); +} + +void CAHPInstPrinter::printRegName(raw_ostream &O, unsigned RegNo) const { + O << getRegisterName(RegNo); +} + +void CAHPInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O, + const char *Modifier) { + assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); + const MCOperand &MO = MI->getOperand(OpNo); + + if (MO.isReg()) { + printRegName(O, MO.getReg()); + return; + } + + if (MO.isImm()) { + O << MO.getImm(); + return; + } + + assert(MO.isExpr() && "Unknown operand kind in printOperand"); + MO.getExpr()->print(O, &MAI); +} diff --git a/llvm/lib/Target/CAHP/InstPrinter/CAHPInstPrinter.h b/llvm/lib/Target/CAHP/InstPrinter/CAHPInstPrinter.h new file mode 100644 index 000000000000..97cd75f177cc --- /dev/null +++ b/llvm/lib/Target/CAHP/InstPrinter/CAHPInstPrinter.h @@ -0,0 +1,35 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#ifndef LLVM_LIB_TARGET_CAHP_INSTPRINTER_CAHPINSTPRINTER_H +#define LLVM_LIB_TARGET_CAHP_INSTPRINTER_CAHPINSTPRINTER_H + +#include "MCTargetDesc/CAHPMCTargetDesc.h" +#include "llvm/MC/MCInstPrinter.h" + +namespace llvm { +class MCOperand; + +class CAHPInstPrinter : public MCInstPrinter { +public: + CAHPInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, + const MCRegisterInfo &MRI) + : MCInstPrinter(MAI, MII, MRI) {} + + void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot, + const MCSubtargetInfo &STI) override; + void printRegName(raw_ostream &O, unsigned RegNo) const override; + + void printOperand(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, + raw_ostream &O, const char *Modifier = nullptr); + + // Autogenerated by tblgen. + void printInstruction(const MCInst *MI, const MCSubtargetInfo &STI, + raw_ostream &O); + static const char *getRegisterName(unsigned RegNo, + unsigned AltIdx = CAHP::ABIRegAltName); +}; +} // namespace llvm + +#endif diff --git a/llvm/lib/Target/CAHP/InstPrinter/CMakeLists.txt b/llvm/lib/Target/CAHP/InstPrinter/CMakeLists.txt new file mode 100644 index 000000000000..c0f247788336 --- /dev/null +++ b/llvm/lib/Target/CAHP/InstPrinter/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_library(LLVMCAHPAsmPrinter + CAHPInstPrinter.cpp + ) diff --git a/llvm/lib/Target/CAHP/InstPrinter/LLVMBuild.txt b/llvm/lib/Target/CAHP/InstPrinter/LLVMBuild.txt new file mode 100644 index 000000000000..2031db0ba364 --- /dev/null +++ b/llvm/lib/Target/CAHP/InstPrinter/LLVMBuild.txt @@ -0,0 +1,10 @@ +; This file is copied and modified from The LLVM Compiler Infrastructure, which +; is distributed under the Apache License v2.0 with LLVM Exceptions (see +; LICENSE.TXT for details). This file is licensed under the same license. + +[component_0] +type = Library +name = CAHPAsmPrinter +parent = CAHP +required_libraries = MC Support +add_to_library_groups = CAHP diff --git a/llvm/lib/Target/CAHP/LLVMBuild.txt b/llvm/lib/Target/CAHP/LLVMBuild.txt new file mode 100644 index 000000000000..3681c230dc6b --- /dev/null +++ b/llvm/lib/Target/CAHP/LLVMBuild.txt @@ -0,0 +1,22 @@ +; This file is copied and modified from The LLVM Compiler Infrastructure, which +; is distributed under the Apache License v2.0 with LLVM Exceptions (see +; LICENSE.TXT for details). This file is licensed under the same license. + +[common] +subdirectories = AsmParser Disassembler InstPrinter TargetInfo MCTargetDesc + +[component_0] +type = TargetGroup +name = CAHP +parent = Target +has_asmparser = 1 +has_asmprinter = 1 +has_disassembler = 1 + +[component_1] +type = Library +name = CAHPCodeGen +parent = CAHP +required_libraries = AsmPrinter CAHPAsmPrinter CAHPDesc CAHPInfo + CodeGen Core MC SelectionDAG Support Target +add_to_library_groups = CAHP diff --git a/llvm/lib/Target/CAHP/MCTargetDesc/CAHPAsmBackend.cpp b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPAsmBackend.cpp new file mode 100644 index 000000000000..fd697cee7c9b --- /dev/null +++ b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPAsmBackend.cpp @@ -0,0 +1,189 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "MCTargetDesc/CAHPFixupKinds.h" +#include "MCTargetDesc/CAHPMCTargetDesc.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDirectives.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +namespace { +class CAHPAsmBackend : public MCAsmBackend { + uint8_t OSABI; + +public: + CAHPAsmBackend(uint8_t OSABI) : MCAsmBackend(support::little), OSABI(OSABI) {} + ~CAHPAsmBackend() override {} + + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef Data, + uint64_t Value, bool IsResolved, + const MCSubtargetInfo *STI) const override; + + std::unique_ptr + createObjectTargetWriter() const override; + + bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, + const MCRelaxableFragment *DF, + const MCAsmLayout &Layout) const override { + return false; + } + + unsigned getNumFixupKinds() const override { + return CAHP::NumTargetFixupKinds; + } + + const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override { + if (Kind < FirstTargetFixupKind) + return MCAsmBackend::getFixupKindInfo(Kind); + + // MCFixupKindInfo{name, offset, bits, flag} + switch ((unsigned)Kind) { + case CAHP::fixup_cahp_hi6: { + const static MCFixupKindInfo info{"fixup_cahp_hi6", 0, 16, 0}; + return info; + } + + case CAHP::fixup_cahp_lo10: { + const static MCFixupKindInfo info{"fixup_cahp_lo10", 0, 24, 0}; + return info; + } + + case CAHP::fixup_cahp_pcrel_10: { + const static MCFixupKindInfo info{"fixup_cahp_pcrel_10", 0, 24, + MCFixupKindInfo::FKF_IsPCRel}; + return info; + } + + case CAHP::fixup_cahp_pcrel_11: { + const static MCFixupKindInfo info{"fixup_cahp_pcrel_11", 5, 11, + MCFixupKindInfo::FKF_IsPCRel}; + return info; + } + + default: + llvm_unreachable("Invalid kind!"); + } + } + + bool mayNeedRelaxation(const MCInst &Inst, + const MCSubtargetInfo &STI) const override { + return false; + } + + void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, + MCInst &Res) const override { + + report_fatal_error("CAHPAsmBackend::relaxInstruction() unimplemented"); + } + + bool writeNopData(raw_ostream &OS, uint64_t Count) const override; +}; + +bool CAHPAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const { + if ((Count % 2) != 0) + return false; + + Count /= 2; + for (uint64_t i = 0; i < Count; ++i) + OS.write("\0\0", 2); + + return true; +} + +static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, + MCContext &Ctx) { + unsigned Kind = Fixup.getKind(); + switch (Kind) { + default: + llvm_unreachable("Unknown fixup kind!"); + + case FK_Data_1: + case FK_Data_2: + case FK_Data_4: + case FK_Data_8: + return Value; + + case CAHP::fixup_cahp_hi6: + // Add 1 if bit 9 is 1, to compensate for low 10 bits being negative. + Value = ((Value + 0x200) >> 10) & 0x3f; + // Need to produce (imm[3:0] << 12)|(imm[5:4] << 6) from the 6-bit Value. + return ((Value & 0xf) << 12) | (((Value >> 4) & 3) << 6); + + case CAHP::fixup_cahp_lo10: + Value = Value & 0x3ff; + // Need to produce (imm[7:0] << 16)|(imm[9:8] << 6) + return ((Value & 0xff) << 16) | (((Value >> 8) & 3) << 6); + + case CAHP::fixup_cahp_pcrel_10: + if (!isInt<10>(Value)) + Ctx.reportError(Fixup.getLoc(), + "fixup value out of range (fixup_cahp_pcrel_10)"); + // Need to produce (imm[7:0] << 16)|(imm[9:8] << 6) from the 10-bit Value. + return ((Value & 0xff) << 16) | (((Value >> 8) & 0x3) << 6); + + case CAHP::fixup_cahp_pcrel_11: + if (!isInt<11>(Value)) + Ctx.reportError(Fixup.getLoc(), + "fixup value out of range (fixup_cahp_pcrel_11)"); + return Value; + } +} + +void CAHPAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, + MutableArrayRef Data, uint64_t Value, + bool IsResolved, + const MCSubtargetInfo *STI) const { + if (!Value) + return; // Doesn't change encoding. + + MCContext &Ctx = Asm.getContext(); + MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind()); + // Apply any target-specific value adjustments. + Value = adjustFixupValue(Fixup, Value, Ctx); + + // Shift the value into position. + Value <<= Info.TargetOffset; + + unsigned Offset = Fixup.getOffset(); + unsigned NumBytes = alignTo(Info.TargetSize + Info.TargetOffset, 8) / 8; + + assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); + + // For each byte of the fragment that the fixup touches, mask in the + // bits from the fixup value. + for (unsigned i = 0; i != NumBytes; ++i) { + Data[Offset + i] |= static_cast((Value >> (i * 8)) & 0xff); + } + + return; +} + +std::unique_ptr +CAHPAsmBackend::createObjectTargetWriter() const { + return createCAHPELFObjectWriter(OSABI); +} + +} // end anonymous namespace + +MCAsmBackend *llvm::createCAHPAsmBackend(const Target &T, + const MCSubtargetInfo &STI, + const MCRegisterInfo &MRI, + const MCTargetOptions &Options) { + const Triple &TT = STI.getTargetTriple(); + uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS()); + return new CAHPAsmBackend(OSABI); +} diff --git a/llvm/lib/Target/CAHP/MCTargetDesc/CAHPBaseInfo.h b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPBaseInfo.h new file mode 100644 index 000000000000..13b205e5b6f6 --- /dev/null +++ b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPBaseInfo.h @@ -0,0 +1,20 @@ +#ifndef LLVM_LIB_TARGET_CAHP_MCTARGETDESC_CAHPBASEINFO_H +#define LLVM_LIB_TARGET_CAHP_MCTARGETDESC_CAHPBASEINFO_H + +#include "CAHPMCTargetDesc.h" + +namespace llvm { + +// CAHPII - This namespace holds all of the target specific flags that +// instruction info tracks. All definitions must match CAHPInstrFormats.td. +namespace CAHPII { +enum { + MO_None, + MO_LO, + MO_HI, +}; +} // namespace CAHPII + +} // namespace llvm + +#endif diff --git a/llvm/lib/Target/CAHP/MCTargetDesc/CAHPELFObjectWriter.cpp b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPELFObjectWriter.cpp new file mode 100644 index 000000000000..2c9c5a8078bf --- /dev/null +++ b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPELFObjectWriter.cpp @@ -0,0 +1,55 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "MCTargetDesc/CAHPFixupKinds.h" +#include "MCTargetDesc/CAHPMCTargetDesc.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +namespace { +class CAHPELFObjectWriter : public MCELFObjectTargetWriter { +public: + CAHPELFObjectWriter(uint8_t OSABI); + + ~CAHPELFObjectWriter() override; + +protected: + unsigned getRelocType(MCContext &Ctx, const MCValue &Target, + const MCFixup &Fixup, bool IsPCRel) const override; +}; +} // namespace + +CAHPELFObjectWriter::CAHPELFObjectWriter(uint8_t OSABI) + : MCELFObjectTargetWriter(false, OSABI, ELF::EM_CAHP, + /*HasRelocationAddend*/ true) {} + +CAHPELFObjectWriter::~CAHPELFObjectWriter() {} + +unsigned CAHPELFObjectWriter::getRelocType(MCContext &Ctx, + const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel) const { + // Determine the type of the relocation + switch ((unsigned)Fixup.getKind()) { + default: + llvm_unreachable("invalid fixup kind!"); + case FK_Data_2: + return ELF::R_CAHP_16; + case CAHP::fixup_cahp_hi6: + return ELF::R_CAHP_HI6; + case CAHP::fixup_cahp_lo10: + return ELF::R_CAHP_LO10; + case CAHP::fixup_cahp_pcrel_11: + return ELF::R_CAHP_PCREL_11; + } +} + +std::unique_ptr +llvm::createCAHPELFObjectWriter(uint8_t OSABI) { + return llvm::make_unique(OSABI); +} diff --git a/llvm/lib/Target/CAHP/MCTargetDesc/CAHPFixupKinds.h b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPFixupKinds.h new file mode 100644 index 000000000000..061ff71ab394 --- /dev/null +++ b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPFixupKinds.h @@ -0,0 +1,32 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#ifndef LLVM_LIB_TARGET_CAHP_MCTARGETDESC_CAHPFIXUPKINDS_H +#define LLVM_LIB_TARGET_CAHP_MCTARGETDESC_CAHPFIXUPKINDS_H + +#include "llvm/MC/MCFixup.h" + +#undef CAHP + +namespace llvm { +namespace CAHP { +enum Fixups { + // Fixups for hi/lo + fixup_cahp_hi6 = FirstTargetFixupKind, + fixup_cahp_lo10, + + // 10-bit pc relative. e.g. bcc + fixup_cahp_pcrel_10, + + // 11-bit pc relative. e.g. js, jsal + fixup_cahp_pcrel_11, + + // fixup_rv16k_invalid - used as a sentinel and a marker, must be last fixup + fixup_cahp_invalid, + NumTargetFixupKinds = fixup_cahp_invalid - FirstTargetFixupKind +}; +} // end namespace CAHP +} // end namespace llvm + +#endif diff --git a/llvm/lib/Target/CAHP/MCTargetDesc/CAHPMCAsmInfo.cpp b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPMCAsmInfo.cpp new file mode 100644 index 000000000000..22d0ddd12b72 --- /dev/null +++ b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPMCAsmInfo.cpp @@ -0,0 +1,16 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "CAHPMCAsmInfo.h" +#include "llvm/ADT/Triple.h" +using namespace llvm; + +void CAHPMCAsmInfo::anchor() {} + +CAHPMCAsmInfo::CAHPMCAsmInfo(const Triple &TT) { + CodePointerSize = 2; + CalleeSaveStackSlotSize = 2; + CommentString = "#"; + SupportsDebugInformation = true; +} diff --git a/llvm/lib/Target/CAHP/MCTargetDesc/CAHPMCAsmInfo.h b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPMCAsmInfo.h new file mode 100644 index 000000000000..05336c067008 --- /dev/null +++ b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPMCAsmInfo.h @@ -0,0 +1,25 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#ifndef LLVM_LIB_TARGET_CAHP_MCTARGETDESC_CAHPMCASMINFO_H +#define LLVM_LIB_TARGET_CAHP_MCTARGETDESC_CAHPMCASMINFO_H + +#include "llvm/MC/MCAsmInfoELF.h" + +namespace llvm { +class Triple; + +class CAHPMCAsmInfo : public MCAsmInfoELF { + // This function MUST BE placed here to reduce the size of object files. + // See also: + // https://stackoverflow.com/questions/16801222/out-of-line-virtual-method + void anchor() override; + +public: + explicit CAHPMCAsmInfo(const Triple &TargetTriple); +}; + +} // namespace llvm + +#endif diff --git a/llvm/lib/Target/CAHP/MCTargetDesc/CAHPMCCodeEmitter.cpp b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPMCCodeEmitter.cpp new file mode 100644 index 000000000000..226092a4938c --- /dev/null +++ b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPMCCodeEmitter.cpp @@ -0,0 +1,193 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "MCTargetDesc/CAHPFixupKinds.h" +#include "MCTargetDesc/CAHPMCExpr.h" +#include "MCTargetDesc/CAHPMCTargetDesc.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstBuilder.h" +#include "llvm/MC/MCInstrDesc.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/EndianStream.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#define DEBUG_TYPE "mccodeemitter" + +STATISTIC(MCNumEmitted, "Number of MC instructions emitted"); +STATISTIC(MCNumFixups, "Number of MC fixups created"); + +namespace { +class CAHPMCCodeEmitter : public MCCodeEmitter { + CAHPMCCodeEmitter(const CAHPMCCodeEmitter &) = delete; + void operator=(const CAHPMCCodeEmitter &) = delete; + MCContext &Ctx; + MCInstrInfo const &MCII; + +public: + CAHPMCCodeEmitter(MCContext &ctx, const MCInstrInfo &MCII) + : Ctx(ctx), MCII(MCII) {} + + ~CAHPMCCodeEmitter() override {} + + void encodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const override; + + /// TableGen'erated function for getting the binary encoding for an + /// instruction. + uint64_t getBinaryCodeForInstr(const MCInst &MI, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + /// Return binary encoding of operand. If the machine operand requires + /// relocation, record the relocation and return zero. + unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getImmOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + +private: + void expandHlt(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; +}; +} // end anonymous namespace + +MCCodeEmitter *llvm::createCAHPMCCodeEmitter(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + MCContext &Ctx) { + return new CAHPMCCodeEmitter(Ctx, MCII); +} + +void CAHPMCCodeEmitter::expandHlt(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + // Emit `js 0` + MCInst TmpInst = MCInstBuilder(CAHP::JS).addImm(0); + uint16_t Bits = getBinaryCodeForInstr(TmpInst, Fixups, STI); + support::endian::write(OS, Bits, support::little); +} + +void CAHPMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); + + if (MI.getOpcode() == CAHP::PseudoHLT) { + expandHlt(MI, OS, Fixups, STI); + MCNumEmitted += 2; + return; + } + + // Get byte count of instruction. + unsigned Size = Desc.getSize(); + + switch (Size) { + default: + llvm_unreachable("Unhandled encodeInstruction length!"); + case 2: { + uint16_t Bits = getBinaryCodeForInstr(MI, Fixups, STI); + support::endian::write(OS, Bits, support::little); + break; + } + case 3: { + uint32_t Bits = getBinaryCodeForInstr(MI, Fixups, STI); + support::endian::write(OS, Bits & 0xffff, support::little); + OS.write((Bits >> 16) & 0xff); + break; + } + } + + ++MCNumEmitted; // Keep track of the # of mi's emitted. +} + +unsigned +CAHPMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + + if (MO.isReg()) + return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg()); + + if (MO.isImm()) + return static_cast(MO.getImm()); + + llvm_unreachable("Unhandled expression!"); + return 0; +} + +unsigned CAHPMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + + if (MO.isImm()) + return MO.getImm(); + + assert(MO.isExpr() && "getImmOpValue expects only expressions or immediates"); + + const MCExpr *Expr = MO.getExpr(); + MCExpr::ExprKind Kind = Expr->getKind(); + CAHP::Fixups FixupKind = CAHP::fixup_cahp_invalid; + unsigned Offset = 0; + + if (Kind == MCExpr::Target) { + const CAHPMCExpr *CAHPExpr = cast(Expr); + + switch (CAHPExpr->getKind()) { + case CAHPMCExpr::VK_CAHP_None: + case CAHPMCExpr::VK_CAHP_Invalid: + llvm_unreachable("Unhandled fixup kind!"); + + case CAHPMCExpr::VK_CAHP_LO: + FixupKind = CAHP::fixup_cahp_lo10; + break; + + case CAHPMCExpr::VK_CAHP_HI: + FixupKind = CAHP::fixup_cahp_hi6; + break; + } + } else if (Kind == MCExpr::SymbolRef && + cast(Expr)->getKind() == + MCSymbolRefExpr::VK_None) { + switch (MI.getOpcode()) { + case CAHP::JS: + case CAHP::JSAL: + FixupKind = CAHP::fixup_cahp_pcrel_11; + break; + + case CAHP::BEQ: + case CAHP::BNE: + case CAHP::BLT: + case CAHP::BLTU: + case CAHP::BLE: + case CAHP::BLEU: + FixupKind = CAHP::fixup_cahp_pcrel_10; + break; + } + } + + assert(FixupKind != CAHP::fixup_cahp_invalid && "Unhandled expression!"); + + Fixups.push_back(MCFixup::create( + Offset, Expr, static_cast(FixupKind), MI.getLoc())); + ++MCNumFixups; + + return 0; +} + +#include "CAHPGenMCCodeEmitter.inc" diff --git a/llvm/lib/Target/CAHP/MCTargetDesc/CAHPMCExpr.cpp b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPMCExpr.cpp new file mode 100644 index 000000000000..650b7a2cabb9 --- /dev/null +++ b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPMCExpr.cpp @@ -0,0 +1,83 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "CAHPMCExpr.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbolELF.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +#define DEBUG_TYPE "riscvmcexpr" + +const CAHPMCExpr *CAHPMCExpr::create(const MCExpr *Expr, VariantKind Kind, + MCContext &Ctx) { + return new (Ctx) CAHPMCExpr(Expr, Kind); +} + +void CAHPMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { + bool HasVariant = getKind() != VK_CAHP_None; + if (HasVariant) + OS << '%' << getVariantKindName(getKind()) << '('; + Expr->print(OS, MAI); + if (HasVariant) + OS << ')'; +} + +bool CAHPMCExpr::evaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout, + const MCFixup *Fixup) const { + return getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup); +} + +void CAHPMCExpr::visitUsedExpr(MCStreamer &Streamer) const { + Streamer.visitUsedExpr(*getSubExpr()); +} + +CAHPMCExpr::VariantKind CAHPMCExpr::getVariantKindForName(StringRef name) { + return StringSwitch(name) + .Case("lo", VK_CAHP_LO) + .Case("hi", VK_CAHP_HI) + .Default(VK_CAHP_Invalid); +} + +StringRef CAHPMCExpr::getVariantKindName(VariantKind Kind) { + switch (Kind) { + default: + llvm_unreachable("Invalid ELF symbol kind"); + case VK_CAHP_LO: + return "lo"; + case VK_CAHP_HI: + return "hi"; + } +} + +bool CAHPMCExpr::evaluateAsConstant(int64_t &Res) const { + MCValue Value; + + if (!getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr)) + return false; + + if (!Value.isAbsolute()) + return false; + + Res = evaluateAsInt64(Value.getConstant()); + return true; +} + +int64_t CAHPMCExpr::evaluateAsInt64(int64_t Value) const { + switch (Kind) { + default: + llvm_unreachable("Invalid kind"); + case VK_CAHP_LO: + return SignExtend64<10>(Value); + case VK_CAHP_HI: + // Add 1 if bit 9 is 1, to compensate for low 10 bits being negative. + return ((Value + 0x200) >> 10) & 0x3f; + } +} diff --git a/llvm/lib/Target/CAHP/MCTargetDesc/CAHPMCExpr.h b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPMCExpr.h new file mode 100644 index 000000000000..7b98e9b9630e --- /dev/null +++ b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPMCExpr.h @@ -0,0 +1,59 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#ifndef LLVM_LIB_TARGET_CAHP_MCTARGETDESC_CAHPMCEXPR_H +#define LLVM_LIB_TARGET_CAHP_MCTARGETDESC_CAHPMCEXPR_H + +#include "llvm/MC/MCExpr.h" + +namespace llvm { + +class StringRef; +class CAHPMCExpr : public MCTargetExpr { +public: + enum VariantKind { VK_CAHP_None, VK_CAHP_LO, VK_CAHP_HI, VK_CAHP_Invalid }; + +private: + const MCExpr *Expr; + const VariantKind Kind; + + int64_t evaluateAsInt64(int64_t Value) const; + + explicit CAHPMCExpr(const MCExpr *Expr, VariantKind Kind) + : Expr(Expr), Kind(Kind) {} + +public: + static const CAHPMCExpr *create(const MCExpr *Expr, VariantKind Kind, + MCContext &Ctx); + + VariantKind getKind() const { return Kind; } + + const MCExpr *getSubExpr() const { return Expr; } + + void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override; + bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout, + const MCFixup *Fixup) const override; + void visitUsedExpr(MCStreamer &Streamer) const override; + MCFragment *findAssociatedFragment() const override { + return getSubExpr()->findAssociatedFragment(); + } + + // There are no TLS CAHPMCExprs at the moment. + void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override {} + + bool evaluateAsConstant(int64_t &Res) const; + + static bool classof(const MCExpr *E) { + return E->getKind() == MCExpr::Target; + } + + static bool classof(const CAHPMCExpr *) { return true; } + + static VariantKind getVariantKindForName(StringRef name); + static StringRef getVariantKindName(VariantKind Kind); +}; + +} // end namespace llvm. + +#endif diff --git a/llvm/lib/Target/CAHP/MCTargetDesc/CAHPMCTargetDesc.cpp b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPMCTargetDesc.cpp new file mode 100644 index 000000000000..5c85711b2920 --- /dev/null +++ b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPMCTargetDesc.cpp @@ -0,0 +1,73 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "CAHPMCTargetDesc.h" +#include "CAHPMCAsmInfo.h" +#include "InstPrinter/CAHPInstPrinter.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" + +#define GET_INSTRINFO_MC_DESC +#include "CAHPGenInstrInfo.inc" + +#define GET_REGINFO_MC_DESC +#include "CAHPGenRegisterInfo.inc" + +#define GET_SUBTARGETINFO_MC_DESC +#include "CAHPGenSubtargetInfo.inc" + +using namespace llvm; + +static MCInstrInfo *createCAHPMCInstrInfo() { + MCInstrInfo *X = new MCInstrInfo(); + InitCAHPMCInstrInfo(X); + return X; +} + +static MCRegisterInfo *createCAHPMCRegisterInfo(const Triple &TT) { + MCRegisterInfo *X = new MCRegisterInfo(); + + // X0 is the return address register. + InitCAHPMCRegisterInfo(X, CAHP::X0); + + return X; +} + +static MCAsmInfo *createCAHPMCAsmInfo(const MCRegisterInfo &MRI, + const Triple &TT) { + return new CAHPMCAsmInfo(TT); +} + +static MCSubtargetInfo *createCAHPMCSubtargetInfo(const Triple &TT, + StringRef CPU, StringRef FS) { + std::string CPUName = CPU; + if (CPUName.empty()) + CPUName = "generic"; + return createCAHPMCSubtargetInfoImpl(TT, CPUName, FS); +} + +static MCInstPrinter *createCAHPMCInstPrinter(const Triple &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI) { + return new CAHPInstPrinter(MAI, MII, MRI); +} + +extern "C" void LLVMInitializeCAHPTargetMC() { + Target &T = getTheCAHPTarget(); + TargetRegistry::RegisterMCAsmInfo(T, createCAHPMCAsmInfo); + TargetRegistry::RegisterMCInstrInfo(T, createCAHPMCInstrInfo); + TargetRegistry::RegisterMCRegInfo(T, createCAHPMCRegisterInfo); + TargetRegistry::RegisterMCAsmBackend(T, createCAHPAsmBackend); + TargetRegistry::RegisterMCSubtargetInfo(T, createCAHPMCSubtargetInfo); + TargetRegistry::RegisterMCCodeEmitter(T, createCAHPMCCodeEmitter); + TargetRegistry::RegisterMCInstPrinter(T, createCAHPMCInstPrinter); +} diff --git a/llvm/lib/Target/CAHP/MCTargetDesc/CAHPMCTargetDesc.h b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPMCTargetDesc.h new file mode 100644 index 000000000000..7cef4c7246fa --- /dev/null +++ b/llvm/lib/Target/CAHP/MCTargetDesc/CAHPMCTargetDesc.h @@ -0,0 +1,48 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#ifndef LLVM_LIB_TARGET_CAHP_MCTARGETDESC_CAHPMCTARGETDESC_H +#define LLVM_LIB_TARGET_CAHP_MCTARGETDESC_CAHPMCTARGETDESC_H + +#include "llvm/Config/config.h" +#include "llvm/MC/MCTargetOptions.h" +#include "llvm/Support/DataTypes.h" +#include + +namespace llvm { +class MCAsmBackend; +class MCCodeEmitter; +class MCContext; +class MCInstrInfo; +class MCObjectTargetWriter; +class MCRegisterInfo; +class MCSubtargetInfo; +class StringRef; +class Target; +class Triple; +class raw_ostream; +class raw_pwrite_stream; + +Target &getTheCAHPTarget(); + +MCCodeEmitter *createCAHPMCCodeEmitter(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + MCContext &Ctx); + +MCAsmBackend *createCAHPAsmBackend(const Target &T, const MCSubtargetInfo &STI, + const MCRegisterInfo &MRI, + const MCTargetOptions &Options); + +std::unique_ptr createCAHPELFObjectWriter(uint8_t OSABI); +} // namespace llvm + +// Defines symbolic names for CAHP registers. +#define GET_REGINFO_ENUM +#include "CAHPGenRegisterInfo.inc" + +// Defines symbolic names for CAHP instructions. +#define GET_INSTRINFO_ENUM +#include "CAHPGenInstrInfo.inc" + +#endif diff --git a/llvm/lib/Target/CAHP/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/CAHP/MCTargetDesc/CMakeLists.txt new file mode 100644 index 000000000000..fb967f57d2b4 --- /dev/null +++ b/llvm/lib/Target/CAHP/MCTargetDesc/CMakeLists.txt @@ -0,0 +1,8 @@ +add_llvm_library(LLVMCAHPDesc + CAHPMCTargetDesc.cpp + CAHPMCAsmInfo.cpp + CAHPAsmBackend.cpp + CAHPELFObjectWriter.cpp + CAHPMCCodeEmitter.cpp + CAHPMCExpr.cpp +) diff --git a/llvm/lib/Target/CAHP/MCTargetDesc/LLVMBuild.txt b/llvm/lib/Target/CAHP/MCTargetDesc/LLVMBuild.txt new file mode 100644 index 000000000000..1538585a7e95 --- /dev/null +++ b/llvm/lib/Target/CAHP/MCTargetDesc/LLVMBuild.txt @@ -0,0 +1,10 @@ +; This file is copied and modified from The LLVM Compiler Infrastructure, which +; is distributed under the Apache License v2.0 with LLVM Exceptions (see +; LICENSE.TXT for details). This file is licensed under the same license. + +[component_0] +type = Library +name = CAHPDesc +parent = CAHP +required_libraries = MC CAHPAsmPrinter CAHPInfo Support +add_to_library_groups = CAHP diff --git a/llvm/lib/Target/CAHP/TargetInfo/CAHPTargetInfo.cpp b/llvm/lib/Target/CAHP/TargetInfo/CAHPTargetInfo.cpp new file mode 100644 index 000000000000..e1c960079ba6 --- /dev/null +++ b/llvm/lib/Target/CAHP/TargetInfo/CAHPTargetInfo.cpp @@ -0,0 +1,17 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "llvm/Support/TargetRegistry.h" +using namespace llvm; + +namespace llvm { +Target &getTheCAHPTarget() { + static Target TheCAHPTarget; + return TheCAHPTarget; +} +} // namespace llvm + +extern "C" void LLVMInitializeCAHPTargetInfo() { + RegisterTarget X(getTheCAHPTarget(), "cahp", "CAHP", "CAHP"); +} diff --git a/llvm/lib/Target/CAHP/TargetInfo/CMakeLists.txt b/llvm/lib/Target/CAHP/TargetInfo/CMakeLists.txt new file mode 100644 index 000000000000..17afa06d7638 --- /dev/null +++ b/llvm/lib/Target/CAHP/TargetInfo/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_library(LLVMCAHPInfo + CAHPTargetInfo.cpp + ) diff --git a/llvm/lib/Target/CAHP/TargetInfo/LLVMBuild.txt b/llvm/lib/Target/CAHP/TargetInfo/LLVMBuild.txt new file mode 100644 index 000000000000..e0563e6528d3 --- /dev/null +++ b/llvm/lib/Target/CAHP/TargetInfo/LLVMBuild.txt @@ -0,0 +1,6 @@ +[component_0] +type = Library +name = CAHPInfo +parent = CAHP +required_libraries = Support +add_to_library_groups = CAHP diff --git a/llvm/lib/Target/LLVMBuild.txt b/llvm/lib/Target/LLVMBuild.txt index d6a95a3c6713..62d9db2a5fc7 100644 --- a/llvm/lib/Target/LLVMBuild.txt +++ b/llvm/lib/Target/LLVMBuild.txt @@ -24,6 +24,7 @@ subdirectories = AArch64 AVR BPF + CAHP Lanai Hexagon MSP430 diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index 1f7d095bf49b..aee434cb0067 100644 --- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -3625,8 +3625,25 @@ void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, TOut.emitRRR(isGP64bit() ? Mips::DADDu : Mips::ADDu, TmpReg, TmpReg, BaseReg, IDLoc, STI); TOut.emitRRI(Inst.getOpcode(), DstReg, TmpReg, LoOffset, IDLoc, STI); + return; + } + + assert(OffsetOp.isExpr() && "expected expression operand kind"); + if (inPicMode()) { + // FIXME: + // a) Fix lw/sw $reg, symbol($reg) instruction expanding. + // b) If expression includes offset (sym + number), do not + // encode the offset into a relocation. Take it in account + // in the last load/store instruction. + // c) Check that immediates of R_MIPS_GOT16/R_MIPS_LO16 relocations + // do not exceed 16-bit. + // d) Use R_MIPS_GOT_PAGE/R_MIPS_GOT_OFST relocations instead + // of R_MIPS_GOT_DISP in appropriate cases to reduce number + // of GOT entries. + expandLoadAddress(TmpReg, Mips::NoRegister, OffsetOp, !ABI.ArePtrs64bit(), + IDLoc, Out, STI); + TOut.emitRRI(Inst.getOpcode(), DstReg, TmpReg, 0, IDLoc, STI); } else { - assert(OffsetOp.isExpr() && "expected expression operand kind"); const MCExpr *ExprOffset = OffsetOp.getExpr(); MCOperand LoOperand = MCOperand::createExpr( MipsMCExpr::create(MipsMCExpr::MEK_LO, ExprOffset, getContext())); diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp index bd87ce06b4fb..269b84b4e8d8 100644 --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -866,8 +866,10 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { const GlobalValue *GValue = MO.getGlobal(); MCSymbol *MOSymbol = getSymbol(GValue); const MCExpr *Exp = - MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_PPC_GOT_TPREL_LO, - OutContext); + MCSymbolRefExpr::create(MOSymbol, + isPPC64 ? MCSymbolRefExpr::VK_PPC_GOT_TPREL_LO + : MCSymbolRefExpr::VK_PPC_GOT_TPREL, + OutContext); TmpInst.getOperand(1) = MCOperand::createExpr(Exp); EmitToStreamer(*OutStreamer, TmpInst); return; diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index 0172c6298772..f10f7a2b77d6 100644 --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -1208,6 +1208,24 @@ OperandMatchResultTy RISCVAsmParser::parseBareSymbol(OperandVector &Operands) { Res = V; } else Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + + MCBinaryExpr::Opcode Opcode; + switch (getLexer().getKind()) { + default: + Operands.push_back(RISCVOperand::createImm(Res, S, E, isRV64())); + return MatchOperand_Success; + case AsmToken::Plus: + Opcode = MCBinaryExpr::Add; + break; + case AsmToken::Minus: + Opcode = MCBinaryExpr::Sub; + break; + } + + const MCExpr *Expr; + if (getParser().parseExpression(Expr)) + return MatchOperand_ParseFail; + Res = MCBinaryExpr::create(Opcode, Res, Expr, getContext()); Operands.push_back(RISCVOperand::createImm(Res, S, E, isRV64())); return MatchOperand_Success; } diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp index 32c3b9684d2c..bbaa16c08634 100644 --- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp @@ -40,8 +40,16 @@ void RISCVFrameLowering::determineFrameLayout(MachineFunction &MF) const { uint64_t FrameSize = MFI.getStackSize(); // Get the alignment. - uint64_t StackAlign = RI->needsStackRealignment(MF) ? MFI.getMaxAlignment() - : getStackAlignment(); + unsigned StackAlign = getStackAlignment(); + if (RI->needsStackRealignment(MF)) { + unsigned MaxStackAlign = std::max(StackAlign, MFI.getMaxAlignment()); + FrameSize += (MaxStackAlign - StackAlign); + StackAlign = MaxStackAlign; + } + + // Set Max Call Frame Size + uint64_t MaxCallSize = alignTo(MFI.getMaxCallFrameSize(), StackAlign); + MFI.setMaxCallFrameSize(MaxCallSize); // Make sure the frame is aligned. FrameSize = alignTo(FrameSize, StackAlign); @@ -101,6 +109,12 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF, const RISCVInstrInfo *TII = STI.getInstrInfo(); MachineBasicBlock::iterator MBBI = MBB.begin(); + if (RI->needsStackRealignment(MF) && MFI.hasVarSizedObjects()) { + report_fatal_error( + "RISC-V backend can't currently handle functions that need stack " + "realignment and have variable sized objects"); + } + unsigned FPReg = getFPReg(STI); unsigned SPReg = getSPReg(STI); @@ -158,6 +172,29 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF, nullptr, RI->getDwarfRegNum(FPReg, true), 0)); BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex); + + // Realign Stack + const RISCVRegisterInfo *RI = STI.getRegisterInfo(); + if (RI->needsStackRealignment(MF)) { + unsigned MaxAlignment = MFI.getMaxAlignment(); + + const RISCVInstrInfo *TII = STI.getInstrInfo(); + if (isInt<12>(-(int)MaxAlignment)) { + BuildMI(MBB, MBBI, DL, TII->get(RISCV::ANDI), SPReg) + .addReg(SPReg) + .addImm(-(int)MaxAlignment); + } else { + unsigned ShiftAmount = countTrailingZeros(MaxAlignment); + unsigned VR = + MF.getRegInfo().createVirtualRegister(&RISCV::GPRRegClass); + BuildMI(MBB, MBBI, DL, TII->get(RISCV::SRLI), VR) + .addReg(SPReg) + .addImm(ShiftAmount); + BuildMI(MBB, MBBI, DL, TII->get(RISCV::SLLI), SPReg) + .addReg(VR) + .addImm(ShiftAmount); + } + } } } @@ -257,6 +294,13 @@ int RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF, if (FI >= MinCSFI && FI <= MaxCSFI) { FrameReg = RISCV::X2; Offset += MF.getFrameInfo().getStackSize(); + } else if (RI->needsStackRealignment(MF)) { + assert(!MFI.hasVarSizedObjects() && + "Unexpected combination of stack realignment and varsized objects"); + // If the stack was realigned, the frame pointer is set in order to allow + // SP to be restored, but we still access stack objects using SP. + FrameReg = RISCV::X2; + Offset += MF.getFrameInfo().getStackSize(); } else { FrameReg = RI->getFrameRegister(MF); if (hasFP(MF)) diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp index d0a3af375a6d..8439278b4ed5 100644 --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -179,6 +179,9 @@ bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand( // operand and need no special handling. OutOps.push_back(Op); return false; + case InlineAsm::Constraint_A: + OutOps.push_back(Op); + return false; default: break; } diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index ce7b85911ab6..2b0f64fa6db6 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -1007,12 +1007,14 @@ bool RISCVTargetLowering::isDesirableToCommuteWithShift( // We can materialise `c1 << c2` into an add immediate, so it's "free", // and the combine should happen, to potentially allow further combines // later. - if (isLegalAddImmediate(ShiftedC1Int.getSExtValue())) + if (ShiftedC1Int.getMinSignedBits() <= 64 && + isLegalAddImmediate(ShiftedC1Int.getSExtValue())) return true; // We can materialise `c1` in an add immediate, so it's "free", and the // combine should be prevented. - if (isLegalAddImmediate(C1Int.getSExtValue())) + if (C1Int.getMinSignedBits() <= 64 && + isLegalAddImmediate(C1Int.getSExtValue())) return false; // Neither constant will fit into an immediate, so find materialisation @@ -2397,6 +2399,27 @@ const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const { return nullptr; } +/// getConstraintType - Given a constraint letter, return the type of +/// constraint it is for this target. +RISCVTargetLowering::ConstraintType +RISCVTargetLowering::getConstraintType(StringRef Constraint) const { + if (Constraint.size() == 1) { + switch (Constraint[0]) { + default: + break; + case 'f': + return C_RegisterClass; + case 'I': + case 'J': + case 'K': + return C_Immediate; + case 'A': + return C_Memory; + } + } + return TargetLowering::getConstraintType(Constraint); +} + std::pair RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, @@ -2407,6 +2430,12 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, switch (Constraint[0]) { case 'r': return std::make_pair(0U, &RISCV::GPRRegClass); + case 'f': + if (Subtarget.hasStdExtF() && VT == MVT::f32) + return std::make_pair(0U, &RISCV::FPR32RegClass); + if (Subtarget.hasStdExtD() && VT == MVT::f64) + return std::make_pair(0U, &RISCV::FPR64RegClass); + break; default: break; } @@ -2415,6 +2444,21 @@ RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); } +unsigned +RISCVTargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const { + // Currently only support length 1 constraints. + if (ConstraintCode.size() == 1) { + switch (ConstraintCode[0]) { + case 'A': + return InlineAsm::Constraint_A; + default: + break; + } + } + + return TargetLowering::getInlineAsmMemConstraint(ConstraintCode); +} + void RISCVTargetLowering::LowerAsmOperandForConstraint( SDValue Op, std::string &Constraint, std::vector &Ops, SelectionDAG &DAG) const { diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h index 17db03bbb69e..e2059e70831d 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -92,6 +92,10 @@ class RISCVTargetLowering : public TargetLowering { // This method returns the name of a target specific DAG node. const char *getTargetNodeName(unsigned Opcode) const override; + ConstraintType getConstraintType(StringRef Constraint) const override; + + unsigned getInlineAsmMemConstraint(StringRef ConstraintCode) const override; + std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const override; diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp index a6d440fa8aa2..804f7ba74edf 100644 --- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp +++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp @@ -3183,7 +3183,7 @@ SparcTargetLowering::getConstraintType(StringRef Constraint) const { case 'e': return C_RegisterClass; case 'I': // SIMM13 - return C_Other; + return C_Immediate; } } diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp index 78820f511ab4..e7b7a5b0cd53 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -956,7 +956,7 @@ SystemZTargetLowering::getConstraintType(StringRef Constraint) const { case 'K': // Signed 16-bit constant case 'L': // Signed 20-bit displacement (on all targets we support) case 'M': // 0x7fffffff - return C_Other; + return C_Immediate; default: break; diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp index 57c1cf4ec70a..8df19286965b 100644 --- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp +++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp @@ -468,7 +468,7 @@ bool SystemZInstrInfo::analyzeBranch(MachineBasicBlock &MBB, // Can't handle indirect branches. SystemZII::Branch Branch(getBranchInfo(*I)); - if (!Branch.Target->isMBB()) + if (!Branch.hasMBBTarget()) return true; // Punt on compound branches. @@ -478,7 +478,7 @@ bool SystemZInstrInfo::analyzeBranch(MachineBasicBlock &MBB, if (Branch.CCMask == SystemZ::CCMASK_ANY) { // Handle unconditional branches. if (!AllowModify) { - TBB = Branch.Target->getMBB(); + TBB = Branch.getMBBTarget(); continue; } @@ -490,7 +490,7 @@ bool SystemZInstrInfo::analyzeBranch(MachineBasicBlock &MBB, FBB = nullptr; // Delete the JMP if it's equivalent to a fall-through. - if (MBB.isLayoutSuccessor(Branch.Target->getMBB())) { + if (MBB.isLayoutSuccessor(Branch.getMBBTarget())) { TBB = nullptr; I->eraseFromParent(); I = MBB.end(); @@ -498,7 +498,7 @@ bool SystemZInstrInfo::analyzeBranch(MachineBasicBlock &MBB, } // TBB is used to indicate the unconditinal destination. - TBB = Branch.Target->getMBB(); + TBB = Branch.getMBBTarget(); continue; } @@ -506,7 +506,7 @@ bool SystemZInstrInfo::analyzeBranch(MachineBasicBlock &MBB, if (Cond.empty()) { // FIXME: add X86-style branch swap FBB = TBB; - TBB = Branch.Target->getMBB(); + TBB = Branch.getMBBTarget(); Cond.push_back(MachineOperand::CreateImm(Branch.CCValid)); Cond.push_back(MachineOperand::CreateImm(Branch.CCMask)); continue; @@ -517,7 +517,7 @@ bool SystemZInstrInfo::analyzeBranch(MachineBasicBlock &MBB, // Only handle the case where all conditional branches branch to the same // destination. - if (TBB != Branch.Target->getMBB()) + if (TBB != Branch.getMBBTarget()) return true; // If the conditions are the same, we can leave them alone. @@ -547,7 +547,7 @@ unsigned SystemZInstrInfo::removeBranch(MachineBasicBlock &MBB, continue; if (!I->isBranch()) break; - if (!getBranchInfo(*I).Target->isMBB()) + if (!getBranchInfo(*I).hasMBBTarget()) break; // Remove the branch. I->eraseFromParent(); @@ -1545,6 +1545,10 @@ SystemZInstrInfo::getBranchInfo(const MachineInstr &MI) const { return SystemZII::Branch(SystemZII::BranchCLG, SystemZ::CCMASK_ICMP, MI.getOperand(2).getImm(), &MI.getOperand(3)); + case SystemZ::INLINEASM_BR: + // Don't try to analyze asm goto, so pass nullptr as branch target argument. + return SystemZII::Branch(SystemZII::AsmGoto, 0, 0, nullptr); + default: llvm_unreachable("Unrecognized branch opcode"); } diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.h b/llvm/lib/Target/SystemZ/SystemZInstrInfo.h index 2edde175542e..134ed38a41aa 100644 --- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.h +++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.h @@ -100,11 +100,18 @@ enum BranchType { // An instruction that decrements a 64-bit register and branches if // the result is nonzero. - BranchCTG + BranchCTG, + + // An instruction representing an asm goto statement. + AsmGoto }; // Information about a branch instruction. -struct Branch { +class Branch { + // The target of the branch. In case of INLINEASM_BR, this is nullptr. + const MachineOperand *Target; + +public: // The type of the branch. BranchType Type; @@ -114,12 +121,15 @@ struct Branch { // CCMASK_ is set if the branch should be taken when CC == N. unsigned CCMask; - // The target of the branch. - const MachineOperand *Target; - Branch(BranchType type, unsigned ccValid, unsigned ccMask, const MachineOperand *target) - : Type(type), CCValid(ccValid), CCMask(ccMask), Target(target) {} + : Target(target), Type(type), CCValid(ccValid), CCMask(ccMask) {} + + bool isIndirect() { return Target != nullptr && Target->isReg(); } + bool hasMBBTarget() { return Target != nullptr && Target->isMBB(); } + MachineBasicBlock *getMBBTarget() { + return hasMBBTarget() ? Target->getMBB() : nullptr; + } }; // Kinds of fused compares in compare-and-* instructions. Together with type diff --git a/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp b/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp index 95d7e22dec32..dcaf629d240a 100644 --- a/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp +++ b/llvm/lib/Target/SystemZ/SystemZLongBranch.cpp @@ -257,7 +257,7 @@ TerminatorInfo SystemZLongBranch::describeTerminator(MachineInstr &MI) { } Terminator.Branch = &MI; Terminator.TargetBlock = - TII->getBranchInfo(MI).Target->getMBB()->getNumber(); + TII->getBranchInfo(MI).getMBBTarget()->getNumber(); } return Terminator; } diff --git a/llvm/lib/Target/SystemZ/SystemZMachineScheduler.cpp b/llvm/lib/Target/SystemZ/SystemZMachineScheduler.cpp index 0becfaa1d49c..eb9745f71b7d 100644 --- a/llvm/lib/Target/SystemZ/SystemZMachineScheduler.cpp +++ b/llvm/lib/Target/SystemZ/SystemZMachineScheduler.cpp @@ -108,8 +108,8 @@ void SystemZPostRASchedStrategy::enterMBB(MachineBasicBlock *NextMBB) { I != SinglePredMBB->end(); I++) { LLVM_DEBUG(dbgs() << "** Emitting incoming branch: "; I->dump();); bool TakenBranch = (I->isBranch() && - (TII->getBranchInfo(*I).Target->isReg() || // Relative branch - TII->getBranchInfo(*I).Target->getMBB() == MBB)); + (TII->getBranchInfo(*I).isIndirect() || + TII->getBranchInfo(*I).getMBBTarget() == MBB)); HazardRec->emitInstruction(&*I, TakenBranch); if (TakenBranch) break; diff --git a/llvm/lib/Target/TargetMachine.cpp b/llvm/lib/Target/TargetMachine.cpp index 634866d93570..28d783afe56c 100644 --- a/llvm/lib/Target/TargetMachine.cpp +++ b/llvm/lib/Target/TargetMachine.cpp @@ -140,8 +140,8 @@ bool TargetMachine::shouldAssumeDSOLocal(const Module &M, // don't assume the variables to be DSO local unless we actually know // that for sure. This only has to be done for variables; for functions // the linker can insert thunks for calling functions from another DLL. - if (TT.isWindowsGNUEnvironment() && GV && GV->isDeclarationForLinker() && - isa(GV)) + if (TT.isWindowsGNUEnvironment() && TT.isOSBinFormatCOFF() && GV && + GV->isDeclarationForLinker() && isa(GV)) return false; // On COFF, don't mark 'extern_weak' symbols as DSO local. If these symbols @@ -154,7 +154,9 @@ bool TargetMachine::shouldAssumeDSOLocal(const Module &M, // Make an exception for windows OS in the triple: Some firmware builds use // *-win32-macho triples. This (accidentally?) produced windows relocations // without GOT tables in older clang versions; Keep this behaviour. - if (TT.isOSBinFormatCOFF() || (TT.isOSWindows() && TT.isOSBinFormatMachO())) + // Some JIT users use *-win32-elf triples; these shouldn't use GOT tables + // either. + if (TT.isOSBinFormatCOFF() || TT.isOSWindows()) return true; // Most PIC code sequences that assume that a symbol is local cannot diff --git a/llvm/lib/Target/X86/X86.td b/llvm/lib/Target/X86/X86.td index 3112f00c91f2..e20315da55a5 100644 --- a/llvm/lib/Target/X86/X86.td +++ b/llvm/lib/Target/X86/X86.td @@ -95,7 +95,8 @@ def Feature3DNowA : SubtargetFeature<"3dnowa", "X863DNowLevel", "ThreeDNowA", def Feature64Bit : SubtargetFeature<"64bit", "HasX86_64", "true", "Support 64-bit instructions">; def FeatureCMPXCHG16B : SubtargetFeature<"cx16", "HasCmpxchg16b", "true", - "64-bit with cmpxchg16b">; + "64-bit with cmpxchg16b", + [FeatureCMPXCHG8B]>; def FeatureSlowSHLD : SubtargetFeature<"slow-shld", "IsSHLDSlow", "true", "SHLD instruction is slow">; def FeatureSlowPMULLD : SubtargetFeature<"slow-pmulld", "IsPMULLDSlow", "true", diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp index 95d31e62cafc..34ad589d205f 100644 --- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -2464,6 +2464,37 @@ bool X86DAGToDAGISel::selectLEAAddr(SDValue N, Complexity += 2; } + // Heuristic: try harder to form an LEA from ADD if the operands set flags. + // Unlike ADD, LEA does not affect flags, so we will be less likely to require + // duplicating flag-producing instructions later in the pipeline. + if (N.getOpcode() == ISD::ADD) { + auto isMathWithFlags = [](SDValue V) { + switch (V.getOpcode()) { + case X86ISD::ADD: + case X86ISD::SUB: + case X86ISD::ADC: + case X86ISD::SBB: + /* TODO: These opcodes can be added safely, but we may want to justify + their inclusion for different reasons (better for reg-alloc). + case X86ISD::SMUL: + case X86ISD::UMUL: + case X86ISD::OR: + case X86ISD::XOR: + case X86ISD::AND: + */ + // Value 1 is the flag output of the node - verify it's not dead. + return !SDValue(V.getNode(), 1).use_empty(); + default: + return false; + } + }; + // TODO: This could be an 'or' rather than 'and' to make the transform more + // likely to happen. We might want to factor in whether there's a + // load folding opportunity for the math op that disappears with LEA. + if (isMathWithFlags(N.getOperand(0)) && isMathWithFlags(N.getOperand(1))) + Complexity++; + } + if (AM.Disp) Complexity++; @@ -3302,8 +3333,12 @@ bool X86DAGToDAGISel::matchBitExtract(SDNode *Node) { SDValue ImplDef = SDValue( CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, DL, MVT::i32), 0); insertDAGNode(*CurDAG, SDValue(Node, 0), ImplDef); - NBits = CurDAG->getTargetInsertSubreg(X86::sub_8bit, DL, MVT::i32, ImplDef, - NBits); + + SDValue SRIdxVal = CurDAG->getTargetConstant(X86::sub_8bit, DL, MVT::i32); + insertDAGNode(*CurDAG, SDValue(Node, 0), SRIdxVal); + NBits = SDValue( + CurDAG->getMachineNode(TargetOpcode::INSERT_SUBREG, DL, MVT::i32, ImplDef, + NBits, SRIdxVal), 0); insertDAGNode(*CurDAG, SDValue(Node, 0), NBits); if (Subtarget->hasBMI2()) { diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index 0b4bf687e6cf..0c5b8a79dd62 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -4069,6 +4069,11 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, InFlag = Chain.getValue(1); DAG.addCallSiteInfo(Chain.getNode(), std::move(CSInfo)); + // Save heapallocsite metadata. + if (CLI.CS) + if (MDNode *HeapAlloc = CLI.CS->getMetadata("heapallocsite")) + DAG.addHeapAllocSite(Chain.getNode(), HeapAlloc); + // Create the CALLSEQ_END node. unsigned NumBytesForCalleeToPop; if (X86::isCalleePop(CallConv, Is64Bit, isVarArg, @@ -5054,6 +5059,14 @@ bool X86TargetLowering::shouldFoldMaskToVariableShiftPair(SDValue Y) const { return true; } +bool X86TargetLowering::shouldExpandShift(SelectionDAG &DAG, + SDNode *N) const { + if (DAG.getMachineFunction().getFunction().hasMinSize() && + !Subtarget.isOSWindows()) + return false; + return true; +} + bool X86TargetLowering::shouldSplatInsEltVarIndex(EVT VT) const { // Any legal vector type can be splatted more efficiently than // loading/spilling from memory. @@ -5500,6 +5513,7 @@ static bool collectConcatOps(SDNode *N, SmallVectorImpl &Ops) { if (VT.getSizeInBits() == (SubVT.getSizeInBits() * 2) && Idx == (VT.getVectorNumElements() / 2) && Src.getOpcode() == ISD::INSERT_SUBVECTOR && + Src.getOperand(1).getValueType() == SubVT && isNullConstant(Src.getOperand(2))) { Ops.push_back(Src.getOperand(1)); Ops.push_back(Sub); @@ -7636,17 +7650,22 @@ static SDValue EltsFromConsecutiveLoads(EVT VT, ArrayRef Elts, // IsConsecutiveLoadWithZeros - we need to create a shuffle of the loaded // vector and a zero vector to clear out the zero elements. if (!isAfterLegalize && VT.isVector()) { - SmallVector ClearMask(NumElems, -1); - for (unsigned i = 0; i < NumElems; ++i) { - if (ZeroMask[i]) - ClearMask[i] = i + NumElems; - else if (LoadMask[i]) - ClearMask[i] = i; + unsigned NumMaskElts = VT.getVectorNumElements(); + if ((NumMaskElts % NumElems) == 0) { + unsigned Scale = NumMaskElts / NumElems; + SmallVector ClearMask(NumMaskElts, -1); + for (unsigned i = 0; i < NumElems; ++i) { + if (UndefMask[i]) + continue; + int Offset = ZeroMask[i] ? NumMaskElts : 0; + for (unsigned j = 0; j != Scale; ++j) + ClearMask[(i * Scale) + j] = (i * Scale) + j + Offset; + } + SDValue V = CreateLoad(VT, LDBase); + SDValue Z = VT.isInteger() ? DAG.getConstant(0, DL, VT) + : DAG.getConstantFP(0.0, DL, VT); + return DAG.getVectorShuffle(VT, DL, V, Z, ClearMask); } - SDValue V = CreateLoad(VT, LDBase); - SDValue Z = VT.isInteger() ? DAG.getConstant(0, DL, VT) - : DAG.getConstantFP(0.0, DL, VT); - return DAG.getVectorShuffle(VT, DL, V, Z, ClearMask); } } @@ -31650,8 +31669,8 @@ static bool matchUnaryPermuteShuffle(MVT MaskVT, ArrayRef Mask, if (!ContainsZeros && AllowIntDomain && MaskScalarSizeInBits == 16) { SmallVector RepeatedMask; if (is128BitLaneRepeatedShuffleMask(MaskEltVT, Mask, RepeatedMask)) { - ArrayRef LoMask(Mask.data() + 0, 4); - ArrayRef HiMask(Mask.data() + 4, 4); + ArrayRef LoMask(RepeatedMask.data() + 0, 4); + ArrayRef HiMask(RepeatedMask.data() + 4, 4); // PSHUFLW: permute lower 4 elements only. if (isUndefOrInRange(LoMask, 0, 4) && @@ -33580,7 +33599,7 @@ static SDValue combineShuffleOfConcatUndef(SDNode *N, SelectionDAG &DAG, } /// Eliminate a redundant shuffle of a horizontal math op. -static SDValue foldShuffleOfHorizOp(SDNode *N) { +static SDValue foldShuffleOfHorizOp(SDNode *N, SelectionDAG &DAG) { unsigned Opcode = N->getOpcode(); if (Opcode != X86ISD::MOVDDUP && Opcode != X86ISD::VBROADCAST) if (Opcode != ISD::VECTOR_SHUFFLE || !N->getOperand(1).isUndef()) @@ -33611,6 +33630,25 @@ static SDValue foldShuffleOfHorizOp(SDNode *N) { HOp.getOperand(0) != HOp.getOperand(1)) return SDValue(); + // The shuffle that we are eliminating may have allowed the horizontal op to + // have an undemanded (undefined) operand. Duplicate the other (defined) + // operand to ensure that the results are defined across all lanes without the + // shuffle. + auto updateHOp = [](SDValue HorizOp, SelectionDAG &DAG) { + SDValue X; + if (HorizOp.getOperand(0).isUndef()) { + assert(!HorizOp.getOperand(1).isUndef() && "Not expecting foldable h-op"); + X = HorizOp.getOperand(1); + } else if (HorizOp.getOperand(1).isUndef()) { + assert(!HorizOp.getOperand(0).isUndef() && "Not expecting foldable h-op"); + X = HorizOp.getOperand(0); + } else { + return HorizOp; + } + return DAG.getNode(HorizOp.getOpcode(), SDLoc(HorizOp), + HorizOp.getValueType(), X, X); + }; + // When the operands of a horizontal math op are identical, the low half of // the result is the same as the high half. If a target shuffle is also // replicating low and high halves, we don't need the shuffle. @@ -33621,7 +33659,7 @@ static SDValue foldShuffleOfHorizOp(SDNode *N) { assert((HOp.getValueType() == MVT::v2f64 || HOp.getValueType() == MVT::v4f64) && HOp.getValueType() == VT && "Unexpected type for h-op"); - return HOp; + return updateHOp(HOp, DAG); } return SDValue(); } @@ -33635,14 +33673,14 @@ static SDValue foldShuffleOfHorizOp(SDNode *N) { (isTargetShuffleEquivalent(Mask, {0, 0}) || isTargetShuffleEquivalent(Mask, {0, 1, 0, 1}) || isTargetShuffleEquivalent(Mask, {0, 1, 2, 3, 0, 1, 2, 3}))) - return HOp; + return updateHOp(HOp, DAG); if (HOp.getValueSizeInBits() == 256 && (isTargetShuffleEquivalent(Mask, {0, 0, 2, 2}) || isTargetShuffleEquivalent(Mask, {0, 1, 0, 1, 4, 5, 4, 5}) || isTargetShuffleEquivalent( Mask, {0, 1, 2, 3, 0, 1, 2, 3, 8, 9, 10, 11, 8, 9, 10, 11}))) - return HOp; + return updateHOp(HOp, DAG); return SDValue(); } @@ -33696,7 +33734,7 @@ static SDValue combineShuffle(SDNode *N, SelectionDAG &DAG, if (SDValue AddSub = combineShuffleToAddSubOrFMAddSub(N, Subtarget, DAG)) return AddSub; - if (SDValue HAddSub = foldShuffleOfHorizOp(N)) + if (SDValue HAddSub = foldShuffleOfHorizOp(N, DAG)) return HAddSub; } @@ -34062,25 +34100,6 @@ bool X86TargetLowering::SimplifyDemandedVectorEltsForTargetNode( return true; break; } - case X86ISD::SUBV_BROADCAST: { - // Reduce size of broadcast if we don't need the upper half. - unsigned HalfElts = NumElts / 2; - if (DemandedElts.extractBits(HalfElts, HalfElts).isNullValue()) { - SDValue Src = Op.getOperand(0); - MVT SrcVT = Src.getSimpleValueType(); - - SDValue Half = Src; - if (SrcVT.getVectorNumElements() != HalfElts) { - MVT HalfVT = MVT::getVectorVT(SrcVT.getScalarType(), HalfElts); - Half = TLO.DAG.getNode(X86ISD::SUBV_BROADCAST, SDLoc(Op), HalfVT, Src); - } - - return TLO.CombineTo(Op, insertSubVector(TLO.DAG.getUNDEF(VT), Half, 0, - TLO.DAG, SDLoc(Op), - Half.getValueSizeInBits())); - } - break; - } case X86ISD::VPERMV: { SDValue Mask = Op.getOperand(0); APInt MaskUndef, MaskZero; @@ -34134,6 +34153,21 @@ bool X86TargetLowering::SimplifyDemandedVectorEltsForTargetNode( SDValue Insert = insertSubVector(UndefVec, ExtOp, 0, TLO.DAG, DL, ExtSizeInBits); return TLO.CombineTo(Op, Insert); + } + // Subvector broadcast. + case X86ISD::SUBV_BROADCAST: { + SDLoc DL(Op); + SDValue Src = Op.getOperand(0); + if (Src.getValueSizeInBits() > ExtSizeInBits) + Src = extractSubVector(Src, 0, TLO.DAG, DL, ExtSizeInBits); + else if (Src.getValueSizeInBits() < ExtSizeInBits) { + MVT SrcSVT = Src.getSimpleValueType().getScalarType(); + MVT SrcVT = + MVT::getVectorVT(SrcSVT, ExtSizeInBits / SrcSVT.getSizeInBits()); + Src = TLO.DAG.getNode(X86ISD::SUBV_BROADCAST, DL, SrcVT, Src); + } + return TLO.CombineTo(Op, insertSubVector(TLO.DAG.getUNDEF(VT), Src, 0, + TLO.DAG, DL, ExtSizeInBits)); } // Byte shifts by immediate. case X86ISD::VSHLDQ: @@ -43839,6 +43873,7 @@ static SDValue combineInsertSubvector(SDNode *N, SelectionDAG &DAG, Vec.getOpcode() == ISD::INSERT_SUBVECTOR && OpVT.getSizeInBits() == SubVecVT.getSizeInBits() * 2 && isNullConstant(Vec.getOperand(2)) && !Vec.getOperand(0).isUndef() && + Vec.getOperand(1).getValueSizeInBits() == SubVecVT.getSizeInBits() && Vec.hasOneUse()) { Vec = DAG.getNode(ISD::INSERT_SUBVECTOR, dl, OpVT, DAG.getUNDEF(OpVT), Vec.getOperand(1), Vec.getOperand(2)); @@ -44093,7 +44128,8 @@ static SDValue combineScalarToVector(SDNode *N, SelectionDAG &DAG) { // Simplify PMULDQ and PMULUDQ operations. static SDValue combinePMULDQ(SDNode *N, SelectionDAG &DAG, - TargetLowering::DAGCombinerInfo &DCI) { + TargetLowering::DAGCombinerInfo &DCI, + const X86Subtarget &Subtarget) { SDValue LHS = N->getOperand(0); SDValue RHS = N->getOperand(1); @@ -44103,8 +44139,9 @@ static SDValue combinePMULDQ(SDNode *N, SelectionDAG &DAG, return DAG.getNode(N->getOpcode(), SDLoc(N), N->getValueType(0), RHS, LHS); // Multiply by zero. + // Don't return RHS as it may contain UNDEFs. if (ISD::isBuildVectorAllZeros(RHS.getNode())) - return RHS; + return getZeroVector(N->getSimpleValueType(0), Subtarget, DAG, SDLoc(N)); // Aggressively peek through ops to get at the demanded low bits. APInt DemandedMask = APInt::getLowBitsSet(64, 32); @@ -44312,7 +44349,7 @@ SDValue X86TargetLowering::PerformDAGCombine(SDNode *N, case X86ISD::PCMPEQ: case X86ISD::PCMPGT: return combineVectorCompare(N, DAG, Subtarget); case X86ISD::PMULDQ: - case X86ISD::PMULUDQ: return combinePMULDQ(N, DAG, DCI); + case X86ISD::PMULUDQ: return combinePMULDQ(N, DAG, DCI, Subtarget); } return SDValue(); @@ -44660,10 +44697,11 @@ X86TargetLowering::getConstraintType(StringRef Constraint) const { case 'I': case 'J': case 'K': - case 'L': - case 'M': case 'N': case 'G': + case 'L': + case 'M': + return C_Immediate; case 'C': case 'e': case 'Z': diff --git a/llvm/lib/Target/X86/X86ISelLowering.h b/llvm/lib/Target/X86/X86ISelLowering.h index e0be03bc3f9d..db36bcb929e3 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.h +++ b/llvm/lib/Target/X86/X86ISelLowering.h @@ -863,11 +863,7 @@ namespace llvm { return VTIsOk(XVT) && VTIsOk(KeptBitsVT); } - bool shouldExpandShift(SelectionDAG &DAG, SDNode *N) const override { - if (DAG.getMachineFunction().getFunction().hasMinSize()) - return false; - return true; - } + bool shouldExpandShift(SelectionDAG &DAG, SDNode *N) const override; bool shouldSplatInsEltVarIndex(EVT VT) const override; diff --git a/llvm/lib/Target/X86/X86Subtarget.cpp b/llvm/lib/Target/X86/X86Subtarget.cpp index d5bb56603df9..61fc3d05b8b3 100644 --- a/llvm/lib/Target/X86/X86Subtarget.cpp +++ b/llvm/lib/Target/X86/X86Subtarget.cpp @@ -146,6 +146,9 @@ unsigned char X86Subtarget::classifyGlobalReference(const GlobalValue *GV, return X86II::MO_DLLIMPORT; return X86II::MO_COFFSTUB; } + // Some JIT users use *-win32-elf triples; these shouldn't use GOT tables. + if (isOSWindows()) + return X86II::MO_NO_FLAG; if (is64Bit()) { // ELF supports a large, truly PIC code model with non-PC relative GOT diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 3a4283ae5406..147af8bc37c9 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -3288,26 +3288,35 @@ foldShiftIntoShiftInAnotherHandOfAndInICmp(ICmpInst &I, const SimplifyQuery SQ, // Look for an 'and' of two (opposite) logical shifts. // Pick the single-use shift as XShift. - Value *XShift, *YShift; + Instruction *XShift, *YShift; if (!match(I.getOperand(0), - m_c_And(m_OneUse(m_CombineAnd(m_AnyLogicalShift, m_Value(XShift))), - m_CombineAnd(m_AnyLogicalShift, m_Value(YShift))))) + m_c_And(m_CombineAnd(m_AnyLogicalShift, m_Instruction(XShift)), + m_CombineAnd(m_AnyLogicalShift, m_Instruction(YShift))))) return nullptr; - // If YShift is a single-use 'lshr', swap the shifts around. - if (match(YShift, m_OneUse(m_AnyLShr))) + // If YShift is a 'lshr', swap the shifts around. + if (match(YShift, m_AnyLShr)) std::swap(XShift, YShift); // The shifts must be in opposite directions. - Instruction::BinaryOps XShiftOpcode = - cast(XShift)->getOpcode(); - if (XShiftOpcode == cast(YShift)->getOpcode()) + auto XShiftOpcode = XShift->getOpcode(); + if (XShiftOpcode == YShift->getOpcode()) return nullptr; // Do not care about same-direction shifts here. Value *X, *XShAmt, *Y, *YShAmt; match(XShift, m_BinOp(m_Value(X), m_Value(XShAmt))); match(YShift, m_BinOp(m_Value(Y), m_Value(YShAmt))); + // If one of the values being shifted is a constant, then we will end with + // and+icmp, and shift instr will be constant-folded. If they are not, + // however, we will need to ensure that we won't increase instruction count. + if (!isa(X) && !isa(Y)) { + // At least one of the hands of the 'and' should be one-use shift. + if (!match(I.getOperand(0), + m_c_And(m_OneUse(m_AnyLogicalShift), m_Value()))) + return nullptr; + } + // Can we fold (XShAmt+YShAmt) ? Value *NewShAmt = SimplifyBinOp(Instruction::BinaryOps::Add, XShAmt, YShAmt, SQ.getWithInstruction(&I)); diff --git a/llvm/lib/Transforms/Scalar/DivRemPairs.cpp b/llvm/lib/Transforms/Scalar/DivRemPairs.cpp index 876681b4f9de..e64651d97495 100644 --- a/llvm/lib/Transforms/Scalar/DivRemPairs.cpp +++ b/llvm/lib/Transforms/Scalar/DivRemPairs.cpp @@ -23,6 +23,7 @@ #include "llvm/Support/DebugCounter.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils/BypassSlowDivision.h" + using namespace llvm; #define DEBUG_TYPE "div-rem-pairs" @@ -32,24 +33,44 @@ STATISTIC(NumDecomposed, "Number of instructions decomposed"); DEBUG_COUNTER(DRPCounter, "div-rem-pairs-transform", "Controls transformations in div-rem-pairs pass"); -/// Find matching pairs of integer div/rem ops (they have the same numerator, -/// denominator, and signedness). If they exist in different basic blocks, bring -/// them together by hoisting or replace the common division operation that is -/// implicit in the remainder: -/// X % Y <--> X - ((X / Y) * Y). -/// -/// We can largely ignore the normal safety and cost constraints on speculation -/// of these ops when we find a matching pair. This is because we are already -/// guaranteed that any exceptions and most cost are already incurred by the -/// first member of the pair. -/// -/// Note: This transform could be an oddball enhancement to EarlyCSE, GVN, or -/// SimplifyCFG, but it's split off on its own because it's different enough -/// that it doesn't quite match the stated objectives of those passes. -static bool optimizeDivRem(Function &F, const TargetTransformInfo &TTI, - const DominatorTree &DT) { - bool Changed = false; +/// A thin wrapper to store two values that we matched as div-rem pair. +/// We want this extra indirection to avoid dealing with RAUW'ing the map keys. +struct DivRemPairWorklistEntry { + /// The actual udiv/sdiv instruction. Source of truth. + AssertingVH DivInst; + + /// The instruction that we have matched as a remainder instruction. + /// Should only be used as Value, don't introspect it. + AssertingVH RemInst; + + DivRemPairWorklistEntry(Instruction *DivInst_, Instruction *RemInst_) + : DivInst(DivInst_), RemInst(RemInst_) { + assert((DivInst->getOpcode() == Instruction::UDiv || + DivInst->getOpcode() == Instruction::SDiv) && + "Not a division."); + assert(DivInst->getType() == RemInst->getType() && "Types should match."); + // We can't check anything else about remainder instruction, + // it's not strictly required to be a urem/srem. + } + /// The type for this pair, identical for both the div and rem. + Type *getType() const { return DivInst->getType(); } + + /// Is this pair signed or unsigned? + bool isSigned() const { return DivInst->getOpcode() == Instruction::SDiv; } + + /// In this pair, what are the divident and divisor? + Value *getDividend() const { return DivInst->getOperand(0); } + Value *getDivisor() const { return DivInst->getOperand(1); } +}; +using DivRemWorklistTy = SmallVector; + +/// Find matching pairs of integer div/rem ops (they have the same numerator, +/// denominator, and signedness). Place those pairs into a worklist for further +/// processing. This indirection is needed because we have to use TrackingVH<> +/// because we will be doing RAUW, and if one of the rem instructions we change +/// happens to be an input to another div/rem in the maps, we'd have problems. +static DivRemWorklistTy getWorklist(Function &F) { // Insert all divide and remainder instructions into maps keyed by their // operands and opcode (signed or unsigned). DenseMap DivMap; @@ -69,6 +90,9 @@ static bool optimizeDivRem(Function &F, const TargetTransformInfo &TTI, } } + // We'll accumulate the matching pairs of div-rem instructions here. + DivRemWorklistTy Worklist; + // We can iterate over either map because we are only looking for matched // pairs. Choose remainders for efficiency because they are usually even more // rare than division. @@ -78,12 +102,45 @@ static bool optimizeDivRem(Function &F, const TargetTransformInfo &TTI, if (!DivInst) continue; - // We have a matching pair of div/rem instructions. If one dominates the - // other, hoist and/or replace one. + // We have a matching pair of div/rem instructions. NumPairs++; Instruction *RemInst = RemPair.second; - bool IsSigned = DivInst->getOpcode() == Instruction::SDiv; - bool HasDivRemOp = TTI.hasDivRemOp(DivInst->getType(), IsSigned); + + // Place it in the worklist. + Worklist.emplace_back(DivInst, RemInst); + } + + return Worklist; +} + +/// Find matching pairs of integer div/rem ops (they have the same numerator, +/// denominator, and signedness). If they exist in different basic blocks, bring +/// them together by hoisting or replace the common division operation that is +/// implicit in the remainder: +/// X % Y <--> X - ((X / Y) * Y). +/// +/// We can largely ignore the normal safety and cost constraints on speculation +/// of these ops when we find a matching pair. This is because we are already +/// guaranteed that any exceptions and most cost are already incurred by the +/// first member of the pair. +/// +/// Note: This transform could be an oddball enhancement to EarlyCSE, GVN, or +/// SimplifyCFG, but it's split off on its own because it's different enough +/// that it doesn't quite match the stated objectives of those passes. +static bool optimizeDivRem(Function &F, const TargetTransformInfo &TTI, + const DominatorTree &DT) { + bool Changed = false; + + // Get the matching pairs of div-rem instructions. We want this extra + // indirection to avoid dealing with having to RAUW the keys of the maps. + DivRemWorklistTy Worklist = getWorklist(F); + + // Process each entry in the worklist. + for (DivRemPairWorklistEntry &E : Worklist) { + bool HasDivRemOp = TTI.hasDivRemOp(E.getType(), E.isSigned()); + + auto &DivInst = E.DivInst; + auto &RemInst = E.RemInst; // If the target supports div+rem and the instructions are in the same block // already, there's nothing to do. The backend should handle this. If the @@ -110,8 +167,8 @@ static bool optimizeDivRem(Function &F, const TargetTransformInfo &TTI, // The target does not have a single div/rem operation. Decompose the // remainder calculation as: // X % Y --> X - ((X / Y) * Y). - Value *X = RemInst->getOperand(0); - Value *Y = RemInst->getOperand(1); + Value *X = E.getDividend(); + Value *Y = E.getDivisor(); Instruction *Mul = BinaryOperator::CreateMul(DivInst, Y); Instruction *Sub = BinaryOperator::CreateSub(X, Mul); @@ -152,8 +209,13 @@ static bool optimizeDivRem(Function &F, const TargetTransformInfo &TTI, // Now kill the explicit remainder. We have replaced it with: // (sub X, (mul (div X, Y), Y) - RemInst->replaceAllUsesWith(Sub); - RemInst->eraseFromParent(); + Sub->setName(RemInst->getName() + ".decomposed"); + Instruction *OrigRemInst = RemInst; + // Update AssertingVH<> with new instruction so it doesn't assert. + RemInst = Sub; + // And replace the original instruction with the new one. + OrigRemInst->replaceAllUsesWith(Sub); + OrigRemInst->eraseFromParent(); NumDecomposed++; } Changed = true; @@ -188,7 +250,7 @@ struct DivRemPairsLegacyPass : public FunctionPass { return optimizeDivRem(F, TTI, DT); } }; -} +} // namespace char DivRemPairsLegacyPass::ID = 0; INITIALIZE_PASS_BEGIN(DivRemPairsLegacyPass, "div-rem-pairs", diff --git a/llvm/lib/Transforms/Scalar/SpeculateAroundPHIs.cpp b/llvm/lib/Transforms/Scalar/SpeculateAroundPHIs.cpp index c13fb3e04516..e6db11f47ead 100644 --- a/llvm/lib/Transforms/Scalar/SpeculateAroundPHIs.cpp +++ b/llvm/lib/Transforms/Scalar/SpeculateAroundPHIs.cpp @@ -777,8 +777,10 @@ static bool tryToSpeculatePHIs(SmallVectorImpl &PNs, // speculation if the predecessor is an invoke. This doesn't seem // fundamental and we should probably be splitting critical edges // differently. - if (isa(PredBB->getTerminator()) || - isa(PredBB->getTerminator())) { + const auto *TermInst = PredBB->getTerminator(); + if (isa(TermInst) || + isa(TermInst) || + isa(TermInst)) { LLVM_DEBUG(dbgs() << " Invalid: predecessor terminator: " << PredBB->getName() << "\n"); return false; diff --git a/llvm/lib/Transforms/Utils/LoopUnroll.cpp b/llvm/lib/Transforms/Utils/LoopUnroll.cpp index e39ade523714..4a1edb3700c0 100644 --- a/llvm/lib/Transforms/Utils/LoopUnroll.cpp +++ b/llvm/lib/Transforms/Utils/LoopUnroll.cpp @@ -711,7 +711,7 @@ LoopUnrollResult llvm::UnrollLoop(Loop *L, UnrollLoopOptions ULO, LoopInfo *LI, auto setDest = [LoopExit, ContinueOnTrue](BasicBlock *Src, BasicBlock *Dest, ArrayRef NextBlocks, - BasicBlock *CurrentHeader, + BasicBlock *BlockInLoop, bool NeedConditional) { auto *Term = cast(Src->getTerminator()); if (NeedConditional) { @@ -723,7 +723,9 @@ LoopUnrollResult llvm::UnrollLoop(Loop *L, UnrollLoopOptions ULO, LoopInfo *LI, if (Dest != LoopExit) { BasicBlock *BB = Src; for (BasicBlock *Succ : successors(BB)) { - if (Succ == CurrentHeader) + // Preserve the incoming value from BB if we are jumping to the block + // in the current loop. + if (Succ == BlockInLoop) continue; for (PHINode &Phi : Succ->phis()) Phi.removeIncomingValue(BB, false); @@ -794,7 +796,7 @@ LoopUnrollResult llvm::UnrollLoop(Loop *L, UnrollLoopOptions ULO, LoopInfo *LI, // unconditional branch for some iterations. NeedConditional = false; - setDest(Headers[i], Dest, Headers, Headers[i], NeedConditional); + setDest(Headers[i], Dest, Headers, HeaderSucc[i], NeedConditional); } // Set up latches to branch to the new header in the unrolled iterations or diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp index e0def81d5eee..e938ae6cb42f 100644 --- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -1480,8 +1480,8 @@ Value *LibCallSimplifier::optimizePow(CallInst *Pow, IRBuilder<> &B) { if (match(Expo, m_SpecificFP(-1.0))) return B.CreateFDiv(ConstantFP::get(Ty, 1.0), Base, "reciprocal"); - // pow(x, 0.0) -> 1.0 - if (match(Expo, m_SpecificFP(0.0))) + // pow(x, +/-0.0) -> 1.0 + if (match(Expo, m_AnyZeroFP())) return ConstantFP::get(Ty, 1.0); // pow(x, 1.0) -> x diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp index 6ef8dc2d3cd7..138f18e49c92 100644 --- a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp @@ -631,6 +631,7 @@ bool LoopVectorizationLegality::canVectorizeInstrs() { // Unsafe cyclic dependencies with header phis are identified during // legalization for reduction, induction and first order // recurrences. + AllowedExit.insert(&I); continue; } diff --git a/llvm/test/CodeGen/AArch64/O3-pipeline.ll b/llvm/test/CodeGen/AArch64/O3-pipeline.ll index a331ac87f8f4..4aabcf3c7982 100644 --- a/llvm/test/CodeGen/AArch64/O3-pipeline.ll +++ b/llvm/test/CodeGen/AArch64/O3-pipeline.ll @@ -98,9 +98,9 @@ ; CHECK-NEXT: MachineDominator Tree Construction ; CHECK-NEXT: Machine Natural Loop Construction ; CHECK-NEXT: Early Machine Loop Invariant Code Motion +; CHECK-NEXT: Machine Block Frequency Analysis ; CHECK-NEXT: Machine Common Subexpression Elimination ; CHECK-NEXT: MachinePostDominator Tree Construction -; CHECK-NEXT: Machine Block Frequency Analysis ; CHECK-NEXT: Machine code sinking ; CHECK-NEXT: Peephole Optimizations ; CHECK-NEXT: Remove dead machine instructions diff --git a/llvm/test/CodeGen/AArch64/arm64-indexed-vector-ldst.ll b/llvm/test/CodeGen/AArch64/arm64-indexed-vector-ldst.ll index 8b6a4cae7ed5..f3ac9b21f53b 100644 --- a/llvm/test/CodeGen/AArch64/arm64-indexed-vector-ldst.ll +++ b/llvm/test/CodeGen/AArch64/arm64-indexed-vector-ldst.ll @@ -6319,3 +6319,22 @@ define void @test_ld1lane_build_i8(i8* %a, i8* %b, i8* %c, i8* %d, i8* %e, i8* store <8 x i8> %sub, <8 x i8>* %p ret void } + +define <4 x i32> @test_inc_cycle(<4 x i32> %vec, i32* %in) { +; CHECK-LABEL: test_inc_cycle: +; CHECK: ld1.s { v0 }[0], [x0]{{$}} + + %elt = load i32, i32* %in + %newvec = insertelement <4 x i32> %vec, i32 %elt, i32 0 + + ; %inc cannot be %elt directly because we check that the load is only + ; used by the insert before trying to form post-inc. + %inc.vec = bitcast <4 x i32> %newvec to <2 x i64> + %inc = extractelement <2 x i64> %inc.vec, i32 0 + %newaddr = getelementptr i32, i32* %in, i64 %inc + store i32* %newaddr, i32** @var + + ret <4 x i32> %newvec +} + +@var = global i32* null diff --git a/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-I.ll b/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-I.ll index 7dc9f7260037..7784c9b24426 100644 --- a/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-I.ll +++ b/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-I.ll @@ -2,7 +2,7 @@ ; RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s ; Check for at least one invalid constant. -; CHECK-ERRORS: error: invalid operand for inline asm constraint 'I' +; CHECK-ERRORS: error: value out of range for constraint 'I' define i32 @constraint_I(i32 %i, i32 %j) nounwind ssp { entry: diff --git a/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-J.ll b/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-J.ll index 592875b0cb0c..c90178513d27 100644 --- a/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-J.ll +++ b/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-J.ll @@ -2,7 +2,7 @@ ; RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s ; Check for at least one invalid constant. -; CHECK-ERRORS: error: invalid operand for inline asm constraint 'J' +; CHECK-ERRORS: error: value out of range for constraint 'J' define i32 @constraint_J(i32 %i, i32 %j) nounwind ssp { entry: diff --git a/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-K.ll b/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-K.ll index 893e8d29e65d..e5baf85e9542 100644 --- a/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-K.ll +++ b/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-K.ll @@ -2,7 +2,7 @@ ; RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s ; Check for at least one invalid constant. -; CHECK-ERRORS: error: invalid operand for inline asm constraint 'K' +; CHECK-ERRORS: error: value out of range for constraint 'K' define i32 @constraint_K(i32 %i, i32 %j) nounwind { entry: diff --git a/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-L.ll b/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-L.ll index b2fb822aa299..cdba05627556 100644 --- a/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-L.ll +++ b/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-L.ll @@ -2,7 +2,7 @@ ; RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s ; Check for at least one invalid constant. -; CHECK-ERRORS: error: invalid operand for inline asm constraint 'L' +; CHECK-ERRORS: error: value out of range for constraint 'L' define i32 @constraint_L(i32 %i, i32 %j) nounwind { entry: diff --git a/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-M.ll b/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-M.ll index aaee933fd6dc..c7a786b26bbe 100644 --- a/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-M.ll +++ b/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-M.ll @@ -2,7 +2,7 @@ ; RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s ; Check for at least one invalid constant. -; CHECK-ERRORS: error: invalid operand for inline asm constraint 'M' +; CHECK-ERRORS: error: value out of range for constraint 'M' define i32 @constraint_M(i32 %i, i32 %j) nounwind { entry: diff --git a/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-N.ll b/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-N.ll index d1d2e03548e2..38b0ab8fa296 100644 --- a/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-N.ll +++ b/llvm/test/CodeGen/AArch64/arm64-inline-asm-error-N.ll @@ -2,7 +2,7 @@ ; RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s ; Check for at least one invalid constant. -; CHECK-ERRORS: error: invalid operand for inline asm constraint 'N' +; CHECK-ERRORS: error: value out of range for constraint 'N' define i32 @constraint_N(i32 %i, i32 %j) nounwind { entry: diff --git a/llvm/test/CodeGen/AArch64/bcmp-inline-small.ll b/llvm/test/CodeGen/AArch64/bcmp-inline-small.ll new file mode 100644 index 000000000000..da42b1d6863c --- /dev/null +++ b/llvm/test/CodeGen/AArch64/bcmp-inline-small.ll @@ -0,0 +1,44 @@ +; RUN: llc -O2 < %s -mtriple=aarch64-linux-gnu | FileCheck %s --check-prefixes=CHECK,CHECKN +; RUN: llc -O2 < %s -mtriple=aarch64-linux-gnu -mattr=strict-align | FileCheck %s --check-prefixes=CHECK,CHECKS + +declare i32 @bcmp(i8*, i8*, i64) nounwind readonly +declare i32 @memcmp(i8*, i8*, i64) nounwind readonly + +define i1 @bcmp_b2(i8* %s1, i8* %s2) { +entry: + %bcmp = call i32 @bcmp(i8* %s1, i8* %s2, i64 15) + %ret = icmp eq i32 %bcmp, 0 + ret i1 %ret + +; CHECK-LABEL: bcmp_b2: +; CHECK-NOT: bl bcmp +; CHECKN: ldr x +; CHECKN-NEXT: ldr x +; CHECKN-NEXT: ldur x +; CHECKN-NEXT: ldur x +; CHECKS: ldr x +; CHECKS-NEXT: ldr x +; CHECKS-NEXT: ldr w +; CHECKS-NEXT: ldr w +; CHECKS-NEXT: ldrh w +; CHECKS-NEXT: ldrh w +; CHECKS-NEXT: ldrb w +; CHECKS-NEXT: ldrb w +} + +define i1 @bcmp_bs(i8* %s1, i8* %s2) optsize { +entry: + %memcmp = call i32 @memcmp(i8* %s1, i8* %s2, i64 31) + %ret = icmp eq i32 %memcmp, 0 + ret i1 %ret + +; CHECK-LABEL: bcmp_bs: +; CHECKN-NOT: bl memcmp +; CHECKN: ldp x +; CHECKN-NEXT: ldp x +; CHECKN-NEXT: ldr x +; CHECKN-NEXT: ldr x +; CHECKN-NEXT: ldur x +; CHECKN-NEXT: ldur x +; CHECKS: bl memcmp +} diff --git a/llvm/test/CodeGen/AArch64/callbr-asm-label.ll b/llvm/test/CodeGen/AArch64/callbr-asm-label.ll new file mode 100644 index 000000000000..583587da71a9 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/callbr-asm-label.ll @@ -0,0 +1,63 @@ +; RUN: llc < %s -mtriple=aarch64-linux-gnu | FileCheck %s + +@X = common local_unnamed_addr global i32 0, align 4 + +define i32 @test1() { +; CHECK-LABEL: test1: +; CHECK: .word b +; CHECK-NEXT: .word .Ltmp0 +; CHECK-LABEL: .Ltmp0: +; CHECK-LABEL: .LBB0_1: // %l_yes +; CHECK-LABEL: .LBB0_2: // %cleanup +entry: + callbr void asm sideeffect "1:\0A\09.word b, ${0:l}\0A\09", "X"(i8* blockaddress(@test1, %l_yes)) + to label %cleanup [label %l_yes] + +l_yes: + br label %cleanup + +cleanup: + %retval.0 = phi i32 [ 1, %l_yes ], [ 0, %entry ] + ret i32 %retval.0 +} + +define void @test2() { +; CHECK-LABEL: test2: +entry: + %0 = load i32, i32* @X, align 4 + %and = and i32 %0, 1 + %tobool = icmp eq i32 %and, 0 + br i1 %tobool, label %if.end10, label %if.then + +if.then: +; CHECK: .word b +; CHECK-NEXT: .word .Ltmp2 +; CHECK-LABEL: .Ltmp2: +; CHECK-NEXT: .LBB1_3: // %if.end6 + callbr void asm sideeffect "1:\0A\09.word b, ${0:l}\0A\09", "X"(i8* blockaddress(@test2, %if.end6)) + to label %if.then4 [label %if.end6] + +if.then4: + %call5 = tail call i32 bitcast (i32 (...)* @g to i32 ()*)() + br label %if.end6 + +if.end6: + %.pre = load i32, i32* @X, align 4 + %.pre13 = and i32 %.pre, 1 + %phitmp = icmp eq i32 %.pre13, 0 + br i1 %phitmp, label %if.end10, label %if.then9 + +if.then9: +; CHECK-LABEL: .Ltmp4: +; CHECK-NEXT: .LBB1_5: // %l_yes + callbr void asm sideeffect "", "X"(i8* blockaddress(@test2, %l_yes)) + to label %if.end10 [label %l_yes] + +if.end10: + br label %l_yes + +l_yes: + ret void +} + +declare i32 @g(...) diff --git a/llvm/test/CodeGen/AArch64/callbr-asm-obj-file.ll b/llvm/test/CodeGen/AArch64/callbr-asm-obj-file.ll new file mode 100644 index 000000000000..579158568b6f --- /dev/null +++ b/llvm/test/CodeGen/AArch64/callbr-asm-obj-file.ll @@ -0,0 +1,102 @@ +; RUN: llc < %s -mtriple=aarch64-unknown-linux-gnu -filetype=obj -o - \ +; RUN: | llvm-objdump -triple aarch64-unknown-linux-gnu -d - \ +; RUN: | FileCheck %s + +%struct.c = type { i1 (...)* } + +@l = common hidden local_unnamed_addr global i32 0, align 4 + +; CHECK-LABEL: 0000000000000000 test1: +; CHECK-LABEL: 0000000000000018 $d.1: +; CHECK-LABEL: 0000000000000020 $x.2: +; CHECK-NEXT: b #16 <$x.4+0x4> +; CHECK-LABEL: 000000000000002c $x.4: +; CHECK-NEXT: b #4 <$x.4+0x4> +; CHECK-NEXT: mov w0, wzr +; CHECK-NEXT: ldr x30, [sp], #16 +; CHECK-NEXT: ret +define hidden i32 @test1() { + %1 = tail call i32 bitcast (i32 (...)* @g to i32 ()*)() + %2 = icmp eq i32 %1, 0 + br i1 %2, label %3, label %5 + +3: ; preds = %0 + callbr void asm sideeffect "1: nop\0A\09.quad a\0A\09b ${1:l}\0A\09.quad ${0:c}", "i,X"(i32* null, i8* blockaddress(@test1, %7)) + to label %4 [label %7] + +4: ; preds = %3 + br label %7 + +5: ; preds = %0 + %6 = tail call i32 bitcast (i32 (...)* @i to i32 ()*)() + br label %7 + +7: ; preds = %3, %4, %5 + %8 = phi i32 [ %6, %5 ], [ 0, %4 ], [ 0, %3 ] + ret i32 %8 +} + +declare dso_local i32 @g(...) local_unnamed_addr + +declare dso_local i32 @i(...) local_unnamed_addr + +; CHECK-LABEL: 000000000000003c test2: +; CHECK: bl #0 +; CHECK-LABEL: 0000000000000064 $d.5: +; CHECK-LABEL: 000000000000006c $x.6: +; CHECK-NEXT: b #-24 +define hidden i32 @test2() local_unnamed_addr { + %1 = load i32, i32* @l, align 4 + %2 = icmp eq i32 %1, 0 + br i1 %2, label %10, label %3 + +3: ; preds = %0 + %4 = tail call i32 bitcast (i32 (...)* @g to i32 ()*)() + %5 = icmp eq i32 %4, 0 + br i1 %5, label %6, label %7 + +6: ; preds = %3 + callbr void asm sideeffect "1: nop\0A\09.quad b\0A\09b ${1:l}\0A\09.quad ${0:c}", "i,X"(i32* null, i8* blockaddress(@test2, %7)) + to label %10 [label %9] + +7: ; preds = %3 + %8 = tail call i32 bitcast (i32 (...)* @i to i32 ()*)() + br label %10 + +9: ; preds = %6 + br label %10 + +10: ; preds = %7, %0, %6, %9 + ret i32 undef +} + +; CHECK-LABEL: 0000000000000084 test3: +; CHECK-LABEL: 00000000000000a8 $d.9: +; CHECK-LABEL: 00000000000000b0 $x.10: +; CHECK-NEXT: b #20 <$x.12+0x8> +; CHECK-LABEL: 00000000000000bc $x.12: +; CHECK-NEXT: b #4 <$x.12+0x4> +; CHECK-NEXT: mov w0, wzr +; CHECK-NEXT: ldr x30, [sp], #16 +; CHECK-NEXT: ret +define internal i1 @test3() { + %1 = tail call i32 bitcast (i32 (...)* @g to i32 ()*)() + %2 = icmp eq i32 %1, 0 + br i1 %2, label %3, label %5 + +3: ; preds = %0 + callbr void asm sideeffect "1: nop\0A\09.quad c\0A\09b ${1:l}\0A\09.quad ${0:c}", "i,X"(i32* null, i8* blockaddress(@test3, %8)) + to label %4 [label %8] + +4: ; preds = %3 + br label %8 + +5: ; preds = %0 + %6 = tail call i32 bitcast (i32 (...)* @i to i32 ()*)() + %7 = icmp ne i32 %6, 0 + br label %8 + +8: ; preds = %3, %4, %5 + %9 = phi i1 [ %7, %5 ], [ false, %4 ], [ false, %3 ] + ret i1 %9 +} diff --git a/llvm/test/CodeGen/AArch64/shift_minsize.ll b/llvm/test/CodeGen/AArch64/shift_minsize.ll index d1b95e87577b..2728b3f4c733 100644 --- a/llvm/test/CodeGen/AArch64/shift_minsize.ll +++ b/llvm/test/CodeGen/AArch64/shift_minsize.ll @@ -1,5 +1,10 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=aarch64-unknown-unknown | FileCheck %s +; RUN: llc < %s -mtriple=aarch64-windows | FileCheck %s -check-prefix=CHECK-WIN + +; The Windows runtime doesn't have these. +; CHECK-WIN-NOT: __ashlti3 +; CHECK-WIN-NOT: __ashrti3 define i64 @f0(i64 %val, i64 %amt) minsize optsize { ; CHECK-LABEL: f0: @@ -53,6 +58,7 @@ define dso_local { i64, i64 } @shl128(i64 %x.coerce0, i64 %x.coerce1, i8 signext ; CHECK-NEXT: bl __ashlti3 ; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload ; CHECK-NEXT: ret + entry: %x.sroa.2.0.insert.ext = zext i64 %x.coerce1 to i128 %x.sroa.2.0.insert.shift = shl nuw i128 %x.sroa.2.0.insert.ext, 64 diff --git a/llvm/test/CodeGen/AArch64/wineh1.mir b/llvm/test/CodeGen/AArch64/wineh1.mir index b01d4cb529c1..1ffaa25d30d8 100644 --- a/llvm/test/CodeGen/AArch64/wineh1.mir +++ b/llvm/test/CodeGen/AArch64/wineh1.mir @@ -1,5 +1,7 @@ # RUN: llc -o - %s -mtriple=aarch64-windows -start-after=prologepilog -filetype=obj \ # RUN: | llvm-readobj --unwind | FileCheck %s +# RUN: llc -o - %s -mtriple=aarch64-windows -run-pass=aarch64-ldst-opt \ +# RUN: | FileCheck %s --check-prefix=CHECK-LDSTOPT # This test case checks the basic validity of the .xdata section. It's # documented at: # https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling @@ -7,7 +9,7 @@ # We expect to see the following in the .xdata section: # CHECK: ExceptionData { -# CHECK-NEXT: FunctionLength: 92 +# CHECK-NEXT: FunctionLength: 96 # CHECK-NEXT: Version: 0 # CHECK-NEXT: ExceptionData: No # CHECK-NEXT: EpiloguePacked: No @@ -24,7 +26,7 @@ # CHECK-NEXT: ] # CHECK-NEXT: EpilogueScopes [ # CHECK-NEXT: EpilogueScope { -# CHECK-NEXT: StartOffset: 15 +# CHECK-NEXT: StartOffset: 16 # CHECK-NEXT: EpilogueStartIndex: 13 # CHECK-NEXT: Opcodes [ # CHECK-NEXT: 0xc808 ; ldp x19, x20, [sp, #64] @@ -39,6 +41,12 @@ # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: } + +# Check that the load-store optimizer does not merge the two +# callee-saved stores in the prologue. +# CHECK-LDSTOPT: name: test +# CHECK-LDSTOPT: frame-setup STRXui killed $x21, $sp, 6 +# CHECK-LDSTOPT: frame-setup STRXui killed $x22, $sp, 7 ... --- name: test diff --git a/llvm/test/CodeGen/AArch64/wineh2.mir b/llvm/test/CodeGen/AArch64/wineh2.mir index 9352181c473f..05a232f753f3 100644 --- a/llvm/test/CodeGen/AArch64/wineh2.mir +++ b/llvm/test/CodeGen/AArch64/wineh2.mir @@ -3,7 +3,7 @@ # Test that the pre/post increment save of a flating point register is correct. # CHECK: ExceptionData { -# CHECK-NEXT: FunctionLength: 136 +# CHECK-NEXT: FunctionLength: 144 # CHECK-NEXT: Version: 0 # CHECK-NEXT: ExceptionData: No # CHECK-NEXT: EpiloguePacked: No @@ -23,7 +23,7 @@ # CHECK-NEXT: ] # CHECK-NEXT: EpilogueScopes [ # CHECK-NEXT: EpilogueScope { -# CHECK-NEXT: StartOffset: 25 +# CHECK-NEXT: StartOffset: 26 # CHECK-NEXT: EpilogueStartIndex: 19 # CHECK-NEXT: Opcodes [ # CHECK-NEXT: 0xc80e ; ldp x19, x20, [sp, #112] diff --git a/llvm/test/CodeGen/AMDGPU/propagate-attributes-bitcast-function.ll b/llvm/test/CodeGen/AMDGPU/propagate-attributes-bitcast-function.ll index c1d8009d08b1..173bc72db851 100644 --- a/llvm/test/CodeGen/AMDGPU/propagate-attributes-bitcast-function.ll +++ b/llvm/test/CodeGen/AMDGPU/propagate-attributes-bitcast-function.ll @@ -1,4 +1,4 @@ -; RUN: llc -march=amdgcn -mcpu=gfx1010 -verify-machineinstrs < %s | FileCheck -check-prefix=GCN %s +; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1010 -verify-machineinstrs < %s | FileCheck -check-prefix=GCN %s ; GCN: foo1: ; v_cndmask_b32_e64 v0, 0, 1, vcc_lo{{$}} diff --git a/llvm/test/CodeGen/AMDGPU/propagate-attributes-clone.ll b/llvm/test/CodeGen/AMDGPU/propagate-attributes-clone.ll index b9c36217aaa9..cb0406c5b1f8 100644 --- a/llvm/test/CodeGen/AMDGPU/propagate-attributes-clone.ll +++ b/llvm/test/CodeGen/AMDGPU/propagate-attributes-clone.ll @@ -1,5 +1,5 @@ ; RUN: opt -S -mtriple=amdgcn-amd-amdhsa -O1 < %s | FileCheck -check-prefix=OPT %s -; RUN: llc -march=amdgcn -mcpu=gfx1010 -verify-machineinstrs < %s | FileCheck -check-prefix=LLC %s +; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1010 -verify-machineinstrs < %s | FileCheck -check-prefix=LLC %s ; OPT: declare void @foo4() local_unnamed_addr #0 ; OPT: define internal fastcc void @foo3.2() unnamed_addr #1 diff --git a/llvm/test/CodeGen/AMDGPU/propagate-attributes-single-set.ll b/llvm/test/CodeGen/AMDGPU/propagate-attributes-single-set.ll index 348825865336..cb4283c8c67a 100644 --- a/llvm/test/CodeGen/AMDGPU/propagate-attributes-single-set.ll +++ b/llvm/test/CodeGen/AMDGPU/propagate-attributes-single-set.ll @@ -1,5 +1,5 @@ ; RUN: opt -S -mtriple=amdgcn-amd-amdhsa -O1 < %s | FileCheck -check-prefix=OPT %s -; RUN: llc -march=amdgcn -mcpu=gfx1010 -verify-machineinstrs < %s | FileCheck -check-prefix=LLC %s +; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1010 -verify-machineinstrs < %s | FileCheck -check-prefix=LLC %s ; OPT: declare void @foo4() local_unnamed_addr #0 ; OPT: define void @foo3() local_unnamed_addr #1 diff --git a/llvm/test/CodeGen/ARM/O3-pipeline.ll b/llvm/test/CodeGen/ARM/O3-pipeline.ll index f81f8ce51d18..ec96f055a056 100644 --- a/llvm/test/CodeGen/ARM/O3-pipeline.ll +++ b/llvm/test/CodeGen/ARM/O3-pipeline.ll @@ -72,9 +72,9 @@ ; CHECK-NEXT: MachineDominator Tree Construction ; CHECK-NEXT: Machine Natural Loop Construction ; CHECK-NEXT: Early Machine Loop Invariant Code Motion +; CHECK-NEXT: Machine Block Frequency Analysis ; CHECK-NEXT: Machine Common Subexpression Elimination ; CHECK-NEXT: MachinePostDominator Tree Construction -; CHECK-NEXT: Machine Block Frequency Analysis ; CHECK-NEXT: Machine code sinking ; CHECK-NEXT: Peephole Optimizations ; CHECK-NEXT: Remove dead machine instructions diff --git a/llvm/test/CodeGen/ARM/ifcvt-diamond-unanalyzable-common.mir b/llvm/test/CodeGen/ARM/ifcvt-diamond-unanalyzable-common.mir new file mode 100644 index 000000000000..a2218b149f1b --- /dev/null +++ b/llvm/test/CodeGen/ARM/ifcvt-diamond-unanalyzable-common.mir @@ -0,0 +1,57 @@ +# RUN: llc %s -o - -run-pass=if-converter -verify-machineinstrs | FileCheck %s +# Make sure we correctly if-convert blocks containing an INLINEASM_BR. +# CHECK: t2CMPri killed renamable $r2, 34 +# CHECK-NEXT: $r0 = t2MOVi 2, 1, $cpsr, $noreg +# CHECK-NEXT: $r0 = t2MOVi 3, 0, killed $cpsr, $noreg, implicit killed $r0 +# CHECK-NEXT: tBL 14, $noreg, @fn2 +# CHECK-NEXT: INLINEASM_BR &"", 9, 13, 0, 13, blockaddress(@fn1, %ir-block.l_yes) +# CHECK-NEXT: t2B %bb.1, 14, $noreg +--- | + target triple = "thumbv7-unknown-linux-gnueabi" + + define dso_local void @fn1() { + l_yes: + ret void + } + + declare dso_local i32 @fn2(...) +... +--- +name: fn1 +alignment: 1 +tracksRegLiveness: true +body: | + bb.0: + successors: %bb.1(0x40000000), %bb.2(0x40000000) + liveins: $r0, $r1, $r2, $r4, $lr + + $sp = frame-setup t2STMDB_UPD $sp, 14, $noreg, killed $r4, killed $lr + t2CMPri killed renamable $r2, 34, 14, $noreg, implicit-def $cpsr + t2Bcc %bb.2, 1, killed $cpsr + + bb.1: + successors: %bb.3(0x40000000), %bb.4(0x40000000) + liveins: $r1 + + $r0 = t2MOVi 3, 14, $noreg, $noreg + tBL 14, $noreg, @fn2, csr_aapcs, implicit-def dead $lr, implicit $sp, implicit $r0, implicit $r1, implicit-def $sp, implicit-def dead $r0 + INLINEASM_BR &"", 9, 13, 0, 13, blockaddress(@fn1, %ir-block.l_yes) + t2B %bb.3, 14, $noreg + + bb.2: + successors: %bb.3(0x40000000), %bb.4(0x40000000) + liveins: $r1 + + $r0 = t2MOVi 2, 14, $noreg, $noreg + tBL 14, $noreg, @fn2, csr_aapcs, implicit-def dead $lr, implicit $sp, implicit $r0, implicit $r1, implicit-def $sp, implicit-def dead $r0 + INLINEASM_BR &"", 9, 13, 0, 13, blockaddress(@fn1, %ir-block.l_yes) + t2B %bb.3, 14, $noreg + + bb.3: + INLINEASM &"", 1 + $sp = t2LDMIA_RET $sp, 14, $noreg, def $r4, def $pc + + bb.4.l_yes (address-taken): + $sp = t2LDMIA_RET $sp, 14, $noreg, def $r4, def $pc + +... diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-access-str.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-access-str.ll new file mode 100644 index 000000000000..5625bf99fa48 --- /dev/null +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-access-str.ll @@ -0,0 +1,95 @@ +; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck %s +; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck %s +; +; Source code: +; struct s { int a; int b; }; +; struct t { int c; int d; }; +; #define _(x) (__builtin_preserve_access_index(x)) +; int get_value(const void *addr1, const void *addr2); +; int test(struct s *arg1, struct t *arg2) { +; return get_value(_(&arg1->b), _(&arg2->d)); +; } +; clang -target bpf -S -O2 -g -emit-llvm test.c + +%struct.s = type { i32, i32 } +%struct.t = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @test(%struct.s* %arg1, %struct.t* %arg2) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata %struct.s* %arg1, metadata !22, metadata !DIExpression()), !dbg !24 + call void @llvm.dbg.value(metadata %struct.t* %arg2, metadata !23, metadata !DIExpression()), !dbg !24 + %0 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s* %arg1, i32 1, i32 1), !dbg !25, !llvm.preserve.access.index !12 + %1 = bitcast i32* %0 to i8*, !dbg !25 + %2 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ts(%struct.t* %arg2, i32 1, i32 1), !dbg !26, !llvm.preserve.access.index !17 + %3 = bitcast i32* %2 to i8*, !dbg !26 + %call = tail call i32 @get_value(i8* %1, i8* %3) #4, !dbg !27 + ret i32 %call, !dbg !28 +} + +; CHECK: .section .BTF,"",@progbits +; CHECK: .ascii ".text" # string offset=[[SEC_INDEX:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .ascii "0:1" # string offset=[[ACCESS_STR:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .section .BTF.ext,"",@progbits +; CHECK: .long 12 # OffsetReloc +; CHECK-NEXT: .long [[SEC_INDEX]] # Offset reloc section string offset=[[SEC_INDEX]] +; CHECK-NEXT: .long 2 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long {{[0-9]+}} +; CHECK-NEXT: .long [[ACCESS_STR]] +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long {{[0-9]+}} +; CHECK-NEXT: .long [[ACCESS_STR]] + +declare dso_local i32 @get_value(i8*, i8*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ts(%struct.t*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 366831) (llvm/trunk 366867)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/core-bugs") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 10.0.0 (trunk 366831) (llvm/trunk 366867)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 5, type: !8, scopeLine: 5, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !21) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11, !16} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 64, elements: !13) +!13 = !{!14, !15} +!14 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !12, file: !1, line: 1, baseType: !10, size: 32) +!15 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !12, file: !1, line: 1, baseType: !10, size: 32, offset: 32) +!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !17, size: 64) +!17 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t", file: !1, line: 2, size: 64, elements: !18) +!18 = !{!19, !20} +!19 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !17, file: !1, line: 2, baseType: !10, size: 32) +!20 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !17, file: !1, line: 2, baseType: !10, size: 32, offset: 32) +!21 = !{!22, !23} +!22 = !DILocalVariable(name: "arg1", arg: 1, scope: !7, file: !1, line: 5, type: !11) +!23 = !DILocalVariable(name: "arg2", arg: 2, scope: !7, file: !1, line: 5, type: !16) +!24 = !DILocation(line: 0, scope: !7) +!25 = !DILocation(line: 6, column: 20, scope: !7) +!26 = !DILocation(line: 6, column: 33, scope: !7) +!27 = !DILocation(line: 6, column: 10, scope: !7) +!28 = !DILocation(line: 6, column: 3, scope: !7) diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll new file mode 100644 index 000000000000..7843c52c5ad8 --- /dev/null +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-array.ll @@ -0,0 +1,97 @@ +; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck %s +; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck %s +; +; Source code: +; typedef const int arr_t[7]; +; typedef arr_t __arr; +; typedef __arr _arr; +; struct __s { _arr a; }; +; typedef struct __s s; +; #define _(x) (__builtin_preserve_access_index(x)) +; int get_value(const void *addr); +; int test(s *arg) { +; return get_value(_(&arg->a[1])); +; } +; clang -target bpf -S -O2 -g -emit-llvm test.c + +%struct.__s = type { [7 x i32] } + +; Function Attrs: nounwind +define dso_local i32 @test(%struct.__s* %arg) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata %struct.__s* %arg, metadata !24, metadata !DIExpression()), !dbg !25 + %0 = tail call [7 x i32]* @llvm.preserve.struct.access.index.p0a7i32.p0s_struct.__ss(%struct.__s* %arg, i32 0, i32 0), !dbg !26, !llvm.preserve.access.index !13 + %1 = tail call i32* @llvm.preserve.array.access.index.p0i32.p0a7i32([7 x i32]* %0, i32 1, i32 1), !dbg !26 + %2 = bitcast i32* %1 to i8*, !dbg !26 + %call = tail call i32 @get_value(i8* %2) #4, !dbg !27 + ret i32 %call, !dbg !28 +} + +; CHECK: .cfi_startproc +; CHECK: [[RELOC:.Ltmp[0-9]+]]: +; CHECK: r2 = 4 +; CHECK: r1 += r2 +; CHECK: call get_value + +; CHECK: .long {{[0-9]+}} # BTF_KIND_STRUCT(id = [[TYPE_ID:[0-9]+]]) +; CHECK: .ascii ".text" # string offset=[[SEC_INDEX:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .ascii "0:0:1" # string offset=[[ACCESS_STR:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .long 12 # OffsetReloc +; CHECK-NEXT: .long [[SEC_INDEX]] # Offset reloc section string offset=[[SEC_INDEX]] +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long [[RELOC]] +; CHECK-NEXT: .long [[TYPE_ID]] +; CHECK-NEXT: .long [[ACCESS_STR]] + +declare dso_local i32 @get_value(i8*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare [7 x i32]* @llvm.preserve.struct.access.index.p0a7i32.p0s_struct.__ss(%struct.__s*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.array.access.index.p0i32.p0a7i32([7 x i32]*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 366831) (llvm/trunk 366867)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/core-bugs") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 10.0.0 (trunk 366831) (llvm/trunk 366867)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 8, type: !8, scopeLine: 8, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !23) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "s", file: !1, line: 5, baseType: !13) +!13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__s", file: !1, line: 4, size: 224, elements: !14) +!14 = !{!15} +!15 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !13, file: !1, line: 4, baseType: !16, size: 224) +!16 = !DIDerivedType(tag: DW_TAG_typedef, name: "_arr", file: !1, line: 3, baseType: !17) +!17 = !DIDerivedType(tag: DW_TAG_typedef, name: "__arr", file: !1, line: 2, baseType: !18) +!18 = !DIDerivedType(tag: DW_TAG_typedef, name: "arr_t", file: !1, line: 1, baseType: !19) +!19 = !DICompositeType(tag: DW_TAG_array_type, baseType: !20, size: 224, elements: !21) +!20 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !10) +!21 = !{!22} +!22 = !DISubrange(count: 7) +!23 = !{!24} +!24 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 8, type: !11) +!25 = !DILocation(line: 0, scope: !7) +!26 = !DILocation(line: 9, column: 20, scope: !7) +!27 = !DILocation(line: 9, column: 10, scope: !7) +!28 = !DILocation(line: 9, column: 3, scope: !7) diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-struct.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-struct.ll new file mode 100644 index 000000000000..a0d7532bf480 --- /dev/null +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-struct.ll @@ -0,0 +1,90 @@ +; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck %s +; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck %s +; +; Source code: +; typedef int _int; +; typedef _int __int; +; struct __s { __int a; __int b; }; +; typedef struct __s _s; +; typedef _s s; +; #define _(x) (__builtin_preserve_access_index(x)) +; int get_value(const void *addr); +; int test(s *arg) { +; return get_value(_(&arg->b)); +; } +; clang -target bpf -S -O2 -g -emit-llvm test.c + +%struct.__s = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @test(%struct.__s* %arg) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata %struct.__s* %arg, metadata !21, metadata !DIExpression()), !dbg !22 + %0 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.__ss(%struct.__s* %arg, i32 1, i32 1), !dbg !23, !llvm.preserve.access.index !14 + %1 = bitcast i32* %0 to i8*, !dbg !23 + %call = tail call i32 @get_value(i8* %1) #4, !dbg !24 + ret i32 %call, !dbg !25 +} + +; CHECK: .cfi_startproc +; CHECK: [[RELOC:.Ltmp[0-9]+]]: +; CHECK: r2 = 4 +; CHECK: r1 += r2 +; CHECK: call get_value + +; CHECK: .long {{[0-9]+}} # BTF_KIND_STRUCT(id = [[TYPE_ID:[0-9]+]]) +; CHECK: .ascii ".text" # string offset=[[SEC_STR:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .ascii "0:1" # string offset=[[ACCESS_STR:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .long 12 # OffsetReloc +; CHECK-NEXT: .long [[SEC_STR]] # Offset reloc section string offset={{[0-9]+}} +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long [[RELOC]] +; CHECK-NEXT: .long [[TYPE_ID]] +; CHECK-NEXT: .long [[ACCESS_STR]] + +declare dso_local i32 @get_value(i8*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.__ss(%struct.__s*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 366831) (llvm/trunk 366867)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/core-bugs") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 10.0.0 (trunk 366831) (llvm/trunk 366867)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 8, type: !8, scopeLine: 8, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !20) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "s", file: !1, line: 5, baseType: !13) +!13 = !DIDerivedType(tag: DW_TAG_typedef, name: "_s", file: !1, line: 4, baseType: !14) +!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__s", file: !1, line: 3, size: 64, elements: !15) +!15 = !{!16, !19} +!16 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !14, file: !1, line: 3, baseType: !17, size: 32) +!17 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 2, baseType: !18) +!18 = !DIDerivedType(tag: DW_TAG_typedef, name: "_int", file: !1, line: 1, baseType: !10) +!19 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !14, file: !1, line: 3, baseType: !17, size: 32, offset: 32) +!20 = !{!21} +!21 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 8, type: !11) +!22 = !DILocation(line: 0, scope: !7) +!23 = !DILocation(line: 9, column: 20, scope: !7) +!24 = !DILocation(line: 9, column: 10, scope: !7) +!25 = !DILocation(line: 9, column: 3, scope: !7) diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-union.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-union.ll new file mode 100644 index 000000000000..caefc2b4bc6a --- /dev/null +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef-union.ll @@ -0,0 +1,90 @@ +; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck %s +; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck %s +; +; Source code: +; typedef int _int; +; typedef _int __int; +; union __s { __int a; __int b; }; +; typedef union __s _s; +; typedef _s s; +; #define _(x) (__builtin_preserve_access_index(x)) +; int get_value(const void *addr); +; int test(s *arg) { +; return get_value(_(&arg->b)); +; } +; clang -target bpf -S -O2 -g -emit-llvm test.c + +%union.__s = type { i32 } + +; Function Attrs: nounwind +define dso_local i32 @test(%union.__s* %arg) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata %union.__s* %arg, metadata !21, metadata !DIExpression()), !dbg !22 + %0 = tail call %union.__s* @llvm.preserve.union.access.index.p0s_union.__ss.p0s_union.__ss(%union.__s* %arg, i32 1), !dbg !23, !llvm.preserve.access.index !14 + %1 = bitcast %union.__s* %0 to i8*, !dbg !23 + %call = tail call i32 @get_value(i8* %1) #4, !dbg !24 + ret i32 %call, !dbg !25 +} + +; CHECK: .cfi_startproc +; CHECK: [[RELOC:.Ltmp[0-9]+]]: +; CHECK: r2 = 0 +; CHECK: r1 += r2 +; CHECK: call get_value + +; CHECK: .long {{[0-9]+}} # BTF_KIND_UNION(id = [[TYPE_ID:[0-9]+]]) +; CHECK: .ascii ".text" # string offset=[[SEC_INDEX:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .ascii "0:1" # string offset=[[ACCESS_STR:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .long 12 # OffsetReloc +; CHECK-NEXT: .long [[SEC_INDEX]] # Offset reloc section string offset=[[SEC_INDEX]] +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long [[RELOC]] +; CHECK-NEXT: .long [[TYPE_ID]] +; CHECK-NEXT: .long [[ACCESS_STR]] + +declare dso_local i32 @get_value(i8*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare %union.__s* @llvm.preserve.union.access.index.p0s_union.__ss.p0s_union.__ss(%union.__s*, i32 immarg) #2 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 366831) (llvm/trunk 366867)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/core-bugs") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 10.0.0 (trunk 366831) (llvm/trunk 366867)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 8, type: !8, scopeLine: 8, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !20) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "s", file: !1, line: 5, baseType: !13) +!13 = !DIDerivedType(tag: DW_TAG_typedef, name: "_s", file: !1, line: 4, baseType: !14) +!14 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "__s", file: !1, line: 3, size: 32, elements: !15) +!15 = !{!16, !19} +!16 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !14, file: !1, line: 3, baseType: !17, size: 32) +!17 = !DIDerivedType(tag: DW_TAG_typedef, name: "__int", file: !1, line: 2, baseType: !18) +!18 = !DIDerivedType(tag: DW_TAG_typedef, name: "_int", file: !1, line: 1, baseType: !10) +!19 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !14, file: !1, line: 3, baseType: !17, size: 32) +!20 = !{!21} +!21 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 8, type: !11) +!22 = !DILocation(line: 0, scope: !7) +!23 = !DILocation(line: 9, column: 20, scope: !7) +!24 = !DILocation(line: 9, column: 10, scope: !7) +!25 = !DILocation(line: 9, column: 3, scope: !7) diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll new file mode 100644 index 000000000000..c09d97991d9e --- /dev/null +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-typedef.ll @@ -0,0 +1,111 @@ +; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck %s +; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck %s +; +; Source code: +; struct s { int a; int b; }; +; typedef struct s __s; +; union u { __s c; __s d; }; +; typedef union u __u; +; typedef __u arr_t[7]; +; typedef arr_t __arr; +; +; #define _(x) (__builtin_preserve_access_index(x)) +; int get_value(const void *addr); +; int test(__arr *arg) { +; return get_value(_(&arg[1]->d.b)); +; } +; clang -target bpf -S -O2 -g -emit-llvm test.c +; The offset reloc offset should be 12 from the base "arg". + +%union.u = type { %struct.s } +%struct.s = type { i32, i32 } + +; Function Attrs: nounwind +define dso_local i32 @test([7 x %union.u]* %arg) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata [7 x %union.u]* %arg, metadata !28, metadata !DIExpression()), !dbg !29 + %0 = tail call [7 x %union.u]* @llvm.preserve.array.access.index.p0a7s_union.us.p0a7s_union.us([7 x %union.u]* %arg, i32 0, i32 1), !dbg !30 + %arraydecay = getelementptr inbounds [7 x %union.u], [7 x %union.u]* %0, i64 0, i64 0, !dbg !30 + %1 = tail call %union.u* @llvm.preserve.union.access.index.p0s_union.us.p0s_union.us(%union.u* %arraydecay, i32 1), !dbg !30, !llvm.preserve.access.index !16 + %d = getelementptr inbounds %union.u, %union.u* %1, i64 0, i32 0, !dbg !30 + %2 = tail call i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s* %d, i32 1, i32 1), !dbg !30, !llvm.preserve.access.index !20 + %3 = bitcast i32* %2 to i8*, !dbg !30 + %call = tail call i32 @get_value(i8* %3) #4, !dbg !31 + ret i32 %call, !dbg !32 +} + +; CHECK: .cfi_startproc +; CHECK: [[RELOC:.Ltmp[0-9]+]]: +; CHECK: r2 = 12 +; CHECK: r1 += r2 +; CHECK: call get_value + +; CHECK: .long {{[0-9]+}} # BTF_KIND_UNION(id = [[TYPE_ID:[0-9]+]]) +; CHECK: .ascii ".text" # string offset=[[SEC_STR:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .ascii "1:1:1" # string offset=[[ACCESS_STR:[0-9]+]] +; CHECK-NEXT: .byte 0 +; CHECK: .long 12 # OffsetReloc +; CHECK-NEXT: .long [[SEC_STR:[0-9]+]] # Offset reloc section string offset=[[SEC_STR:[0-9]+]] +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long [[RELOC:.Ltmp[0-9]+]] +; CHECK-NEXT: .long [[TYPE_ID:[0-9]+]] +; CHECK-NEXT: .long [[ACCESS_STR:[0-9]+]] + +declare dso_local i32 @get_value(i8*) local_unnamed_addr #1 + +; Function Attrs: nounwind readnone +declare [7 x %union.u]* @llvm.preserve.array.access.index.p0a7s_union.us.p0a7s_union.us([7 x %union.u]*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone +declare %union.u* @llvm.preserve.union.access.index.p0s_union.us.p0s_union.us(%union.u*, i32 immarg) #2 + +; Function Attrs: nounwind readnone +declare i32* @llvm.preserve.struct.access.index.p0i32.p0s_struct.ss(%struct.s*, i32 immarg, i32 immarg) #2 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone } +attributes #3 = { nounwind readnone speculatable } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (trunk 366831) (llvm/trunk 366867)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/work/tests/llvm/core-bugs") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 10.0.0 (trunk 366831) (llvm/trunk 366867)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 10, type: !8, scopeLine: 10, flags: DIFlagPrototyped, isDefinition: true, isOptimized: true, unit: !0, retainedNodes: !27) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !11} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) +!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "__arr", file: !1, line: 6, baseType: !13) +!13 = !DIDerivedType(tag: DW_TAG_typedef, name: "arr_t", file: !1, line: 5, baseType: !14) +!14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !15, size: 448, elements: !25) +!15 = !DIDerivedType(tag: DW_TAG_typedef, name: "__u", file: !1, line: 4, baseType: !16) +!16 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "u", file: !1, line: 3, size: 64, elements: !17) +!17 = !{!18, !24} +!18 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !16, file: !1, line: 3, baseType: !19, size: 64) +!19 = !DIDerivedType(tag: DW_TAG_typedef, name: "__s", file: !1, line: 2, baseType: !20) +!20 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 64, elements: !21) +!21 = !{!22, !23} +!22 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !20, file: !1, line: 1, baseType: !10, size: 32) +!23 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !20, file: !1, line: 1, baseType: !10, size: 32, offset: 32) +!24 = !DIDerivedType(tag: DW_TAG_member, name: "d", scope: !16, file: !1, line: 3, baseType: !19, size: 64) +!25 = !{!26} +!26 = !DISubrange(count: 7) +!27 = !{!28} +!28 = !DILocalVariable(name: "arg", arg: 1, scope: !7, file: !1, line: 10, type: !11) +!29 = !DILocation(line: 0, scope: !7) +!30 = !DILocation(line: 11, column: 20, scope: !7) +!31 = !DILocation(line: 11, column: 10, scope: !7) +!32 = !DILocation(line: 11, column: 3, scope: !7) diff --git a/llvm/test/CodeGen/BPF/objdump_two_funcs.ll b/llvm/test/CodeGen/BPF/objdump_two_funcs.ll new file mode 100644 index 000000000000..689cf6f707f7 --- /dev/null +++ b/llvm/test/CodeGen/BPF/objdump_two_funcs.ll @@ -0,0 +1,69 @@ +; RUN: llc -march=bpfel -filetype=obj -o - %s | llvm-objdump -S - | FileCheck %s +; RUN: llc -march=bpfeb -filetype=obj -o - %s | llvm-objdump -S - | FileCheck %s +; +; Source code: +; __attribute__((section("s1"))) +; int func1(int a) { +; return a * a; +; } +; __attribute__((section("s2"))) +; int func2(int a) { +; return a * a * a; +; } +; Compiler flag to generate IR: +; clang -target bpf -S -gdwarf-5 -gembed-source -emit-llvm -g -O2 bug.c + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @func1(i32 %a) local_unnamed_addr #0 section "s1" !dbg !7 { +entry: +; CHECK: func1: + call void @llvm.dbg.value(metadata i32 %a, metadata !12, metadata !DIExpression()), !dbg !13 + %mul = mul nsw i32 %a, %a, !dbg !14 + ret i32 %mul, !dbg !15 +; CHECK: ; return a * a; +} + +; Function Attrs: norecurse nounwind readnone +define dso_local i32 @func2(i32 %a) local_unnamed_addr #0 section "s2" !dbg !16 { +entry: +; CHECK: func2: + call void @llvm.dbg.value(metadata i32 %a, metadata !18, metadata !DIExpression()), !dbg !19 + %mul = mul nsw i32 %a, %a, !dbg !20 + %mul1 = mul nsw i32 %mul, %a, !dbg !21 + ret i32 %mul1, !dbg !22 +; CHECK: ; return a * a * a; +} + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { norecurse nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 9.0.0 (trunk 366422) (llvm/trunk 366423)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "bug.c", directory: "/tmp/home/yhs/work/tests/llvm/reloc", checksumkind: CSK_MD5, checksum: "c7c9938d4e6989ca33db748213aab194", source: "__attribute__((section(\22s1\22)))\0Aint func1(int a) {\0A return a * a;\0A}\0A__attribute__((section(\22s2\22)))\0Aint func2(int a) {\0A return a * a * a;\0A}\0A") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 5} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 9.0.0 (trunk 366422) (llvm/trunk 366423)"} +!7 = distinct !DISubprogram(name: "func1", scope: !1, file: !1, line: 2, type: !8, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !1, line: 2, type: !10) +!13 = !DILocation(line: 0, scope: !7) +!14 = !DILocation(line: 3, column: 14, scope: !7) +!15 = !DILocation(line: 3, column: 5, scope: !7) +!16 = distinct !DISubprogram(name: "func2", scope: !1, file: !1, line: 6, type: !8, scopeLine: 6, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !17) +!17 = !{!18} +!18 = !DILocalVariable(name: "a", arg: 1, scope: !16, file: !1, line: 6, type: !10) +!19 = !DILocation(line: 0, scope: !16) +!20 = !DILocation(line: 7, column: 14, scope: !16) +!21 = !DILocation(line: 7, column: 18, scope: !16) +!22 = !DILocation(line: 7, column: 5, scope: !16) diff --git a/llvm/test/CodeGen/CAHP/alloca.ll b/llvm/test/CodeGen/CAHP/alloca.ll new file mode 100644 index 000000000000..e84caa437c47 --- /dev/null +++ b/llvm/test/CodeGen/CAHP/alloca.ll @@ -0,0 +1,63 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=CAHP + +declare void @notdead(i8*) + +; These tests must ensure the stack pointer is restored using the frame +; pointer + +define void @simple_alloca(i32 %n) nounwind { +; CAHP-LABEL: simple_alloca: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -4 +; CAHP-NEXT: swsp ra, 2(sp) +; CAHP-NEXT: swsp fp, 0(sp) +; CAHP-NEXT: addi fp, sp, 4 +; CAHP-NEXT: addi2 a0, 1 +; CAHP-NEXT: andi2 a0, -2 +; CAHP-NEXT: sub a0, sp, a0 +; CAHP-NEXT: mov sp, a0 +; CAHP-NEXT: jsal notdead +; CAHP-NEXT: addi sp, fp, -4 +; CAHP-NEXT: lwsp fp, 0(sp) +; CAHP-NEXT: lwsp ra, 2(sp) +; CAHP-NEXT: addi2 sp, 4 +; CAHP-NEXT: jr ra + + %1 = alloca i8, i32 %n + call void @notdead(i8* %1) + ret void +} + +declare i8* @llvm.stacksave() +declare void @llvm.stackrestore(i8*) + +define void @scoped_alloca(i32 %n) nounwind { +; CAHP-LABEL: scoped_alloca: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -6 +; CAHP-NEXT: swsp ra, 4(sp) +; CAHP-NEXT: swsp fp, 2(sp) +; CAHP-NEXT: swsp s0, 0(sp) +; CAHP-NEXT: addi fp, sp, 6 +; CAHP-NEXT: mov s0, sp +; CAHP-NEXT: addi2 a0, 1 +; CAHP-NEXT: andi2 a0, -2 +; CAHP-NEXT: sub a0, sp, a0 +; CAHP-NEXT: mov sp, a0 +; CAHP-NEXT: jsal notdead +; CAHP-NEXT: mov sp, s0 +; CAHP-NEXT: addi sp, fp, -6 +; CAHP-NEXT: lwsp s0, 0(sp) +; CAHP-NEXT: lwsp fp, 2(sp) +; CAHP-NEXT: lwsp ra, 4(sp) +; CAHP-NEXT: addi2 sp, 6 +; CAHP-NEXT: jr ra + + %sp = call i8* @llvm.stacksave() + %addr = alloca i8, i32 %n + call void @notdead(i8* %addr) + call void @llvm.stackrestore(i8* %sp) + ret void +} diff --git a/llvm/test/CodeGen/CAHP/alu16.ll b/llvm/test/CodeGen/CAHP/alu16.ll new file mode 100644 index 000000000000..6c987465873a --- /dev/null +++ b/llvm/test/CodeGen/CAHP/alu16.ll @@ -0,0 +1,259 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=CAHP + +; Register-immediate instructions + +define i16 @addi(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: addi: +; CAHP: # %bb.0: +; CAHP-NEXT: addi a0, a1, 1 +; CAHP-NEXT: jr ra + %1 = add i16 %b, 1 + ret i16 %1 +} + +define i16 @addi2(i16 %a) nounwind { +; CAHP-LABEL: addi2: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 a0, 1 +; CAHP-NEXT: jr ra + %1 = add i16 %a, 1 + ret i16 %1 +} + +define i16 @xori(i16 %a) nounwind { +; CAHP-LABEL: xori: +; CAHP: # %bb.0: +; CAHP-NEXT: xori a0, a0, 4 +; CAHP-NEXT: jr ra + %1 = xor i16 %a, 4 + ret i16 %1 +} + +define i16 @ori(i16 %a) nounwind { +; CAHP-LABEL: ori: +; CAHP: # %bb.0: +; CAHP-NEXT: ori a0, a0, 5 +; CAHP-NEXT: jr ra + %1 = or i16 %a, 5 + ret i16 %1 +} + +define i16 @andi(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: andi: +; CAHP: # %bb.0: +; CAHP-NEXT: andi a0, a1, 6 +; CAHP-NEXT: jr ra + %1 = and i16 %b, 6 + ret i16 %1 +} + +define i16 @andi2(i16 %a) nounwind { +; CAHP-LABEL: andi2: +; CAHP: # %bb.0: +; CAHP-NEXT: andi2 a0, 6 +; CAHP-NEXT: jr ra + %1 = and i16 %a, 6 + ret i16 %1 +} + +define i16 @lsli(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: lsli: +; CAHP: # %bb.0: +; CAHP-NEXT: lsli a0, a1, 7 +; CAHP-NEXT: jr ra + %1 = shl i16 %b, 7 + ret i16 %1 +} + +define i16 @lsli2(i16 %a) nounwind { +; CAHP-LABEL: lsli2: +; CAHP: # %bb.0: +; CAHP-NEXT: lsli2 a0, 7 +; CAHP-NEXT: jr ra + %1 = shl i16 %a, 7 + ret i16 %1 +} + +define i16 @lsri(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: lsri: +; CAHP: # %bb.0: +; CAHP-NEXT: lsri a0, a1, 8 +; CAHP-NEXT: jr ra + %1 = lshr i16 %b, 8 + ret i16 %1 +} + +define i16 @lsri2(i16 %a) nounwind { +; CAHP-LABEL: lsri2: +; CAHP: # %bb.0: +; CAHP-NEXT: lsri2 a0, 8 +; CAHP-NEXT: jr ra + %1 = lshr i16 %a, 8 + ret i16 %1 +} + +define i16 @asri(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: asri: +; CAHP: # %bb.0: +; CAHP-NEXT: asri a0, a1, 9 +; CAHP-NEXT: jr ra + %1 = ashr i16 %b, 9 + ret i16 %1 +} + +define i16 @asri2(i16 %a) nounwind { +; CAHP-LABEL: asri2: +; CAHP: # %bb.0: +; CAHP-NEXT: asri2 a0, 9 +; CAHP-NEXT: jr ra + %1 = ashr i16 %a, 9 + ret i16 %1 +} + +; Register-register instructions + +define i16 @add(i16 %a, i16 %b, i16 %c) nounwind { +; CAHP-LABEL: add: +; CAHP: # %bb.0: +; CAHP-NEXT: add a0, a1, a2 +; CAHP-NEXT: jr ra + %1 = add i16 %b, %c + ret i16 %1 +} + +define i16 @add2(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: add2: +; CAHP: # %bb.0: +; CAHP-NEXT: add2 a0, a1 +; CAHP-NEXT: jr ra + %1 = add i16 %a, %b + ret i16 %1 +} + +define i16 @sub(i16 %a, i16 %b, i16 %c) nounwind { +; CAHP-LABEL: sub: +; CAHP: # %bb.0: +; CAHP-NEXT: sub a0, a1, a2 +; CAHP-NEXT: jr ra + %1 = sub i16 %b, %c + ret i16 %1 +} + +define i16 @sub2(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: sub2: +; CAHP: # %bb.0: +; CAHP-NEXT: sub2 a0, a1 +; CAHP-NEXT: jr ra + %1 = sub i16 %a, %b + ret i16 %1 +} + +define i16 @lsl(i16 %a, i16 %b, i16 %c) nounwind { +; CAHP-LABEL: lsl: +; CAHP: # %bb.0: +; CAHP-NEXT: lsl a0, a1, a2 +; CAHP-NEXT: jr ra + %1 = shl i16 %b, %c + ret i16 %1 +} + +define i16 @lsl2(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: lsl2: +; CAHP: # %bb.0: +; CAHP-NEXT: lsl2 a0, a1 +; CAHP-NEXT: jr ra + %1 = shl i16 %a, %b + ret i16 %1 +} + +define i16 @xor(i16 %a, i16 %b, i16 %c) nounwind { +; CAHP-LABEL: xor: +; CAHP: # %bb.0: +; CAHP-NEXT: xor a0, a1, a2 +; CAHP-NEXT: jr ra + %1 = xor i16 %b, %c + ret i16 %1 +} + +define i16 @xor2(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: xor2: +; CAHP: # %bb.0: +; CAHP-NEXT: xor2 a0, a1 +; CAHP-NEXT: jr ra + %1 = xor i16 %a, %b + ret i16 %1 +} + +define i16 @lsr(i16 %a, i16 %b, i16 %c) nounwind { +; CAHP-LABEL: lsr: +; CAHP: # %bb.0: +; CAHP-NEXT: lsr a0, a1, a2 +; CAHP-NEXT: jr ra + %1 = lshr i16 %b, %c + ret i16 %1 +} + +define i16 @lsr2(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: lsr2: +; CAHP: # %bb.0: +; CAHP-NEXT: lsr2 a0, a1 +; CAHP-NEXT: jr ra + %1 = lshr i16 %a, %b + ret i16 %1 +} + +define i16 @asr(i16 %a, i16 %b, i16 %c) nounwind { +; CAHP-LABEL: asr: +; CAHP: # %bb.0: +; CAHP-NEXT: asr a0, a1, a2 +; CAHP-NEXT: jr ra + %1 = ashr i16 %b, %c + ret i16 %1 +} + +define i16 @asr2(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: asr2: +; CAHP: # %bb.0: +; CAHP-NEXT: asr2 a0, a1 +; CAHP-NEXT: jr ra + %1 = ashr i16 %a, %b + ret i16 %1 +} + +define i16 @or(i16 %a, i16 %b, i16 %c) nounwind { +; CAHP-LABEL: or: +; CAHP: # %bb.0: +; CAHP-NEXT: or a0, a1, a2 +; CAHP-NEXT: jr ra + %1 = or i16 %b, %c + ret i16 %1 +} + +define i16 @or2(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: or2: +; CAHP: # %bb.0: +; CAHP-NEXT: or2 a0, a1 +; CAHP-NEXT: jr ra + %1 = or i16 %a, %b + ret i16 %1 +} + +define i16 @and(i16 %a, i16 %b, i16 %c) nounwind { +; CAHP-LABEL: and: +; CAHP: # %bb.0: +; CAHP-NEXT: and a0, a1, a2 +; CAHP-NEXT: jr ra + %1 = and i16 %b, %c + ret i16 %1 +} + +define i16 @and2(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: and2: +; CAHP: # %bb.0: +; CAHP-NEXT: and2 a0, a1 +; CAHP-NEXT: jr ra + %1 = and i16 %a, %b + ret i16 %1 +} diff --git a/llvm/test/CodeGen/CAHP/analyze-branch.ll b/llvm/test/CodeGen/CAHP/analyze-branch.ll new file mode 100644 index 000000000000..861d06e7deb6 --- /dev/null +++ b/llvm/test/CodeGen/CAHP/analyze-branch.ll @@ -0,0 +1,79 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=CAHP %s + +; This test checks that LLVM can do basic stripping and reapplying of branches +; to basic blocks. + +declare void @test_true() +declare void @test_false() + +; !0 corresponds to a branch being taken, !1 to not being takne. +!0 = !{!"branch_weights", i32 64, i32 4} +!1 = !{!"branch_weights", i32 4, i32 64} + +define void @test_bcc_fallthrough_taken(i16 %in) nounwind { +; CAHP-LABEL: test_bcc_fallthrough_taken: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -2 +; CAHP-NEXT: swsp ra, 0(sp) +; CAHP-NEXT: li a1, 42 +; CAHP-NEXT: bne a0, a1, .LBB0_3 +; CAHP-NEXT:# %bb.1: # %true +; CAHP-NEXT: jsal test_true +; CAHP-NEXT:.LBB0_2: # %true +; CAHP-NEXT: lwsp ra, 0(sp) +; CAHP-NEXT: addi2 sp, 2 +; CAHP-NEXT: jr ra +; CAHP-NEXT:.LBB0_3: # %false +; CAHP-NEXT: jsal test_false +; CAHP-NEXT: js .LBB0_2 + %tst = icmp eq i16 %in, 42 + br i1 %tst, label %true, label %false, !prof !0 + +; Expected layout order is: Entry, TrueBlock, FalseBlock +; Entry->TrueBlock is the common path, which should be taken whenever the +; conditional branch is false. + +true: + call void @test_true() + ret void + +false: + call void @test_false() + ret void +} + +define void @test_bcc_fallthrough_nottaken(i16 %in) nounwind { +; CAHP-LABEL: test_bcc_fallthrough_nottaken: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -2 +; CAHP-NEXT: swsp ra, 0(sp) +; CAHP-NEXT: li a1, 42 +; CAHP-NEXT: beq a0, a1, .LBB1_3 +; CAHP-NEXT:# %bb.1: # %false +; CAHP-NEXT: jsal test_false +; CAHP-NEXT:.LBB1_2: # %true +; CAHP-NEXT: lwsp ra, 0(sp) +; CAHP-NEXT: addi2 sp, 2 +; CAHP-NEXT: jr ra +; CAHP-NEXT:.LBB1_3: # %true +; CAHP-NEXT: jsal test_true +; CAHP-NEXT: js .LBB1_2 +%tst = icmp eq i16 %in, 42 +br i1 %tst, label %true, label %false, !prof !1 + +; Expected layout order is: Entry, FalseBlock, TrueBlock +; Entry->FalseBlock is the common path, which should be taken whenever the +; conditional branch is false + +true: + call void @test_true() + ret void + +false: + call void @test_false() + ret void +} + +; TODO: how can we expand the coverage of the branch analysis functions? diff --git a/llvm/test/CodeGen/CAHP/bare-select.ll b/llvm/test/CodeGen/CAHP/bare-select.ll new file mode 100644 index 000000000000..4b6009ce672a --- /dev/null +++ b/llvm/test/CodeGen/CAHP/bare-select.ll @@ -0,0 +1,19 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=CAHP + +define i16 @bare_select(i1 %a, i16 %b, i16 %c) { +; CAHP-LABEL: bare_select: +; CAHP: # %bb.0: +; CHAP-NEXT: andi a3, a0, 1 +; CHAP-NEXT: lsi a4, 0 +; CHAP-NEXT: mov a0, a1 +; CHAP-NEXT: bne a3, a4, .LBB0_2 +; CHAP-NEXT:# %bb.1: +; CHAP-NEXT: mov a0, a2 +; CHAP-NEXT:.LBB0_2: +; CHAP-NEXT: jr ra + + %1 = select i1 %a, i16 %b, i16 %c + ret i16 %1 +} diff --git a/llvm/test/CodeGen/CAHP/branch-relaxation.ll b/llvm/test/CodeGen/CAHP/branch-relaxation.ll new file mode 100644 index 000000000000..a6704639e8bc --- /dev/null +++ b/llvm/test/CodeGen/CAHP/branch-relaxation.ll @@ -0,0 +1,27 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs -filetype=obj < %s \ +; RUN: -o /dev/null 2>&1 +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s | FileCheck %s + +define void @relax_bcc(i1 %a) { +; CHECK-LABEL: relax_bcc: +; CHECK: # %bb.0: +; CHECK-NEXT: andi2 a0, 1 +; CHECK-NEXT: lsi a1, 0 +; CHECK-NEXT: bne a0, a1, .LBB0_1 +; CHECK-NEXT: js .LBB0_2 +; CHECK-NEXT:.LBB0_1: # %iftrue +; CHECK-NEXT: #APP +; CHECK-NEXT: .space 512 +; CHECK-NEXT: #NO_APP +; CHECK-NEXT:.LBB0_2: # %tail +; CHECK-NEXT: jr ra + br i1 %a, label %iftrue, label %tail + +iftrue: + call void asm sideeffect ".space 512", ""() + br label %tail + +tail: + ret void +} diff --git a/llvm/test/CodeGen/CAHP/branch.ll b/llvm/test/CodeGen/CAHP/branch.ll new file mode 100644 index 000000000000..27c897e8462f --- /dev/null +++ b/llvm/test/CodeGen/CAHP/branch.ll @@ -0,0 +1,106 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=CAHP %s + +define void @foo(i16 %a, i16 *%b, i1 %c) { +; CAHP-LABEL: foo: +; CAHP: # %bb.0: +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: beq a2, a0, .LBB0_11 +; CAHP-NEXT: # %bb.1: # %test2 +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: bne a2, a0, .LBB0_11 +; CAHP-NEXT: # %bb.2: # %test3 +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: blt a2, a0, .LBB0_11 +; CAHP-NEXT: # %bb.3: # %test4 +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: ble a2, a0, .LBB0_11 +; CAHP-NEXT: # %bb.4: # %test5 +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: bltu a2, a0, .LBB0_11 +; CAHP-NEXT: # %bb.5: # %test6 +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: bleu a2, a0, .LBB0_11 +; CAHP-NEXT: # %bb.6: # %test7 +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: blt a0, a2, .LBB0_11 +; CAHP-NEXT: # %bb.7: # %test8 +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: ble a0, a2, .LBB0_11 +; CAHP-NEXT: # %bb.8: # %test9 +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: bltu a0, a2, .LBB0_11 +; CAHP-NEXT: # %bb.9: # %test10 +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: bleu a0, a2, .LBB0_11 +; CAHP-NEXT: # %bb.10: # %test12 +; CAHP-NEXT: lw a0, 0(a1) +; CAHP-NEXT: .LBB0_11: # %end +; CAHP-NEXT: jr ra + + %val1 = load volatile i16, i16* %b + %tst1 = icmp eq i16 %val1, %a + br i1 %tst1, label %end, label %test2 + +test2: + %val2 = load volatile i16, i16* %b + %tst2 = icmp ne i16 %val2, %a + br i1 %tst2, label %end, label %test3 + +test3: + %val3 = load volatile i16, i16* %b + %tst3 = icmp slt i16 %val3, %a + br i1 %tst3, label %end, label %test4 + +test4: + %val4 = load volatile i16, i16* %b + %tst4 = icmp sle i16 %val4, %a + br i1 %tst4, label %end, label %test5 + +test5: + %val5 = load volatile i16, i16* %b + %tst5 = icmp ult i16 %val5, %a + br i1 %tst5, label %end, label %test6 + +test6: + %val6 = load volatile i16, i16* %b + %tst6 = icmp ule i16 %val6, %a + br i1 %tst6, label %end, label %test7 + +; Check for condition codes that don't have a matching instruction + +test7: + %val7 = load volatile i16, i16* %b + %tst7 = icmp sgt i16 %val7, %a + br i1 %tst7, label %end, label %test8 + +test8: + %val8 = load volatile i16, i16* %b + %tst8 = icmp sge i16 %val8, %a + br i1 %tst8, label %end, label %test9 + +test9: + %val9 = load volatile i16, i16* %b + %tst9 = icmp ugt i16 %val9, %a + br i1 %tst9, label %end, label %test10 + +test10: + %val10 = load volatile i16, i16* %b + %tst10 = icmp uge i16 %val10, %a + br i1 %tst10, label %end, label %test12 + +;; Check the case of a branch where the condition was generated in another +;; function +; +;test11: +; %val11 = load volatile i16, i16* %b +; br i1 %c, label %end, label %test12 + +test12: + %val12 = load volatile i16, i16* %b + br label %end + +end: + ret void +} diff --git a/llvm/test/CodeGen/CAHP/byval.ll b/llvm/test/CodeGen/CAHP/byval.ll new file mode 100644 index 000000000000..c9998bd20f54 --- /dev/null +++ b/llvm/test/CodeGen/CAHP/byval.ll @@ -0,0 +1,50 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=CAHP %s + +%struct.Foo = type { i16, i16, i16, i16, i8 } +@foo = global %struct.Foo { i16 1, i16 2, i16 3, i16 4, i8 5 } + +define i16 @callee(%struct.Foo* byval %f) { +; CAHP-LABEL: callee: +; CAHP: # %bb.0: +; CAHP-NEXT: lw a0, 0(a0) +; CAHP-NEXT: jr ra + %1 = getelementptr inbounds %struct.Foo, %struct.Foo* %f, i32 0, i32 0 + %2 = load i16, i16* %1 + ret i16 %2 +} + +define void @caller() { +; CAHP-LABEL: caller: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -12 +; CAHP-NEXT: swsp ra, 10(sp) +; CAHP-NEXT: lui a0, %hi(foo+8) +; CAHP-NEXT: addi a0, a0, %lo(foo+8) +; CAHP-NEXT: lw a0, 0(a0) +; CAHP-NEXT: swsp a0, 8(sp) +; CAHP-NEXT: lui a0, %hi(foo+6) +; CAHP-NEXT: addi a0, a0, %lo(foo+6) +; CAHP-NEXT: lw a0, 0(a0) +; CAHP-NEXT: swsp a0, 6(sp) +; CAHP-NEXT: lui a0, %hi(foo+4) +; CAHP-NEXT: addi a0, a0, %lo(foo+4) +; CAHP-NEXT: lw a0, 0(a0) +; CAHP-NEXT: swsp a0, 4(sp) +; CAHP-NEXT: lui a0, %hi(foo+2) +; CAHP-NEXT: addi a0, a0, %lo(foo+2) +; CAHP-NEXT: lw a0, 0(a0) +; CAHP-NEXT: swsp a0, 2(sp) +; CAHP-NEXT: lui a0, %hi(foo) +; CAHP-NEXT: addi a0, a0, %lo(foo) +; CAHP-NEXT: lw a0, 0(a0) +; CAHP-NEXT: swsp a0, 0(sp) +; CAHP-NEXT: addi a0, sp, 0 +; CAHP-NEXT: jsal callee +; CAHP-NEXT: lwsp ra, 10(sp) +; CAHP-NEXT: addi2 sp, 12 +; CAHP-NEXT: jr ra + %call = call i16 @callee(%struct.Foo* byval @foo) + ret void +} diff --git a/llvm/test/CodeGen/CAHP/calls.ll b/llvm/test/CodeGen/CAHP/calls.ll new file mode 100644 index 000000000000..12264d979e6b --- /dev/null +++ b/llvm/test/CodeGen/CAHP/calls.ll @@ -0,0 +1,173 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=CAHP %s + +declare i16 @external_function(i16) + +define i16 @test_call_external(i16 %a) nounwind { +; CAHP-LABEL: test_call_external: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -2 +; CAHP-NEXT: swsp ra, 0(sp) +; CAHP-NEXT: jsal external_function +; CAHP-NEXT: lwsp ra, 0(sp) +; CAHP-NEXT: addi2 sp, 2 +; CAHP-NEXT: jr ra + %1 = call i16 @external_function(i16 %a) + ret i16 %1 +} + +define i16 @defined_function(i16 %a) nounwind { +; CAHP-LABEL: defined_function: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 a0, 1 +; CAHP-NEXT: jr ra + %1 = add i16 %a, 1 + ret i16 %1 +} + +define i16 @test_call_defined(i16 %a) nounwind { +; CAHP-LABEL: test_call_defined: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -2 +; CAHP-NEXT: swsp ra, 0(sp) +; CAHP-NEXT: jsal defined_function +; CAHP-NEXT: lwsp ra, 0(sp) +; CAHP-NEXT: addi2 sp, 2 +; CAHP-NEXT: jr ra + %1 = call i16 @defined_function(i16 %a) nounwind + ret i16 %1 +} + +define i16 @test_call_indirect(i16 (i16)* %a, i16 %b) nounwind { +; CAHP-LABEL: test_call_indirect: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -2 +; CAHP-NEXT: swsp ra, 0(sp) +; CAHP-NEXT: mov a2, a0 +; CAHP-NEXT: mov a0, a1 +; CAHP-NEXT: jalr a2 +; CAHP-NEXT: lwsp ra, 0(sp) +; CAHP-NEXT: addi2 sp, 2 +; CAHP-NEXT: jr ra + %1 = call i16 %a(i16 %b) + ret i16 %1 +} + +define fastcc i16 @fastcc_function(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: fastcc_function: +; CAHP: # %bb.0: +; CAHP-NEXT: add2 a0, a1 +; CAHP-NEXT: jr ra + + %1 = add i16 %a, %b + ret i16 %1 +} + +define i16 @test_call_fastcc(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: test_call_fastcc: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -4 +; CAHP-NEXT: swsp ra, 2(sp) +; CAHP-NEXT: swsp s0, 0(sp) +; CAHP-NEXT: mov s0, a0 +; CAHP-NEXT: jsal fastcc_function +; CAHP-NEXT: mov a0, s0 +; CAHP-NEXT: lwsp s0, 0(sp) +; CAHP-NEXT: lwsp ra, 2(sp) +; CAHP-NEXT: addi2 sp, 4 +; CAHP-NEXT: jr ra + + %1 = call fastcc i16 @fastcc_function(i16 %a, i16 %b) + ret i16 %a +} + +declare i16 @external_many_args(i16, i16, i16, i16, i16, i16, i16, i16, i16, i16) nounwind + +define i16 @test_call_external_many_args(i16 %a) nounwind { +; CAHP-LABEL: test_call_external_many_args: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -12 +; CAHP-NEXT: swsp ra, 10(sp) +; CAHP-NEXT: swsp s0, 8(sp) +; CAHP-NEXT: mov s0, a0 +; CAHP-NEXT: swsp a0, 6(sp) +; CAHP-NEXT: swsp a0, 4(sp) +; CAHP-NEXT: swsp a0, 2(sp) +; CAHP-NEXT: swsp a0, 0(sp) +; CAHP-NEXT: mov a1, a0 +; CAHP-NEXT: mov a2, a0 +; CAHP-NEXT: mov a3, a0 +; CAHP-NEXT: mov a4, a0 +; CAHP-NEXT: mov a5, a0 +; CAHP-NEXT: jsal external_many_args +; CAHP-NEXT: mov a0, s0 +; CAHP-NEXT: lwsp s0, 8(sp) +; CAHP-NEXT: lwsp ra, 10(sp) +; CAHP-NEXT: addi2 sp, 12 +; CAHP-NEXT: jr ra + %1 = call i16 @external_many_args(i16 %a, i16 %a, i16 %a, i16 %a, i16 %a, + i16 %a, i16 %a, i16 %a, i16 %a, i16 %a) + ret i16 %a +} + +define i16 @defined_many_args(i16, i16, i16, i16, i16, i16, i16, i16, i16, i16 %j) nounwind { +; CAHP-LABEL: defined_many_args: +; CAHP: # %bb.0: +; CAHP-NEXT: lwsp a0, 6(sp) +; CAHP-NEXT: addi2 a0, 1 +; CAHP-NEXT: jr ra + %added = add i16 %j, 1 + ret i16 %added +} + +define i16 @test_call_defined_many_args(i16 %a) nounwind { +; CAHP-LABEL: test_call_defined_many_args: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -10 +; CAHP-NEXT: swsp ra, 8(sp) +; CAHP-NEXT: swsp a0, 6(sp) +; CAHP-NEXT: swsp a0, 4(sp) +; CAHP-NEXT: swsp a0, 2(sp) +; CAHP-NEXT: swsp a0, 0(sp) +; CAHP-NEXT: mov a1, a0 +; CAHP-NEXT: mov a2, a0 +; CAHP-NEXT: mov a3, a0 +; CAHP-NEXT: mov a4, a0 +; CAHP-NEXT: mov a5, a0 +; CAHP-NEXT: jsal defined_many_args +; CAHP-NEXT: lwsp ra, 8(sp) +; CAHP-NEXT: addi2 sp, 10 +; CAHP-NEXT: jr ra + %1 = call i16 @defined_many_args(i16 %a, i16 %a, i16 %a, i16 %a, i16 %a, + i16 %a, i16 %a, i16 %a, i16 %a, i16 %a) + ret i16 %1 +} + +declare i16 @callee_i32_scalars(i16, i32, i32, i32, i32, i32, i32) + +define i16 @caller_i32_scalars(i32 %a) nounwind { +; CAHP-LABEL: caller_i32_scalars: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -16 +; CAHP-NEXT: swsp ra, 14(sp) +; CAHP-NEXT: mov a2, a1 +; CAHP-NEXT: mov a1, a0 +; CAHP-NEXT: swsp a2, 12(sp) +; CAHP-NEXT: swsp a0, 10(sp) +; CAHP-NEXT: swsp a2, 8(sp) +; CAHP-NEXT: swsp a0, 6(sp) +; CAHP-NEXT: swsp a2, 4(sp) +; CAHP-NEXT: swsp a0, 2(sp) +; CAHP-NEXT: li a0, 42 +; CAHP-NEXT: swsp a2, 0(sp) +; CAHP-NEXT: mov a3, a1 +; CAHP-NEXT: mov a4, a2 +; CAHP-NEXT: mov a5, a1 +; CAHP-NEXT: jsal callee_i32_scalars +; CAHP-NEXT: lwsp ra, 14(sp) +; CAHP-NEXT: addi2 sp, 16 +; CAHP-NEXT: jr ra + %1 = call i16 @callee_i32_scalars(i16 42, i32 %a, i32 %a, i32 %a, i32 %a, i32 %a, i32 %a) + ret i16 %1 +} diff --git a/llvm/test/CodeGen/CAHP/div.ll b/llvm/test/CodeGen/CAHP/div.ll new file mode 100644 index 000000000000..8a1d475b744f --- /dev/null +++ b/llvm/test/CodeGen/CAHP/div.ll @@ -0,0 +1,134 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=CAHP + +define i16 @udiv(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: udiv: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -2 +; CAHP-NEXT: swsp ra, 0(sp) +; CAHP-NEXT: jsal __udivhi3 +; CAHP-NEXT: lwsp ra, 0(sp) +; CAHP-NEXT: addi2 sp, 2 +; CAHP-NEXT: jr ra + %1 = udiv i16 %a, %b + ret i16 %1 +} + +define i16 @udiv_constant(i16 %a) nounwind { +; CAHP-LABEL: udiv_constant: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -2 +; CAHP-NEXT: swsp ra, 0(sp) +; CAHP-NEXT: lsi a1, 5 +; CAHP-NEXT: jsal __udivhi3 +; CAHP-NEXT: lwsp ra, 0(sp) +; CAHP-NEXT: addi2 sp, 2 +; CAHP-NEXT: jr ra + %1 = udiv i16 %a, 5 + ret i16 %1 +} + +define i16 @udiv_pow2(i16 %a) nounwind { +; CAHP-LABEL: udiv_pow2: +; CAHP: # %bb.0: +; CAHP-NEXT: lsri2 a0, 3 +; CAHP-NEXT: jr ra + %1 = udiv i16 %a, 8 + ret i16 %1 +} + +define i32 @udiv32(i32 %a, i32 %b) nounwind { +; CAHP-LABEL: udiv32: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -2 +; CAHP-NEXT: swsp ra, 0(sp) +; CAHP-NEXT: jsal __udivsi3 +; CAHP-NEXT: lwsp ra, 0(sp) +; CAHP-NEXT: addi2 sp, 2 +; CAHP-NEXT: jr ra + %1 = udiv i32 %a, %b + ret i32 %1 +} + +define i32 @udiv32_constant(i32 %a) nounwind { +; CAHP-LABEL: udiv32_constant: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -2 +; CAHP-NEXT: swsp ra, 0(sp) +; CAHP-NEXT: lsi a2, 5 +; CAHP-NEXT: lsi a3, 0 +; CAHP-NEXT: jsal __udivsi3 +; CAHP-NEXT: lwsp ra, 0(sp) +; CAHP-NEXT: addi2 sp, 2 +; CAHP-NEXT: jr ra + %1 = udiv i32 %a, 5 + ret i32 %1 +} + +define i16 @sdiv(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: sdiv: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -2 +; CAHP-NEXT: swsp ra, 0(sp) +; CAHP-NEXT: jsal __divhi3 +; CAHP-NEXT: lwsp ra, 0(sp) +; CAHP-NEXT: addi2 sp, 2 +; CAHP-NEXT: jr ra + %1 = sdiv i16 %a, %b + ret i16 %1 +} + +define i16 @sdiv_constant(i16 %a) nounwind { +; CAHP-LABEL: sdiv_constant: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -2 +; CAHP-NEXT: swsp ra, 0(sp) +; CAHP-NEXT: lsi a1, 5 +; CAHP-NEXT: jsal __divhi3 +; CAHP-NEXT: lwsp ra, 0(sp) +; CAHP-NEXT: addi2 sp, 2 +; CAHP-NEXT: jr ra + %1 = sdiv i16 %a, 5 + ret i16 %1 +} + +define i16 @sdiv_pow2(i16 %a) nounwind { +; CAHP-LABEL: sdiv_pow2: +; CAHP: # %bb.0: +; CAHP-NEXT: asri a1, a0, 15 +; CAHP-NEXT: lsri2 a1, 13 +; CAHP-NEXT: add2 a0, a1 +; CAHP-NEXT: asri2 a0, 3 +; CAHP-NEXT: jr ra + %1 = sdiv i16 %a, 8 + ret i16 %1 +} + +define i32 @sdiv32(i32 %a, i32 %b) nounwind { +; CAHP-LABEL: sdiv32: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -2 +; CAHP-NEXT: swsp ra, 0(sp) +; CAHP-NEXT: jsal __divsi3 +; CAHP-NEXT: lwsp ra, 0(sp) +; CAHP-NEXT: addi2 sp, 2 +; CAHP-NEXT: jr ra + %1 = sdiv i32 %a, %b + ret i32 %1 +} + +define i32 @sdiv32_constant(i32 %a) nounwind { +; CAHP-LABEL: sdiv32_constant: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -2 +; CAHP-NEXT: swsp ra, 0(sp) +; CAHP-NEXT: lsi a2, 5 +; CAHP-NEXT: lsi a3, 0 +; CAHP-NEXT: jsal __divsi3 +; CAHP-NEXT: lwsp ra, 0(sp) +; CAHP-NEXT: addi2 sp, 2 +; CAHP-NEXT: jr ra + %1 = sdiv i32 %a, 5 + ret i32 %1 +} diff --git a/llvm/test/CodeGen/CAHP/frame.ll b/llvm/test/CodeGen/CAHP/frame.ll new file mode 100644 index 000000000000..6a88d65e843b --- /dev/null +++ b/llvm/test/CodeGen/CAHP/frame.ll @@ -0,0 +1,44 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=CAHP %s + +%struct.key_t = type { i16, [16 x i8] } + +; FIXME: prologue and epilogue insertion must be implemented to complete this +; test + +define i16 @test() nounwind { +; CAHP-LABEL: test: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -24 +; CAHP-NEXT: swsp ra, 22(sp) +; CAHP-NEXT: swsp fp, 20(sp) +; CAHP-NEXT: swsp s0, 18(sp) +; CAHP-NEXT: addi fp, sp, 24 +; CAHP-NEXT: lsi s0, 0 +; CAHP-NEXT: sw s0, -16(fp) +; CAHP-NEXT: sw s0, -18(fp) +; CAHP-NEXT: sw s0, -20(fp) +; CAHP-NEXT: sw s0, -22(fp) +; CAHP-NEXT: sw s0, -24(fp) +; CAHP-NEXT: addi a0, fp, -22 +; CAHP-NEXT: jsal test1 +; CAHP-NEXT: mov a0, s0 +; CAHP-NEXT: addi sp, fp, -24 +; CAHP-NEXT: lwsp s0, 18(sp) +; CAHP-NEXT: lwsp fp, 20(sp) +; CAHP-NEXT: lwsp ra, 22(sp) +; CAHP-NEXT: addi2 sp, 24 +; CAHP-NEXT: jr ra + + %key = alloca %struct.key_t, align 2 + %1 = bitcast %struct.key_t* %key to i8* + call void @llvm.memset.p0i8.i64(i8* %1, i8 0, i64 10, i32 2, i1 false) + %2 = getelementptr inbounds %struct.key_t, %struct.key_t* %key, i64 0, i32 1, i64 0 + call void @test1(i8* %2) + ret i16 0 +} + +declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) + +declare void @test1(i8*) diff --git a/llvm/test/CodeGen/CAHP/frameaddr-returnaddr.ll b/llvm/test/CodeGen/CAHP/frameaddr-returnaddr.ll new file mode 100644 index 000000000000..c9275a760a59 --- /dev/null +++ b/llvm/test/CodeGen/CAHP/frameaddr-returnaddr.ll @@ -0,0 +1,70 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=CAHP %s + +declare i8* @llvm.frameaddress(i32) +declare i8* @llvm.returnaddress(i32) + +define i8* @test_frameaddress_0() nounwind { +; CAHP-LABEL: test_frameaddress_0: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -4 +; CAHP-NEXT: swsp ra, 2(sp) +; CAHP-NEXT: swsp fp, 0(sp) +; CAHP-NEXT: addi fp, sp, 4 +; CAHP-NEXT: mov a0, fp +; CAHP-NEXT: lwsp fp, 0(sp) +; CAHP-NEXT: lwsp ra, 2(sp) +; CAHP-NEXT: addi2 sp, 4 +; CAHP-NEXT: jr ra + + %1 = call i8* @llvm.frameaddress(i32 0) + ret i8* %1 +} + +define i8* @test_frameaddress_2() nounwind { +; CAHP-LABEL: test_frameaddress_2: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -4 +; CAHP-NEXT: swsp ra, 2(sp) +; CAHP-NEXT: swsp fp, 0(sp) +; CAHP-NEXT: addi fp, sp, 4 +; CAHP-NEXT: lw a0, -4(fp) +; CAHP-NEXT: lw a0, -4(a0) +; CAHP-NEXT: lwsp fp, 0(sp) +; CAHP-NEXT: lwsp ra, 2(sp) +; CAHP-NEXT: addi2 sp, 4 +; CAHP-NEXT: jr ra + + %1 = call i8* @llvm.frameaddress(i32 2) + ret i8* %1 +} + +define i8* @test_returnaddress_0() nounwind { +; CAHP-LABEL: test_returnaddress_0: +; CAHP: # %bb.0: +; CAHP-NEXT: mov a0, ra +; CAHP-NEXT: jr ra + + %1 = call i8* @llvm.returnaddress(i32 0) + ret i8* %1 +} + +define i8* @test_returnaddress_2() nounwind { +; CAHP-LABEL: test_returnaddress_2: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -4 +; CAHP-NEXT: swsp ra, 2(sp) +; CAHP-NEXT: swsp fp, 0(sp) +; CAHP-NEXT: addi fp, sp, 4 +; CAHP-NEXT: lw a0, -4(fp) +; CAHP-NEXT: lw a0, -4(a0) +; CAHP-NEXT: lw a0, -2(a0) +; CAHP-NEXT: lwsp fp, 0(sp) +; CAHP-NEXT: lwsp ra, 2(sp) +; CAHP-NEXT: addi2 sp, 4 +; CAHP-NEXT: jr ra + + %1 = call i8* @llvm.returnaddress(i32 2) + ret i8* %1 +} diff --git a/llvm/test/CodeGen/CAHP/frameindex.ll b/llvm/test/CodeGen/CAHP/frameindex.ll new file mode 100644 index 000000000000..e790f255877e --- /dev/null +++ b/llvm/test/CodeGen/CAHP/frameindex.ll @@ -0,0 +1,23 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=CAHP %s + +declare i16 @bar(i16*) + +define i16 @foo() { +; CAHP-LABEL: foo: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -4 +; CAHP-NEXT: swsp ra, 2(sp) +; CAHP-NEXT: addi a0, sp, 0 +; CAHP-NEXT: jsal bar +; CAHP-NEXT: lwsp a0, 0(sp) +; CAHP-NEXT: lwsp ra, 2(sp) +; CAHP-NEXT: addi2 sp, 4 +; CAHP-NEXT: jr ra + %1 = alloca i16 + %2 = call i16 @bar(i16* %1) + %3 = getelementptr inbounds i16, i16* %1, i16 0 + %4 = load i16, i16* %3 + ret i16 %4 +} diff --git a/llvm/test/CodeGen/CAHP/i16-icmp.ll b/llvm/test/CodeGen/CAHP/i16-icmp.ll new file mode 100644 index 000000000000..dfb0d7083fd2 --- /dev/null +++ b/llvm/test/CodeGen/CAHP/i16-icmp.ll @@ -0,0 +1,168 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=CAHP + +; TODO: check the generated instructions for the equivalent of seqz, snez, +; sltz, sgtz map to something simple + +define i16 @icmp_eq(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: icmp_eq: +; CAHP: # %bb.0: +; CAHP-NEXT: beq a0, a1, .LBB0_2 +; CAHP-NEXT:# %bb.1: +; CAHP-NEXT: lsi a0, 0 +; CAHP-NEXT: jr ra +; CAHP-NEXT:.LBB0_2: +; CAHP-NEXT: lsi a0, 1 +; CAHP-NEXT: jr ra + + %1 = icmp eq i16 %a, %b + %2 = zext i1 %1 to i16 + ret i16 %2 +} + +define i16 @icmp_ne(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: icmp_ne: +; CAHP: # %bb.0: +; CAHP-NEXT: bne a0, a1, .LBB1_2 +; CAHP-NEXT:# %bb.1: +; CAHP-NEXT: lsi a0, 0 +; CAHP-NEXT: jr ra +; CAHP-NEXT:.LBB1_2: +; CAHP-NEXT: lsi a0, 1 +; CAHP-NEXT: jr ra + + %1 = icmp ne i16 %a, %b + %2 = zext i1 %1 to i16 + ret i16 %2 +} + +define i16 @icmp_ugt(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: icmp_ugt: +; CAHP: # %bb.0: +; CAHP-NEXT: bltu a1, a0, .LBB2_2 +; CAHP-NEXT:# %bb.1: +; CAHP-NEXT: lsi a0, 0 +; CAHP-NEXT: jr ra +; CAHP-NEXT:.LBB2_2: +; CAHP-NEXT: lsi a0, 1 +; CAHP-NEXT: jr ra + + %1 = icmp ugt i16 %a, %b + %2 = zext i1 %1 to i16 + ret i16 %2 +} + +define i16 @icmp_uge(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: icmp_uge: +; CAHP: # %bb.0: +; CAHP-NEXT: bleu a1, a0, .LBB3_2 +; CAHP-NEXT:# %bb.1: +; CAHP-NEXT: lsi a0, 0 +; CAHP-NEXT: jr ra +; CAHP-NEXT:.LBB3_2: +; CAHP-NEXT: lsi a0, 1 +; CAHP-NEXT: jr ra + + %1 = icmp uge i16 %a, %b + %2 = zext i1 %1 to i16 + ret i16 %2 +} + +define i16 @icmp_ult(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: icmp_ult: +; CAHP: # %bb.0: +; CAHP-NEXT: bltu a0, a1, .LBB4_2 +; CAHP-NEXT:# %bb.1: +; CAHP-NEXT: lsi a0, 0 +; CAHP-NEXT: jr ra +; CAHP-NEXT:.LBB4_2: +; CAHP-NEXT: lsi a0, 1 +; CAHP-NEXT: jr ra + + %1 = icmp ult i16 %a, %b + %2 = zext i1 %1 to i16 + ret i16 %2 +} + +define i16 @icmp_ule(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: icmp_ule: +; CAHP: # %bb.0: +; CAHP-NEXT: bleu a0, a1, .LBB5_2 +; CAHP-NEXT:# %bb.1: +; CAHP-NEXT: lsi a0, 0 +; CAHP-NEXT: jr ra +; CAHP-NEXT:.LBB5_2: +; CAHP-NEXT: lsi a0, 1 +; CAHP-NEXT: jr ra + + %1 = icmp ule i16 %a, %b + %2 = zext i1 %1 to i16 + ret i16 %2 +} + +define i16 @icmp_sgt(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: icmp_sgt: +; CAHP: # %bb.0: +; CAHP-NEXT: blt a1, a0, .LBB6_2 +; CAHP-NEXT:# %bb.1: +; CAHP-NEXT: lsi a0, 0 +; CAHP-NEXT: jr ra +; CAHP-NEXT:.LBB6_2: +; CAHP-NEXT: lsi a0, 1 +; CAHP-NEXT: jr ra + + %1 = icmp sgt i16 %a, %b + %2 = zext i1 %1 to i16 + ret i16 %2 +} + +define i16 @icmp_sge(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: icmp_sge: +; CAHP: # %bb.0: +; CAHP-NEXT: ble a1, a0, .LBB7_2 +; CAHP-NEXT:# %bb.1: +; CAHP-NEXT: lsi a0, 0 +; CAHP-NEXT: jr ra +; CAHP-NEXT:.LBB7_2: +; CAHP-NEXT: lsi a0, 1 +; CAHP-NEXT: jr ra + + %1 = icmp sge i16 %a, %b + %2 = zext i1 %1 to i16 + ret i16 %2 +} + +define i16 @icmp_slt(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: icmp_slt: +; CAHP: # %bb.0: +; CAHP-NEXT: blt a0, a1, .LBB8_2 +; CAHP-NEXT:# %bb.1: +; CAHP-NEXT: lsi a0, 0 +; CAHP-NEXT: jr ra +; CAHP-NEXT:.LBB8_2: +; CAHP-NEXT: lsi a0, 1 +; CAHP-NEXT: jr ra + + %1 = icmp slt i16 %a, %b + %2 = zext i1 %1 to i16 + ret i16 %2 +} + +define i16 @icmp_sle(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: icmp_sle: +; CAHP: # %bb.0: +; CAHP-NEXT: ble a0, a1, .LBB9_2 +; CAHP-NEXT:# %bb.1: +; CAHP-NEXT: lsi a0, 0 +; CAHP-NEXT: jr ra +; CAHP-NEXT:.LBB9_2: +; CAHP-NEXT: lsi a0, 1 +; CAHP-NEXT: jr ra + + %1 = icmp sle i16 %a, %b + %2 = zext i1 %1 to i16 + ret i16 %2 +} + +; TODO: check variants with an immediate? diff --git a/llvm/test/CodeGen/CAHP/imm.ll b/llvm/test/CodeGen/CAHP/imm.ll new file mode 100644 index 000000000000..31304675a970 --- /dev/null +++ b/llvm/test/CodeGen/CAHP/imm.ll @@ -0,0 +1,79 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=CAHP + +; Materializing constants + +define i16 @zero() nounwind { +; CAHP-LABEL: zero: +; CAHP: # %bb.0: +; CAHP-NEXT: lsi a0, 0 +; CAHP-NEXT: jr ra + ret i16 0 +} + +define i16 @pos_small1() nounwind { +; CAHP-LABEL: pos_small1: +; CAHP: # %bb.0: +; CAHP-NEXT: lsi a0, 31 +; CAHP-NEXT: jr ra + ret i16 31 +} + +define i16 @neg_small1() nounwind { +; CAHP-LABEL: neg_small1: +; CAHP: # %bb.0: +; CAHP-NEXT: lsi a0, -32 +; CAHP-NEXT: jr ra + ret i16 -32 +} + +define i16 @pos_small2() nounwind { +; CAHP-LABEL: pos_small2: +; CAHP: # %bb.0: +; CAHP-NEXT: li a0, 511 +; CAHP-NEXT: jr ra + ret i16 511 +} + +define i16 @neg_small2() nounwind { +; CAHP-LABEL: neg_small2: +; CAHP: # %bb.0: +; CAHP-NEXT: li a0, -512 +; CAHP-NEXT: jr ra + ret i16 -512 +} + +define i16 @pos_i16() nounwind { +; CAHP-LABEL: pos_i16: +; CAHP: # %bb.0: +; CAHP-NEXT: lui a0, 22 +; CAHP-NEXT: addi a0, a0, 457 +; CAHP-NEXT: jr ra + ret i16 22985 +} + +define i16 @neg_i16() nounwind { +; CAHP-LABEL: neg_i16: +; CAHP: # %bb.0: +; CAHP-NEXT: lui a0, 42 +; CAHP-NEXT: addi a0, a0, -457 +; CAHP-NEXT: jr ra + ret i16 -22985 +} + +define i16 @pos_i16_hi6_only() nounwind { +; CAHP-LABEL: pos_i16_hi6_only: +; CAHP: # %bb.0: +; CAHP-NEXT: lui a0, 16 +; CAHP-NEXT: jr ra + ret i16 16384 +} + +define i16 @neg_i16_hi6_only() nounwind { +; CAHP-LABEL: neg_i16_hi6_only: +; CAHP: # %bb.0: +; CAHP-NEXT: lui a0, 32 +; CAHP-NEXT: jr ra + ret i16 -32768 +} diff --git a/llvm/test/CodeGen/CAHP/inline-asm.ll b/llvm/test/CodeGen/CAHP/inline-asm.ll new file mode 100644 index 000000000000..6ffd6333ccae --- /dev/null +++ b/llvm/test/CodeGen/CAHP/inline-asm.ll @@ -0,0 +1,53 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=CAHP %s + +@gi = external global i16 + +define i16 @constraint_r(i16 %a) { +; CAHP-LABEL: constraint_r: +; CAHP: # %bb.0: +; CAHP-NEXT: lui a1, %hi(gi) +; CAHP-NEXT: addi a1, a1, %lo(gi) +; CAHP-NEXT: lw a1, 0(a1) +; CAHP-NEXT: #APP +; CAHP-NEXT: add a0, a0, a1 +; CAHP-NEXT: #NO_APP +; CAHP-NEXT: jr ra + %1 = load i16, i16* @gi + %2 = tail call i16 asm "add $0, $1, $2", "=r,r,r"(i16 %a, i16 %1) + ret i16 %2 +} + +define i16 @constraint_i(i16 %a) { +; CAHP-LABEL: constraint_i: +; CAHP: # %bb.0: +; CAHP-NEXT: #APP +; CAHP-NEXT: addi a0, a0, 113 +; CAHP-NEXT: #NO_APP +; CAHP-NEXT: jr ra + %1 = load i16, i16* @gi + %2 = tail call i16 asm "addi $0, $1, $2", "=r,r,i"(i16 %a, i16 113) + ret i16 %2 +} + +define void @constraint_m(i16* %a) { +; CAHP-LABEL: constraint_m: +; CAHP: # %bb.0: +; CAHP-NEXT: #APP +; CAHP-NEXT: #NO_APP +; CAHP-NEXT: jr ra + call void asm sideeffect "", "=*m"(i16* %a) + ret void +} + +define i16 @constraint_m2(i16* %a) { +; CAHP-LABEL: constraint_m2: +; CAHP: # %bb.0: +; CAHP-NEXT: #APP +; CAHP-NEXT: lw a0, 0(a0) +; CAHP-NEXT: #NO_APP +; CAHP-NEXT: jr ra + %1 = tail call i16 asm "lw $0, $1", "=r,*m"(i16* %a) nounwind + ret i16 %1 +} diff --git a/llvm/test/CodeGen/CAHP/jumptable.ll b/llvm/test/CodeGen/CAHP/jumptable.ll new file mode 100644 index 000000000000..33965ca9defa --- /dev/null +++ b/llvm/test/CodeGen/CAHP/jumptable.ll @@ -0,0 +1,59 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=CAHP + +define void @jt(i16 %in, i16* %out) { +; CAHP-LABEL: jt: +; CAHP: # %bb.0: # %entry +; CAHP-NEXT: lsi a2, 2 +; CAHP-NEXT: blt a2, a0, .LBB0_4 +; CAHP-NEXT:# %bb.1: # %entry +; CAHP-NEXT: lsi a3, 1 +; CAHP-NEXT: beq a0, a3, .LBB0_7 +; CAHP-NEXT:# %bb.2: # %entry +; CAHP-NEXT: bne a0, a2, .LBB0_9 +; CAHP-NEXT:# %bb.3: # %bb2 +; CAHP-NEXT: lsi a0, 3 +; CAHP-NEXT: sw a0, 0(a1) +; CAHP-NEXT: jr ra +; CAHP-NEXT:.LBB0_4: # %entry +; CAHP-NEXT: lsi a3, 3 +; CAHP-NEXT: beq a0, a3, .LBB0_8 +; CAHP-NEXT:# %bb.5: # %entry +; CAHP-NEXT: lsi a2, 4 +; CAHP-NEXT: bne a0, a2, .LBB0_9 +; CAHP-NEXT:# %bb.6: # %bb4 +; CAHP-NEXT: lsi a0, 1 +; CAHP-NEXT: sw a0, 0(a1) +; CAHP-NEXT: jr ra +; CAHP-NEXT:.LBB0_7: # %bb1 +; CAHP-NEXT: lsi a0, 4 +; CAHP-NEXT: sw a0, 0(a1) +; CAHP-NEXT: jr ra +; CAHP-NEXT:.LBB0_8: # %bb3 +; CAHP-NEXT: sw a2, 0(a1) +; CAHP-NEXT:.LBB0_9: # %exit +; CAHP-NEXT: jr ra + +entry: + switch i16 %in, label %exit [ + i16 1, label %bb1 + i16 2, label %bb2 + i16 3, label %bb3 + i16 4, label %bb4 + ] +bb1: + store i16 4, i16* %out + br label %exit +bb2: + store i16 3, i16* %out + br label %exit +bb3: + store i16 2, i16* %out + br label %exit +bb4: + store i16 1, i16* %out + br label %exit +exit: + ret void +} diff --git a/llvm/test/CodeGen/CAHP/large-stack.ll b/llvm/test/CodeGen/CAHP/large-stack.ll new file mode 100644 index 000000000000..0c8546f50da9 --- /dev/null +++ b/llvm/test/CodeGen/CAHP/large-stack.ll @@ -0,0 +1,282 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=CAHP-FPELIM %s +; RUN: llc -mtriple=cahp -verify-machineinstrs -frame-pointer=all < %s \ +; RUN: | FileCheck -check-prefix=CAHP-WITHFP %s + +; TODO: the quality of the generated code is poor + +define void @test() nounwind { +; CAHP-WITHFP-LABEL: test: +; CAHP-WITHFP: # %bb.0: +; CAHP-WITHFP-NEXT: lui a0, 3 +; CAHP-WITHFP-NEXT: addi a0, a0, -66 +; CAHP-WITHFP-NEXT: sub2 sp, a0 +; CAHP-WITHFP-NEXT: lui a0, 3 +; CAHP-WITHFP-NEXT: addi a0, a0, -68 +; CAHP-WITHFP-NEXT: add2 a0, sp +; CAHP-WITHFP-NEXT: sw ra, 0(a0) +; CAHP-WITHFP-NEXT: lui a0, 3 +; CAHP-WITHFP-NEXT: addi a0, a0, -70 +; CAHP-WITHFP-NEXT: add2 a0, sp +; CAHP-WITHFP-NEXT: sw fp, 0(a0) +; CAHP-WITHFP-NEXT: lui a0, 3 +; CAHP-WITHFP-NEXT: addi a0, a0, -66 +; CAHP-WITHFP-NEXT: add fp, sp, a0 +; CAHP-WITHFP-NEXT: lui a0, 3 +; CAHP-WITHFP-NEXT: addi a0, a0, -70 +; CAHP-WITHFP-NEXT: add2 a0, sp +; CAHP-WITHFP-NEXT: lw fp, 0(a0) +; CAHP-WITHFP-NEXT: lui a0, 3 +; CAHP-WITHFP-NEXT: addi a0, a0, -68 +; CAHP-WITHFP-NEXT: add2 a0, sp +; CAHP-WITHFP-NEXT: lw ra, 0(a0) +; CAHP-WITHFP-NEXT: lui a0, 3 +; CAHP-WITHFP-NEXT: addi a0, a0, -66 +; CAHP-WITHFP-NEXT: add2 sp, a0 +; CAHP-WITHFP-NEXT: jr ra + +; CAHP-FPELIM-LABEL: test: +; CAHP-FPELIM: # %bb.0: +; CAHP-FPELIM-NEXT: lui a0, 3 +; CAHP-FPELIM-NEXT: addi a0, a0, -70 +; CAHP-FPELIM-NEXT: sub2 sp, a0 +; CAHP-FPELIM-NEXT: lui a0, 3 +; CAHP-FPELIM-NEXT: addi a0, a0, -70 +; CAHP-FPELIM-NEXT: add2 sp, a0 +; CAHP-FPELIM-NEXT: jr ra + + %tmp = alloca [ 3000 x i8 ] , align 2 + ret void +} + +; This test case artificially produces register pressure which should force +; use of the emergency spill slot. + +define void @test_emergency_spill_slot(i16 %a) nounwind { +; CAHP-LABEL: test_emergency_spill_slot: +; CAHP: # %bb.0: +; CAHP-NEXT: lui a1, 6 +; CAHP-NEXT: addi a1, a1, -98 +; CAHP-NEXT: sub2 sp, a1 +; CAHP-NEXT: lui a1, 6 +; CAHP-NEXT: addi a1, a1, -100 +; CAHP-NEXT: add2 a1, sp +; CAHP-NEXT: sw ra, 0(a1) +; CAHP-NEXT: lui a1, 6 +; CAHP-NEXT: addi a1, a1, -102 +; CAHP-NEXT: add2 a1, sp +; CAHP-NEXT: sw fp, 0(a1) +; CAHP-NEXT: lui a1, 6 +; CAHP-NEXT: addi a1, a1, -104 +; CAHP-NEXT: add2 a1, sp +; CAHP-NEXT: sw s0, 0(a1) +; CAHP-NEXT: lui a1, 6 +; CAHP-NEXT: addi a1, a1, -106 +; CAHP-NEXT: add2 a1, sp +; CAHP-NEXT: sw s1, 0(a1) +; CAHP-NEXT: lui a1, 6 +; CAHP-NEXT: addi a1, a1, -108 +; CAHP-NEXT: add2 a1, sp +; CAHP-NEXT: sw s2, 0(a1) +; CAHP-NEXT: lui a1, 6 +; CAHP-NEXT: addi a1, a1, -110 +; CAHP-NEXT: add2 a1, sp +; CAHP-NEXT: sw s3, 0(a1) +; CAHP-NEXT: lui a1, 6 +; CAHP-NEXT: addi a1, a1, -112 +; CAHP-NEXT: add2 a1, sp +; CAHP-NEXT: sw s4, 0(a1) +; CAHP-NEXT: lui a1, 6 +; CAHP-NEXT: addi a1, a1, -98 +; CAHP-NEXT: add fp, sp, a1 +; CAHP-NEXT: lui a1, 58 +; CAHP-NEXT: addi a1, a1, 100 +; CAHP-NEXT: add2 a1, fp +; CAHP-NEXT: sw a0, 0(a1) +; CAHP-NEXT: lui a1, 2 +; CAHP-NEXT: addi a1, a1, -48 +; CAHP-NEXT: lui a0, 58 +; CAHP-NEXT: addi a0, a0, 128 +; CAHP-NEXT: add2 a0, fp +; CAHP-NEXT: addi a2, a0, 0 +; CAHP-NEXT: add a0, a2, a1 +; CAHP-NEXT: lui a1, 58 +; CAHP-NEXT: addi a1, a1, 98 +; CAHP-NEXT: add2 a1, fp +; CAHP-NEXT: sw a0, 0(a1) +; CAHP-NEXT: #APP +; CAHP-NEXT: nop +; CAHP-NEXT: #NO_APP +; CAHP-NEXT: sw a1, -16(fp) +; CAHP-NEXT: lui a1, 58 +; CAHP-NEXT: addi a1, a1, 102 +; CAHP-NEXT: add2 a1, fp +; CAHP-NEXT: sw a0, 0(a1) +; CAHP-NEXT: lw a1, -16(fp) +; CAHP-NEXT: lui a0, 58 +; CAHP-NEXT: addi a0, a0, 104 +; CAHP-NEXT: add2 a0, fp +; CAHP-NEXT: sw a1, 0(a0) +; CAHP-NEXT: lui a0, 58 +; CAHP-NEXT: addi a0, a0, 106 +; CAHP-NEXT: add2 a0, fp +; CAHP-NEXT: sw s4, 0(a0) +; CAHP-NEXT: lui a0, 58 +; CAHP-NEXT: addi a0, a0, 108 +; CAHP-NEXT: add2 a0, fp +; CAHP-NEXT: sw s3, 0(a0) +; CAHP-NEXT: lui a0, 58 +; CAHP-NEXT: addi a0, a0, 110 +; CAHP-NEXT: add2 a0, fp +; CAHP-NEXT: sw s2, 0(a0) +; CAHP-NEXT: lui a0, 58 +; CAHP-NEXT: addi a0, a0, 112 +; CAHP-NEXT: add2 a0, fp +; CAHP-NEXT: sw s1, 0(a0) +; CAHP-NEXT: lui a0, 58 +; CAHP-NEXT: addi a0, a0, 114 +; CAHP-NEXT: add2 a0, fp +; CAHP-NEXT: sw s0, 0(a0) +; CAHP-NEXT: lui a0, 58 +; CAHP-NEXT: addi a0, a0, 116 +; CAHP-NEXT: add2 a0, fp +; CAHP-NEXT: sw t1, 0(a0) +; CAHP-NEXT: lui a0, 58 +; CAHP-NEXT: addi a0, a0, 118 +; CAHP-NEXT: add2 a0, fp +; CAHP-NEXT: sw t0, 0(a0) +; CAHP-NEXT: lui a0, 58 +; CAHP-NEXT: addi a0, a0, 120 +; CAHP-NEXT: add2 a0, fp +; CAHP-NEXT: sw a5, 0(a0) +; CAHP-NEXT: lui a0, 58 +; CAHP-NEXT: addi a0, a0, 122 +; CAHP-NEXT: add2 a0, fp +; CAHP-NEXT: sw a4, 0(a0) +; CAHP-NEXT: lui a0, 58 +; CAHP-NEXT: addi a0, a0, 124 +; CAHP-NEXT: add2 a0, fp +; CAHP-NEXT: sw a3, 0(a0) +; CAHP-NEXT: lui a0, 58 +; CAHP-NEXT: addi a0, a0, 126 +; CAHP-NEXT: add2 a0, fp +; CAHP-NEXT: sw a2, 0(a0) +; CAHP-NEXT: lui a0, 58 +; CAHP-NEXT: addi a0, a0, 100 +; CAHP-NEXT: add2 a0, fp +; CAHP-NEXT: lw a0, 0(a0) +; CAHP-NEXT: lui a1, 58 +; CAHP-NEXT: addi a1, a1, 98 +; CAHP-NEXT: add2 a1, fp +; CAHP-NEXT: lw a1, 0(a1) +; CAHP-NEXT: sw a0, 0(a1) +; CAHP-NEXT: lui a0, 58 +; CAHP-NEXT: addi a0, a0, 126 +; CAHP-NEXT: add2 a0, fp +; CAHP-NEXT: lw a0, 0(a0) +; CAHP-NEXT: lui a1, 58 +; CAHP-NEXT: addi a1, a1, 124 +; CAHP-NEXT: add2 a1, fp +; CAHP-NEXT: lw a1, 0(a1) +; CAHP-NEXT: lui a2, 58 +; CAHP-NEXT: addi a2, a2, 122 +; CAHP-NEXT: add2 a2, fp +; CAHP-NEXT: lw a2, 0(a2) +; CAHP-NEXT: lui a3, 58 +; CAHP-NEXT: addi a3, a3, 120 +; CAHP-NEXT: add2 a3, fp +; CAHP-NEXT: lw a3, 0(a3) +; CAHP-NEXT: lui a4, 58 +; CAHP-NEXT: addi a4, a4, 118 +; CAHP-NEXT: add2 a4, fp +; CAHP-NEXT: lw a4, 0(a4) +; CAHP-NEXT: lui a5, 58 +; CAHP-NEXT: addi a5, a5, 116 +; CAHP-NEXT: add2 a5, fp +; CAHP-NEXT: lw a5, 0(a5) +; CAHP-NEXT: lui t0, 58 +; CAHP-NEXT: addi t0, t0, 114 +; CAHP-NEXT: add2 t0, fp +; CAHP-NEXT: lw t0, 0(t0) +; CAHP-NEXT: lui t1, 58 +; CAHP-NEXT: addi t1, t1, 112 +; CAHP-NEXT: add2 t1, fp +; CAHP-NEXT: lw t1, 0(t1) +; CAHP-NEXT: lui s0, 58 +; CAHP-NEXT: addi s0, s0, 110 +; CAHP-NEXT: add2 s0, fp +; CAHP-NEXT: lw s0, 0(s0) +; CAHP-NEXT: lui s1, 58 +; CAHP-NEXT: addi s1, s1, 108 +; CAHP-NEXT: add2 s1, fp +; CAHP-NEXT: lw s1, 0(s1) +; CAHP-NEXT: lui s2, 58 +; CAHP-NEXT: addi s2, s2, 106 +; CAHP-NEXT: add2 s2, fp +; CAHP-NEXT: lw s2, 0(s2) +; CAHP-NEXT: lui s3, 58 +; CAHP-NEXT: addi s3, s3, 104 +; CAHP-NEXT: add2 s3, fp +; CAHP-NEXT: lw s3, 0(s3) +; CAHP-NEXT: lui s4, 58 +; CAHP-NEXT: addi s4, s4, 102 +; CAHP-NEXT: add2 s4, fp +; CAHP-NEXT: lw s4, 0(s4) +; CAHP-NEXT: #APP +; CAHP-NEXT: nop +; CAHP-NEXT: #NO_APP +; CAHP-NEXT: lui a0, 6 +; CAHP-NEXT: addi a0, a0, -112 +; CAHP-NEXT: add2 a0, sp +; CAHP-NEXT: lw s4, 0(a0) +; CAHP-NEXT: lui a0, 6 +; CAHP-NEXT: addi a0, a0, -110 +; CAHP-NEXT: add2 a0, sp +; CAHP-NEXT: lw s3, 0(a0) +; CAHP-NEXT: lui a0, 6 +; CAHP-NEXT: addi a0, a0, -108 +; CAHP-NEXT: add2 a0, sp +; CAHP-NEXT: lw s2, 0(a0) +; CAHP-NEXT: lui a0, 6 +; CAHP-NEXT: addi a0, a0, -106 +; CAHP-NEXT: add2 a0, sp +; CAHP-NEXT: lw s1, 0(a0) +; CAHP-NEXT: lui a0, 6 +; CAHP-NEXT: addi a0, a0, -104 +; CAHP-NEXT: add2 a0, sp +; CAHP-NEXT: lw s0, 0(a0) +; CAHP-NEXT: lui a0, 6 +; CAHP-NEXT: addi a0, a0, -102 +; CAHP-NEXT: add2 a0, sp +; CAHP-NEXT: lw fp, 0(a0) +; CAHP-NEXT: lui a0, 6 +; CAHP-NEXT: addi a0, a0, -100 +; CAHP-NEXT: add2 a0, sp +; CAHP-NEXT: lw ra, 0(a0) +; CAHP-NEXT: lui a0, 6 +; CAHP-NEXT: addi a0, a0, -98 +; CAHP-NEXT: add2 sp, a0 +; CAHP-NEXT: jr ra + + %data = alloca [ 3000 x i16 ], align 2 + %ptr = getelementptr inbounds [3000 x i16], [3000 x i16]* %data, i16 0, i16 1000 + %1 = tail call { i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16 } asm sideeffect "nop", "=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r,=r"() + %asmresult0 = extractvalue { i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16 } %1, 0 + %asmresult1 = extractvalue { i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16 } %1, 1 + %asmresult2 = extractvalue { i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16 } %1, 2 + %asmresult3 = extractvalue { i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16 } %1, 3 + %asmresult4 = extractvalue { i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16 } %1, 4 + %asmresult5 = extractvalue { i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16 } %1, 5 + %asmresult6 = extractvalue { i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16 } %1, 6 + %asmresult7 = extractvalue { i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16 } %1, 7 + %asmresult8 = extractvalue { i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16 } %1, 8 + %asmresult9 = extractvalue { i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16 } %1, 9 + %asmresult10 = extractvalue { i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16 } %1, 10 + %asmresult11 = extractvalue { i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16 } %1, 11 + %asmresult12 = extractvalue { i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16 } %1, 12 + store volatile i16 %a, i16* %ptr + tail call void asm sideeffect "nop", "r,r,r,r,r,r,r,r,r,r,r,r,r"(i16 %asmresult0, i16 %asmresult1, i16 %asmresult2, i16 %asmresult3, i16 %asmresult4, i16 %asmresult5, i16 %asmresult6, i16 %asmresult7, i16 %asmresult8, i16 %asmresult9, i16 %asmresult10, i16 %asmresult11, i16 %asmresult12) + + ret void +} diff --git a/llvm/test/CodeGen/CAHP/lit.local.cfg b/llvm/test/CodeGen/CAHP/lit.local.cfg new file mode 100644 index 000000000000..519647fc4da4 --- /dev/null +++ b/llvm/test/CodeGen/CAHP/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'CAHP' in config.root.targets: + config.unsupported = True diff --git a/llvm/test/CodeGen/CAHP/mem.ll b/llvm/test/CodeGen/CAHP/mem.ll new file mode 100644 index 000000000000..2c460b410ad9 --- /dev/null +++ b/llvm/test/CodeGen/CAHP/mem.ll @@ -0,0 +1,140 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=CAHP + +; Check indexed and unindexed, sext, zext and anyext loads + +define i16 @lb(i8 *%a) nounwind { +; CAHP-LABEL: lb: +; CAHP: # %bb.0: +; CAHP-NEXT: lb a1, 1(a0) +; CAHP-NEXT: lb a0, 0(a0) +; CAHP-NEXT: mov a0, a1 +; CAHP-NEXT: jr ra + %1 = getelementptr i8, i8* %a, i16 1 + %2 = load i8, i8* %1 + %3 = sext i8 %2 to i16 + ; the unused load will produce an anyext for selection + %4 = load volatile i8, i8* %a + ret i16 %3 +} + +define i16 @lw(i16 *%a) nounwind { +; CAHP-LABEL: lw: +; CAHP: # %bb.0: +; CAHP-NEXT: lw a1, 6(a0) +; CAHP-NEXT: lw a0, 0(a0) +; CAHP-NEXT: mov a0, a1 +; CAHP-NEXT: jr ra + %1 = getelementptr i16, i16* %a, i16 3 + %2 = load i16, i16* %1 + %3 = load volatile i16, i16* %a + ret i16 %2 +} + +define i16 @lbu(i8 *%a) nounwind { +; CAHP-LABEL: lbu: +; CAHP: # %bb.0: +; CAHP-NEXT: lbu a1, 4(a0) +; CAHP-NEXT: lbu a0, 0(a0) +; CAHP-NEXT: add2 a0, a1 +; CAHP-NEXT: jr ra + %1 = getelementptr i8, i8* %a, i16 4 + %2 = load i8, i8* %1 + %3 = zext i8 %2 to i16 + %4 = load volatile i8, i8* %a + %5 = zext i8 %4 to i16 + %6 = add i16 %3, %5 + ret i16 %6 +} + +; Check indexed and unindexed stores + +define void @sb(i8 *%a, i8 %b) nounwind { +; CAHP-LABEL: sb: +; CAHP: # %bb.0: +; CAHP-NEXT: sb a1, 0(a0) +; CAHP-NEXT: sb a1, 6(a0) +; CAHP-NEXT: jr ra + store i8 %b, i8* %a + %1 = getelementptr i8, i8* %a, i16 6 + store i8 %b, i8* %1 + ret void +} + +define void @sw(i16 *%a, i16 %b) nounwind { +; CAHP-LABEL: sw: +; CAHP: # %bb.0: +; CAHP-NEXT: sw a1, 0(a0) +; CAHP-NEXT: sw a1, 16(a0) +; CAHP-NEXT: jr ra + store i16 %b, i16* %a + %1 = getelementptr i16, i16* %a, i16 8 + store i16 %b, i16* %1 + ret void +} + +; Check load and store to an i1 location +define i16 @load_sext_zext_anyext_i1(i1 *%a) nounwind { +; CAHP-LABEL: load_sext_zext_anyext_i1: +; CAHP: # %bb.0: +; CAHP-NEXT: lbu a1, 1(a0) +; CAHP-NEXT: lbu a2, 2(a0) +; CAHP-NEXT: lb a0, 0(a0) +; CAHP-NEXT: sub a0, a2, a1 +; CAHP-NEXT: jr ra + ; sextload i1 + %1 = getelementptr i1, i1* %a, i16 1 + %2 = load i1, i1* %1 + %3 = sext i1 %2 to i16 + ; zextload i1 + %4 = getelementptr i1, i1* %a, i16 2 + %5 = load i1, i1* %4 + %6 = zext i1 %5 to i16 + %7 = add i16 %3, %6 + ; extload i1 (anyext). Produced as the load is unused. + %8 = load volatile i1, i1* %a + ret i16 %7 +} + +; Ensure that 1 is added to the high 6 bits if bit 9 of the low part is 1 +define i16 @lw_sw_constant(i16 %a) nounwind { +; TODO: the addi should be folded in to the lw/sw +; CAHP-LABEL: lw_sw_constant: +; CAHP: # %bb.0: +; CAHP-NEXT: lui a1, 11 +; CAHP-NEXT: addi a2, a1, -139 +; CAHP-NEXT: lw a1, 0(a2) +; CAHP-NEXT: sw a0, 0(a2) +; CAHP-NEXT: mov a0, a1 +; CAHP-NEXT: jr ra + %1 = inttoptr i16 11125 to i16* + %2 = load volatile i16, i16* %1 + store i16 %a, i16* %1 + ret i16 %2 +} + +; Check load and store to a global +@G = global i16 0 + +define i16 @lw_sw_global(i16 %a) nounwind { +; CAHP-LABEL: lw_sw_global: +; CAHP: # %bb.0: +; CAHP-NEXT: lui a1, %hi(G) +; CAHP-NEXT: addi a2, a1, %lo(G) +; CAHP-NEXT: lw a1, 0(a2) +; CAHP-NEXT: sw a0, 0(a2) +; CAHP-NEXT: lui a2, %hi(G+18) +; CAHP-NEXT: addi a2, a2, %lo(G+18) +; CAHP-NEXT: lw a3, 0(a2) +; CAHP-NEXT: sw a0, 0(a2) +; CAHP-NEXT: mov a0, a1 +; CAHP-NEXT: jr ra + + %1 = load volatile i16, i16* @G + store i16 %a, i16* @G + %2 = getelementptr i16, i16* @G, i16 9 + %3 = load volatile i16, i16* %2 + store i16 %a, i16* %2 + ret i16 %1 +} diff --git a/llvm/test/CodeGen/CAHP/mul.ll b/llvm/test/CodeGen/CAHP/mul.ll new file mode 100644 index 000000000000..645d0f52e5f4 --- /dev/null +++ b/llvm/test/CodeGen/CAHP/mul.ll @@ -0,0 +1,81 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=CAHP + +define i16 @square(i16 %a) nounwind { +; CAHP-LABEL: square: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -2 +; CAHP-NEXT: swsp ra, 0(sp) +; CAHP-NEXT: mov a1, a0 +; CAHP-NEXT: jsal __mulhi3 +; CAHP-NEXT: lwsp ra, 0(sp) +; CAHP-NEXT: addi2 sp, 2 +; CAHP-NEXT: jr ra + %1 = mul i16 %a, %a + ret i16 %1 +} + +define i16 @mul(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: mul: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -2 +; CAHP-NEXT: swsp ra, 0(sp) +; CAHP-NEXT: jsal __mulhi3 +; CAHP-NEXT: lwsp ra, 0(sp) +; CAHP-NEXT: addi2 sp, 2 +; CAHP-NEXT: jr ra + %1 = mul i16 %a, %b + ret i16 %1 +} + +define i16 @mul_constant(i16 %a) nounwind { +; CAHP-LABEL: mul_constant: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -2 +; CAHP-NEXT: swsp ra, 0(sp) +; CAHP-NEXT: lsi a1, 5 +; CAHP-NEXT: jsal __mulhi3 +; CAHP-NEXT: lwsp ra, 0(sp) +; CAHP-NEXT: addi2 sp, 2 +; CAHP-NEXT: jr ra + %1 = mul i16 %a, 5 + ret i16 %1 +} + +define i16 @mul_pow2(i16 %a) nounwind { +; CAHP-LABEL: mul_pow2: +; CAHP: # %bb.0: +; CAHP-NEXT: lsli2 a0, 3 +; CAHP-NEXT: jr ra + %1 = mul i16 %a, 8 + ret i16 %1 +} + +define i32 @mul32(i32 %a, i32 %b) nounwind { +; CAHP-LABEL: mul32: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -2 +; CAHP-NEXT: swsp ra, 0(sp) +; CAHP-NEXT: jsal __mulsi3 +; CAHP-NEXT: lwsp ra, 0(sp) +; CAHP-NEXT: addi2 sp, 2 +; CAHP-NEXT: jr ra + %1 = mul i32 %a, %b + ret i32 %1 +} + +define i32 @mul32_constant(i32 %a) nounwind { +; CAHP-LABEL: mul32_constant: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -2 +; CAHP-NEXT: swsp ra, 0(sp) +; CAHP-NEXT: lsi a2, 5 +; CAHP-NEXT: lsi a3, 0 +; CAHP-NEXT: jsal __mulsi3 +; CAHP-NEXT: lwsp ra, 0(sp) +; CAHP-NEXT: addi2 sp, 2 +; CAHP-NEXT: jr ra + %1 = mul i32 %a, 5 + ret i32 %1 +} diff --git a/llvm/test/CodeGen/CAHP/rem.ll b/llvm/test/CodeGen/CAHP/rem.ll new file mode 100644 index 000000000000..f7c34b5f0712 --- /dev/null +++ b/llvm/test/CodeGen/CAHP/rem.ll @@ -0,0 +1,29 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=CAHP + +define i16 @urem(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: urem: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -2 +; CAHP-NEXT: swsp ra, 0(sp) +; CAHP-NEXT: jsal __umodhi3 +; CAHP-NEXT: lwsp ra, 0(sp) +; CAHP-NEXT: addi2 sp, 2 +; CAHP-NEXT: jr ra + %1 = urem i16 %a, %b + ret i16 %1 +} + +define i16 @srem(i16 %a, i16 %b) nounwind { +; CAHP-LABEL: srem: +; CAHP: # %bb.0: +; CAHP-NEXT: addi2 sp, -2 +; CAHP-NEXT: swsp ra, 0(sp) +; CAHP-NEXT: jsal __modhi3 +; CAHP-NEXT: lwsp ra, 0(sp) +; CAHP-NEXT: addi2 sp, 2 +; CAHP-NEXT: jr ra + %1 = srem i16 %a, %b + ret i16 %1 +} diff --git a/llvm/test/CodeGen/CAHP/select-cc.ll b/llvm/test/CodeGen/CAHP/select-cc.ll new file mode 100644 index 000000000000..811d5f715def --- /dev/null +++ b/llvm/test/CodeGen/CAHP/select-cc.ll @@ -0,0 +1,119 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=CAHP + +define i16 @foo(i16 %a, i16 *%b) { +; CAHP-LABEL: foo: +; CAHP: # %bb.0: +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: bne a0, a2, .LBB0_11 +; CAHP-NEXT:# %bb.1: +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: beq a0, a2, .LBB0_12 +; CAHP-NEXT:.LBB0_2: +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: bleu a0, a2, .LBB0_13 +; CAHP-NEXT:.LBB0_3: +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: bltu a0, a2, .LBB0_14 +; CAHP-NEXT:.LBB0_4: +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: bleu a2, a0, .LBB0_15 +; CAHP-NEXT:.LBB0_5: +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: bltu a2, a0, .LBB0_16 +; CAHP-NEXT:.LBB0_6: +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: ble a0, a2, .LBB0_17 +; CAHP-NEXT:.LBB0_7: +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: blt a0, a2, .LBB0_18 +; CAHP-NEXT:.LBB0_8: +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: ble a2, a0, .LBB0_19 +; CAHP-NEXT:.LBB0_9: +; CAHP-NEXT: lw a1, 0(a1) +; CAHP-NEXT: blt a1, a0, .LBB0_20 +; CAHP-NEXT:.LBB0_10: +; CAHP-NEXT: jr ra +; CAHP-NEXT:.LBB0_11: +; CAHP-NEXT: mov a0, a2 +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: bne a0, a2, .LBB0_2 +; CAHP-NEXT:.LBB0_12: +; CAHP-NEXT: mov a0, a2 +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: bltu a2, a0, .LBB0_3 +; CAHP-NEXT:.LBB0_13: +; CAHP-NEXT: mov a0, a2 +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: bleu a2, a0, .LBB0_4 +; CAHP-NEXT:.LBB0_14: +; CAHP-NEXT: mov a0, a2 +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: bltu a0, a2, .LBB0_5 +; CAHP-NEXT:.LBB0_15: +; CAHP-NEXT: mov a0, a2 +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: bleu a0, a2, .LBB0_6 +; CAHP-NEXT:.LBB0_16: +; CAHP-NEXT: mov a0, a2 +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: blt a2, a0, .LBB0_7 +; CAHP-NEXT:.LBB0_17: +; CAHP-NEXT: mov a0, a2 +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: ble a2, a0, .LBB0_8 +; CAHP-NEXT:.LBB0_18: +; CAHP-NEXT: mov a0, a2 +; CAHP-NEXT: lw a2, 0(a1) +; CAHP-NEXT: blt a0, a2, .LBB0_9 +; CAHP-NEXT:.LBB0_19: +; CAHP-NEXT: mov a0, a2 +; CAHP-NEXT: lw a1, 0(a1) +; CAHP-NEXT: ble a0, a1, .LBB0_10 +; CAHP-NEXT:.LBB0_20: +; CAHP-NEXT: mov a0, a1 +; CAHP-NEXT: jr ra + %val1 = load volatile i16, i16* %b + %tst1 = icmp eq i16 %a, %val1 + %val2 = select i1 %tst1, i16 %a, i16 %val1 + + %val3 = load volatile i16, i16* %b + %tst2 = icmp ne i16 %val2, %val3 + %val4 = select i1 %tst2, i16 %val2, i16 %val3 + + %val5 = load volatile i16, i16* %b + %tst3 = icmp ugt i16 %val4, %val5 + %val6 = select i1 %tst3, i16 %val4, i16 %val5 + + %val7 = load volatile i16, i16* %b + %tst4 = icmp uge i16 %val6, %val7 + %val8 = select i1 %tst4, i16 %val6, i16 %val7 + + %val9 = load volatile i16, i16* %b + %tst5 = icmp ult i16 %val8, %val9 + %val10 = select i1 %tst5, i16 %val8, i16 %val9 + + %val11 = load volatile i16, i16* %b + %tst6 = icmp ule i16 %val10, %val11 + %val12 = select i1 %tst6, i16 %val10, i16 %val11 + + %val13 = load volatile i16, i16* %b + %tst7 = icmp sgt i16 %val12, %val13 + %val14 = select i1 %tst7, i16 %val12, i16 %val13 + + %val15 = load volatile i16, i16* %b + %tst8 = icmp sge i16 %val14, %val15 + %val16 = select i1 %tst8, i16 %val14, i16 %val15 + + %val17 = load volatile i16, i16* %b + %tst9 = icmp slt i16 %val16, %val17 + %val18 = select i1 %tst9, i16 %val16, i16 %val17 + + %val19 = load volatile i16, i16* %b + %tst10 = icmp sle i16 %val18, %val19 + %val20 = select i1 %tst10, i16 %val18, i16 %val19 + + ret i16 %val20 +} diff --git a/llvm/test/CodeGen/CAHP/sext-zext-trunc.ll b/llvm/test/CodeGen/CAHP/sext-zext-trunc.ll new file mode 100644 index 000000000000..eea9f5d4ab33 --- /dev/null +++ b/llvm/test/CodeGen/CAHP/sext-zext-trunc.ll @@ -0,0 +1,180 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=CAHP + +; FIXME: an unncessary register is allocated just to store 0. X0 should be +; used instead + +define i8 @sext_i1_to_i8(i1 %a) { +; TODO: the addi that stores 0 in t1 is unnecessary +; CAHP-LABEL: sext_i1_to_i8: +; CAHP: # %bb.0: +; CAHP-NEXT: andi2 a0, 1 +; CAHP-NEXT: lsi a1, 0 +; CAHP-NEXT: sub a0, a1, a0 +; CAHP-NEXT: jr ra + %1 = sext i1 %a to i8 + ret i8 %1 +} + +define i16 @sext_i1_to_i16(i1 %a) { +; TODO: the addi that stores 0 in t1 is unnecessary +; CAHP-LABEL: sext_i1_to_i16: +; CAHP: # %bb.0: +; CAHP-NEXT: andi2 a0, 1 +; CAHP-NEXT: lsi a1, 0 +; CAHP-NEXT: sub a0, a1, a0 +; CAHP-NEXT: jr ra + %1 = sext i1 %a to i16 + ret i16 %1 +} + +define i32 @sext_i1_to_i32(i1 %a) { +; TODO: the addi that stores 0 in t1 is unnecessary +; CAHP-LABEL: sext_i1_to_i32: +; CAHP: # %bb.0: +; CAHP-NEXT: andi2 a0, 1 +; CAHP-NEXT: lsi a1, 0 +; CAHP-NEXT: sub a0, a1, a0 +; CAHP-NEXT: mov a1, a0 +; CAHP-NEXT: jr ra + %1 = sext i1 %a to i32 + ret i32 %1 +} + +define i16 @sext_i8_to_i16(i8 %a) { +; CAHP-LABEL: sext_i8_to_i16: +; CAHP: # %bb.0: +; CAHP-NEXT: lsli2 a0, 8 +; CAHP-NEXT: asri2 a0, 8 +; CAHP-NEXT: jr ra + %1 = sext i8 %a to i16 + ret i16 %1 +} + +define i32 @sext_i8_to_i32(i8 %a) { +; CAHP-LABEL: sext_i8_to_i32: +; CAHP: # %bb.0: +; CAHP-NEXT: lsli a1, a0, 8 +; CAHP-NEXT: asri a0, a1, 8 +; CAHP-NEXT: asri2 a1, 15 +; CAHP-NEXT: jr ra + %1 = sext i8 %a to i32 + ret i32 %1 +} + +define i32 @sext_i16_to_i32(i16 %a) { +; CAHP-LABEL: sext_i16_to_i32: +; CAHP: # %bb.0: +; CAHP-NEXT: asri a1, a0, 15 +; CAHP-NEXT: jr ra + %1 = sext i16 %a to i32 + ret i32 %1 +} + +define i8 @zext_i1_to_i8(i1 %a) { +; CAHP-LABEL: zext_i1_to_i8: +; CAHP: # %bb.0: +; CAHP-NEXT: andi2 a0, 1 +; CAHP-NEXT: jr ra + %1 = zext i1 %a to i8 + ret i8 %1 +} + +define i16 @zext_i1_to_i16(i1 %a) { +; CAHP-LABEL: zext_i1_to_i16: +; CAHP: # %bb.0: +; CAHP-NEXT: andi2 a0, 1 +; CAHP-NEXT: jr ra + %1 = zext i1 %a to i16 + ret i16 %1 +} + +define i32 @zext_i1_to_i32(i1 %a) { +; CAHP-LABEL: zext_i1_to_i32: +; CAHP: # %bb.0: +; CAHP-NEXT: andi2 a0, 1 +; CAHP-NEXT: lsi a1, 0 +; CAHP-NEXT: jr ra + %1 = zext i1 %a to i32 + ret i32 %1 +} + +define i16 @zext_i8_to_i16(i8 %a) { +; CAHP-LABEL: zext_i8_to_i16: +; CAHP: # %bb.0: +; CAHP-NEXT: andi a0, a0, 255 +; CAHP-NEXT: jr ra + %1 = zext i8 %a to i16 + ret i16 %1 +} + +define i32 @zext_i8_to_i32(i8 %a) { +; CAHP-LABEL: zext_i8_to_i32: +; CAHP: # %bb.0: +; CAHP-NEXT: andi a0, a0, 255 +; CAHP-NEXT: lsi a1, 0 +; CAHP-NEXT: jr ra + %1 = zext i8 %a to i32 + ret i32 %1 +} + +define i32 @zext_i16_to_i32(i16 %a) { +; CAHP-LABEL: zext_i16_to_i32: +; CAHP: # %bb.0: +; CAHP-NEXT: lsi a1, 0 +; CAHP-NEXT: jr ra + %1 = zext i16 %a to i32 + ret i32 %1 +} + +; TODO: should the trunc tests explicitly ensure no code is generated before +; jalr? + +define i1 @trunc_i8_to_i1(i8 %a) { +; CAHP-LABEL: trunc_i8_to_i1: +; CAHP: # %bb.0: +; CAHP-NEXT: jr ra + %1 = trunc i8 %a to i1 + ret i1 %1 +} + +define i1 @trunc_i16_to_i1(i16 %a) { +; CAHP-LABEL: trunc_i16_to_i1: +; CAHP: # %bb.0: +; CAHP-NEXT: jr ra + %1 = trunc i16 %a to i1 + ret i1 %1 +} + +define i1 @trunc_i32_to_i1(i32 %a) { +; CAHP-LABEL: trunc_i32_to_i1: +; CAHP: # %bb.0: +; CAHP-NEXT: jr ra + %1 = trunc i32 %a to i1 + ret i1 %1 +} + +define i8 @trunc_i16_to_i8(i16 %a) { +; CAHP-LABEL: trunc_i16_to_i8: +; CAHP: # %bb.0: +; CAHP-NEXT: jr ra + %1 = trunc i16 %a to i8 + ret i8 %1 +} + +define i8 @trunc_i32_to_i8(i32 %a) { +; CAHP-LABEL: trunc_i32_to_i8: +; CAHP: # %bb.0: +; CAHP-NEXT: jr ra + %1 = trunc i32 %a to i8 + ret i8 %1 +} + +define i16 @trunc_i32_to_i16(i32 %a) { +; CAHP-LABEL: trunc_i32_to_i16: +; CAHP: # %bb.0: +; CAHP-NEXT: jr ra + %1 = trunc i32 %a to i16 + ret i16 %1 +} diff --git a/llvm/test/CodeGen/CAHP/wide-mem.ll b/llvm/test/CodeGen/CAHP/wide-mem.ll new file mode 100644 index 000000000000..56304ef93ac6 --- /dev/null +++ b/llvm/test/CodeGen/CAHP/wide-mem.ll @@ -0,0 +1,35 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=cahp -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=CAHP + +; Check load/store operations on values wider than what is natively supported + +define i32 @load_i32(i32 *%a) nounwind { +; CAHP-LABEL: load_i32: +; CAHP: # %bb.0: +; CAHP-NEXT: lw a2, 0(a0) +; CAHP-NEXT: lw a1, 2(a0) +; CAHP-NEXT: mov a0, a2 +; CAHP-NEXT: jr ra + %1 = load i32, i32* %a + ret i32 %1 +} + +@val32 = local_unnamed_addr global i32 2863311, align 8 + +; TODO: codegen on this should be improved. It shouldn't be necessary to +; generate two addi +define i32 @load_i32_global() nounwind { +; CAHP-LABEL: load_i32_global: +; CAHP: # %bb.0: +; CAHP-NEXT: lui a0, %hi(val32) +; CAHP-NEXT: addi a0, a0, %lo(val32) +; CAHP-NEXT: lw a0, 0(a0) +; CAHP-NEXT: lui a1, %hi(val32+2) +; CAHP-NEXT: addi a1, a1, %lo(val32+2) +; CAHP-NEXT: lw a1, 0(a1) +; CAHP-NEXT: jr ra + + %1 = load i32, i32* @val32 + ret i32 %1 +} diff --git a/llvm/test/CodeGen/Hexagon/pic-jt-big.ll b/llvm/test/CodeGen/Hexagon/pic-jt-big.ll index f5b4c2df52c8..25ee04521b64 100644 --- a/llvm/test/CodeGen/Hexagon/pic-jt-big.ll +++ b/llvm/test/CodeGen/Hexagon/pic-jt-big.ll @@ -1,4 +1,4 @@ -; RUN: llc -march=hexagon -relocation-model=pic < %s | FileCheck %s +; RUN: llc -mtriple=hexagon-unknown-elf -relocation-model=pic < %s | FileCheck %s ; CHECK: r{{[0-9]+}} = add({{pc|PC}},##.LJTI{{[0-9_]+}}@PCREL) ; CHECK: r{{[0-9]+}} = memw(r{{[0-9]}}+##g0@GOT diff --git a/llvm/test/CodeGen/Hexagon/pic-sdata.ll b/llvm/test/CodeGen/Hexagon/pic-sdata.ll index 3e4dc2dc93e9..446734b9ca01 100644 --- a/llvm/test/CodeGen/Hexagon/pic-sdata.ll +++ b/llvm/test/CodeGen/Hexagon/pic-sdata.ll @@ -1,5 +1,5 @@ -; RUN: llc -march=hexagon -hexagon-small-data-threshold=8 -relocation-model=static < %s | FileCheck --check-prefixes=CHECK,STATIC %s -; RUN: llc -march=hexagon -hexagon-small-data-threshold=8 -relocation-model=pic < %s | FileCheck --check-prefixes=CHECK,PIC %s +; RUN: llc -mtriple=hexagon-unknown-elf -hexagon-small-data-threshold=8 -relocation-model=static < %s | FileCheck --check-prefixes=CHECK,STATIC %s +; RUN: llc -mtriple=hexagon-unknown-elf -hexagon-small-data-threshold=8 -relocation-model=pic < %s | FileCheck --check-prefixes=CHECK,PIC %s ; If a global has a specified section, it should probably be placed in that ; section, but with PIC any accesses to globals in small data should still diff --git a/llvm/test/CodeGen/PowerPC/machine-pre.ll b/llvm/test/CodeGen/PowerPC/machine-pre.ll index 39dd3c53bf7a..596c0a4624c4 100644 --- a/llvm/test/CodeGen/PowerPC/machine-pre.ll +++ b/llvm/test/CodeGen/PowerPC/machine-pre.ll @@ -8,25 +8,25 @@ define i32 @t(i32 %n, i32 %delta, i32 %a) { ; CHECK-P9: # %bb.0: # %entry ; CHECK-P9-NEXT: lis r7, 0 ; CHECK-P9-NEXT: li r6, 0 +; CHECK-P9-NEXT: li r8, 0 ; CHECK-P9-NEXT: li r9, 0 -; CHECK-P9-NEXT: li r10, 0 ; CHECK-P9-NEXT: ori r7, r7, 65535 ; CHECK-P9-NEXT: .p2align 5 ; CHECK-P9-NEXT: .LBB0_1: # %header ; CHECK-P9-NEXT: # -; CHECK-P9-NEXT: addi r10, r10, 1 -; CHECK-P9-NEXT: cmpw r10, r3 -; CHECK-P9-NEXT: addi r8, r5, 1024 +; CHECK-P9-NEXT: addi r9, r9, 1 +; CHECK-P9-NEXT: cmpw r9, r3 ; CHECK-P9-NEXT: blt cr0, .LBB0_4 ; CHECK-P9-NEXT: # %bb.2: # %cont ; CHECK-P9-NEXT: # -; CHECK-P9-NEXT: add r9, r9, r4 -; CHECK-P9-NEXT: cmpw r9, r7 +; CHECK-P9-NEXT: add r8, r8, r4 +; CHECK-P9-NEXT: cmpw r8, r7 ; CHECK-P9-NEXT: bgt cr0, .LBB0_1 ; CHECK-P9-NEXT: # %bb.3: # %cont.1 -; CHECK-P9-NEXT: mr r6, r8 +; CHECK-P9-NEXT: addi r6, r5, 1024 ; CHECK-P9-NEXT: .LBB0_4: # %return -; CHECK-P9-NEXT: mullw r3, r6, r8 +; CHECK-P9-NEXT: addi r3, r5, 1024 +; CHECK-P9-NEXT: mullw r3, r6, r3 ; CHECK-P9-NEXT: blr entry: br label %header @@ -75,16 +75,19 @@ define dso_local signext i32 @foo(i32 signext %x, i32 signext %y) local_unnamed_ ; CHECK-P9-NEXT: lis r3, 21845 ; CHECK-P9-NEXT: add r28, r30, r29 ; CHECK-P9-NEXT: ori r27, r3, 21846 -; CHECK-P9-NEXT: b .LBB1_3 +; CHECK-P9-NEXT: b .LBB1_4 ; CHECK-P9-NEXT: .p2align 4 ; CHECK-P9-NEXT: .LBB1_1: # %sw.bb3 ; CHECK-P9-NEXT: # -; CHECK-P9-NEXT: add r28, r3, r28 +; CHECK-P9-NEXT: mulli r3, r30, 23 ; CHECK-P9-NEXT: .LBB1_2: # %sw.epilog ; CHECK-P9-NEXT: # +; CHECK-P9-NEXT: add r28, r3, r28 +; CHECK-P9-NEXT: .LBB1_3: # %sw.epilog +; CHECK-P9-NEXT: # ; CHECK-P9-NEXT: cmpwi r28, 1025 -; CHECK-P9-NEXT: bge cr0, .LBB1_6 -; CHECK-P9-NEXT: .LBB1_3: # %while.cond +; CHECK-P9-NEXT: bge cr0, .LBB1_7 +; CHECK-P9-NEXT: .LBB1_4: # %while.cond ; CHECK-P9-NEXT: # ; CHECK-P9-NEXT: extsw r3, r29 ; CHECK-P9-NEXT: bl bar @@ -101,41 +104,40 @@ define dso_local signext i32 @foo(i32 signext %x, i32 signext %y) local_unnamed_ ; CHECK-P9-NEXT: add r4, r4, r5 ; CHECK-P9-NEXT: slwi r5, r4, 1 ; CHECK-P9-NEXT: add r4, r4, r5 -; CHECK-P9-NEXT: subf r5, r4, r3 -; CHECK-P9-NEXT: mulli r4, r29, 13 -; CHECK-P9-NEXT: mulli r3, r30, 23 -; CHECK-P9-NEXT: cmplwi r5, 1 +; CHECK-P9-NEXT: subf r3, r4, r3 +; CHECK-P9-NEXT: cmplwi r3, 1 ; CHECK-P9-NEXT: beq cr0, .LBB1_1 -; CHECK-P9-NEXT: # %bb.4: # %while.cond +; CHECK-P9-NEXT: # %bb.5: # %while.cond ; CHECK-P9-NEXT: # -; CHECK-P9-NEXT: cmplwi r5, 0 -; CHECK-P9-NEXT: bne cr0, .LBB1_2 -; CHECK-P9-NEXT: # %bb.5: # %sw.bb +; CHECK-P9-NEXT: cmplwi r3, 0 +; CHECK-P9-NEXT: bne cr0, .LBB1_3 +; CHECK-P9-NEXT: # %bb.6: # %sw.bb ; CHECK-P9-NEXT: # -; CHECK-P9-NEXT: add r28, r4, r28 -; CHECK-P9-NEXT: cmpwi r28, 1025 -; CHECK-P9-NEXT: blt cr0, .LBB1_3 -; CHECK-P9-NEXT: .LBB1_6: # %while.end -; CHECK-P9-NEXT: lis r5, -13108 -; CHECK-P9-NEXT: ori r5, r5, 52429 -; CHECK-P9-NEXT: mullw r5, r28, r5 -; CHECK-P9-NEXT: lis r6, 13107 -; CHECK-P9-NEXT: ori r6, r6, 13108 -; CHECK-P9-NEXT: cmplw r5, r6 -; CHECK-P9-NEXT: blt cr0, .LBB1_8 -; CHECK-P9-NEXT: # %bb.7: # %if.then8 -; CHECK-P9-NEXT: extsw r4, r4 -; CHECK-P9-NEXT: extsw r5, r28 +; CHECK-P9-NEXT: mulli r3, r29, 13 +; CHECK-P9-NEXT: b .LBB1_2 +; CHECK-P9-NEXT: .LBB1_7: # %while.end +; CHECK-P9-NEXT: lis r3, -13108 +; CHECK-P9-NEXT: ori r3, r3, 52429 +; CHECK-P9-NEXT: mullw r3, r28, r3 +; CHECK-P9-NEXT: lis r4, 13107 +; CHECK-P9-NEXT: ori r4, r4, 13108 +; CHECK-P9-NEXT: cmplw r3, r4 +; CHECK-P9-NEXT: blt cr0, .LBB1_9 +; CHECK-P9-NEXT: # %bb.8: # %if.then8 +; CHECK-P9-NEXT: mulli r3, r29, 13 +; CHECK-P9-NEXT: mulli r5, r30, 23 +; CHECK-P9-NEXT: extsw r4, r28 ; CHECK-P9-NEXT: extsw r3, r3 +; CHECK-P9-NEXT: extsw r5, r5 +; CHECK-P9-NEXT: sub r3, r4, r3 ; CHECK-P9-NEXT: sub r4, r5, r4 -; CHECK-P9-NEXT: sub r3, r3, r5 -; CHECK-P9-NEXT: rldicl r4, r4, 1, 63 ; CHECK-P9-NEXT: rldicl r3, r3, 1, 63 -; CHECK-P9-NEXT: or r3, r4, r3 -; CHECK-P9-NEXT: b .LBB1_9 -; CHECK-P9-NEXT: .LBB1_8: # %cleanup20 -; CHECK-P9-NEXT: li r3, 0 +; CHECK-P9-NEXT: rldicl r4, r4, 1, 63 +; CHECK-P9-NEXT: or r3, r3, r4 +; CHECK-P9-NEXT: b .LBB1_10 ; CHECK-P9-NEXT: .LBB1_9: # %cleanup20 +; CHECK-P9-NEXT: li r3, 0 +; CHECK-P9-NEXT: .LBB1_10: # %cleanup20 ; CHECK-P9-NEXT: addi r1, r1, 80 ; CHECK-P9-NEXT: ld r0, 16(r1) ; CHECK-P9-NEXT: mtlr r0 diff --git a/llvm/test/CodeGen/PowerPC/tls.ll b/llvm/test/CodeGen/PowerPC/tls.ll index 6a0ab6956422..1d6b22e3f8f6 100644 --- a/llvm/test/CodeGen/PowerPC/tls.ll +++ b/llvm/test/CodeGen/PowerPC/tls.ll @@ -43,7 +43,7 @@ entry: ;OPT0-PPC32-LABEL: main2: ;OPT0-PPC32: li [[REG1:[0-9]+]], _GLOBAL_OFFSET_TABLE_@l ;OPT0-PPC32: addis [[REG1]], [[REG1]], _GLOBAL_OFFSET_TABLE_@ha -;OPT0-PPC32: lwz [[REG2:[0-9]+]], a2@got@tprel@l([[REG1]]) +;OPT0-PPC32: lwz [[REG2:[0-9]+]], a2@got@tprel([[REG1]]) ;OPT0-PPC32: add 3, [[REG2]], a2@tls ;OPT0-PPC32-PIC-LABEL: main2: @@ -51,4 +51,4 @@ entry: ;OPT0-PPC32-PIC-NOT: li {{[0-9]+}}, _GLOBAL_OFFSET_TABLE_@l ;OPT0-PPC32-PIC-NOT: addis {{[0-9]+}}, {{[0-9+]}}, _GLOBAL_OFFSET_TABLE_@ha ;OPT0-PPC32-PIC-NOT: bl __tls_get_addr(a2@tlsgd)@PLT -;OPT0-PPC32-PIC: lwz {{[0-9]+}}, a2@got@tprel@l({{[0-9]+}}) +;OPT0-PPC32-PIC: lwz {{[0-9]+}}, a2@got@tprel({{[0-9]+}}) diff --git a/llvm/test/CodeGen/RISCV/add-before-shl.ll b/llvm/test/CodeGen/RISCV/add-before-shl.ll index 05bcc191b6cb..3279de3ea99b 100644 --- a/llvm/test/CodeGen/RISCV/add-before-shl.ll +++ b/llvm/test/CodeGen/RISCV/add-before-shl.ll @@ -91,3 +91,43 @@ define signext i24 @add_non_machine_type(i24 signext %a) nounwind { %2 = shl i24 %1, 12 ret i24 %2 } + +define i128 @add_wide_operand(i128 %a) nounwind { +; RV32I-LABEL: add_wide_operand: +; RV32I: # %bb.0: +; RV32I-NEXT: lw a2, 0(a1) +; RV32I-NEXT: srli a3, a2, 29 +; RV32I-NEXT: lw a4, 4(a1) +; RV32I-NEXT: slli a5, a4, 3 +; RV32I-NEXT: or a6, a5, a3 +; RV32I-NEXT: srli a4, a4, 29 +; RV32I-NEXT: lw a5, 8(a1) +; RV32I-NEXT: slli a3, a5, 3 +; RV32I-NEXT: or a3, a3, a4 +; RV32I-NEXT: slli a2, a2, 3 +; RV32I-NEXT: sw a2, 0(a0) +; RV32I-NEXT: sw a3, 8(a0) +; RV32I-NEXT: sw a6, 4(a0) +; RV32I-NEXT: srli a2, a5, 29 +; RV32I-NEXT: lw a1, 12(a1) +; RV32I-NEXT: slli a1, a1, 3 +; RV32I-NEXT: or a1, a1, a2 +; RV32I-NEXT: lui a2, 128 +; RV32I-NEXT: add a1, a1, a2 +; RV32I-NEXT: sw a1, 12(a0) +; RV32I-NEXT: ret +; +; RV64I-LABEL: add_wide_operand: +; RV64I: # %bb.0: +; RV64I-NEXT: slli a1, a1, 3 +; RV64I-NEXT: srli a2, a0, 61 +; RV64I-NEXT: or a1, a1, a2 +; RV64I-NEXT: addi a2, zero, 1 +; RV64I-NEXT: slli a2, a2, 51 +; RV64I-NEXT: add a1, a1, a2 +; RV64I-NEXT: slli a0, a0, 3 +; RV64I-NEXT: ret + %1 = add i128 %a, 5192296858534827628530496329220096 + %2 = shl i128 %1, 3 + ret i128 %2 +} diff --git a/llvm/test/CodeGen/RISCV/inline-asm-d-constraint-f.ll b/llvm/test/CodeGen/RISCV/inline-asm-d-constraint-f.ll new file mode 100644 index 000000000000..251c06343805 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/inline-asm-d-constraint-f.ll @@ -0,0 +1,40 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32F %s +; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV64F %s + +@gd = external global double + +define double @constraint_f_double(double %a) nounwind { +; RV32F-LABEL: constraint_f_double: +; RV32F: # %bb.0: +; RV32F-NEXT: addi sp, sp, -16 +; RV32F-NEXT: sw a0, 8(sp) +; RV32F-NEXT: sw a1, 12(sp) +; RV32F-NEXT: fld ft0, 8(sp) +; RV32F-NEXT: lui a0, %hi(gd) +; RV32F-NEXT: fld ft1, %lo(gd)(a0) +; RV32F-NEXT: #APP +; RV32F-NEXT: fadd.d ft0, ft0, ft1 +; RV32F-NEXT: #NO_APP +; RV32F-NEXT: fsd ft0, 8(sp) +; RV32F-NEXT: lw a0, 8(sp) +; RV32F-NEXT: lw a1, 12(sp) +; RV32F-NEXT: addi sp, sp, 16 +; RV32F-NEXT: ret +; +; RV64F-LABEL: constraint_f_double: +; RV64F: # %bb.0: +; RV64F-NEXT: fmv.d.x ft0, a0 +; RV64F-NEXT: lui a0, %hi(gd) +; RV64F-NEXT: fld ft1, %lo(gd)(a0) +; RV64F-NEXT: #APP +; RV64F-NEXT: fadd.d ft0, ft0, ft1 +; RV64F-NEXT: #NO_APP +; RV64F-NEXT: fmv.x.d a0, ft0 +; RV64F-NEXT: ret + %1 = load double, double* @gd + %2 = tail call double asm "fadd.d $0, $1, $2", "=f,f,f"(double %a, double %1) + ret double %2 +} diff --git a/llvm/test/CodeGen/RISCV/inline-asm-f-constraint-f.ll b/llvm/test/CodeGen/RISCV/inline-asm-f-constraint-f.ll new file mode 100644 index 000000000000..e342789ca7cf --- /dev/null +++ b/llvm/test/CodeGen/RISCV/inline-asm-f-constraint-f.ll @@ -0,0 +1,34 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -mattr=+f -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32F %s +; RUN: llc -mtriple=riscv64 -mattr=+f -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV64F %s + +@gf = external global float + +define float @constraint_f_float(float %a) nounwind { +; RV32F-LABEL: constraint_f_float: +; RV32F: # %bb.0: +; RV32F-NEXT: fmv.w.x ft0, a0 +; RV32F-NEXT: lui a0, %hi(gf) +; RV32F-NEXT: flw ft1, %lo(gf)(a0) +; RV32F-NEXT: #APP +; RV32F-NEXT: fadd.s ft0, ft0, ft1 +; RV32F-NEXT: #NO_APP +; RV32F-NEXT: fmv.x.w a0, ft0 +; RV32F-NEXT: ret +; +; RV64F-LABEL: constraint_f_float: +; RV64F: # %bb.0: +; RV64F-NEXT: fmv.w.x ft0, a0 +; RV64F-NEXT: lui a0, %hi(gf) +; RV64F-NEXT: flw ft1, %lo(gf)(a0) +; RV64F-NEXT: #APP +; RV64F-NEXT: fadd.s ft0, ft0, ft1 +; RV64F-NEXT: #NO_APP +; RV64F-NEXT: fmv.x.w a0, ft0 +; RV64F-NEXT: ret + %1 = load float, float* @gf + %2 = tail call float asm "fadd.s $0, $1, $2", "=f,f,f"(float %a, float %1) + ret float %2 +} diff --git a/llvm/test/CodeGen/RISCV/inline-asm-invalid.ll b/llvm/test/CodeGen/RISCV/inline-asm-invalid.ll index ee9c04322a52..20ac5ef11111 100644 --- a/llvm/test/CodeGen/RISCV/inline-asm-invalid.ll +++ b/llvm/test/CodeGen/RISCV/inline-asm-invalid.ll @@ -2,23 +2,31 @@ ; RUN: not llc -mtriple=riscv64 < %s 2>&1 | FileCheck %s define void @constraint_I() { -; CHECK: error: invalid operand for inline asm constraint 'I' +; CHECK: error: value out of range for constraint 'I' tail call void asm sideeffect "addi a0, a0, $0", "I"(i32 2048) -; CHECK: error: invalid operand for inline asm constraint 'I' +; CHECK: error: value out of range for constraint 'I' tail call void asm sideeffect "addi a0, a0, $0", "I"(i32 -2049) ret void } define void @constraint_J() { -; CHECK: error: invalid operand for inline asm constraint 'J' +; CHECK: error: value out of range for constraint 'J' tail call void asm sideeffect "addi a0, a0, $0", "J"(i32 1) ret void } define void @constraint_K() { -; CHECK: error: invalid operand for inline asm constraint 'K' +; CHECK: error: value out of range for constraint 'K' tail call void asm sideeffect "csrwi mstatus, $0", "K"(i32 32) -; CHECK: error: invalid operand for inline asm constraint 'K' +; CHECK: error: value out of range for constraint 'K' tail call void asm sideeffect "csrwi mstatus, $0", "K"(i32 -1) ret void } + +define void @constraint_f() nounwind { +; CHECK: error: couldn't allocate input reg for constraint 'f' + tail call void asm "fadd.s fa0, fa0, $0", "f"(float 0.0) +; CHECK: error: couldn't allocate input reg for constraint 'f' + tail call void asm "fadd.d fa0, fa0, $0", "f"(double 0.0) + ret void +} diff --git a/llvm/test/CodeGen/RISCV/inline-asm.ll b/llvm/test/CodeGen/RISCV/inline-asm.ll index 10f8a3452aba..394033602154 100644 --- a/llvm/test/CodeGen/RISCV/inline-asm.ll +++ b/llvm/test/CodeGen/RISCV/inline-asm.ll @@ -150,6 +150,31 @@ define void @constraint_K() nounwind { ret void } +define void @constraint_A(i8* %a) nounwind { +; RV32I-LABEL: constraint_A: +; RV32I: # %bb.0: +; RV32I-NEXT: #APP +; RV32I-NEXT: sb s0, 0(a0) +; RV32I-NEXT: #NO_APP +; RV32I-NEXT: #APP +; RV32I-NEXT: lb s1, 0(a0) +; RV32I-NEXT: #NO_APP +; RV32I-NEXT: ret +; +; RV64I-LABEL: constraint_A: +; RV64I: # %bb.0: +; RV64I-NEXT: #APP +; RV64I-NEXT: sb s0, 0(a0) +; RV64I-NEXT: #NO_APP +; RV64I-NEXT: #APP +; RV64I-NEXT: lb s1, 0(a0) +; RV64I-NEXT: #NO_APP +; RV64I-NEXT: ret + tail call void asm sideeffect "sb s0, $0", "*A"(i8* %a) + tail call void asm sideeffect "lb s1, $0", "*A"(i8* %a) + ret void +} + define i32 @modifier_z_zero(i32 %a) nounwind { ; RV32I-LABEL: modifier_z_zero: ; RV32I: # %bb.0: diff --git a/llvm/test/CodeGen/RISCV/stack-realignment-unsupported.ll b/llvm/test/CodeGen/RISCV/stack-realignment-unsupported.ll new file mode 100644 index 000000000000..f2f11b073cfb --- /dev/null +++ b/llvm/test/CodeGen/RISCV/stack-realignment-unsupported.ll @@ -0,0 +1,13 @@ +; RUN: not llc -mtriple=riscv32 < %s 2>&1 | FileCheck %s +; RUN: not llc -mtriple=riscv64 < %s 2>&1 | FileCheck %s + +; CHECK: LLVM ERROR: RISC-V backend can't currently handle functions that need stack realignment and have variable sized objects + +declare void @callee(i8*, i32*) + +define void @caller(i32 %n) nounwind { + %1 = alloca i8, i32 %n + %2 = alloca i32, align 64 + call void @callee(i8* %1, i32 *%2) + ret void +} diff --git a/llvm/test/CodeGen/RISCV/stack-realignment.ll b/llvm/test/CodeGen/RISCV/stack-realignment.ll new file mode 100644 index 000000000000..252a099d0986 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/stack-realignment.ll @@ -0,0 +1,627 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I +; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \ +; RUN: | FileCheck %s -check-prefix=RV64I + +declare void @callee(i8*) + +define void @caller32() nounwind { +; RV32I-LABEL: caller32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -64 +; RV32I-NEXT: sw ra, 60(sp) +; RV32I-NEXT: sw s0, 56(sp) +; RV32I-NEXT: addi s0, sp, 64 +; RV32I-NEXT: andi sp, sp, -32 +; RV32I-NEXT: addi a0, sp, 32 +; RV32I-NEXT: call callee +; RV32I-NEXT: addi sp, s0, -64 +; RV32I-NEXT: lw s0, 56(sp) +; RV32I-NEXT: lw ra, 60(sp) +; RV32I-NEXT: addi sp, sp, 64 +; RV32I-NEXT: ret +; +; RV64I-LABEL: caller32: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -64 +; RV64I-NEXT: sd ra, 56(sp) +; RV64I-NEXT: sd s0, 48(sp) +; RV64I-NEXT: addi s0, sp, 64 +; RV64I-NEXT: andi sp, sp, -32 +; RV64I-NEXT: addi a0, sp, 32 +; RV64I-NEXT: call callee +; RV64I-NEXT: addi sp, s0, -64 +; RV64I-NEXT: ld s0, 48(sp) +; RV64I-NEXT: ld ra, 56(sp) +; RV64I-NEXT: addi sp, sp, 64 +; RV64I-NEXT: ret + %1 = alloca i8, align 32 + call void @callee(i8* %1) + ret void +} + +define void @caller_no_realign32() nounwind "no-realign-stack" { +; RV32I-LABEL: caller_no_realign32: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: mv a0, sp +; RV32I-NEXT: call callee +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret +; +; RV64I-LABEL: caller_no_realign32: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: mv a0, sp +; RV64I-NEXT: call callee +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret + %1 = alloca i8, align 32 + call void @callee(i8* %1) + ret void +} + +define void @caller64() nounwind { +; RV32I-LABEL: caller64: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -128 +; RV32I-NEXT: sw ra, 124(sp) +; RV32I-NEXT: sw s0, 120(sp) +; RV32I-NEXT: addi s0, sp, 128 +; RV32I-NEXT: andi sp, sp, -64 +; RV32I-NEXT: addi a0, sp, 64 +; RV32I-NEXT: call callee +; RV32I-NEXT: addi sp, s0, -128 +; RV32I-NEXT: lw s0, 120(sp) +; RV32I-NEXT: lw ra, 124(sp) +; RV32I-NEXT: addi sp, sp, 128 +; RV32I-NEXT: ret +; +; RV64I-LABEL: caller64: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -128 +; RV64I-NEXT: sd ra, 120(sp) +; RV64I-NEXT: sd s0, 112(sp) +; RV64I-NEXT: addi s0, sp, 128 +; RV64I-NEXT: andi sp, sp, -64 +; RV64I-NEXT: addi a0, sp, 64 +; RV64I-NEXT: call callee +; RV64I-NEXT: addi sp, s0, -128 +; RV64I-NEXT: ld s0, 112(sp) +; RV64I-NEXT: ld ra, 120(sp) +; RV64I-NEXT: addi sp, sp, 128 +; RV64I-NEXT: ret + %1 = alloca i8, align 64 + call void @callee(i8* %1) + ret void +} + +define void @caller_no_realign64() nounwind "no-realign-stack" { +; RV32I-LABEL: caller_no_realign64: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: mv a0, sp +; RV32I-NEXT: call callee +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret +; +; RV64I-LABEL: caller_no_realign64: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: mv a0, sp +; RV64I-NEXT: call callee +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret + %1 = alloca i8, align 64 + call void @callee(i8* %1) + ret void +} + +define void @caller128() nounwind { +; RV32I-LABEL: caller128: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -256 +; RV32I-NEXT: sw ra, 252(sp) +; RV32I-NEXT: sw s0, 248(sp) +; RV32I-NEXT: addi s0, sp, 256 +; RV32I-NEXT: andi sp, sp, -128 +; RV32I-NEXT: addi a0, sp, 128 +; RV32I-NEXT: call callee +; RV32I-NEXT: addi sp, s0, -256 +; RV32I-NEXT: lw s0, 248(sp) +; RV32I-NEXT: lw ra, 252(sp) +; RV32I-NEXT: addi sp, sp, 256 +; RV32I-NEXT: ret +; +; RV64I-LABEL: caller128: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -256 +; RV64I-NEXT: sd ra, 248(sp) +; RV64I-NEXT: sd s0, 240(sp) +; RV64I-NEXT: addi s0, sp, 256 +; RV64I-NEXT: andi sp, sp, -128 +; RV64I-NEXT: addi a0, sp, 128 +; RV64I-NEXT: call callee +; RV64I-NEXT: addi sp, s0, -256 +; RV64I-NEXT: ld s0, 240(sp) +; RV64I-NEXT: ld ra, 248(sp) +; RV64I-NEXT: addi sp, sp, 256 +; RV64I-NEXT: ret + %1 = alloca i8, align 128 + call void @callee(i8* %1) + ret void +} + +define void @caller_no_realign128() nounwind "no-realign-stack" { +; RV32I-LABEL: caller_no_realign128: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: mv a0, sp +; RV32I-NEXT: call callee +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret +; +; RV64I-LABEL: caller_no_realign128: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: mv a0, sp +; RV64I-NEXT: call callee +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret + %1 = alloca i8, align 128 + call void @callee(i8* %1) + ret void +} + +define void @caller256() nounwind { +; RV32I-LABEL: caller256: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -512 +; RV32I-NEXT: sw ra, 508(sp) +; RV32I-NEXT: sw s0, 504(sp) +; RV32I-NEXT: addi s0, sp, 512 +; RV32I-NEXT: andi sp, sp, -256 +; RV32I-NEXT: addi a0, sp, 256 +; RV32I-NEXT: call callee +; RV32I-NEXT: addi sp, s0, -512 +; RV32I-NEXT: lw s0, 504(sp) +; RV32I-NEXT: lw ra, 508(sp) +; RV32I-NEXT: addi sp, sp, 512 +; RV32I-NEXT: ret +; +; RV64I-LABEL: caller256: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -512 +; RV64I-NEXT: sd ra, 504(sp) +; RV64I-NEXT: sd s0, 496(sp) +; RV64I-NEXT: addi s0, sp, 512 +; RV64I-NEXT: andi sp, sp, -256 +; RV64I-NEXT: addi a0, sp, 256 +; RV64I-NEXT: call callee +; RV64I-NEXT: addi sp, s0, -512 +; RV64I-NEXT: ld s0, 496(sp) +; RV64I-NEXT: ld ra, 504(sp) +; RV64I-NEXT: addi sp, sp, 512 +; RV64I-NEXT: ret + %1 = alloca i8, align 256 + call void @callee(i8* %1) + ret void +} + +define void @caller_no_realign256() nounwind "no-realign-stack" { +; RV32I-LABEL: caller_no_realign256: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: mv a0, sp +; RV32I-NEXT: call callee +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret +; +; RV64I-LABEL: caller_no_realign256: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: mv a0, sp +; RV64I-NEXT: call callee +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret + %1 = alloca i8, align 256 + call void @callee(i8* %1) + ret void +} + +define void @caller512() nounwind { +; RV32I-LABEL: caller512: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -1536 +; RV32I-NEXT: sw ra, 1532(sp) +; RV32I-NEXT: sw s0, 1528(sp) +; RV32I-NEXT: addi s0, sp, 1536 +; RV32I-NEXT: andi sp, sp, -512 +; RV32I-NEXT: addi a0, sp, 1024 +; RV32I-NEXT: call callee +; RV32I-NEXT: addi sp, s0, -1536 +; RV32I-NEXT: lw s0, 1528(sp) +; RV32I-NEXT: lw ra, 1532(sp) +; RV32I-NEXT: addi sp, sp, 1536 +; RV32I-NEXT: ret +; +; RV64I-LABEL: caller512: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -1536 +; RV64I-NEXT: sd ra, 1528(sp) +; RV64I-NEXT: sd s0, 1520(sp) +; RV64I-NEXT: addi s0, sp, 1536 +; RV64I-NEXT: andi sp, sp, -512 +; RV64I-NEXT: addi a0, sp, 1024 +; RV64I-NEXT: call callee +; RV64I-NEXT: addi sp, s0, -1536 +; RV64I-NEXT: ld s0, 1520(sp) +; RV64I-NEXT: ld ra, 1528(sp) +; RV64I-NEXT: addi sp, sp, 1536 +; RV64I-NEXT: ret + %1 = alloca i8, align 512 + call void @callee(i8* %1) + ret void +} + +define void @caller_no_realign512() nounwind "no-realign-stack" { +; RV32I-LABEL: caller_no_realign512: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: mv a0, sp +; RV32I-NEXT: call callee +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret +; +; RV64I-LABEL: caller_no_realign512: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: mv a0, sp +; RV64I-NEXT: call callee +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret + %1 = alloca i8, align 512 + call void @callee(i8* %1) + ret void +} + +define void @caller1024() nounwind { +; RV32I-LABEL: caller1024: +; RV32I: # %bb.0: +; RV32I-NEXT: lui a0, 1 +; RV32I-NEXT: addi a0, a0, -1024 +; RV32I-NEXT: sub sp, sp, a0 +; RV32I-NEXT: lui a0, 1 +; RV32I-NEXT: addi a0, a0, -1028 +; RV32I-NEXT: add a0, sp, a0 +; RV32I-NEXT: sw ra, 0(a0) +; RV32I-NEXT: lui a0, 1 +; RV32I-NEXT: addi a0, a0, -1032 +; RV32I-NEXT: add a0, sp, a0 +; RV32I-NEXT: sw s0, 0(a0) +; RV32I-NEXT: lui a0, 1 +; RV32I-NEXT: addi a0, a0, -1024 +; RV32I-NEXT: add s0, sp, a0 +; RV32I-NEXT: andi sp, sp, -1024 +; RV32I-NEXT: lui a0, 1 +; RV32I-NEXT: addi a0, a0, -2048 +; RV32I-NEXT: add a0, sp, a0 +; RV32I-NEXT: mv a0, a0 +; RV32I-NEXT: call callee +; RV32I-NEXT: lui a0, 1 +; RV32I-NEXT: addi a0, a0, -1024 +; RV32I-NEXT: sub sp, s0, a0 +; RV32I-NEXT: lui a0, 1 +; RV32I-NEXT: addi a0, a0, -1032 +; RV32I-NEXT: add a0, sp, a0 +; RV32I-NEXT: lw s0, 0(a0) +; RV32I-NEXT: lui a0, 1 +; RV32I-NEXT: addi a0, a0, -1028 +; RV32I-NEXT: add a0, sp, a0 +; RV32I-NEXT: lw ra, 0(a0) +; RV32I-NEXT: lui a0, 1 +; RV32I-NEXT: addi a0, a0, -1024 +; RV32I-NEXT: add sp, sp, a0 +; RV32I-NEXT: ret +; +; RV64I-LABEL: caller1024: +; RV64I: # %bb.0: +; RV64I-NEXT: lui a0, 1 +; RV64I-NEXT: addi a0, a0, -1024 +; RV64I-NEXT: sub sp, sp, a0 +; RV64I-NEXT: lui a0, 1 +; RV64I-NEXT: addi a0, a0, -1032 +; RV64I-NEXT: add a0, sp, a0 +; RV64I-NEXT: sd ra, 0(a0) +; RV64I-NEXT: lui a0, 1 +; RV64I-NEXT: addi a0, a0, -1040 +; RV64I-NEXT: add a0, sp, a0 +; RV64I-NEXT: sd s0, 0(a0) +; RV64I-NEXT: lui a0, 1 +; RV64I-NEXT: addi a0, a0, -1024 +; RV64I-NEXT: add s0, sp, a0 +; RV64I-NEXT: andi sp, sp, -1024 +; RV64I-NEXT: lui a0, 1 +; RV64I-NEXT: addi a0, a0, -2048 +; RV64I-NEXT: add a0, sp, a0 +; RV64I-NEXT: mv a0, a0 +; RV64I-NEXT: call callee +; RV64I-NEXT: lui a0, 1 +; RV64I-NEXT: addi a0, a0, -1024 +; RV64I-NEXT: sub sp, s0, a0 +; RV64I-NEXT: lui a0, 1 +; RV64I-NEXT: addi a0, a0, -1040 +; RV64I-NEXT: add a0, sp, a0 +; RV64I-NEXT: ld s0, 0(a0) +; RV64I-NEXT: lui a0, 1 +; RV64I-NEXT: addi a0, a0, -1032 +; RV64I-NEXT: add a0, sp, a0 +; RV64I-NEXT: ld ra, 0(a0) +; RV64I-NEXT: lui a0, 1 +; RV64I-NEXT: addi a0, a0, -1024 +; RV64I-NEXT: add sp, sp, a0 +; RV64I-NEXT: ret + %1 = alloca i8, align 1024 + call void @callee(i8* %1) + ret void +} + +define void @caller_no_realign1024() nounwind "no-realign-stack" { +; RV32I-LABEL: caller_no_realign1024: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: mv a0, sp +; RV32I-NEXT: call callee +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret +; +; RV64I-LABEL: caller_no_realign1024: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: mv a0, sp +; RV64I-NEXT: call callee +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret + %1 = alloca i8, align 1024 + call void @callee(i8* %1) + ret void +} + +define void @caller2048() nounwind { +; RV32I-LABEL: caller2048: +; RV32I: # %bb.0: +; RV32I-NEXT: lui a0, 2 +; RV32I-NEXT: addi a0, a0, -2048 +; RV32I-NEXT: sub sp, sp, a0 +; RV32I-NEXT: lui a0, 1 +; RV32I-NEXT: addi a0, a0, 2044 +; RV32I-NEXT: add a0, sp, a0 +; RV32I-NEXT: sw ra, 0(a0) +; RV32I-NEXT: lui a0, 1 +; RV32I-NEXT: addi a0, a0, 2040 +; RV32I-NEXT: add a0, sp, a0 +; RV32I-NEXT: sw s0, 0(a0) +; RV32I-NEXT: lui a0, 2 +; RV32I-NEXT: addi a0, a0, -2048 +; RV32I-NEXT: add s0, sp, a0 +; RV32I-NEXT: andi sp, sp, -2048 +; RV32I-NEXT: lui a0, 1 +; RV32I-NEXT: mv a0, a0 +; RV32I-NEXT: add a0, sp, a0 +; RV32I-NEXT: mv a0, a0 +; RV32I-NEXT: call callee +; RV32I-NEXT: lui a0, 2 +; RV32I-NEXT: addi a0, a0, -2048 +; RV32I-NEXT: sub sp, s0, a0 +; RV32I-NEXT: lui a0, 1 +; RV32I-NEXT: addi a0, a0, 2040 +; RV32I-NEXT: add a0, sp, a0 +; RV32I-NEXT: lw s0, 0(a0) +; RV32I-NEXT: lui a0, 1 +; RV32I-NEXT: addi a0, a0, 2044 +; RV32I-NEXT: add a0, sp, a0 +; RV32I-NEXT: lw ra, 0(a0) +; RV32I-NEXT: lui a0, 2 +; RV32I-NEXT: addi a0, a0, -2048 +; RV32I-NEXT: add sp, sp, a0 +; RV32I-NEXT: ret +; +; RV64I-LABEL: caller2048: +; RV64I: # %bb.0: +; RV64I-NEXT: lui a0, 2 +; RV64I-NEXT: addi a0, a0, -2048 +; RV64I-NEXT: sub sp, sp, a0 +; RV64I-NEXT: lui a0, 1 +; RV64I-NEXT: addi a0, a0, 2040 +; RV64I-NEXT: add a0, sp, a0 +; RV64I-NEXT: sd ra, 0(a0) +; RV64I-NEXT: lui a0, 1 +; RV64I-NEXT: addi a0, a0, 2032 +; RV64I-NEXT: add a0, sp, a0 +; RV64I-NEXT: sd s0, 0(a0) +; RV64I-NEXT: lui a0, 2 +; RV64I-NEXT: addi a0, a0, -2048 +; RV64I-NEXT: add s0, sp, a0 +; RV64I-NEXT: andi sp, sp, -2048 +; RV64I-NEXT: lui a0, 1 +; RV64I-NEXT: mv a0, a0 +; RV64I-NEXT: add a0, sp, a0 +; RV64I-NEXT: mv a0, a0 +; RV64I-NEXT: call callee +; RV64I-NEXT: lui a0, 2 +; RV64I-NEXT: addi a0, a0, -2048 +; RV64I-NEXT: sub sp, s0, a0 +; RV64I-NEXT: lui a0, 1 +; RV64I-NEXT: addi a0, a0, 2032 +; RV64I-NEXT: add a0, sp, a0 +; RV64I-NEXT: ld s0, 0(a0) +; RV64I-NEXT: lui a0, 1 +; RV64I-NEXT: addi a0, a0, 2040 +; RV64I-NEXT: add a0, sp, a0 +; RV64I-NEXT: ld ra, 0(a0) +; RV64I-NEXT: lui a0, 2 +; RV64I-NEXT: addi a0, a0, -2048 +; RV64I-NEXT: add sp, sp, a0 +; RV64I-NEXT: ret + %1 = alloca i8, align 2048 + call void @callee(i8* %1) + ret void +} + +define void @caller_no_realign2048() nounwind "no-realign-stack" { +; RV32I-LABEL: caller_no_realign2048: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: mv a0, sp +; RV32I-NEXT: call callee +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret +; +; RV64I-LABEL: caller_no_realign2048: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: mv a0, sp +; RV64I-NEXT: call callee +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret + %1 = alloca i8, align 2048 + call void @callee(i8* %1) + ret void +} + +define void @caller4096() nounwind { +; RV32I-LABEL: caller4096: +; RV32I: # %bb.0: +; RV32I-NEXT: lui a0, 3 +; RV32I-NEXT: mv a0, a0 +; RV32I-NEXT: sub sp, sp, a0 +; RV32I-NEXT: lui a0, 3 +; RV32I-NEXT: addi a0, a0, -4 +; RV32I-NEXT: add a0, sp, a0 +; RV32I-NEXT: sw ra, 0(a0) +; RV32I-NEXT: lui a0, 3 +; RV32I-NEXT: addi a0, a0, -8 +; RV32I-NEXT: add a0, sp, a0 +; RV32I-NEXT: sw s0, 0(a0) +; RV32I-NEXT: lui a0, 3 +; RV32I-NEXT: mv a0, a0 +; RV32I-NEXT: add s0, sp, a0 +; RV32I-NEXT: srli a0, sp, 12 +; RV32I-NEXT: slli sp, a0, 12 +; RV32I-NEXT: lui a0, 2 +; RV32I-NEXT: mv a0, a0 +; RV32I-NEXT: add a0, sp, a0 +; RV32I-NEXT: mv a0, a0 +; RV32I-NEXT: call callee +; RV32I-NEXT: lui a0, 3 +; RV32I-NEXT: mv a0, a0 +; RV32I-NEXT: sub sp, s0, a0 +; RV32I-NEXT: lui a0, 3 +; RV32I-NEXT: addi a0, a0, -8 +; RV32I-NEXT: add a0, sp, a0 +; RV32I-NEXT: lw s0, 0(a0) +; RV32I-NEXT: lui a0, 3 +; RV32I-NEXT: addi a0, a0, -4 +; RV32I-NEXT: add a0, sp, a0 +; RV32I-NEXT: lw ra, 0(a0) +; RV32I-NEXT: lui a0, 3 +; RV32I-NEXT: mv a0, a0 +; RV32I-NEXT: add sp, sp, a0 +; RV32I-NEXT: ret +; +; RV64I-LABEL: caller4096: +; RV64I: # %bb.0: +; RV64I-NEXT: lui a0, 3 +; RV64I-NEXT: mv a0, a0 +; RV64I-NEXT: sub sp, sp, a0 +; RV64I-NEXT: lui a0, 3 +; RV64I-NEXT: addi a0, a0, -8 +; RV64I-NEXT: add a0, sp, a0 +; RV64I-NEXT: sd ra, 0(a0) +; RV64I-NEXT: lui a0, 3 +; RV64I-NEXT: addi a0, a0, -16 +; RV64I-NEXT: add a0, sp, a0 +; RV64I-NEXT: sd s0, 0(a0) +; RV64I-NEXT: lui a0, 3 +; RV64I-NEXT: mv a0, a0 +; RV64I-NEXT: add s0, sp, a0 +; RV64I-NEXT: srli a0, sp, 12 +; RV64I-NEXT: slli sp, a0, 12 +; RV64I-NEXT: lui a0, 2 +; RV64I-NEXT: mv a0, a0 +; RV64I-NEXT: add a0, sp, a0 +; RV64I-NEXT: mv a0, a0 +; RV64I-NEXT: call callee +; RV64I-NEXT: lui a0, 3 +; RV64I-NEXT: mv a0, a0 +; RV64I-NEXT: sub sp, s0, a0 +; RV64I-NEXT: lui a0, 3 +; RV64I-NEXT: addi a0, a0, -16 +; RV64I-NEXT: add a0, sp, a0 +; RV64I-NEXT: ld s0, 0(a0) +; RV64I-NEXT: lui a0, 3 +; RV64I-NEXT: addi a0, a0, -8 +; RV64I-NEXT: add a0, sp, a0 +; RV64I-NEXT: ld ra, 0(a0) +; RV64I-NEXT: lui a0, 3 +; RV64I-NEXT: mv a0, a0 +; RV64I-NEXT: add sp, sp, a0 +; RV64I-NEXT: ret + %1 = alloca i8, align 4096 + call void @callee(i8* %1) + ret void +} + +define void @caller_no_realign4096() nounwind "no-realign-stack" { +; RV32I-LABEL: caller_no_realign4096: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: mv a0, sp +; RV32I-NEXT: call callee +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret +; +; RV64I-LABEL: caller_no_realign4096: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: mv a0, sp +; RV64I-NEXT: call callee +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret + %1 = alloca i8, align 4096 + call void @callee(i8* %1) + ret void +} diff --git a/llvm/test/CodeGen/SPARC/tls.ll b/llvm/test/CodeGen/SPARC/tls.ll index 1b1af2e99c38..843769df8d93 100644 --- a/llvm/test/CodeGen/SPARC/tls.ll +++ b/llvm/test/CodeGen/SPARC/tls.ll @@ -1,12 +1,12 @@ -; RUN: llc <%s -march=sparc -relocation-model=static | FileCheck %s --check-prefix=v8abs -; RUN: llc <%s -march=sparcv9 -relocation-model=static | FileCheck %s --check-prefix=v9abs -; RUN: llc <%s -march=sparc -relocation-model=pic | FileCheck %s --check-prefix=pic -; RUN: llc <%s -march=sparcv9 -relocation-model=pic | FileCheck %s --check-prefix=pic - -; RUN: llc <%s -march=sparc -relocation-model=static -filetype=obj | llvm-readobj -r --symbols | FileCheck %s --check-prefix=v8abs-obj -; RUN: llc <%s -march=sparcv9 -relocation-model=static -filetype=obj | llvm-readobj -r --symbols | FileCheck %s --check-prefix=v9abs-obj -; RUN: llc <%s -march=sparc -relocation-model=pic -filetype=obj | llvm-readobj -r --symbols | FileCheck %s --check-prefix=pic-obj -; RUN: llc <%s -march=sparcv9 -relocation-model=pic -filetype=obj | llvm-readobj -r --symbols | FileCheck %s --check-prefix=pic-obj +; RUN: llc <%s -mtriple=sparc-unknown-linux -relocation-model=static | FileCheck %s --check-prefix=v8abs +; RUN: llc <%s -mtriple=sparcv9-unknown-linux -relocation-model=static | FileCheck %s --check-prefix=v9abs +; RUN: llc <%s -mtriple=sparc-unknown-linux -relocation-model=pic | FileCheck %s --check-prefix=pic +; RUN: llc <%s -mtriple=sparcv9-unknown-linux -relocation-model=pic | FileCheck %s --check-prefix=pic + +; RUN: llc <%s -mtriple=sparc-unknown-linux -relocation-model=static -filetype=obj | llvm-readobj -r --symbols | FileCheck %s --check-prefix=v8abs-obj +; RUN: llc <%s -mtriple=sparcv9-unknown-linux -relocation-model=static -filetype=obj | llvm-readobj -r --symbols | FileCheck %s --check-prefix=v9abs-obj +; RUN: llc <%s -mtriple=sparc-unknown-linux -relocation-model=pic -filetype=obj | llvm-readobj -r --symbols | FileCheck %s --check-prefix=pic-obj +; RUN: llc <%s -mtriple=sparcv9-unknown-linux -relocation-model=pic -filetype=obj | llvm-readobj -r --symbols | FileCheck %s --check-prefix=pic-obj @local_symbol = internal thread_local global i32 0 @extern_symbol = external thread_local global i32 diff --git a/llvm/test/CodeGen/SystemZ/asm-20.ll b/llvm/test/CodeGen/SystemZ/asm-20.ll new file mode 100644 index 000000000000..e80a0085bf9c --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/asm-20.ll @@ -0,0 +1,15 @@ +; Test that asm goto can be compiled. +; +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z14 + +define i32 @c() { +entry: + callbr void asm sideeffect "j d", "X"(i8* blockaddress(@c, %d)) + to label %asm.fallthrough [label %d] + +asm.fallthrough: ; preds = %entry + br label %d + +d: ; preds = %asm.fallthrough, %entry + ret i32 undef +} diff --git a/llvm/test/CodeGen/Thumb/pr42760.ll b/llvm/test/CodeGen/Thumb/pr42760.ll new file mode 100644 index 000000000000..fc9a18bb3342 --- /dev/null +++ b/llvm/test/CodeGen/Thumb/pr42760.ll @@ -0,0 +1,56 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=thumbv6m-none-unknown-eabi -tail-dup-placement-threshold=3 < %s | FileCheck %s + +define hidden void @test() { +; CHECK-LABEL: test: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: movs r0, #1 +; CHECK-NEXT: lsls r1, r0, #2 +; CHECK-NEXT: b .LBB0_2 +; CHECK-NEXT: .LBB0_1: @ %bb2 +; CHECK-NEXT: @ in Loop: Header=BB0_2 Depth=1 +; CHECK-NEXT: cmp r0, #0 +; CHECK-NEXT: bne .LBB0_6 +; CHECK-NEXT: .LBB0_2: @ %switch +; CHECK-NEXT: @ =>This Inner Loop Header: Depth=1 +; CHECK-NEXT: adr r2, .LJTI0_0 +; CHECK-NEXT: ldr r2, [r2, r1] +; CHECK-NEXT: mov pc, r2 +; CHECK-NEXT: @ %bb.3: +; CHECK-NEXT: .p2align 2 +; CHECK-NEXT: .LJTI0_0: +; CHECK-NEXT: .long .LBB0_6+1 +; CHECK-NEXT: .long .LBB0_4+1 +; CHECK-NEXT: .long .LBB0_6+1 +; CHECK-NEXT: .long .LBB0_5+1 +; CHECK-NEXT: .LBB0_4: @ %switch +; CHECK-NEXT: @ in Loop: Header=BB0_2 Depth=1 +; CHECK-NEXT: b .LBB0_1 +; CHECK-NEXT: .LBB0_5: @ %bb +; CHECK-NEXT: @ in Loop: Header=BB0_2 Depth=1 +; CHECK-NEXT: cmp r0, #0 +; CHECK-NEXT: beq .LBB0_1 +; CHECK-NEXT: .LBB0_6: @ %dead +entry: + br label %switch + +switch: ; preds = %bb2, %entry + switch i32 undef, label %dead2 [ + i32 0, label %dead + i32 1, label %bb2 + i32 2, label %dead + i32 3, label %bb + ] + +dead: ; preds = %bb2, %bb, %switch, %switch + unreachable + +dead2: ; preds = %switch + unreachable + +bb: ; preds = %switch + br i1 undef, label %dead, label %bb2 + +bb2: ; preds = %bb, %switch + br i1 undef, label %dead, label %switch +} diff --git a/llvm/test/CodeGen/WebAssembly/multi-return.ll b/llvm/test/CodeGen/WebAssembly/multi-return.ll new file mode 100644 index 000000000000..d5db601b8f3a --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/multi-return.ll @@ -0,0 +1,200 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers | FileCheck %s + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +; Return multiple values, some of which will be legalized into multiple values. +declare { i64, i128, i192, i128, i64 } @return_multi_multi() + +; Test returning a single value from @return_multi_multi. + +define i64 @test0() { +; CHECK-LABEL: test0 +; CHECK: call return_multi_multi +; CHECK: i64.load $0=, 8($1) +; CHECK: local.copy $push8=, $0 + %t0 = call { i64, i128, i192, i128, i64 } @return_multi_multi() + %t1 = extractvalue { i64, i128, i192, i128, i64 } %t0, 0 + ret i64 %t1 +} + +define i128 @test1() { +; CHECK-LABEL: test1 +; CHECK: call return_multi_multi +; CHECK: i64.load $1=, 16($2) +; CHECK: i32.const $push0=, 24 +; CHECK: i32.add $push1=, $2, $pop0 +; CHECK: i64.load $push2=, 0($pop1) +; CHECK: i64.store 8($0), $pop2 +; CHECK: i64.store 0($0), $1 + %t0 = call { i64, i128, i192, i128, i64 } @return_multi_multi() + %t1 = extractvalue { i64, i128, i192, i128, i64 } %t0, 1 + ret i128 %t1 +} + +define i192 @test2() { +; CHECK-LABEL: test2 +; CHECK: call return_multi_multi +; CHECK: i32.const $push0=, 40 +; CHECK: i32.add $push1=, $3, $pop0 +; CHECK: i64.load $1=, 0($pop1) +; CHECK: i64.load $2=, 32($3) +; CHECK: i32.const $push2=, 48 +; CHECK: i32.add $push3=, $3, $pop2 +; CHECK: i64.load $push4=, 0($pop3) +; CHECK: i64.store 16($0), $pop4 +; CHECK: i64.store 0($0), $2 +; CHECK: i64.store 8($0), $1 + %t0 = call { i64, i128, i192, i128, i64 } @return_multi_multi() + %t1 = extractvalue { i64, i128, i192, i128, i64 } %t0, 2 + ret i192 %t1 +} + +define i128 @test3() { +; CHECK-LABEL: test3 +; CHECK: call return_multi_multi +; CHECK: i64.load $1=, 56($2) +; CHECK: i32.const $push0=, 64 +; CHECK: i32.add $push1=, $2, $pop0 +; CHECK: i64.load $push2=, 0($pop1) +; CHECK: i64.store 8($0), $pop2 +; CHECK: i64.store 0($0), $1 + %t0 = call { i64, i128, i192, i128, i64 } @return_multi_multi() + %t1 = extractvalue { i64, i128, i192, i128, i64 } %t0, 3 + ret i128 %t1 +} + +define i64 @test4() { +; CHECK-LABEL: test4 +; CHECK: call return_multi_multi +; CHECK: i64.load $0=, 72($1) +; CHECK: local.copy $push8=, $0 + %t0 = call { i64, i128, i192, i128, i64 } @return_multi_multi() + %t1 = extractvalue { i64, i128, i192, i128, i64 } %t0, 4 + ret i64 %t1 +} + +; Test returning multiple values from @return_multi_multi. + +define { i64, i128 } @test5() { +; CHECK-LABEL: test5 +; CHECK: call return_multi_multi +; CHECK: i32.const $push10=, 8 +; CHECK: i32.add $push11=, $3, $pop10 +; CHECK: i32.const $push0=, 16 +; CHECK: i32.add $push1=, $pop11, $pop0 +; CHECK: i64.load $1=, 0($pop1) +; CHECK: i64.load $2=, 8($3) +; CHECK: i64.load $push2=, 16($3) +; CHECK: i64.store 8($0), $pop2 +; CHECK: i32.const $push12=, 16 +; CHECK: i32.add $push3=, $0, $pop12 +; CHECK: i64.store 0($pop3), $1 +; CHECK: i64.store 0($0), $2 + %t0 = call { i64, i128, i192, i128, i64 } @return_multi_multi() + %r0 = extractvalue { i64, i128, i192, i128, i64 } %t0, 0 + %r1 = extractvalue { i64, i128, i192, i128, i64 } %t0, 1 + %s0 = insertvalue { i64, i128 } undef, i64 %r0, 0 + %s1 = insertvalue { i64, i128 } %s0, i128 %r1, 1 + ret { i64, i128 } %s1 +} + +define { i128, i128 } @test6() { +; CHECK-LABEL: test6 +; CHECK: call return_multi_multi +; CHECK: i32.const $push0=, 24 +; CHECK: i32.add $push1=, $4, $pop0 +; CHECK: i64.load $1=, 0($pop1) +; CHECK: i32.const $push2=, 64 +; CHECK: i32.add $push3=, $4, $pop2 +; CHECK: i64.load $2=, 0($pop3) +; CHECK: i64.load $3=, 16($4) +; CHECK: i64.load $push4=, 56($4) +; CHECK: i64.store 16($0), $pop4 +; CHECK: i32.const $push5=, 24 +; CHECK: i32.add $push6=, $0, $pop5 +; CHECK: i64.store 0($pop6), $2 +; CHECK: i64.store 0($0), $3 +; CHECK: i64.store 8($0), $1 + %t0 = call { i64, i128, i192, i128, i64 } @return_multi_multi() + %r1 = extractvalue { i64, i128, i192, i128, i64 } %t0, 1 + %r3 = extractvalue { i64, i128, i192, i128, i64 } %t0, 3 + %s0 = insertvalue { i128, i128 } undef, i128 %r1, 0 + %s1 = insertvalue { i128, i128 } %s0, i128 %r3, 1 + ret { i128, i128 } %s1 +} + +define { i64, i192 } @test7() { +; CHECK-LABEL: test7 +; CHECK: call return_multi_multi +; CHECK: i32.const $push2=, 40 +; CHECK: i32.add $push3=, $4, $pop2 +; CHECK: i64.load $1=, 0($pop3) +; CHECK: i64.load $2=, 8($4) +; CHECK: i64.load $3=, 32($4) +; CHECK: i32.const $push0=, 24 +; CHECK: i32.add $push1=, $0, $pop0 +; CHECK: i32.const $push4=, 48 +; CHECK: i32.add $push5=, $4, $pop4 +; CHECK: i64.load $push6=, 0($pop5) +; CHECK: i64.store 0($pop1), $pop6 +; CHECK: i64.store 8($0), $3 +; CHECK: i32.const $push7=, 16 +; CHECK: i32.add $push8=, $0, $pop7 +; CHECK: i64.store 0($pop8), $1 +; CHECK: i64.store 0($0), $2 + %t0 = call { i64, i128, i192, i128, i64 } @return_multi_multi() + %r0 = extractvalue { i64, i128, i192, i128, i64 } %t0, 0 + %r2 = extractvalue { i64, i128, i192, i128, i64 } %t0, 2 + %s0 = insertvalue { i64, i192 } undef, i64 %r0, 0 + %s1 = insertvalue { i64, i192 } %s0, i192 %r2, 1 + ret { i64, i192 } %s1 +} + +define { i128, i192, i128, i64 } @test8() { +; CHECK-LABEL: test8 +; CHECK: call return_multi_multi +; CHECK: i32.const $push0=, 64 +; CHECK: i32.add $push1=, $8, $pop0 +; CHECK: i64.load $1=, 0($pop1) +; CHECK: i32.const $push20=, 8 +; CHECK: i32.add $push21=, $8, $pop20 +; CHECK: i32.const $push2=, 32 +; CHECK: i32.add $push3=, $pop21, $pop2 +; CHECK: i64.load $2=, 0($pop3) +; CHECK: i32.const $push4=, 48 +; CHECK: i32.add $push5=, $8, $pop4 +; CHECK: i64.load $3=, 0($pop5) +; CHECK: i32.const $push6=, 24 +; CHECK: i32.add $push7=, $8, $pop6 +; CHECK: i64.load $4=, 0($pop7) +; CHECK: i64.load $5=, 8($8) +; CHECK: i64.load $6=, 56($8) +; CHECK: i64.load $7=, 32($8) +; CHECK: i64.load $push8=, 16($8) +; CHECK: i64.store 40($0), $pop8 +; CHECK: i32.const $push9=, 48 +; CHECK: i32.add $push10=, $0, $pop9 +; CHECK: i64.store 0($pop10), $4 +; CHECK: i32.const $push22=, 32 +; CHECK: i32.add $push11=, $0, $pop22 +; CHECK: i64.store 0($pop11), $3 +; CHECK: i64.store 16($0), $7 +; CHECK: i32.const $push12=, 24 +; CHECK: i32.add $push13=, $0, $pop12 +; CHECK: i64.store 0($pop13), $2 +; CHECK: i64.store 0($0), $6 +; CHECK: i64.store 8($0), $1 +; CHECK: i64.store 56($0), $5 + %t0 = call { i64, i128, i192, i128, i64 } @return_multi_multi() + %r0 = extractvalue { i64, i128, i192, i128, i64 } %t0, 0 + %r1 = extractvalue { i64, i128, i192, i128, i64 } %t0, 1 + %r2 = extractvalue { i64, i128, i192, i128, i64 } %t0, 2 + %r3 = extractvalue { i64, i128, i192, i128, i64 } %t0, 3 + %s0 = insertvalue { i128, i192, i128, i64 } undef, i128 %r3, 0 + %s1 = insertvalue { i128, i192, i128, i64 } %s0, i192 %r2, 1 + %s2 = insertvalue { i128, i192, i128, i64 } %s1, i128 %r1, 2 + %s3 = insertvalue { i128, i192, i128, i64 } %s2, i64 %r0, 3 + ret { i128, i192, i128, i64 } %s3 +} diff --git a/llvm/test/CodeGen/X86/O3-pipeline.ll b/llvm/test/CodeGen/X86/O3-pipeline.ll index 7364d950f458..48bc2992a7ed 100644 --- a/llvm/test/CodeGen/X86/O3-pipeline.ll +++ b/llvm/test/CodeGen/X86/O3-pipeline.ll @@ -84,9 +84,9 @@ ; CHECK-NEXT: MachineDominator Tree Construction ; CHECK-NEXT: Machine Natural Loop Construction ; CHECK-NEXT: Early Machine Loop Invariant Code Motion +; CHECK-NEXT: Machine Block Frequency Analysis ; CHECK-NEXT: Machine Common Subexpression Elimination ; CHECK-NEXT: MachinePostDominator Tree Construction -; CHECK-NEXT: Machine Block Frequency Analysis ; CHECK-NEXT: Machine code sinking ; CHECK-NEXT: Peephole Optimizations ; CHECK-NEXT: Remove dead machine instructions diff --git a/llvm/test/CodeGen/X86/callbr-asm-label-addr.ll b/llvm/test/CodeGen/X86/callbr-asm-label-addr.ll new file mode 100644 index 000000000000..dc0e83634658 --- /dev/null +++ b/llvm/test/CodeGen/X86/callbr-asm-label-addr.ll @@ -0,0 +1,30 @@ +; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu | FileCheck %s + +define i32 @test1(i32 %x) { +; CHECK-LABEL: test1: +; CHECK: .quad .Ltmp0 +; CHECK-NEXT: .quad .Ltmp1 +; CHECK-LABEL: .Ltmp1: +; CHECK-LABEL: .LBB0_1: # %bar +; CHECK-NEXT: callq foo +; CHECK-LABEL: .Ltmp0: +; CHECK-NEXT: # %bb.2: # %baz +entry: + callbr void asm sideeffect ".quad ${0:l}\0A\09.quad ${1:l}", "i,X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@test1, %baz), i8* blockaddress(@test1, %bar)) + to label %asm.fallthrough [label %bar] + +asm.fallthrough: + br label %bar + +bar: + %call = tail call i32 @foo(i32 %x) + br label %baz + +baz: + %call1 = tail call i32 @mux(i32 %call) + ret i32 %call1 +} + +declare i32 @foo(i32) + +declare i32 @mux(i32) diff --git a/llvm/test/CodeGen/X86/callbr-asm-obj-file.ll b/llvm/test/CodeGen/X86/callbr-asm-obj-file.ll new file mode 100644 index 000000000000..d526045f93c0 --- /dev/null +++ b/llvm/test/CodeGen/X86/callbr-asm-obj-file.ll @@ -0,0 +1,19 @@ +; RUN: llc < %s -mtriple=x86_64-linux-gnu -filetype=obj -o - \ +; RUN: | llvm-objdump -triple x86_64-linux-gnu -d - \ +; RUN: | FileCheck %s + +; CHECK: 0000000000000000 test1: +; CHECK-NEXT: 0: 74 00 je 0 +; CHECK-NEXT: 2: c3 retq + +define void @test1() { +entry: + callbr void asm sideeffect "je ${0:l}", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@test1, %a.b.normal.jump)) + to label %asm.fallthrough [label %a.b.normal.jump] + +asm.fallthrough: + ret void + +a.b.normal.jump: + ret void +} diff --git a/llvm/test/CodeGen/X86/callbr-asm.ll b/llvm/test/CodeGen/X86/callbr-asm.ll index 48a80ae167ba..ed3c314ed424 100644 --- a/llvm/test/CodeGen/X86/callbr-asm.ll +++ b/llvm/test/CodeGen/X86/callbr-asm.ll @@ -12,7 +12,7 @@ define i32 @test1(i32 %a) { ; CHECK-NEXT: addl $4, %eax ; CHECK-NEXT: #APP ; CHECK-NEXT: xorl %eax, %eax -; CHECK-NEXT: jmp .Ltmp00 +; CHECK-NEXT: jmp .Ltmp0 ; CHECK-NEXT: #NO_APP ; CHECK-NEXT: .LBB0_1: # %normal ; CHECK-NEXT: xorl %eax, %eax @@ -87,17 +87,17 @@ define dso_local i32 @test3(i32 %a) { ; CHECK-NEXT: # Parent Loop BB2_3 Depth=3 ; CHECK-NEXT: # => This Inner Loop Header: Depth=4 ; CHECK-NEXT: #APP -; CHECK-NEXT: jmp .Ltmp10 -; CHECK-NEXT: jmp .Ltmp20 -; CHECK-NEXT: jmp .Ltmp30 +; CHECK-NEXT: jmp .Ltmp1 +; CHECK-NEXT: jmp .Ltmp2 +; CHECK-NEXT: jmp .Ltmp3 ; CHECK-NEXT: #NO_APP ; CHECK-NEXT: .LBB2_5: # %normal0 ; CHECK-NEXT: # in Loop: Header=BB2_4 Depth=4 ; CHECK-NEXT: #APP -; CHECK-NEXT: jmp .Ltmp10 -; CHECK-NEXT: jmp .Ltmp20 -; CHECK-NEXT: jmp .Ltmp30 -; CHECK-NEXT: jmp .Ltmp40 +; CHECK-NEXT: jmp .Ltmp1 +; CHECK-NEXT: jmp .Ltmp2 +; CHECK-NEXT: jmp .Ltmp3 +; CHECK-NEXT: jmp .Ltmp4 ; CHECK-NEXT: #NO_APP ; CHECK-NEXT: .LBB2_6: # %normal1 ; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax diff --git a/llvm/test/CodeGen/X86/cmpxchg8b.ll b/llvm/test/CodeGen/X86/cmpxchg8b.ll index 8eb3dda6b6eb..caf40c541e28 100644 --- a/llvm/test/CodeGen/X86/cmpxchg8b.ll +++ b/llvm/test/CodeGen/X86/cmpxchg8b.ll @@ -2,6 +2,7 @@ ; RUN: llc < %s -mtriple=i686-unknown- -mcpu=core2 | FileCheck %s --check-prefixes=CHECK,X86 ; RUN: llc < %s -mtriple=x86_64-unknown- -mcpu=core2 | FileCheck %s --check-prefixes=CHECK,X64 ; RUN: llc < %s -mtriple=i686-unknown- -mcpu=i486 | FileCheck %s --check-prefixes=I486 +; RUN: llc < %s -mtriple=i686-unknown- -mcpu=znver1 | FileCheck %s --check-prefixes=CHECK,X86 ; Basic 64-bit cmpxchg define void @t1(i64* nocapture %p) nounwind ssp { diff --git a/llvm/test/CodeGen/X86/combine-pmuldq.ll b/llvm/test/CodeGen/X86/combine-pmuldq.ll index 5b5ae387f41e..82387c936233 100644 --- a/llvm/test/CodeGen/X86/combine-pmuldq.ll +++ b/llvm/test/CodeGen/X86/combine-pmuldq.ll @@ -172,3 +172,118 @@ bb34: ; preds = %bb10 %tmp35 = add <4 x i64> %tmp29, %tmp28 ret void } + +define i32 @PR43159(<4 x i32>* %a0) { +; SSE-LABEL: PR43159: +; SSE: # %bb.0: # %entry +; SSE-NEXT: movdqa (%rdi), %xmm0 +; SSE-NEXT: movdqa {{.*#+}} xmm1 = [1645975491,344322273,2164392969,1916962805] +; SSE-NEXT: pshufd {{.*#+}} xmm2 = xmm1[1,1,3,3] +; SSE-NEXT: pshufd {{.*#+}} xmm3 = xmm0[1,1,3,3] +; SSE-NEXT: pmuludq %xmm2, %xmm3 +; SSE-NEXT: movdqa %xmm0, %xmm2 +; SSE-NEXT: psrld $1, %xmm2 +; SSE-NEXT: pblendw {{.*#+}} xmm2 = xmm0[0,1,2,3],xmm2[4,5],xmm0[6,7] +; SSE-NEXT: pmuludq %xmm1, %xmm2 +; SSE-NEXT: pshufd {{.*#+}} xmm1 = xmm2[1,1,3,3] +; SSE-NEXT: pblendw {{.*#+}} xmm1 = xmm1[0,1],xmm3[2,3],xmm1[4,5],xmm3[6,7] +; SSE-NEXT: psubd %xmm1, %xmm0 +; SSE-NEXT: pshufd {{.*#+}} xmm0 = xmm0[1,1,3,3] +; SSE-NEXT: pmuludq {{.*}}(%rip), %xmm0 +; SSE-NEXT: pxor %xmm2, %xmm2 +; SSE-NEXT: pblendw {{.*#+}} xmm2 = xmm2[0,1],xmm0[2,3],xmm2[4,5],xmm0[6,7] +; SSE-NEXT: paddd %xmm1, %xmm2 +; SSE-NEXT: movdqa %xmm2, %xmm0 +; SSE-NEXT: psrld $7, %xmm0 +; SSE-NEXT: psrld $6, %xmm2 +; SSE-NEXT: movd %xmm2, %edi +; SSE-NEXT: pextrd $1, %xmm0, %esi +; SSE-NEXT: pextrd $2, %xmm2, %edx +; SSE-NEXT: pextrd $3, %xmm0, %ecx +; SSE-NEXT: jmp foo # TAILCALL +; +; AVX2-LABEL: PR43159: +; AVX2: # %bb.0: # %entry +; AVX2-NEXT: vmovdqa (%rdi), %xmm0 +; AVX2-NEXT: vmovdqa {{.*#+}} xmm1 = [1645975491,344322273,2164392969,1916962805] +; AVX2-NEXT: vpshufd {{.*#+}} xmm2 = xmm1[1,1,3,3] +; AVX2-NEXT: vpsrlvd {{.*}}(%rip), %xmm0, %xmm3 +; AVX2-NEXT: vpshufd {{.*#+}} xmm4 = xmm3[1,1,3,3] +; AVX2-NEXT: vpmuludq %xmm2, %xmm4, %xmm2 +; AVX2-NEXT: vpmuludq %xmm1, %xmm3, %xmm1 +; AVX2-NEXT: vpshufd {{.*#+}} xmm1 = xmm1[1,1,3,3] +; AVX2-NEXT: vpblendd {{.*#+}} xmm1 = xmm1[0],xmm2[1],xmm1[2],xmm2[3] +; AVX2-NEXT: vpsubd %xmm1, %xmm0, %xmm0 +; AVX2-NEXT: vpshufd {{.*#+}} xmm0 = xmm0[1,1,3,3] +; AVX2-NEXT: vpbroadcastd {{.*#+}} xmm2 = [2147483648,2147483648,2147483648,2147483648] +; AVX2-NEXT: vpmuludq %xmm2, %xmm0, %xmm0 +; AVX2-NEXT: vpxor %xmm2, %xmm2, %xmm2 +; AVX2-NEXT: vpblendd {{.*#+}} xmm0 = xmm2[0],xmm0[1],xmm2[2],xmm0[3] +; AVX2-NEXT: vpaddd %xmm1, %xmm0, %xmm0 +; AVX2-NEXT: vpsrlvd {{.*}}(%rip), %xmm0, %xmm0 +; AVX2-NEXT: vmovd %xmm0, %edi +; AVX2-NEXT: vpextrd $1, %xmm0, %esi +; AVX2-NEXT: vpextrd $2, %xmm0, %edx +; AVX2-NEXT: vpextrd $3, %xmm0, %ecx +; AVX2-NEXT: jmp foo # TAILCALL +; +; AVX512VL-LABEL: PR43159: +; AVX512VL: # %bb.0: # %entry +; AVX512VL-NEXT: vmovdqa (%rdi), %xmm0 +; AVX512VL-NEXT: vmovdqa {{.*#+}} xmm1 = [1645975491,344322273,2164392969,1916962805] +; AVX512VL-NEXT: vpshufd {{.*#+}} xmm2 = xmm1[1,1,3,3] +; AVX512VL-NEXT: vpsrlvd {{.*}}(%rip), %xmm0, %xmm3 +; AVX512VL-NEXT: vpshufd {{.*#+}} xmm4 = xmm3[1,1,3,3] +; AVX512VL-NEXT: vpmuludq %xmm2, %xmm4, %xmm2 +; AVX512VL-NEXT: vpmuludq %xmm1, %xmm3, %xmm1 +; AVX512VL-NEXT: vpshufd {{.*#+}} xmm1 = xmm1[1,1,3,3] +; AVX512VL-NEXT: vpblendd {{.*#+}} xmm1 = xmm1[0],xmm2[1],xmm1[2],xmm2[3] +; AVX512VL-NEXT: vpsubd %xmm1, %xmm0, %xmm0 +; AVX512VL-NEXT: vpshufd {{.*#+}} xmm0 = xmm0[1,1,3,3] +; AVX512VL-NEXT: vpbroadcastd {{.*#+}} xmm2 = [2147483648,2147483648,2147483648,2147483648] +; AVX512VL-NEXT: vpmuludq %xmm2, %xmm0, %xmm0 +; AVX512VL-NEXT: vpxor %xmm2, %xmm2, %xmm2 +; AVX512VL-NEXT: vpblendd {{.*#+}} xmm0 = xmm2[0],xmm0[1],xmm2[2],xmm0[3] +; AVX512VL-NEXT: vpaddd %xmm1, %xmm0, %xmm0 +; AVX512VL-NEXT: vpsrlvd {{.*}}(%rip), %xmm0, %xmm0 +; AVX512VL-NEXT: vmovd %xmm0, %edi +; AVX512VL-NEXT: vpextrd $1, %xmm0, %esi +; AVX512VL-NEXT: vpextrd $2, %xmm0, %edx +; AVX512VL-NEXT: vpextrd $3, %xmm0, %ecx +; AVX512VL-NEXT: jmp foo # TAILCALL +; +; AVX512DQVL-LABEL: PR43159: +; AVX512DQVL: # %bb.0: # %entry +; AVX512DQVL-NEXT: vmovdqa (%rdi), %xmm0 +; AVX512DQVL-NEXT: vmovdqa {{.*#+}} xmm1 = [1645975491,344322273,2164392969,1916962805] +; AVX512DQVL-NEXT: vpshufd {{.*#+}} xmm2 = xmm1[1,1,3,3] +; AVX512DQVL-NEXT: vpsrlvd {{.*}}(%rip), %xmm0, %xmm3 +; AVX512DQVL-NEXT: vpshufd {{.*#+}} xmm4 = xmm3[1,1,3,3] +; AVX512DQVL-NEXT: vpmuludq %xmm2, %xmm4, %xmm2 +; AVX512DQVL-NEXT: vpmuludq %xmm1, %xmm3, %xmm1 +; AVX512DQVL-NEXT: vpshufd {{.*#+}} xmm1 = xmm1[1,1,3,3] +; AVX512DQVL-NEXT: vpblendd {{.*#+}} xmm1 = xmm1[0],xmm2[1],xmm1[2],xmm2[3] +; AVX512DQVL-NEXT: vpsubd %xmm1, %xmm0, %xmm0 +; AVX512DQVL-NEXT: vpshufd {{.*#+}} xmm0 = xmm0[1,1,3,3] +; AVX512DQVL-NEXT: vpbroadcastd {{.*#+}} xmm2 = [2147483648,2147483648,2147483648,2147483648] +; AVX512DQVL-NEXT: vpmuludq %xmm2, %xmm0, %xmm0 +; AVX512DQVL-NEXT: vpxor %xmm2, %xmm2, %xmm2 +; AVX512DQVL-NEXT: vpblendd {{.*#+}} xmm0 = xmm2[0],xmm0[1],xmm2[2],xmm0[3] +; AVX512DQVL-NEXT: vpaddd %xmm1, %xmm0, %xmm0 +; AVX512DQVL-NEXT: vpsrlvd {{.*}}(%rip), %xmm0, %xmm0 +; AVX512DQVL-NEXT: vmovd %xmm0, %edi +; AVX512DQVL-NEXT: vpextrd $1, %xmm0, %esi +; AVX512DQVL-NEXT: vpextrd $2, %xmm0, %edx +; AVX512DQVL-NEXT: vpextrd $3, %xmm0, %ecx +; AVX512DQVL-NEXT: jmp foo # TAILCALL +entry: + %0 = load <4 x i32>, <4 x i32>* %a0, align 16 + %div = udiv <4 x i32> %0, + %ext0 = extractelement <4 x i32> %div, i32 0 + %ext1 = extractelement <4 x i32> %div, i32 1 + %ext2 = extractelement <4 x i32> %div, i32 2 + %ext3 = extractelement <4 x i32> %div, i32 3 + %call = tail call i32 @foo(i32 %ext0, i32 %ext1, i32 %ext2, i32 %ext3) + ret i32 %call +} +declare dso_local i32 @foo(i32, i32, i32, i32) diff --git a/llvm/test/CodeGen/X86/combine-sbb.ll b/llvm/test/CodeGen/X86/combine-sbb.ll index bba72c566094..6eb0e1e0f0ce 100644 --- a/llvm/test/CodeGen/X86/combine-sbb.ll +++ b/llvm/test/CodeGen/X86/combine-sbb.ll @@ -309,35 +309,25 @@ define i32 @PR40483_sub5(i32*, i32) nounwind { define i32 @PR40483_sub6(i32*, i32) nounwind { ; X86-LABEL: PR40483_sub6: ; X86: # %bb.0: -; X86-NEXT: pushl %edi -; X86-NEXT: pushl %esi ; X86-NEXT: movl {{[0-9]+}}(%esp), %edx -; X86-NEXT: movl (%edx), %esi -; X86-NEXT: movl {{[0-9]+}}(%esp), %edi -; X86-NEXT: movl %esi, %ecx -; X86-NEXT: subl %edi, %ecx +; X86-NEXT: movl (%edx), %ecx ; X86-NEXT: xorl %eax, %eax -; X86-NEXT: subl %edi, %esi -; X86-NEXT: movl %esi, (%edx) +; X86-NEXT: subl {{[0-9]+}}(%esp), %ecx +; X86-NEXT: movl %ecx, (%edx) ; X86-NEXT: jae .LBB8_2 ; X86-NEXT: # %bb.1: -; X86-NEXT: addl %ecx, %ecx -; X86-NEXT: movl %ecx, %eax +; X86-NEXT: leal (%ecx,%ecx), %eax ; X86-NEXT: .LBB8_2: -; X86-NEXT: popl %esi -; X86-NEXT: popl %edi ; X86-NEXT: retl ; ; X64-LABEL: PR40483_sub6: ; X64: # %bb.0: -; X64-NEXT: movl (%rdi), %ecx -; X64-NEXT: movl %ecx, %edx -; X64-NEXT: subl %esi, %edx -; X64-NEXT: addl %edx, %edx -; X64-NEXT: xorl %eax, %eax -; X64-NEXT: subl %esi, %ecx -; X64-NEXT: movl %ecx, (%rdi) -; X64-NEXT: cmovbl %edx, %eax +; X64-NEXT: movl (%rdi), %eax +; X64-NEXT: xorl %ecx, %ecx +; X64-NEXT: subl %esi, %eax +; X64-NEXT: movl %eax, (%rdi) +; X64-NEXT: leal (%rax,%rax), %eax +; X64-NEXT: cmovael %ecx, %eax ; X64-NEXT: retq %3 = load i32, i32* %0, align 8 %4 = tail call { i8, i32 } @llvm.x86.subborrow.32(i8 0, i32 %3, i32 %1) diff --git a/llvm/test/CodeGen/X86/haddsub-shuf-undef-operand.ll b/llvm/test/CodeGen/X86/haddsub-shuf-undef-operand.ll new file mode 100644 index 000000000000..b56ff9a9ad0e --- /dev/null +++ b/llvm/test/CodeGen/X86/haddsub-shuf-undef-operand.ll @@ -0,0 +1,26 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=x86_64-- -mattr=avx | FileCheck %s + +; Eliminating a shuffle means we have to replace an undef operand of a horizontal op. + +define void @PR43225(<4 x double>* %p0, <4 x double>* %p1, <4 x double> %x, <4 x double> %y, <4 x double> %z) nounwind { +; CHECK-LABEL: PR43225: +; CHECK: # %bb.0: +; CHECK-NEXT: vmovaps (%rdi), %ymm0 +; CHECK-NEXT: vmovaps (%rsi), %ymm0 +; CHECK-NEXT: vhsubpd %ymm2, %ymm2, %ymm0 +; CHECK-NEXT: vmovapd %ymm0, (%rdi) +; CHECK-NEXT: vzeroupper +; CHECK-NEXT: retq + %t39 = load volatile <4 x double>, <4 x double>* %p0, align 32 + %shuffle11 = shufflevector <4 x double> %t39, <4 x double> %x, <4 x i32> + %t40 = load volatile <4 x double>, <4 x double>* %p1, align 32 + %t41 = tail call <4 x double> @llvm.x86.avx.hadd.pd.256(<4 x double> %shuffle11, <4 x double> %t40) + %t42 = tail call <4 x double> @llvm.x86.avx.hsub.pd.256(<4 x double> %z, <4 x double> %t41) + %shuffle12 = shufflevector <4 x double> %t42, <4 x double> undef, <4 x i32> + store volatile <4 x double> %shuffle12, <4 x double>* %p0, align 32 + ret void +} + +declare <4 x double> @llvm.x86.avx.hadd.pd.256(<4 x double>, <4 x double>) +declare <4 x double> @llvm.x86.avx.hsub.pd.256(<4 x double>, <4 x double>) diff --git a/llvm/test/CodeGen/X86/inline-asm-bad-constraint-n.ll b/llvm/test/CodeGen/X86/inline-asm-bad-constraint-n.ll index 967477d076d3..a3099ab36795 100644 --- a/llvm/test/CodeGen/X86/inline-asm-bad-constraint-n.ll +++ b/llvm/test/CodeGen/X86/inline-asm-bad-constraint-n.ll @@ -2,7 +2,7 @@ @x = global i32 0, align 4 -;CHECK: error: invalid operand for inline asm constraint 'n' +; CHECK: error: constraint 'n' expects an integer constant expression define void @foo() { %a = getelementptr i32, i32* @x, i32 1 call void asm sideeffect "foo $0", "n"(i32* %a) nounwind diff --git a/llvm/test/CodeGen/X86/inline-asm-e-constraint.ll b/llvm/test/CodeGen/X86/inline-asm-e-constraint.ll new file mode 100644 index 000000000000..fd10ba424081 --- /dev/null +++ b/llvm/test/CodeGen/X86/inline-asm-e-constraint.ll @@ -0,0 +1,17 @@ +; RUN: not llc -mtriple=x86_64-unknown-unknown -no-integrated-as < %s 2>&1 | FileCheck %s + +%struct.s = type { i32, i32 } + +@pr40890.s = internal global %struct.s zeroinitializer, align 4 + +; CHECK: error: invalid operand for inline asm constraint 'e' +; CHECK: error: invalid operand for inline asm constraint 'e' + +define void @pr40890() { +entry: + ; This pointer cannot be used as an integer constant expression. + tail call void asm sideeffect "\0A#define GLOBAL_A abcd$0\0A", "e,~{dirflag},~{fpsr},~{flags}"(i32* getelementptr inbounds (%struct.s, %struct.s* @pr40890.s, i64 0, i32 0)) + ; Floating-point is also not okay. + tail call void asm sideeffect "\0A#define PI abcd$0\0A", "e,~{dirflag},~{fpsr},~{flags}"(float 0x40091EB860000000) + ret void +} diff --git a/llvm/test/CodeGen/X86/inline-asm-imm-out-of-range.ll b/llvm/test/CodeGen/X86/inline-asm-imm-out-of-range.ll new file mode 100644 index 000000000000..9c5177d02a16 --- /dev/null +++ b/llvm/test/CodeGen/X86/inline-asm-imm-out-of-range.ll @@ -0,0 +1,7 @@ +; RUN: not llc -mtriple=i686-- -no-integrated-as < %s 2>&1 | FileCheck %s + +; CHECK: error: value out of range for constraint 'I' +define void @foo() { + call void asm sideeffect "foo $0", "I"(i32 42) + ret void +} diff --git a/llvm/test/CodeGen/X86/inline-asm-n-constraint.ll b/llvm/test/CodeGen/X86/inline-asm-n-constraint.ll new file mode 100644 index 000000000000..669e464f1f6f --- /dev/null +++ b/llvm/test/CodeGen/X86/inline-asm-n-constraint.ll @@ -0,0 +1,13 @@ +; RUN: llc -mtriple=x86_64-unknown-unknown -no-integrated-as < %s 2>&1 | FileCheck %s + +@x = global i32 0, align 4 + +define void @foo() { +; CHECK-LABEL: foo: + call void asm sideeffect "foo $0", "n"(i32 42) nounwind +; CHECK: #APP +; CHECK-NEXT: foo $42 +; CHECK-NEXT: #NO_APP + ret void +; CHECK-NEXT: retq +} diff --git a/llvm/test/CodeGen/X86/label-heapallocsite.ll b/llvm/test/CodeGen/X86/label-heapallocsite.ll index f693695580ed..deb74c2ea237 100644 --- a/llvm/test/CodeGen/X86/label-heapallocsite.ll +++ b/llvm/test/CodeGen/X86/label-heapallocsite.ll @@ -1,80 +1,96 @@ -; RUN: llc -O0 < %s | FileCheck %s -; FIXME: Add test for llc with optimizations once it is implemented. +; RUN: llc < %s | FileCheck --check-prefixes=DAG,CHECK %s +; RUN: llc -O0 < %s | FileCheck --check-prefixes=FAST,CHECK %s ; Source to regenerate: -; $ clang --target=x86_64-windows-msvc -S heapallocsite.cpp -g -gcodeview -o t.ll \ -; -emit-llvm -O0 -Xclang -disable-llvm-passes -fms-extensions +; $ clang -cc1 -triple x86_64-windows-msvc t.cpp -debug-info-kind=limited \ +; -gcodeview -O2 -fms-extensions -emit-llvm -o t.ll ; -; struct Foo { +; extern "C" struct Foo { ; __declspec(allocator) virtual void *alloc(); ; }; -; ; extern "C" __declspec(allocator) Foo *alloc_foo(); -; -; extern "C" void use_alloc(void*); -; extern "C" void call_virtual(Foo *p) { -; use_alloc(p->alloc()); +; extern "C" void use_result(void *); +; extern "C" Foo *call_tail() { +; return alloc_foo(); ; } -; -; extern "C" void call_multiple() { -; use_alloc(alloc_foo()); -; use_alloc(alloc_foo()); +; extern "C" int call_virtual(Foo *p) { +; use_result(p->alloc()); +; return 0; +; } +; extern "C" int call_multiple() { +; use_result(alloc_foo()); +; use_result(alloc_foo()); +; return 0; ; } +; ModuleID = 't.cpp' +source_filename = "t.cpp" target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-windows-msvc" %struct.Foo = type { i32 (...)** } -; Function Attrs: noinline optnone uwtable -define dso_local void @call_virtual(%struct.Foo* %p) #0 !dbg !8 { +; Function Attrs: nounwind +define dso_local %struct.Foo* @call_tail() local_unnamed_addr #0 !dbg !7 { entry: - %p.addr = alloca %struct.Foo*, align 8 - store %struct.Foo* %p, %struct.Foo** %p.addr, align 8 - call void @llvm.dbg.declare(metadata %struct.Foo** %p.addr, metadata !13, metadata !DIExpression()), !dbg !14 - %0 = load %struct.Foo*, %struct.Foo** %p.addr, align 8, !dbg !15 - %1 = bitcast %struct.Foo* %0 to i8* (%struct.Foo*)***, !dbg !15 - %vtable = load i8* (%struct.Foo*)**, i8* (%struct.Foo*)*** %1, align 8, !dbg !15 - %vfn = getelementptr inbounds i8* (%struct.Foo*)*, i8* (%struct.Foo*)** %vtable, i64 0, !dbg !15 - %2 = load i8* (%struct.Foo*)*, i8* (%struct.Foo*)** %vfn, align 8, !dbg !15 - %call = call i8* %2(%struct.Foo* %0), !dbg !15, !heapallocsite !2 - call void @use_alloc(i8* %call), !dbg !15 - ret void, !dbg !16 + %call = tail call %struct.Foo* @alloc_foo() #3, !dbg !13, !heapallocsite !12 + ret %struct.Foo* %call, !dbg !13 } -; Function Attrs: nounwind readnone speculatable -declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 +declare dso_local %struct.Foo* @alloc_foo() local_unnamed_addr #1 + +; Function Attrs: nounwind +define dso_local i32 @call_virtual(%struct.Foo* %p) local_unnamed_addr #0 !dbg !14 { +entry: + call void @llvm.dbg.value(metadata %struct.Foo* %p, metadata !19, metadata !DIExpression()), !dbg !20 + %0 = bitcast %struct.Foo* %p to i8* (%struct.Foo*)***, !dbg !21 + %vtable = load i8* (%struct.Foo*)**, i8* (%struct.Foo*)*** %0, align 8, !dbg !21, !tbaa !22 + %1 = load i8* (%struct.Foo*)*, i8* (%struct.Foo*)** %vtable, align 8, !dbg !21 + %call = tail call i8* %1(%struct.Foo* %p) #3, !dbg !21, !heapallocsite !2 + tail call void @use_result(i8* %call) #3, !dbg !21 + ret i32 0, !dbg !25 +} -declare dso_local void @use_alloc(i8*) #2 +declare dso_local void @use_result(i8*) local_unnamed_addr #1 -; Function Attrs: noinline optnone uwtable -define dso_local void @call_multiple() #0 !dbg !17 { +; Function Attrs: nounwind +define dso_local i32 @call_multiple() local_unnamed_addr #0 !dbg !26 { entry: - %call = call %struct.Foo* @alloc_foo(), !dbg !20, !heapallocsite !12 - %0 = bitcast %struct.Foo* %call to i8*, !dbg !20 - call void @use_alloc(i8* %0), !dbg !20 - %call1 = call %struct.Foo* @alloc_foo(), !dbg !21, !heapallocsite !12 - %1 = bitcast %struct.Foo* %call1 to i8*, !dbg !21 - call void @use_alloc(i8* %1), !dbg !21 - ret void, !dbg !22 + %call = tail call %struct.Foo* @alloc_foo() #3, !dbg !29, !heapallocsite !12 + %0 = bitcast %struct.Foo* %call to i8*, !dbg !29 + tail call void @use_result(i8* %0) #3, !dbg !29 + %call1 = tail call %struct.Foo* @alloc_foo() #3, !dbg !30, !heapallocsite !12 + %1 = bitcast %struct.Foo* %call1 to i8*, !dbg !30 + tail call void @use_result(i8* %1) #3, !dbg !30 + ret i32 0, !dbg !31 } -declare dso_local %struct.Foo* @alloc_foo() #2 +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #2 -; CHECK-LABEL: call_virtual: # @call_virtual + +; Don't emit metadata for tail calls. +; CHECK-LABEL: call_tail: # @call_tail +; CHECK-NOT: .Lheapallocsite +; CHECK: jmp alloc_foo + +; CHECK-LABEL: call_virtual: # @call_virtual ; CHECK: .Lheapallocsite0: -; CHECK: callq *(%rax) +; CHECK: callq *{{.*}}%rax{{.*}} ; CHECK: .Lheapallocsite1: -; CHECK: retq -; CHECK-LABEL: call_multiple: # @call_multiple -; CHECK: .Lheapallocsite4: +; CHECK-LABEL: call_multiple: # @call_multiple +; FastISel emits instructions in a different order. +; DAG: .Lheapallocsite2: +; FAST: .Lheapallocsite4: ; CHECK: callq alloc_foo -; CHECK: .Lheapallocsite5: -; CHECK: .Lheapallocsite2: +; DAG: .Lheapallocsite3: +; FAST: .Lheapallocsite5: +; DAG: .Lheapallocsite4: +; FAST: .Lheapallocsite2: ; CHECK: callq alloc_foo -; CHECK: .Lheapallocsite3: -; CHECK: retq +; DAG: .Lheapallocsite5: +; FAST: .Lheapallocsite3: ; CHECK-LABEL: .short 4423 # Record kind: S_GPROC32_ID ; CHECK: .short 4446 # Record kind: S_HEAPALLOCSITE @@ -82,48 +98,55 @@ declare dso_local %struct.Foo* @alloc_foo() #2 ; CHECK-NEXT: .secidx .Lheapallocsite0 ; CHECK-NEXT: .short .Lheapallocsite1-.Lheapallocsite0 ; CHECK-NEXT: .long 3 -; CHECK-NEXT: .p2align 2 -; CHECK-LABEL: .short 4431 # Record kind: S_PROC_ID_END - -; CHECK-LABEL: .short 4423 # Record kind: S_GPROC32_ID ; CHECK: .short 4446 # Record kind: S_HEAPALLOCSITE ; CHECK-NEXT: .secrel32 .Lheapallocsite2 ; CHECK-NEXT: .secidx .Lheapallocsite2 ; CHECK-NEXT: .short .Lheapallocsite3-.Lheapallocsite2 ; CHECK-NEXT: .long 4096 -; CHECK-NEXT: .p2align 2 - ; CHECK: .short 4446 # Record kind: S_HEAPALLOCSITE ; CHECK-NEXT: .secrel32 .Lheapallocsite4 ; CHECK-NEXT: .secidx .Lheapallocsite4 ; CHECK-NEXT: .short .Lheapallocsite5-.Lheapallocsite4 ; CHECK-NEXT: .long 4096 -; CHECK-NEXT: .p2align 2 -; CHECK-LABEL: .short 4431 # Record kind: S_PROC_ID_END + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind readnone speculatable willreturn } +attributes #3 = { nounwind } !llvm.dbg.cu = !{!0} -!llvm.module.flags = !{!3, !4, !5, !6} -!llvm.ident = !{!7} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} -!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (https://github.com/llvm/llvm-project.git 9c8073f44f786fbf47335e53f20abe64429e8e47)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None)!1 = !DIFile(filename: "filename", directory: "directory", checksumkind: CSK_MD5, checksum: "096443b661a0af36da9006330c08f97e") +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 10.0.0 (https://github.com/llvm/llvm-project.git fa686ea7650235c6dff988cc8cba49e130b3d5f8)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "", directory: "/usr/local/google/home/akhuang/testing/heapallocsite", checksumkind: CSK_MD5, checksum: "e0a04508b4229fc4aee0baa364e25987") !2 = !{} !3 = !{i32 2, !"CodeView", i32 1} !4 = !{i32 2, !"Debug Info Version", i32 3} !5 = !{i32 1, !"wchar_size", i32 2} -!6 = !{i32 7, !"PIC Level", i32 2} -!7 = !{!"clang version 9.0.0 (https://github.com/llvm/llvm-project.git 9c8073f44f786fbf47335e53f20abe64429e8e47)"} -!8 = distinct !DISubprogram(name: "call_virtual", scope: !1, file: !1, line: 8, type: !9, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!6 = !{!"clang version 10.0.0 (https://github.com/llvm/llvm-project.git fa686ea7650235c6dff988cc8cba49e130b3d5f8)"} +!7 = distinct !DISubprogram(name: "call_tail", scope: !8, file: !8, line: 6, type: !9, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2) +!8 = !DIFile(filename: "t.cpp", directory: "/usr/local/google/home/akhuang/testing/heapallocsite", checksumkind: CSK_MD5, checksum: "e0a04508b4229fc4aee0baa364e25987") !9 = !DISubroutineType(types: !10) -!10 = !{null, !11} +!10 = !{!11} !11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 64) -!12 = !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", file: !1, line: 1, flags: DIFlagFwdDecl, identifier: ".?AUFoo@@") -!13 = !DILocalVariable(name: "p", arg: 1, scope: !8, file: !1, line: 8, type: !11) -!14 = !DILocation(line: 8, scope: !8) -!15 = !DILocation(line: 9, scope: !8) -!16 = !DILocation(line: 10, scope: !8) -!17 = distinct !DISubprogram(name: "call_multiple", scope: !1, file: !1, line: 12, type: !18, scopeLine: 12, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) -!18 = !DISubroutineType(types: !19) -!19 = !{null} -!20 = !DILocation(line: 13, scope: !17) -!21 = !DILocation(line: 14, scope: !17) -!22 = !DILocation(line: 15, scope: !17) +!12 = !DICompositeType(tag: DW_TAG_structure_type, name: "Foo", file: !8, line: 1, flags: DIFlagFwdDecl, identifier: ".?AUFoo@@") +!13 = !DILocation(line: 7, scope: !7) +!14 = distinct !DISubprogram(name: "call_virtual", scope: !8, file: !8, line: 9, type: !15, scopeLine: 9, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !18) +!15 = !DISubroutineType(types: !16) +!16 = !{!17, !11} +!17 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!18 = !{!19} +!19 = !DILocalVariable(name: "p", arg: 1, scope: !14, file: !8, line: 9, type: !11) +!20 = !DILocation(line: 0, scope: !14) +!21 = !DILocation(line: 10, scope: !14) +!22 = !{!23, !23, i64 0} +!23 = !{!"vtable pointer", !24, i64 0} +!24 = !{!"Simple C++ TBAA"} +!25 = !DILocation(line: 11, scope: !14) +!26 = distinct !DISubprogram(name: "call_multiple", scope: !8, file: !8, line: 13, type: !27, scopeLine: 13, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2) +!27 = !DISubroutineType(types: !28) +!28 = !{!17} +!29 = !DILocation(line: 14, scope: !26) +!30 = !DILocation(line: 15, scope: !26) +!31 = !DILocation(line: 16, scope: !26) diff --git a/llvm/test/CodeGen/X86/mingw-refptr.ll b/llvm/test/CodeGen/X86/mingw-refptr.ll index 158462dd2831..8d5712b2a7ed 100644 --- a/llvm/test/CodeGen/X86/mingw-refptr.ll +++ b/llvm/test/CodeGen/X86/mingw-refptr.ll @@ -1,5 +1,6 @@ ; RUN: llc < %s -mtriple=x86_64-w64-mingw32 | FileCheck %s -check-prefix=CHECK-X64 ; RUN: llc < %s -mtriple=i686-w64-mingw32 | FileCheck %s -check-prefix=CHECK-X86 +; RUN: llc < %s -mtriple=i686-w64-mingw32-none-elf | FileCheck %s -check-prefix=CHECK-X86-ELF @var = external local_unnamed_addr global i32, align 4 @dsolocalvar = external dso_local local_unnamed_addr global i32, align 4 @@ -16,6 +17,9 @@ define dso_local i32 @getVar() { ; CHECK-X86: movl .refptr._var, %eax ; CHECK-X86: movl (%eax), %eax ; CHECK-X86: retl +; CHECK-X86-ELF-LABEL: getVar: +; CHECK-X86-ELF: movl var, %eax +; CHECK-X86-ELF: retl entry: %0 = load i32, i32* @var, align 4 ret i32 %0 @@ -66,6 +70,9 @@ define dso_local i32 @getExtVar() { ; CHECK-X86: movl __imp__extvar, %eax ; CHECK-X86: movl (%eax), %eax ; CHECK-X86: retl +; CHECK-X86-ELF-LABEL: getExtVar: +; CHECK-X86-ELF: movl extvar, %eax +; CHECK-X86-ELF: retl entry: %0 = load i32, i32* @extvar, align 4 ret i32 %0 diff --git a/llvm/test/CodeGen/X86/oddsubvector.ll b/llvm/test/CodeGen/X86/oddsubvector.ll index 9bc6c0f380a0..2db39b1b9369 100644 --- a/llvm/test/CodeGen/X86/oddsubvector.ll +++ b/llvm/test/CodeGen/X86/oddsubvector.ll @@ -158,3 +158,271 @@ define void @PR40815(%struct.Mat4* nocapture readonly dereferenceable(64), %stru store <4 x float> %5, <4 x float>* %13, align 16 ret void } + +define <16 x i32> @PR42819(<8 x i32>* %a0) { +; SSE-LABEL: PR42819: +; SSE: # %bb.0: +; SSE-NEXT: movdqu (%rdi), %xmm3 +; SSE-NEXT: pslldq {{.*#+}} xmm3 = zero,zero,zero,zero,xmm3[0,1,2,3,4,5,6,7,8,9,10,11] +; SSE-NEXT: xorps %xmm0, %xmm0 +; SSE-NEXT: xorps %xmm1, %xmm1 +; SSE-NEXT: xorps %xmm2, %xmm2 +; SSE-NEXT: retq +; +; AVX-LABEL: PR42819: +; AVX: # %bb.0: +; AVX-NEXT: vpermilps {{.*#+}} xmm0 = mem[0,0,1,2] +; AVX-NEXT: vinsertf128 $1, %xmm0, %ymm0, %ymm0 +; AVX-NEXT: vxorps %xmm1, %xmm1, %xmm1 +; AVX-NEXT: vblendps {{.*#+}} ymm1 = ymm1[0,1,2,3,4],ymm0[5,6,7] +; AVX-NEXT: vxorps %xmm0, %xmm0, %xmm0 +; AVX-NEXT: retq +; +; AVX512-LABEL: PR42819: +; AVX512: # %bb.0: +; AVX512-NEXT: vmovdqu (%rdi), %xmm0 +; AVX512-NEXT: movw $-8192, %ax # imm = 0xE000 +; AVX512-NEXT: kmovw %eax, %k1 +; AVX512-NEXT: vpexpandd %zmm0, %zmm0 {%k1} {z} +; AVX512-NEXT: retq + %1 = load <8 x i32>, <8 x i32>* %a0, align 4 + %2 = shufflevector <8 x i32> %1, <8 x i32> undef, <16 x i32> + %3 = shufflevector <16 x i32> zeroinitializer, <16 x i32> %2, <16 x i32> + ret <16 x i32> %3 +} + +@b = dso_local local_unnamed_addr global i32 0, align 4 +@c = dso_local local_unnamed_addr global [49 x i32] zeroinitializer, align 16 +@d = dso_local local_unnamed_addr global [49 x i32] zeroinitializer, align 16 + +define void @PR42833() { +; SSE2-LABEL: PR42833: +; SSE2: # %bb.0: +; SSE2-NEXT: movdqa c+{{.*}}(%rip), %xmm1 +; SSE2-NEXT: movdqa c+{{.*}}(%rip), %xmm0 +; SSE2-NEXT: movd %xmm0, %eax +; SSE2-NEXT: addl {{.*}}(%rip), %eax +; SSE2-NEXT: movd %eax, %xmm2 +; SSE2-NEXT: movaps {{.*#+}} xmm3 = +; SSE2-NEXT: movss {{.*#+}} xmm3 = xmm2[0],xmm3[1,2,3] +; SSE2-NEXT: movdqa %xmm0, %xmm4 +; SSE2-NEXT: paddd %xmm3, %xmm4 +; SSE2-NEXT: pslld $23, %xmm3 +; SSE2-NEXT: paddd {{.*}}(%rip), %xmm3 +; SSE2-NEXT: cvttps2dq %xmm3, %xmm3 +; SSE2-NEXT: movdqa %xmm0, %xmm5 +; SSE2-NEXT: pmuludq %xmm3, %xmm5 +; SSE2-NEXT: pshufd {{.*#+}} xmm5 = xmm5[0,2,2,3] +; SSE2-NEXT: pshufd {{.*#+}} xmm3 = xmm3[1,1,3,3] +; SSE2-NEXT: pshufd {{.*#+}} xmm6 = xmm0[1,1,3,3] +; SSE2-NEXT: pmuludq %xmm3, %xmm6 +; SSE2-NEXT: pshufd {{.*#+}} xmm3 = xmm6[0,2,2,3] +; SSE2-NEXT: punpckldq {{.*#+}} xmm5 = xmm5[0],xmm3[0],xmm5[1],xmm3[1] +; SSE2-NEXT: movss {{.*#+}} xmm5 = xmm4[0],xmm5[1,2,3] +; SSE2-NEXT: movdqa d+{{.*}}(%rip), %xmm3 +; SSE2-NEXT: psubd %xmm1, %xmm3 +; SSE2-NEXT: paddd %xmm1, %xmm1 +; SSE2-NEXT: movdqa %xmm1, c+{{.*}}(%rip) +; SSE2-NEXT: movaps %xmm5, c+{{.*}}(%rip) +; SSE2-NEXT: movdqa c+{{.*}}(%rip), %xmm1 +; SSE2-NEXT: movdqa c+{{.*}}(%rip), %xmm4 +; SSE2-NEXT: movdqa d+{{.*}}(%rip), %xmm5 +; SSE2-NEXT: movdqa d+{{.*}}(%rip), %xmm6 +; SSE2-NEXT: movdqa d+{{.*}}(%rip), %xmm7 +; SSE2-NEXT: movss {{.*#+}} xmm0 = xmm2[0],xmm0[1,2,3] +; SSE2-NEXT: psubd %xmm0, %xmm7 +; SSE2-NEXT: psubd %xmm4, %xmm6 +; SSE2-NEXT: psubd %xmm1, %xmm5 +; SSE2-NEXT: movdqa %xmm5, d+{{.*}}(%rip) +; SSE2-NEXT: movdqa %xmm6, d+{{.*}}(%rip) +; SSE2-NEXT: movdqa %xmm3, d+{{.*}}(%rip) +; SSE2-NEXT: movdqa %xmm7, d+{{.*}}(%rip) +; SSE2-NEXT: paddd %xmm4, %xmm4 +; SSE2-NEXT: paddd %xmm1, %xmm1 +; SSE2-NEXT: movdqa %xmm1, c+{{.*}}(%rip) +; SSE2-NEXT: movdqa %xmm4, c+{{.*}}(%rip) +; SSE2-NEXT: retq +; +; SSE42-LABEL: PR42833: +; SSE42: # %bb.0: +; SSE42-NEXT: movdqa c+{{.*}}(%rip), %xmm1 +; SSE42-NEXT: movdqa c+{{.*}}(%rip), %xmm0 +; SSE42-NEXT: movd %xmm0, %eax +; SSE42-NEXT: addl {{.*}}(%rip), %eax +; SSE42-NEXT: movdqa {{.*#+}} xmm2 = +; SSE42-NEXT: pinsrd $0, %eax, %xmm2 +; SSE42-NEXT: movdqa %xmm0, %xmm3 +; SSE42-NEXT: paddd %xmm2, %xmm3 +; SSE42-NEXT: pslld $23, %xmm2 +; SSE42-NEXT: paddd {{.*}}(%rip), %xmm2 +; SSE42-NEXT: cvttps2dq %xmm2, %xmm2 +; SSE42-NEXT: pmulld %xmm0, %xmm2 +; SSE42-NEXT: pblendw {{.*#+}} xmm2 = xmm3[0,1],xmm2[2,3,4,5,6,7] +; SSE42-NEXT: movdqa d+{{.*}}(%rip), %xmm3 +; SSE42-NEXT: psubd %xmm1, %xmm3 +; SSE42-NEXT: paddd %xmm1, %xmm1 +; SSE42-NEXT: movdqa %xmm1, c+{{.*}}(%rip) +; SSE42-NEXT: movdqa %xmm2, c+{{.*}}(%rip) +; SSE42-NEXT: movdqa c+{{.*}}(%rip), %xmm1 +; SSE42-NEXT: movdqa c+{{.*}}(%rip), %xmm2 +; SSE42-NEXT: movdqa d+{{.*}}(%rip), %xmm4 +; SSE42-NEXT: movdqa d+{{.*}}(%rip), %xmm5 +; SSE42-NEXT: movdqa d+{{.*}}(%rip), %xmm6 +; SSE42-NEXT: pinsrd $0, %eax, %xmm0 +; SSE42-NEXT: psubd %xmm0, %xmm6 +; SSE42-NEXT: psubd %xmm2, %xmm5 +; SSE42-NEXT: psubd %xmm1, %xmm4 +; SSE42-NEXT: movdqa %xmm4, d+{{.*}}(%rip) +; SSE42-NEXT: movdqa %xmm5, d+{{.*}}(%rip) +; SSE42-NEXT: movdqa %xmm3, d+{{.*}}(%rip) +; SSE42-NEXT: movdqa %xmm6, d+{{.*}}(%rip) +; SSE42-NEXT: paddd %xmm2, %xmm2 +; SSE42-NEXT: paddd %xmm1, %xmm1 +; SSE42-NEXT: movdqa %xmm1, c+{{.*}}(%rip) +; SSE42-NEXT: movdqa %xmm2, c+{{.*}}(%rip) +; SSE42-NEXT: retq +; +; AVX1-LABEL: PR42833: +; AVX1: # %bb.0: +; AVX1-NEXT: vmovdqa c+{{.*}}(%rip), %xmm0 +; AVX1-NEXT: vmovd %xmm0, %eax +; AVX1-NEXT: addl {{.*}}(%rip), %eax +; AVX1-NEXT: vmovdqa {{.*#+}} xmm1 = +; AVX1-NEXT: vpinsrd $0, %eax, %xmm1, %xmm1 +; AVX1-NEXT: vpaddd %xmm1, %xmm0, %xmm2 +; AVX1-NEXT: vmovdqa c+{{.*}}(%rip), %xmm3 +; AVX1-NEXT: vpslld $23, %xmm1, %xmm1 +; AVX1-NEXT: vpaddd {{.*}}(%rip), %xmm1, %xmm1 +; AVX1-NEXT: vcvttps2dq %xmm1, %xmm1 +; AVX1-NEXT: vpmulld %xmm1, %xmm0, %xmm1 +; AVX1-NEXT: vpslld $1, %xmm3, %xmm3 +; AVX1-NEXT: vinsertf128 $1, %xmm3, %ymm1, %ymm1 +; AVX1-NEXT: vblendps {{.*#+}} ymm1 = ymm2[0],ymm1[1,2,3,4,5,6,7] +; AVX1-NEXT: vmovdqa d+{{.*}}(%rip), %xmm2 +; AVX1-NEXT: vpsubd c+{{.*}}(%rip), %xmm2, %xmm2 +; AVX1-NEXT: vmovups %ymm1, c+{{.*}}(%rip) +; AVX1-NEXT: vpinsrd $0, %eax, %xmm0, %xmm0 +; AVX1-NEXT: vmovdqa d+{{.*}}(%rip), %xmm1 +; AVX1-NEXT: vpsubd %xmm0, %xmm1, %xmm0 +; AVX1-NEXT: vmovdqa d+{{.*}}(%rip), %xmm1 +; AVX1-NEXT: vmovdqa c+{{.*}}(%rip), %xmm3 +; AVX1-NEXT: vpsubd %xmm3, %xmm1, %xmm1 +; AVX1-NEXT: vmovdqa d+{{.*}}(%rip), %xmm4 +; AVX1-NEXT: vmovdqa c+{{.*}}(%rip), %xmm5 +; AVX1-NEXT: vpsubd %xmm5, %xmm4, %xmm4 +; AVX1-NEXT: vmovdqa %xmm2, d+{{.*}}(%rip) +; AVX1-NEXT: vmovdqa %xmm4, d+{{.*}}(%rip) +; AVX1-NEXT: vmovdqa %xmm1, d+{{.*}}(%rip) +; AVX1-NEXT: vmovdqa %xmm0, d+{{.*}}(%rip) +; AVX1-NEXT: vpaddd %xmm3, %xmm3, %xmm0 +; AVX1-NEXT: vpaddd %xmm5, %xmm5, %xmm1 +; AVX1-NEXT: vmovdqa %xmm1, c+{{.*}}(%rip) +; AVX1-NEXT: vmovdqa %xmm0, c+{{.*}}(%rip) +; AVX1-NEXT: vzeroupper +; AVX1-NEXT: retq +; +; AVX2-LABEL: PR42833: +; AVX2: # %bb.0: +; AVX2-NEXT: movl {{.*}}(%rip), %eax +; AVX2-NEXT: vmovdqu c+{{.*}}(%rip), %ymm0 +; AVX2-NEXT: addl c+{{.*}}(%rip), %eax +; AVX2-NEXT: vmovd %eax, %xmm1 +; AVX2-NEXT: vpblendd {{.*#+}} ymm2 = ymm1[0],mem[1,2,3,4,5,6,7] +; AVX2-NEXT: vpaddd %ymm2, %ymm0, %ymm3 +; AVX2-NEXT: vpsllvd %ymm2, %ymm0, %ymm2 +; AVX2-NEXT: vpblendd {{.*#+}} ymm2 = ymm3[0],ymm2[1,2,3,4,5,6,7] +; AVX2-NEXT: vmovdqu %ymm2, c+{{.*}}(%rip) +; AVX2-NEXT: vmovdqu c+{{.*}}(%rip), %ymm2 +; AVX2-NEXT: vmovdqu d+{{.*}}(%rip), %ymm3 +; AVX2-NEXT: vmovdqu d+{{.*}}(%rip), %ymm4 +; AVX2-NEXT: vpblendd {{.*#+}} ymm0 = ymm1[0],ymm0[1,2,3,4,5,6,7] +; AVX2-NEXT: vpsubd %ymm0, %ymm4, %ymm0 +; AVX2-NEXT: vpsubd %ymm2, %ymm3, %ymm1 +; AVX2-NEXT: vmovdqu %ymm1, d+{{.*}}(%rip) +; AVX2-NEXT: vmovdqu %ymm0, d+{{.*}}(%rip) +; AVX2-NEXT: vpaddd %ymm2, %ymm2, %ymm0 +; AVX2-NEXT: vmovdqu %ymm0, c+{{.*}}(%rip) +; AVX2-NEXT: vzeroupper +; AVX2-NEXT: retq +; +; AVX512-LABEL: PR42833: +; AVX512: # %bb.0: +; AVX512-NEXT: movl {{.*}}(%rip), %eax +; AVX512-NEXT: vmovdqu c+{{.*}}(%rip), %ymm0 +; AVX512-NEXT: vmovdqu64 c+{{.*}}(%rip), %zmm1 +; AVX512-NEXT: addl c+{{.*}}(%rip), %eax +; AVX512-NEXT: vmovd %eax, %xmm2 +; AVX512-NEXT: vpblendd {{.*#+}} ymm2 = ymm2[0],mem[1,2,3,4,5,6,7] +; AVX512-NEXT: vpaddd %ymm2, %ymm0, %ymm3 +; AVX512-NEXT: vpsllvd %ymm2, %ymm0, %ymm0 +; AVX512-NEXT: vpblendd {{.*#+}} ymm0 = ymm3[0],ymm0[1,2,3,4,5,6,7] +; AVX512-NEXT: vmovdqa c+{{.*}}(%rip), %xmm2 +; AVX512-NEXT: vmovdqu %ymm0, c+{{.*}}(%rip) +; AVX512-NEXT: vmovdqu c+{{.*}}(%rip), %ymm0 +; AVX512-NEXT: vmovdqu64 d+{{.*}}(%rip), %zmm3 +; AVX512-NEXT: vpinsrd $0, %eax, %xmm2, %xmm2 +; AVX512-NEXT: vinserti32x4 $0, %xmm2, %zmm1, %zmm1 +; AVX512-NEXT: vinserti64x4 $1, %ymm0, %zmm1, %zmm1 +; AVX512-NEXT: vpsubd %zmm1, %zmm3, %zmm1 +; AVX512-NEXT: vmovdqu64 %zmm1, d+{{.*}}(%rip) +; AVX512-NEXT: vpaddd %ymm0, %ymm0, %ymm0 +; AVX512-NEXT: vmovdqu %ymm0, c+{{.*}}(%rip) +; AVX512-NEXT: vzeroupper +; AVX512-NEXT: retq +; +; XOP-LABEL: PR42833: +; XOP: # %bb.0: +; XOP-NEXT: vmovdqa c+{{.*}}(%rip), %xmm0 +; XOP-NEXT: vmovd %xmm0, %eax +; XOP-NEXT: addl {{.*}}(%rip), %eax +; XOP-NEXT: vmovdqa {{.*#+}} xmm1 = +; XOP-NEXT: vpinsrd $0, %eax, %xmm1, %xmm1 +; XOP-NEXT: vpaddd %xmm1, %xmm0, %xmm2 +; XOP-NEXT: vmovdqa c+{{.*}}(%rip), %xmm3 +; XOP-NEXT: vpshld %xmm1, %xmm0, %xmm1 +; XOP-NEXT: vpslld $1, %xmm3, %xmm3 +; XOP-NEXT: vinsertf128 $1, %xmm3, %ymm1, %ymm1 +; XOP-NEXT: vblendps {{.*#+}} ymm1 = ymm2[0],ymm1[1,2,3,4,5,6,7] +; XOP-NEXT: vmovdqa d+{{.*}}(%rip), %xmm2 +; XOP-NEXT: vpsubd c+{{.*}}(%rip), %xmm2, %xmm2 +; XOP-NEXT: vmovups %ymm1, c+{{.*}}(%rip) +; XOP-NEXT: vpinsrd $0, %eax, %xmm0, %xmm0 +; XOP-NEXT: vmovdqa d+{{.*}}(%rip), %xmm1 +; XOP-NEXT: vpsubd %xmm0, %xmm1, %xmm0 +; XOP-NEXT: vmovdqa d+{{.*}}(%rip), %xmm1 +; XOP-NEXT: vmovdqa c+{{.*}}(%rip), %xmm3 +; XOP-NEXT: vpsubd %xmm3, %xmm1, %xmm1 +; XOP-NEXT: vmovdqa d+{{.*}}(%rip), %xmm4 +; XOP-NEXT: vmovdqa c+{{.*}}(%rip), %xmm5 +; XOP-NEXT: vpsubd %xmm5, %xmm4, %xmm4 +; XOP-NEXT: vmovdqa %xmm2, d+{{.*}}(%rip) +; XOP-NEXT: vmovdqa %xmm4, d+{{.*}}(%rip) +; XOP-NEXT: vmovdqa %xmm1, d+{{.*}}(%rip) +; XOP-NEXT: vmovdqa %xmm0, d+{{.*}}(%rip) +; XOP-NEXT: vpaddd %xmm3, %xmm3, %xmm0 +; XOP-NEXT: vpaddd %xmm5, %xmm5, %xmm1 +; XOP-NEXT: vmovdqa %xmm1, c+{{.*}}(%rip) +; XOP-NEXT: vmovdqa %xmm0, c+{{.*}}(%rip) +; XOP-NEXT: vzeroupper +; XOP-NEXT: retq + %1 = load i32, i32* @b, align 4 + %2 = load <8 x i32>, <8 x i32>* bitcast (i32* getelementptr inbounds ([49 x i32], [49 x i32]* @c, i64 0, i64 32) to <8 x i32>*), align 16 + %3 = shufflevector <8 x i32> %2, <8 x i32> undef, <16 x i32> + %4 = extractelement <8 x i32> %2, i32 0 + %5 = add i32 %1, %4 + %6 = insertelement <8 x i32> , i32 %5, i32 0 + %7 = add <8 x i32> %2, %6 + %8 = shl <8 x i32> %2, %6 + %9 = shufflevector <8 x i32> %7, <8 x i32> %8, <8 x i32> + store <8 x i32> %9, <8 x i32>* bitcast (i32* getelementptr inbounds ([49 x i32], [49 x i32]* @c, i64 0, i64 32) to <8 x i32>*), align 16 + %10 = load <8 x i32>, <8 x i32>* bitcast (i32* getelementptr inbounds ([49 x i32], [49 x i32]* @c, i64 0, i64 40) to <8 x i32>*), align 16 + %11 = shufflevector <8 x i32> %10, <8 x i32> undef, <16 x i32> + %12 = load <16 x i32>, <16 x i32>* bitcast (i32* getelementptr inbounds ([49 x i32], [49 x i32]* @d, i64 0, i64 32) to <16 x i32>*), align 16 + %13 = insertelement <16 x i32> %3, i32 %5, i32 0 + %14 = shufflevector <16 x i32> %13, <16 x i32> %11, <16 x i32> + %15 = sub <16 x i32> %12, %14 + store <16 x i32> %15, <16 x i32>* bitcast (i32* getelementptr inbounds ([49 x i32], [49 x i32]* @d, i64 0, i64 32) to <16 x i32>*), align 16 + %16 = shl <8 x i32> %10, + store <8 x i32> %16, <8 x i32>* bitcast (i32* getelementptr inbounds ([49 x i32], [49 x i32]* @c, i64 0, i64 40) to <8 x i32>*), align 16 + ret void +} diff --git a/llvm/test/CodeGen/X86/pr42992.ll b/llvm/test/CodeGen/X86/pr42992.ll new file mode 100644 index 000000000000..f85b5921b108 --- /dev/null +++ b/llvm/test/CodeGen/X86/pr42992.ll @@ -0,0 +1,17 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=bmi2 | FileCheck %s + +define i32 @hoge(i32 %a) { +; CHECK-LABEL: hoge: +; CHECK: # %bb.0: # %bb +; CHECK-NEXT: movl $15, %eax +; CHECK-NEXT: bzhil %edi, %eax, %eax +; CHECK-NEXT: shll $8, %eax +; CHECK-NEXT: retq +bb: + %tmp3 = shl nsw i32 -1, %a + %tmp4 = xor i32 %tmp3, -1 + %tmp5 = shl i32 %tmp4, 8 + %tmp6 = and i32 %tmp5, 3840 + ret i32 %tmp6 +} diff --git a/llvm/test/CodeGen/X86/shift_minsize.ll b/llvm/test/CodeGen/X86/shift_minsize.ll index 5ba46544645f..548c2d37707a 100644 --- a/llvm/test/CodeGen/X86/shift_minsize.ll +++ b/llvm/test/CodeGen/X86/shift_minsize.ll @@ -1,5 +1,11 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; RUN: llc < %s -mtriple=x86_64-unknown | FileCheck %s +; RUN: llc < %s -mtriple=x86_64-unknown | FileCheck %s +; RUN: llc < %s -mtriple=x86_64--windows-msvc | FileCheck %s -check-prefix=CHECK-WIN + +; The Windows runtime doesn't have these. +; CHECK-WIN-NOT: __ashlti3 +; CHECK-WIN-NOT: __ashrti3 +; CHECK-WIN-NOT: __lshrti3 define i64 @f0(i64 %val, i64 %amt) minsize optsize { ; CHECK-LABEL: f0: diff --git a/llvm/test/CodeGen/X86/vector-shuffle-256-v16.ll b/llvm/test/CodeGen/X86/vector-shuffle-256-v16.ll index 0be1fec5ecd2..001288f87d77 100644 --- a/llvm/test/CodeGen/X86/vector-shuffle-256-v16.ll +++ b/llvm/test/CodeGen/X86/vector-shuffle-256-v16.ll @@ -4754,3 +4754,44 @@ define <16 x i16> @unpckh_v16i16(<16 x i16> %x, <16 x i16> %y) { ret <16 x i16> %unpckh } +define <16 x i16> @pr43230(<16 x i16> %a, <16 x i16> %b) { +; AVX1-LABEL: pr43230: +; AVX1: # %bb.0: +; AVX1-NEXT: vextractf128 $1, %ymm1, %xmm1 +; AVX1-NEXT: vpsllw $12, %xmm1, %xmm2 +; AVX1-NEXT: vpsllw $4, %xmm1, %xmm1 +; AVX1-NEXT: vpor %xmm2, %xmm1, %xmm1 +; AVX1-NEXT: vpaddw %xmm1, %xmm1, %xmm2 +; AVX1-NEXT: vextractf128 $1, %ymm0, %xmm0 +; AVX1-NEXT: vpsrlw $8, %xmm0, %xmm3 +; AVX1-NEXT: vpblendvb %xmm1, %xmm3, %xmm0, %xmm0 +; AVX1-NEXT: vpsrlw $4, %xmm0, %xmm1 +; AVX1-NEXT: vpblendvb %xmm2, %xmm1, %xmm0, %xmm0 +; AVX1-NEXT: vpsrlw $2, %xmm0, %xmm1 +; AVX1-NEXT: vpaddw %xmm2, %xmm2, %xmm2 +; AVX1-NEXT: vpblendvb %xmm2, %xmm1, %xmm0, %xmm0 +; AVX1-NEXT: vpsrlw $1, %xmm0, %xmm1 +; AVX1-NEXT: vpaddw %xmm2, %xmm2, %xmm2 +; AVX1-NEXT: vpblendvb %xmm2, %xmm1, %xmm0, %xmm0 +; AVX1-NEXT: vinsertf128 $1, %xmm0, %ymm0, %ymm0 +; AVX1-NEXT: vandps {{.*}}(%rip), %ymm0, %ymm0 +; AVX1-NEXT: retq +; +; AVX2-LABEL: pr43230: +; AVX2: # %bb.0: +; AVX2-NEXT: vpxor %xmm2, %xmm2, %xmm2 +; AVX2-NEXT: vpunpckhwd {{.*#+}} ymm1 = ymm1[4],ymm2[4],ymm1[5],ymm2[5],ymm1[6],ymm2[6],ymm1[7],ymm2[7],ymm1[12],ymm2[12],ymm1[13],ymm2[13],ymm1[14],ymm2[14],ymm1[15],ymm2[15] +; AVX2-NEXT: vpunpckhwd {{.*#+}} ymm0 = ymm2[4],ymm0[4],ymm2[5],ymm0[5],ymm2[6],ymm0[6],ymm2[7],ymm0[7],ymm2[12],ymm0[12],ymm2[13],ymm0[13],ymm2[14],ymm0[14],ymm2[15],ymm0[15] +; AVX2-NEXT: vpsrlvd %ymm1, %ymm0, %ymm0 +; AVX2-NEXT: vpshufb {{.*#+}} ymm0 = zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,zero,ymm0[26,27],zero,zero +; AVX2-NEXT: retq +; +; AVX512VL-LABEL: pr43230: +; AVX512VL: # %bb.0: +; AVX512VL-NEXT: vpsrlvw %ymm1, %ymm0, %ymm0 +; AVX512VL-NEXT: vpand {{.*}}(%rip), %ymm0, %ymm0 +; AVX512VL-NEXT: retq + %shr = lshr <16 x i16> %a, %b + %shuf = shufflevector <16 x i16> zeroinitializer, <16 x i16> %shr, <16 x i32> + ret <16 x i16> %shuf +} diff --git a/llvm/test/CodeGen/X86/vector-shuffle-avx512.ll b/llvm/test/CodeGen/X86/vector-shuffle-avx512.ll index 2092b3bf4530..65472aaeea7e 100644 --- a/llvm/test/CodeGen/X86/vector-shuffle-avx512.ll +++ b/llvm/test/CodeGen/X86/vector-shuffle-avx512.ll @@ -936,3 +936,41 @@ define <16 x float> @test_masked_permps_v16f32(<16 x float>* %vp, <16 x float> % %res = select <16 x i1> , <16 x float> %shuf, <16 x float> %vec2 ret <16 x float> %res } + +%union1= type { <16 x float> } +@src1 = external dso_local local_unnamed_addr global %union1, align 64 + +define void @PR43170(<16 x float>* %a0) { +; SKX64-LABEL: PR43170: +; SKX64: # %bb.0: # %entry +; SKX64-NEXT: vmovaps {{.*}}(%rip), %ymm0 +; SKX64-NEXT: vmovaps %zmm0, (%rdi) +; SKX64-NEXT: vzeroupper +; SKX64-NEXT: retq +; +; KNL64-LABEL: PR43170: +; KNL64: # %bb.0: # %entry +; KNL64-NEXT: vmovaps {{.*}}(%rip), %ymm0 +; KNL64-NEXT: vmovaps %zmm0, (%rdi) +; KNL64-NEXT: retq +; +; SKX32-LABEL: PR43170: +; SKX32: # %bb.0: # %entry +; SKX32-NEXT: movl {{[0-9]+}}(%esp), %eax +; SKX32-NEXT: vmovaps src1, %ymm0 +; SKX32-NEXT: vmovaps %zmm0, (%eax) +; SKX32-NEXT: vzeroupper +; SKX32-NEXT: retl +; +; KNL32-LABEL: PR43170: +; KNL32: # %bb.0: # %entry +; KNL32-NEXT: movl {{[0-9]+}}(%esp), %eax +; KNL32-NEXT: vmovaps src1, %ymm0 +; KNL32-NEXT: vmovaps %zmm0, (%eax) +; KNL32-NEXT: retl +entry: + %0 = load <8 x float>, <8 x float>* bitcast (%union1* @src1 to <8 x float>*), align 64 + %1 = shufflevector <8 x float> %0, <8 x float> zeroinitializer, <16 x i32> + store <16 x float> %1, <16 x float>* %a0, align 64 + ret void +} diff --git a/llvm/test/DebugInfo/COFF/AArch64/arm64-register-variables.ll b/llvm/test/DebugInfo/COFF/AArch64/arm64-register-variables.ll index daa7da201d53..c02eea5da504 100644 --- a/llvm/test/DebugInfo/COFF/AArch64/arm64-register-variables.ll +++ b/llvm/test/DebugInfo/COFF/AArch64/arm64-register-variables.ll @@ -28,9 +28,9 @@ ; OBJ: OffsetInParent: 0 ; OBJ: BasePointerOffset: 12 ; OBJ: LocalVariableAddrRange { -; OBJ: OffsetStart: .text+0x10 +; OBJ: OffsetStart: .text+0x14 ; OBJ: ISectStart: 0x0 -; OBJ: Range: 0x2C +; OBJ: Range: 0x30 ; OBJ: } ; OBJ: } diff --git a/llvm/test/DebugInfo/MIR/X86/live-debug-values-restore.mir b/llvm/test/DebugInfo/MIR/X86/live-debug-values-restore.mir index 2c3feeecdcdc..f43572c7b654 100644 --- a/llvm/test/DebugInfo/MIR/X86/live-debug-values-restore.mir +++ b/llvm/test/DebugInfo/MIR/X86/live-debug-values-restore.mir @@ -14,13 +14,17 @@ # return *(p + 1); # } +# Pick out DILocalVariable numbers for "p" and "q" +# CHECK: ![[PVAR:[0-9]+]] = !DILocalVariable(name: "p", +# CHECK: ![[QVAR:[0-9]+]] = !DILocalVariable(name: "q", + # Ascertain that the spill has been recognized and manifested in a DBG_VALUE. # CHECK: MOV64mr $rsp,{{.*-8.*}}killed{{.*}}$rdi :: (store 8 into %stack.0) -# CHECK-NEXT: DBG_VALUE $rsp,{{.*}}![[MDIX:[0-9]+]],{{.*}}!DIExpression(DW_OP_constu, 8, DW_OP_minus) +# CHECK-NEXT: DBG_VALUE $rsp,{{.*}}![[PVAR]],{{.*}}!DIExpression(DW_OP_constu, 8, DW_OP_minus) # Check for the restore. # CHECK: $rdi = MOV64rm $rsp,{{.*-8.*}}:: (load 8 from %stack.0) -# CHECK-NEXT: DBG_VALUE $rdi,{{.*}}![[MDIX]], !DIExpression() +# CHECK-NEXT: DBG_VALUE $rdi,{{.*}}![[PVAR]], !DIExpression() --- | define dso_local i32 @f(i32* readonly %p) local_unnamed_addr !dbg !7 { @@ -39,6 +43,22 @@ ret i32 %0, !dbg !28 } + define dso_local i32 @g(i32* readonly %p) local_unnamed_addr !dbg !107 { + entry: + call void @llvm.dbg.value(metadata i32* %p, metadata !113, metadata !DIExpression()), !dbg !114 + %tobool = icmp eq i32* %p, null, !dbg !115 + br i1 %tobool, label %if.end, label %if.then, !dbg !117 + + if.then: ; preds = %entry + tail call void asm sideeffect "", "~{rax},~{rbx},~{rcx},~{rdx},~{rsi},~{rdi},~{rbp},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15},~{dirflag},~{fpsr},~{flags}"(), !dbg !118, !srcloc !120 + br label %if.end, !dbg !121 + + if.end: ; preds = %entry, %if.then + %add.ptr = getelementptr inbounds i32, i32* %p, i64 1, !dbg !122 + %0 = load i32, i32* %add.ptr, align 4, !dbg !123, !tbaa !24 + ret i32 %0, !dbg !128 + } + declare void @llvm.dbg.value(metadata, metadata, metadata) !llvm.dbg.cu = !{!0} @@ -74,6 +94,22 @@ !26 = !{!"omnipotent char", !27, i64 0} !27 = !{!"Simple C/C++ TBAA"} !28 = !DILocation(line: 9, column: 3, scope: !7) + !101 = !DIBasicType(name: "looong int", size: 64, encoding: DW_ATE_signed) + !107 = distinct !DISubprogram(name: "g", scope: !1, file: !1, line: 105, type: !8, scopeLine: 105, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !112) + !112 = !{!113} + !113 = !DILocalVariable(name: "q", arg: 1, scope: !107, file: !1, line: 105, type: !101) + !114 = !DILocation(line: 105, column: 12, scope: !107) + !115 = !DILocation(line: 106, column: 7, scope: !116) + !116 = distinct !DILexicalBlock(scope: !107, file: !1, line: 106, column: 7) + !117 = !DILocation(line: 106, column: 7, scope: !107) + !118 = !DILocation(line: 107, column: 5, scope: !119) + !119 = distinct !DILexicalBlock(scope: !116, file: !1, line: 106, column: 10) + !120 = !{i32 -2147471544} + !121 = !DILocation(line: 108, column: 3, scope: !119) + !122 = !DILocation(line: 109, column: 14, scope: !107) + !123 = !DILocation(line: 109, column: 10, scope: !107) + !128 = !DILocation(line: 109, column: 3, scope: !107) + ... --- @@ -187,3 +223,78 @@ body: | RETQ $eax, debug-location !28 ... +--- +# This second function has been appended as a regression test against a +# crash, caused by expressions being created from spill restores that did +# not preserve fragment information. Test that no empty expressions are +# created at all, and the last block describes both variable fragments. + +# CHECK-LABEL: name: g +# CHECK-NOT: !DIExpression() +# CHECK-LABEL: bb.2.if.end: +# CHECK: DBG_VALUE $rdi, $noreg, ![[QVAR]], !DIExpression(DW_OP_LLVM_fragment, 0, 32) +# CHECK-NEXT: DBG_VALUE $rbx, $noreg, ![[QVAR]], !DIExpression(DW_OP_LLVM_fragment, 32, 32) + +name: g +alignment: 4 +tracksRegLiveness: true +liveins: + - { reg: '$rdi', virtual-reg: '' } +frameInfo: + stackSize: 48 + offsetAdjustment: -48 + maxAlignment: 8 + cvBytesOfCalleeSavedRegisters: 48 + localFrameSize: 0 +fixedStack: + - { id: 0, type: spill-slot, offset: -56, size: 8, alignment: 8, stack-id: default, + callee-saved-register: '$rbx', callee-saved-restored: true, debug-info-variable: '', + debug-info-expression: '', debug-info-location: '' } + - { id: 1, type: spill-slot, offset: -48, size: 8, alignment: 16, stack-id: default, + callee-saved-register: '$r12', callee-saved-restored: true, debug-info-variable: '', + debug-info-expression: '', debug-info-location: '' } + - { id: 2, type: spill-slot, offset: -40, size: 8, alignment: 8, stack-id: default, + callee-saved-register: '$r13', callee-saved-restored: true, debug-info-variable: '', + debug-info-expression: '', debug-info-location: '' } + - { id: 3, type: spill-slot, offset: -32, size: 8, alignment: 16, stack-id: default, + callee-saved-register: '$r14', callee-saved-restored: true, debug-info-variable: '', + debug-info-expression: '', debug-info-location: '' } + - { id: 4, type: spill-slot, offset: -24, size: 8, alignment: 8, stack-id: default, + callee-saved-register: '$r15', callee-saved-restored: true, debug-info-variable: '', + debug-info-expression: '', debug-info-location: '' } + - { id: 5, type: spill-slot, offset: -16, size: 8, alignment: 16, stack-id: default, + callee-saved-register: '$rbp', callee-saved-restored: true, debug-info-variable: '', + debug-info-expression: '', debug-info-location: '' } +stack: + - { id: 0, name: '', type: spill-slot, offset: -64, size: 8, alignment: 8, + stack-id: default, callee-saved-register: '', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +constants: [] +body: | + bb.0.entry: + successors: %bb.1(0x50000000) + liveins: $rdi, $rbx, $r12, $r13, $r14, $r15, $rbp + + DBG_VALUE $rdi, $noreg, !113, !DIExpression(DW_OP_LLVM_fragment, 0, 32), debug-location !114 + TEST64rr renamable $rdi, renamable $rdi, implicit-def $eflags, debug-location !115 + JMP_1 %bb.1, implicit $eflags, debug-location !117 + + bb.1.if.then: + successors: %bb.2(0x80000000) + liveins: $rdi, $rbp, $r15, $r14, $r13, $r12, $rbx + + MOV64mr $rsp, 1, $noreg, -8, $noreg, killed renamable $rdi :: (store 8 into %stack.0) + renamable $rdi = MOV64rm $rsp, 1, $noreg, -8, $noreg :: (load 8 from %stack.0) + + bb.2.if.end: + liveins: $rdi, $rbx, $r12, $r13, $r14, $r15, $rbp + + DBG_VALUE $rbx, $noreg, !113, !DIExpression(DW_OP_LLVM_fragment, 32, 32), debug-location !114 + MOV64mr $rsp, 1, $noreg, -8, $noreg, killed renamable $rbx :: (store 8 into %stack.0) + renamable $rsi = MOV64rm $rsp, 1, $noreg, -8, $noreg :: (load 8 from %stack.0) + + renamable $eax = MOV32rm killed renamable $rsi, 1, $noreg, 4, $noreg, debug-location !123 :: (load 4 from %ir.add.ptr, !tbaa !24) + $rdi = MOV64ri 0 + RETQ $eax, debug-location !128 + +... diff --git a/llvm/test/MC/AArch64/SVE/decp.s b/llvm/test/MC/AArch64/SVE/decp.s index 8bbe726a422d..6cf73033e69e 100644 --- a/llvm/test/MC/AArch64/SVE/decp.s +++ b/llvm/test/MC/AArch64/SVE/decp.s @@ -56,19 +56,37 @@ decp xzr, p15.d // CHECK-UNKNOWN: ff 89 ed 25 decp z31.h, p15 -// CHECK-INST: decp z31.h, p15 +// CHECK-INST: decp z31.h, p15.h +// CHECK-ENCODING: [0xff,0x81,0x6d,0x25] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: ff 81 6d 25 + +decp z31.h, p15.h +// CHECK-INST: decp z31.h, p15.h // CHECK-ENCODING: [0xff,0x81,0x6d,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: ff 81 6d 25 decp z31.s, p15 -// CHECK-INST: decp z31.s, p15 +// CHECK-INST: decp z31.s, p15.s +// CHECK-ENCODING: [0xff,0x81,0xad,0x25] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: ff 81 ad 25 + +decp z31.s, p15.s +// CHECK-INST: decp z31.s, p15.s // CHECK-ENCODING: [0xff,0x81,0xad,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: ff 81 ad 25 decp z31.d, p15 -// CHECK-INST: decp z31.d, p15 +// CHECK-INST: decp z31.d, p15.d +// CHECK-ENCODING: [0xff,0x81,0xed,0x25] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: ff 81 ed 25 + +decp z31.d, p15.d +// CHECK-INST: decp z31.d, p15.d // CHECK-ENCODING: [0xff,0x81,0xed,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: ff 81 ed 25 @@ -83,7 +101,7 @@ movprfx z31, z6 // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: df bc 20 04 -decp z31.d, p15 +decp z31.d, p15.d // CHECK-INST: decp z31.d, p15 // CHECK-ENCODING: [0xff,0x81,0xed,0x25] // CHECK-ERROR: instruction requires: sve diff --git a/llvm/test/MC/AArch64/SVE/incp.s b/llvm/test/MC/AArch64/SVE/incp.s index 6bc2c5160925..b180fcc698d2 100644 --- a/llvm/test/MC/AArch64/SVE/incp.s +++ b/llvm/test/MC/AArch64/SVE/incp.s @@ -56,19 +56,37 @@ incp xzr, p15.d // CHECK-UNKNOWN: ff 89 ec 25 incp z31.h, p15 -// CHECK-INST: incp z31.h, p15 +// CHECK-INST: incp z31.h, p15.h +// CHECK-ENCODING: [0xff,0x81,0x6c,0x25] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: ff 81 6c 25 + +incp z31.h, p15.h +// CHECK-INST: incp z31.h, p15.h // CHECK-ENCODING: [0xff,0x81,0x6c,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: ff 81 6c 25 incp z31.s, p15 -// CHECK-INST: incp z31.s, p15 +// CHECK-INST: incp z31.s, p15.s +// CHECK-ENCODING: [0xff,0x81,0xac,0x25] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: ff 81 ac 25 + +incp z31.s, p15.s +// CHECK-INST: incp z31.s, p15.s // CHECK-ENCODING: [0xff,0x81,0xac,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: ff 81 ac 25 incp z31.d, p15 -// CHECK-INST: incp z31.d, p15 +// CHECK-INST: incp z31.d, p15.d +// CHECK-ENCODING: [0xff,0x81,0xec,0x25] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: ff 81 ec 25 + +incp z31.d, p15.d +// CHECK-INST: incp z31.d, p15.d // CHECK-ENCODING: [0xff,0x81,0xec,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: ff 81 ec 25 @@ -83,8 +101,8 @@ movprfx z31, z6 // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: df bc 20 04 -incp z31.d, p15 -// CHECK-INST: incp z31.d, p15 +incp z31.d, p15.d +// CHECK-INST: incp z31.d, p15.d // CHECK-ENCODING: [0xff,0x81,0xec,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: ff 81 ec 25 diff --git a/llvm/test/MC/AArch64/SVE/sqdecp.s b/llvm/test/MC/AArch64/SVE/sqdecp.s index 2a56b182f6bb..7da00beb7b24 100644 --- a/llvm/test/MC/AArch64/SVE/sqdecp.s +++ b/llvm/test/MC/AArch64/SVE/sqdecp.s @@ -56,19 +56,37 @@ sqdecp xzr, p15.d, wzr // CHECK-UNKNOWN: ff 89 ea 25 sqdecp z0.h, p0 -// CHECK-INST: sqdecp z0.h, p0 +// CHECK-INST: sqdecp z0.h, p0.h +// CHECK-ENCODING: [0x00,0x80,0x6a,0x25] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: 00 80 6a 25 + +sqdecp z0.h, p0.h +// CHECK-INST: sqdecp z0.h, p0.h // CHECK-ENCODING: [0x00,0x80,0x6a,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: 00 80 6a 25 sqdecp z0.s, p0 -// CHECK-INST: sqdecp z0.s, p0 +// CHECK-INST: sqdecp z0.s, p0.s +// CHECK-ENCODING: [0x00,0x80,0xaa,0x25] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: 00 80 aa 25 + +sqdecp z0.s, p0.s +// CHECK-INST: sqdecp z0.s, p0.s // CHECK-ENCODING: [0x00,0x80,0xaa,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: 00 80 aa 25 sqdecp z0.d, p0 -// CHECK-INST: sqdecp z0.d, p0 +// CHECK-INST: sqdecp z0.d, p0.d +// CHECK-ENCODING: [0x00,0x80,0xea,0x25] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: 00 80 ea 25 + +sqdecp z0.d, p0.d +// CHECK-INST: sqdecp z0.d, p0.d // CHECK-ENCODING: [0x00,0x80,0xea,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: 00 80 ea 25 @@ -83,8 +101,8 @@ movprfx z0, z7 // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: e0 bc 20 04 -sqdecp z0.d, p0 -// CHECK-INST: sqdecp z0.d, p0 +sqdecp z0.d, p0.d +// CHECK-INST: sqdecp z0.d, p0.d // CHECK-ENCODING: [0x00,0x80,0xea,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: 00 80 ea 25 diff --git a/llvm/test/MC/AArch64/SVE/sqincp.s b/llvm/test/MC/AArch64/SVE/sqincp.s index f7d427b0ca6e..e523796a39f1 100644 --- a/llvm/test/MC/AArch64/SVE/sqincp.s +++ b/llvm/test/MC/AArch64/SVE/sqincp.s @@ -56,19 +56,37 @@ sqincp xzr, p15.d, wzr // CHECK-UNKNOWN: ff 89 e8 25 sqincp z0.h, p0 -// CHECK-INST: sqincp z0.h, p0 +// CHECK-INST: sqincp z0.h, p0.h +// CHECK-ENCODING: [0x00,0x80,0x68,0x25] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: 00 80 68 25 + +sqincp z0.h, p0.h +// CHECK-INST: sqincp z0.h, p0.h // CHECK-ENCODING: [0x00,0x80,0x68,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: 00 80 68 25 sqincp z0.s, p0 -// CHECK-INST: sqincp z0.s, p0 +// CHECK-INST: sqincp z0.s, p0.s +// CHECK-ENCODING: [0x00,0x80,0xa8,0x25] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: 00 80 a8 25 + +sqincp z0.s, p0.s +// CHECK-INST: sqincp z0.s, p0.s // CHECK-ENCODING: [0x00,0x80,0xa8,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: 00 80 a8 25 sqincp z0.d, p0 -// CHECK-INST: sqincp z0.d, p0 +// CHECK-INST: sqincp z0.d, p0.d +// CHECK-ENCODING: [0x00,0x80,0xe8,0x25] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: 00 80 e8 25 + +sqincp z0.d, p0.d +// CHECK-INST: sqincp z0.d, p0.d // CHECK-ENCODING: [0x00,0x80,0xe8,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: 00 80 e8 25 @@ -83,8 +101,8 @@ movprfx z0, z7 // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: e0 bc 20 04 -sqincp z0.d, p0 -// CHECK-INST: sqincp z0.d, p0 +sqincp z0.d, p0.d +// CHECK-INST: sqincp z0.d, p0.d // CHECK-ENCODING: [0x00,0x80,0xe8,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: 00 80 e8 25 diff --git a/llvm/test/MC/AArch64/SVE/uqdecp.s b/llvm/test/MC/AArch64/SVE/uqdecp.s index 3c07a7da2462..6e4717ba9323 100644 --- a/llvm/test/MC/AArch64/SVE/uqdecp.s +++ b/llvm/test/MC/AArch64/SVE/uqdecp.s @@ -56,19 +56,37 @@ uqdecp wzr, p15.d // CHECK-UNKNOWN: ff 89 eb 25 uqdecp z0.h, p0 -// CHECK-INST: uqdecp z0.h, p0 +// CHECK-INST: uqdecp z0.h, p0.h +// CHECK-ENCODING: [0x00,0x80,0x6b,0x25] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: 00 80 6b 25 + +uqdecp z0.h, p0.h +// CHECK-INST: uqdecp z0.h, p0.h // CHECK-ENCODING: [0x00,0x80,0x6b,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: 00 80 6b 25 uqdecp z0.s, p0 -// CHECK-INST: uqdecp z0.s, p0 +// CHECK-INST: uqdecp z0.s, p0.s +// CHECK-ENCODING: [0x00,0x80,0xab,0x25] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: 00 80 ab 25 + +uqdecp z0.s, p0.s +// CHECK-INST: uqdecp z0.s, p0.s // CHECK-ENCODING: [0x00,0x80,0xab,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: 00 80 ab 25 uqdecp z0.d, p0 -// CHECK-INST: uqdecp z0.d, p0 +// CHECK-INST: uqdecp z0.d, p0.d +// CHECK-ENCODING: [0x00,0x80,0xeb,0x25] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: 00 80 eb 25 + +uqdecp z0.d, p0.d +// CHECK-INST: uqdecp z0.d, p0.d // CHECK-ENCODING: [0x00,0x80,0xeb,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: 00 80 eb 25 @@ -83,8 +101,8 @@ movprfx z0, z7 // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: e0 bc 20 04 -uqdecp z0.d, p0 -// CHECK-INST: uqdecp z0.d, p0 +uqdecp z0.d, p0.d +// CHECK-INST: uqdecp z0.d, p0.d // CHECK-ENCODING: [0x00,0x80,0xeb,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: 00 80 eb 25 diff --git a/llvm/test/MC/AArch64/SVE/uqincp.s b/llvm/test/MC/AArch64/SVE/uqincp.s index a4fb8199d994..05cfdea05a30 100644 --- a/llvm/test/MC/AArch64/SVE/uqincp.s +++ b/llvm/test/MC/AArch64/SVE/uqincp.s @@ -56,19 +56,37 @@ uqincp wzr, p15.d // CHECK-UNKNOWN: ff 89 e9 25 uqincp z0.h, p0 -// CHECK-INST: uqincp z0.h, p0 +// CHECK-INST: uqincp z0.h, p0.h +// CHECK-ENCODING: [0x00,0x80,0x69,0x25] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: 00 80 69 25 + +uqincp z0.h, p0.h +// CHECK-INST: uqincp z0.h, p0.h // CHECK-ENCODING: [0x00,0x80,0x69,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: 00 80 69 25 uqincp z0.s, p0 -// CHECK-INST: uqincp z0.s, p0 +// CHECK-INST: uqincp z0.s, p0.s +// CHECK-ENCODING: [0x00,0x80,0xa9,0x25] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: 00 80 a9 25 + +uqincp z0.s, p0.s +// CHECK-INST: uqincp z0.s, p0.s // CHECK-ENCODING: [0x00,0x80,0xa9,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: 00 80 a9 25 uqincp z0.d, p0 -// CHECK-INST: uqincp z0.d, p0 +// CHECK-INST: uqincp z0.d, p0.d +// CHECK-ENCODING: [0x00,0x80,0xe9,0x25] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: 00 80 e9 25 + +uqincp z0.d, p0.d +// CHECK-INST: uqincp z0.d, p0.d // CHECK-ENCODING: [0x00,0x80,0xe9,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: 00 80 e9 25 @@ -83,8 +101,8 @@ movprfx z0, z7 // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: e0 bc 20 04 -uqincp z0.d, p0 -// CHECK-INST: uqincp z0.d, p0 +uqincp z0.d, p0.d +// CHECK-INST: uqincp z0.d, p0.d // CHECK-ENCODING: [0x00,0x80,0xe9,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: 00 80 e9 25 diff --git a/llvm/test/MC/AArch64/SVE2/bdep-diagnostics.s b/llvm/test/MC/AArch64/SVE2/bdep-diagnostics.s index f6dce7958672..08a589e1f963 100644 --- a/llvm/test/MC/AArch64/SVE2/bdep-diagnostics.s +++ b/llvm/test/MC/AArch64/SVE2/bdep-diagnostics.s @@ -1,4 +1,4 @@ -// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+bitperm 2>&1 < %s| FileCheck %s +// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+sve2-bitperm 2>&1 < %s| FileCheck %s // ------------------------------------------------------------------------- // diff --git a/llvm/test/MC/AArch64/SVE2/bdep.s b/llvm/test/MC/AArch64/SVE2/bdep.s index 9d68b5a673c8..0bc935226373 100644 --- a/llvm/test/MC/AArch64/SVE2/bdep.s +++ b/llvm/test/MC/AArch64/SVE2/bdep.s @@ -1,32 +1,32 @@ -// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+bitperm < %s \ +// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sve2-bitperm < %s \ // RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST // RUN: not llvm-mc -triple=aarch64 -show-encoding < %s 2>&1 \ // RUN: | FileCheck %s --check-prefix=CHECK-ERROR -// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+bitperm < %s \ -// RUN: | llvm-objdump -d -mattr=+bitperm - | FileCheck %s --check-prefix=CHECK-INST -// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+bitperm < %s \ +// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sve2-bitperm < %s \ +// RUN: | llvm-objdump -d -mattr=+sve2-bitperm - | FileCheck %s --check-prefix=CHECK-INST +// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sve2-bitperm < %s \ // RUN: | llvm-objdump -d - | FileCheck %s --check-prefix=CHECK-UNKNOWN bdep z0.b, z1.b, z31.b // CHECK-INST: bdep z0.b, z1.b, z31.b // CHECK-ENCODING: [0x20,0xb4,0x1f,0x45] -// CHECK-ERROR: instruction requires: bitperm +// CHECK-ERROR: instruction requires: sve2-bitperm // CHECK-UNKNOWN: 20 b4 1f 45 bdep z0.h, z1.h, z31.h // CHECK-INST: bdep z0.h, z1.h, z31.h // CHECK-ENCODING: [0x20,0xb4,0x5f,0x45] -// CHECK-ERROR: instruction requires: bitperm +// CHECK-ERROR: instruction requires: sve2-bitperm // CHECK-UNKNOWN: 20 b4 5f 45 bdep z0.s, z1.s, z31.s // CHECK-INST: bdep z0.s, z1.s, z31.s // CHECK-ENCODING: [0x20,0xb4,0x9f,0x45] -// CHECK-ERROR: instruction requires: bitperm +// CHECK-ERROR: instruction requires: sve2-bitperm // CHECK-UNKNOWN: 20 b4 9f 45 bdep z0.d, z1.d, z31.d // CHECK-INST: bdep z0.d, z1.d, z31.d // CHECK-ENCODING: [0x20,0xb4,0xdf,0x45] -// CHECK-ERROR: instruction requires: bitperm +// CHECK-ERROR: instruction requires: sve2-bitperm // CHECK-UNKNOWN: 20 b4 df 45 diff --git a/llvm/test/MC/AArch64/SVE2/bext-diagnostics.s b/llvm/test/MC/AArch64/SVE2/bext-diagnostics.s index 7ffe1449cc2c..5faadbcb8f4a 100644 --- a/llvm/test/MC/AArch64/SVE2/bext-diagnostics.s +++ b/llvm/test/MC/AArch64/SVE2/bext-diagnostics.s @@ -1,4 +1,4 @@ -// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+bitperm 2>&1 < %s| FileCheck %s +// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+sve2-bitperm 2>&1 < %s| FileCheck %s // ------------------------------------------------------------------------- // diff --git a/llvm/test/MC/AArch64/SVE2/bext.s b/llvm/test/MC/AArch64/SVE2/bext.s index 2c23bd9b2af4..ae3d0bfbff5e 100644 --- a/llvm/test/MC/AArch64/SVE2/bext.s +++ b/llvm/test/MC/AArch64/SVE2/bext.s @@ -1,32 +1,32 @@ -// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+bitperm < %s \ +// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sve2-bitperm < %s \ // RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST // RUN: not llvm-mc -triple=aarch64 -show-encoding < %s 2>&1 \ // RUN: | FileCheck %s --check-prefix=CHECK-ERROR -// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+bitperm < %s \ -// RUN: | llvm-objdump -d -mattr=+bitperm - | FileCheck %s --check-prefix=CHECK-INST -// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+bitperm < %s \ +// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sve2-bitperm < %s \ +// RUN: | llvm-objdump -d -mattr=+sve2-bitperm - | FileCheck %s --check-prefix=CHECK-INST +// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sve2-bitperm < %s \ // RUN: | llvm-objdump -d - | FileCheck %s --check-prefix=CHECK-UNKNOWN bext z0.b, z1.b, z31.b // CHECK-INST: bext z0.b, z1.b, z31.b // CHECK-ENCODING: [0x20,0xb0,0x1f,0x45] -// CHECK-ERROR: instruction requires: bitperm +// CHECK-ERROR: instruction requires: sve2-bitperm // CHECK-UNKNOWN: 20 b0 1f 45 bext z0.h, z1.h, z31.h // CHECK-INST: bext z0.h, z1.h, z31.h // CHECK-ENCODING: [0x20,0xb0,0x5f,0x45] -// CHECK-ERROR: instruction requires: bitperm +// CHECK-ERROR: instruction requires: sve2-bitperm // CHECK-UNKNOWN: 20 b0 5f 45 bext z0.s, z1.s, z31.s // CHECK-INST: bext z0.s, z1.s, z31.s // CHECK-ENCODING: [0x20,0xb0,0x9f,0x45] -// CHECK-ERROR: instruction requires: bitperm +// CHECK-ERROR: instruction requires: sve2-bitperm // CHECK-UNKNOWN: 20 b0 9f 45 bext z0.d, z1.d, z31.d // CHECK-INST: bext z0.d, z1.d, z31.d // CHECK-ENCODING: [0x20,0xb0,0xdf,0x45] -// CHECK-ERROR: instruction requires: bitperm +// CHECK-ERROR: instruction requires: sve2-bitperm // CHECK-UNKNOWN: 20 b0 df 45 diff --git a/llvm/test/MC/AArch64/SVE2/bgrp-diagnostics.s b/llvm/test/MC/AArch64/SVE2/bgrp-diagnostics.s index 9c05a0c6918d..2ae32c04b78e 100644 --- a/llvm/test/MC/AArch64/SVE2/bgrp-diagnostics.s +++ b/llvm/test/MC/AArch64/SVE2/bgrp-diagnostics.s @@ -1,4 +1,4 @@ -// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+bitperm 2>&1 < %s| FileCheck %s +// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+sve2-bitperm 2>&1 < %s| FileCheck %s // ------------------------------------------------------------------------- // diff --git a/llvm/test/MC/AArch64/SVE2/bgrp.s b/llvm/test/MC/AArch64/SVE2/bgrp.s index b2e7f98a4303..3d994c0a3648 100644 --- a/llvm/test/MC/AArch64/SVE2/bgrp.s +++ b/llvm/test/MC/AArch64/SVE2/bgrp.s @@ -1,32 +1,32 @@ -// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+bitperm < %s \ +// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sve2-bitperm < %s \ // RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST // RUN: not llvm-mc -triple=aarch64 -show-encoding < %s 2>&1 \ // RUN: | FileCheck %s --check-prefix=CHECK-ERROR -// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+bitperm < %s \ -// RUN: | llvm-objdump -d -mattr=+bitperm - | FileCheck %s --check-prefix=CHECK-INST -// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+bitperm < %s \ +// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sve2-bitperm < %s \ +// RUN: | llvm-objdump -d -mattr=+sve2-bitperm - | FileCheck %s --check-prefix=CHECK-INST +// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sve2-bitperm < %s \ // RUN: | llvm-objdump -d - | FileCheck %s --check-prefix=CHECK-UNKNOWN bgrp z0.b, z1.b, z31.b // CHECK-INST: bgrp z0.b, z1.b, z31.b // CHECK-ENCODING: [0x20,0xb8,0x1f,0x45] -// CHECK-ERROR: instruction requires: bitperm +// CHECK-ERROR: instruction requires: sve2-bitperm // CHECK-UNKNOWN: 20 b8 1f 45 bgrp z0.h, z1.h, z31.h // CHECK-INST: bgrp z0.h, z1.h, z31.h // CHECK-ENCODING: [0x20,0xb8,0x5f,0x45] -// CHECK-ERROR: instruction requires: bitperm +// CHECK-ERROR: instruction requires: sve2-bitperm // CHECK-UNKNOWN: 20 b8 5f 45 bgrp z0.s, z1.s, z31.s // CHECK-INST: bgrp z0.s, z1.s, z31.s // CHECK-ENCODING: [0x20,0xb8,0x9f,0x45] -// CHECK-ERROR: instruction requires: bitperm +// CHECK-ERROR: instruction requires: sve2-bitperm // CHECK-UNKNOWN: 20 b8 9f 45 bgrp z0.d, z1.d, z31.d // CHECK-INST: bgrp z0.d, z1.d, z31.d // CHECK-ENCODING: [0x20,0xb8,0xdf,0x45] -// CHECK-ERROR: instruction requires: bitperm +// CHECK-ERROR: instruction requires: sve2-bitperm // CHECK-UNKNOWN: 20 b8 df 45 diff --git a/llvm/test/MC/AArch64/SVE2/directive-arch-negative.s b/llvm/test/MC/AArch64/SVE2/directive-arch-negative.s index 4b2ba039dc38..51775ee5379b 100644 --- a/llvm/test/MC/AArch64/SVE2/directive-arch-negative.s +++ b/llvm/test/MC/AArch64/SVE2/directive-arch-negative.s @@ -24,8 +24,8 @@ rax1 z0.d, z0.d, z0.d // CHECK: error: instruction requires: sve2-sha3 // CHECK-NEXT: rax1 z0.d, z0.d, z0.d -.arch armv8-a+bitperm -.arch armv8-a+nobitperm +.arch armv8-a+sve2-bitperm +.arch armv8-a+nosve2-bitperm bgrp z21.s, z10.s, z21.s -// CHECK: error: instruction requires: bitperm +// CHECK: error: instruction requires: sve2-bitperm // CHECK-NEXT: bgrp z21.s, z10.s, z21.s diff --git a/llvm/test/MC/AArch64/SVE2/directive-arch.s b/llvm/test/MC/AArch64/SVE2/directive-arch.s index 94ef64700755..4e2e71dbb732 100644 --- a/llvm/test/MC/AArch64/SVE2/directive-arch.s +++ b/llvm/test/MC/AArch64/SVE2/directive-arch.s @@ -16,6 +16,6 @@ sm4e z0.s, z0.s, z0.s rax1 z0.d, z0.d, z0.d // CHECK: rax1 z0.d, z0.d, z0.d -.arch armv8-a+bitperm +.arch armv8-a+sve2-bitperm bgrp z21.s, z10.s, z21.s // CHECK: bgrp z21.s, z10.s, z21.s diff --git a/llvm/test/MC/AArch64/SVE2/directive-arch_extension-negative.s b/llvm/test/MC/AArch64/SVE2/directive-arch_extension-negative.s index 5db80e11a910..1a1f81ae7ffb 100644 --- a/llvm/test/MC/AArch64/SVE2/directive-arch_extension-negative.s +++ b/llvm/test/MC/AArch64/SVE2/directive-arch_extension-negative.s @@ -24,8 +24,8 @@ rax1 z0.d, z0.d, z0.d // CHECK: error: instruction requires: sve2-sha3 // CHECK-NEXT: rax1 z0.d, z0.d, z0.d -.arch_extension bitperm -.arch_extension nobitperm +.arch_extension sve2-bitperm +.arch_extension nosve2-bitperm bgrp z21.s, z10.s, z21.s -// CHECK: error: instruction requires: bitperm +// CHECK: error: instruction requires: sve2-bitperm // CHECK-NEXT: bgrp z21.s, z10.s, z21.s diff --git a/llvm/test/MC/AArch64/SVE2/directive-arch_extension.s b/llvm/test/MC/AArch64/SVE2/directive-arch_extension.s index 257f5721d720..90f5bec07d54 100644 --- a/llvm/test/MC/AArch64/SVE2/directive-arch_extension.s +++ b/llvm/test/MC/AArch64/SVE2/directive-arch_extension.s @@ -16,6 +16,6 @@ sm4e z0.s, z0.s, z0.s rax1 z0.d, z0.d, z0.d // CHECK: rax1 z0.d, z0.d, z0.d -.arch_extension bitperm +.arch_extension sve2-bitperm bgrp z21.s, z10.s, z21.s // CHECK: bgrp z21.s, z10.s, z21.s diff --git a/llvm/test/MC/AArch64/SVE2/directive-cpu-negative.s b/llvm/test/MC/AArch64/SVE2/directive-cpu-negative.s index 542a6f692ca3..97d4c3d1ca6d 100644 --- a/llvm/test/MC/AArch64/SVE2/directive-cpu-negative.s +++ b/llvm/test/MC/AArch64/SVE2/directive-cpu-negative.s @@ -24,8 +24,8 @@ rax1 z0.d, z0.d, z0.d // CHECK: error: instruction requires: sve2-sha3 // CHECK-NEXT: rax1 z0.d, z0.d, z0.d -.cpu generic+bitperm -.cpu generic+nobitperm +.cpu generic+sve2-bitperm +.cpu generic+nosve2-bitperm bgrp z21.s, z10.s, z21.s -// CHECK: error: instruction requires: bitperm +// CHECK: error: instruction requires: sve2-bitperm // CHECK-NEXT: bgrp z21.s, z10.s, z21.s diff --git a/llvm/test/MC/AArch64/SVE2/directive-cpu.s b/llvm/test/MC/AArch64/SVE2/directive-cpu.s index a8ca7b389e94..b3cacc46c1dd 100644 --- a/llvm/test/MC/AArch64/SVE2/directive-cpu.s +++ b/llvm/test/MC/AArch64/SVE2/directive-cpu.s @@ -16,6 +16,6 @@ sm4e z0.s, z0.s, z0.s rax1 z0.d, z0.d, z0.d // CHECK: rax1 z0.d, z0.d, z0.d -.cpu generic+bitperm +.cpu generic+sve2-bitperm bgrp z21.s, z10.s, z21.s // CHECK: bgrp z21.s, z10.s, z21.s diff --git a/llvm/test/MC/CAHP/cahp-invalid.s b/llvm/test/MC/CAHP/cahp-invalid.s new file mode 100644 index 000000000000..73ea4237e8f6 --- /dev/null +++ b/llvm/test/MC/CAHP/cahp-invalid.s @@ -0,0 +1,54 @@ +# RUN: not llvm-mc -triple cahp < %s 2>&1 | FileCheck %s + +# Out of range immediates +#operand must be a symbol with %lo modifier or an integer in the range [-512, 511] +lw a4, 512(a2) # CHECK: :[[@LINE]]:8: error: operand must be a symbol with %lo modifier or an integer in the range [-512, 511] +lb a4, -513(a2) # CHECK: :[[@LINE]]:8: error: operand must be a symbol with %lo modifier or an integer in the range [-512, 511] +lbu a4, -513(a2) # CHECK: :[[@LINE]]:9: error: operand must be a symbol with %lo modifier or an integer in the range [-512, 511] +sw a4, -513(a2) # CHECK: :[[@LINE]]:8: error: operand must be a symbol with %lo modifier or an integer in the range [-512, 511] +sb a4, 512(a2) # CHECK: :[[@LINE]]:8: error: operand must be a symbol with %lo modifier or an integer in the range [-512, 511] +li t0, -513 # CHECK: :[[@LINE]]:8: error: operand must be a symbol with %lo modifier or an integer in the range [-512, 511] +li s0, 512 # CHECK: :[[@LINE]]:8: error: operand must be a symbol with %lo modifier or an integer in the range [-512, 511] +addi a0, a1, 512 # CHECK: :[[@LINE]]:14: error: operand must be a symbol with %lo modifier or an integer in the range [-512, 511] +addi a0, a1, -513 # CHECK: :[[@LINE]]:14: error: operand must be a symbol with %lo modifier or an integer in the range [-512, 511] +andi a0, a1, 512 # CHECK: :[[@LINE]]:14: error: operand must be a symbol with %lo modifier or an integer in the range [-512, 511] +xori a0, a1, -513 # CHECK: :[[@LINE]]:14: error: operand must be a symbol with %lo modifier or an integer in the range [-512, 511] +lsli a0, a1, 16 # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [0, 15] +asri a0, a1, -1 # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [0, 15] +lwsp a4, 128(sp) # CHECK: :[[@LINE]]:10: error: immediate must be a multiple of 2 bytes in the range [0, 126] +swsp a3, -2(sp) # CHECK: :[[@LINE]]:10: error: immediate must be a multiple of 2 bytes in the range [0, 126] +lsi a5, 32 # CHECK: :[[@LINE]]:9: error: operand must be a symbol with %hi modifier or an integer in the range [-32, 31] +lsi a5, -33 # CHECK: :[[@LINE]]:9: error: operand must be a symbol with %hi modifier or an integer in the range [-32, 31] +lui a5, 32 # CHECK: :[[@LINE]]:9: error: operand must be a symbol with %hi modifier or an integer in the range [-32, 31] +lui a5, -33 # CHECK: :[[@LINE]]:9: error: operand must be a symbol with %hi modifier or an integer in the range [-32, 31] +js 1024 # CHECK: :[[@LINE]]:4: error: immediate must be an integer in the range [-1024, 1023] +js -1025 # CHECK: :[[@LINE]]:4: error: immediate must be an integer in the range [-1024, 1023] + +# Invalid mnemonics +subs x1, x2 # CHECK: :[[@LINE]]:1: error: unrecognized instruction mnemonic +nandi x14, x13 # CHECK: :[[@LINE]]:1: error: unrecognized instruction mnemonic + +# Invalid register names +add foo, x1, x3 # CHECK: :[[@LINE]]:5: error: invalid operand for instruction +sub x0, x16, x4 # CHECK: :[[@LINE]]:9: error: invalid operand for instruction +mov t2, x8 # CHECK: :[[@LINE]]:5: error: invalid operand for instruction + +# Invalid operand types +add x15, x1, 1 # CHECK: :[[@LINE]]:14: error: invalid operand for instruction + +# Too many operand +mov x8, x9, x10 # CHECK: :[[@LINE]]:13: error: invalid operand for instruction +li x11, x12, x13 # CHECK: :[[@LINE]]:9: error: invalid operand for instruction + +# Too few operands +li x8 # CHECK: :[[@LINE]]:1: error: too few operands for instruction +mov x13 # CHECK: :[[@LINE]]:1: error: too few operands for instruction + +# Illegal operand modifier +lsli a0, a0, %lo(1) # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [0, 15] +ori a0, a1, %hi(foo) # CHECK: :[[@LINE]]:13: error: operand must be a symbol with %lo modifier or an integer in the range [-512, 511] +lui a0, %lo(1) # CHECK: :[[@LINE]]:9: error: operand must be a symbol with %hi modifier or an integer in the range [-32, 31] +addi t0, sp, %modifer(255) # CHECK: :[[@LINE]]:15: error: unrecognized operand modifier +addi t1, %lo(t2), 1 # CHECK: :[[@LINE]]:10: error: invalid operand for instruction +addi a0, a1, foo # CHECK: :[[@LINE]]:14: error: operand must be a symbol with %lo modifier or an integer in the range [-512, 511] +addi2 a0, foo # CHECK: :[[@LINE]]:11: error: operand must be a symbol with %hi modifier or an integer in the range [-32, 31] diff --git a/llvm/test/MC/CAHP/cahp-valid.s b/llvm/test/MC/CAHP/cahp-valid.s new file mode 100644 index 000000000000..8a4ef7cb3049 --- /dev/null +++ b/llvm/test/MC/CAHP/cahp-valid.s @@ -0,0 +1,203 @@ +# RUN: llvm-mc %s -triple=cahp -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s +# RUN: llvm-mc -filetype=obj -triple=cahp < %s \ +# RUN: | llvm-objdump -d - | FileCheck -check-prefix=CHECK-INST %s + +# CHECK-INST: lw ra, -500(sp) +# CHECK: encoding: [0x95,0x10,0x0c] +lw ra, -500(sp) +# CHECK-INST: lb ra, -500(sp) +# CHECK: encoding: [0xa5,0x10,0x0c] +lb ra, -500(sp) +# CHECK-INST: lbu ra, -500(sp) +# CHECK: encoding: [0x85,0x10,0x0c] +lbu ra, -500(sp) +# CHECK-INST: sw ra, -500(sp) +# CHECK: encoding: [0x9d,0x10,0x0c] +sw ra, -500(sp) +# CHECK-INST: sb ra, -500(sp) +# CHECK: encoding: [0x8d,0x10,0x0c] +sb ra, -500(sp) +# CHECK-INST: li ra, -500 +# CHECK: encoding: [0xb5,0x00,0x0c] +li ra, -500 +# CHECK-INST: li a0, 391 +# CHECK: encoding: [0x75,0x08,0x87] +li a0, (0x187000 >> 12) +# CHECK-INST: li a0, 256 +# CHECK: encoding: [0x75,0x08,0x00] +li a0, %lo(0x8500) +# CHECK-INST: add ra, sp, fp +# CHECK: encoding: [0x01,0x10,0x02] +add ra, sp, fp +# CHECK-INST: sub ra, sp, fp +# CHECK: encoding: [0x09,0x10,0x02] +sub ra, sp, fp +# CHECK-INST: and ra, sp, fp +# CHECK: encoding: [0x11,0x10,0x02] +and ra, sp, fp +# CHECK-INST: xor ra, sp, fp +# CHECK: encoding: [0x19,0x10,0x02] +xor ra, sp, fp +# CHECK-INST: or ra, sp, fp +# CHECK: encoding: [0x21,0x10,0x02] +or ra, sp, fp +# CHECK-INST: lsl ra, sp, fp +# CHECK: encoding: [0x29,0x10,0x02] +lsl ra, sp, fp +# CHECK-INST: lsr ra, sp, fp +# CHECK: encoding: [0x31,0x10,0x02] +lsr ra, sp, fp +# CHECK-INST: asr ra, sp, fp +# CHECK: encoding: [0x39,0x10,0x02] +asr ra, sp, fp +# CHECK-INST: addi ra, sp, 10 +# CHECK: encoding: [0x03,0x10,0x0a] +addi ra, sp, 10 +# CHECK-INST: addi ra, sp, -10 +# CHECK: encoding: [0xc3,0x10,0xf6] +addi ra, sp, -10 +# CHECK-INST: andi ra, sp, -246 +# CHECK: encoding: [0xd3,0x10,0x0a] +andi ra, sp, -246 +# CHECK-INST: xori ra, sp, -246 +# CHECK: encoding: [0xdb,0x10,0x0a] +xori ra, sp, -246 +# CHECK-INST: ori ra, sp, -246 +# CHECK: encoding: [0xe3,0x10,0x0a] +ori ra, sp, -246 +# CHECK-INST: ori ra, sp, -246 +# CHECK: encoding: [0xe3,0x10,0x0a] +ori ra, sp, %lo(0xA70A) +# CHECK-INST: lsli ra, sp, 3 +# CHECK: encoding: [0x2b,0x10,0x03] +lsli ra, sp, 3 +# CHECK-INST: lsri ra, sp, 3 +# CHECK: encoding: [0x33,0x10,0x03] +lsri ra, sp, 3 +# CHECK-INST: asri ra, sp, 4 +# CHECK: encoding: [0x3b,0x10,0x04] +asri ra, sp, 4 +# CHECK-INST: beq ra, sp, 16 +# CHECK: encoding: [0x0f,0x01,0x10] +beq ra, sp, 16 +# CHECK-INST: beq ra, sp, 16 +# CHECK: encoding: [0x0f,0x01,0x10] +beq ra, sp, 16 +# CHECK-INST: bne ra, sp, 16 +# CHECK: encoding: [0x2f,0x01,0x10] +bne ra, sp, 16 +# CHECK-INST: bne ra, sp, 16 +# CHECK: encoding: [0x2f,0x01,0x10] +bne ra, sp, 16 +# CHECK-INST: blt ra, sp, 16 +# CHECK: encoding: [0x37,0x01,0x10] +blt ra, sp, 16 +# CHECK-INST: blt ra, sp, 16 +# CHECK: encoding: [0x37,0x01,0x10] +blt ra, sp, 16 +# CHECK-INST: blt ra, sp, 16 +# CHECK: encoding: [0x37,0x01,0x10] +blt ra, sp, 16 +# CHECK-INST: bltu ra, sp, 16 +# CHECK: encoding: [0x17,0x01,0x10] +bltu ra, sp, 16 +# CHECK-INST: bltu ra, sp, 16 +# CHECK: encoding: [0x17,0x01,0x10] +bltu ra, sp, 16 +# CHECK-INST: bltu ra, sp, 16 +# CHECK: encoding: [0x17,0x01,0x10] +bltu ra, sp, 16 +# CHECK-INST: ble ra, sp, 16 +# CHECK: encoding: [0x3f,0x01,0x10] +ble ra, sp, 16 +# CHECK-INST: ble ra, sp, 16 +# CHECK: encoding: [0x3f,0x01,0x10] +ble ra, sp, 16 +# CHECK-INST: ble ra, sp, 16 +# CHECK: encoding: [0x3f,0x01,0x10] +ble ra, sp, 16 +# CHECK-INST: bleu ra, sp, 16 +# CHECK: encoding: [0x1f,0x01,0x10] +bleu ra, sp, 16 +# CHECK-INST: bleu ra, sp, 16 +# CHECK: encoding: [0x1f,0x01,0x10] +bleu ra, sp, 16 +# CHECK-INST: bleu ra, sp, 16 +# CHECK: encoding: [0x1f,0x01,0x10] +bleu ra, sp, 16 +# CHECK-INST: lwsp ra, 32(sp) +# CHECK: encoding: [0x54,0x00] +lwsp ra, 32(sp) +# CHECK-INST: swsp ra, 64(sp) +# CHECK: encoding: [0x9c,0x00] +swsp ra, 64(sp) +# CHECK-INST: lsi ra, -32 +# CHECK: encoding: [0xb4,0x00] +lsi ra, -32 +# CHECK-INST: lui ra, -32 +# CHECK: encoding: [0x84,0x00] +lui ra, -32 +# CHECK-INST: lui a0, 0 +# CHECK: encoding: [0x04,0x08] +lui a0, %hi(2) +# CHECK-INST: mov ra, sp +# CHECK: encoding: [0xc0,0x10] +mov ra, sp +# CHECK-INST: add2 ra, sp +# CHECK: encoding: [0x80,0x10] +add2 ra, sp +# CHECK-INST: sub2 ra, sp +# CHECK: encoding: [0x88,0x10] +sub2 ra, sp +# CHECK-INST: and2 ra, sp +# CHECK: encoding: [0x90,0x10] +and2 ra, sp +# CHECK-INST: xor2 ra, sp +# CHECK: encoding: [0x98,0x10] +xor2 ra, sp +# CHECK-INST: or2 ra, sp +# CHECK: encoding: [0xa0,0x10] +or2 ra, sp +# CHECK-INST: or2 ra, sp +# CHECK: encoding: [0xa0,0x10] +or2 ra, sp +# CHECK-INST: lsl2 ra, sp +# CHECK: encoding: [0xa8,0x10] +lsl2 ra, sp +# CHECK-INST: lsr2 ra, sp +# CHECK: encoding: [0xb0,0x10] +lsr2 ra, sp +# CHECK-INST: asr2 ra, sp +# CHECK: encoding: [0xb8,0x10] +asr2 ra, sp +# CHECK-INST: lsli2 ra, 3 +# CHECK: encoding: [0x2a,0x30] +lsli2 ra, 3 +# CHECK-INST: lsri2 ra, 3 +# CHECK: encoding: [0x32,0x30] +lsri2 ra, 3 +# CHECK-INST: asri2 ra, 3 +# CHECK: encoding: [0x3a,0x30] +asri2 ra, 3 +# CHECK-INST: addi2 ra, -32 +# CHECK: encoding: [0x82,0x00] +addi2 ra, -32 +# CHECK-INST: andi2 ra, 26 +# CHECK: encoding: [0x52,0xa0] +andi2 ra, 26 +# CHECK-INST: jalr sp +# CHECK: encoding: [0x16,0x01] +jalr sp +# CHECK-INST: jr sp +# CHECK: encoding: [0x06,0x01] +jr sp +# CHECK-INST: js 8 +# CHECK: encoding: [0x0e,0x01] +js 8 +# CHECK-INST: jsal 8 +# CHECK: encoding: [0x1e,0x01] +jsal 8 +# CHECK-INST: nop +# CHECK: encoding: [0x00,0x00] +nop diff --git a/llvm/test/MC/CAHP/fixups.s b/llvm/test/MC/CAHP/fixups.s new file mode 100644 index 000000000000..37f94eca19bb --- /dev/null +++ b/llvm/test/MC/CAHP/fixups.s @@ -0,0 +1,67 @@ +# RUN: llvm-mc -triple cahp < %s -show-encoding \ +# RUN: | FileCheck -check-prefix=CHECK-FIXUP %s +# RUN: llvm-mc -filetype=obj -triple cahp < %s \ +# RUN: | llvm-objdump -d - | FileCheck -check-prefix=CHECK-INSTR %s + +# Checks that fixups that can be resolved within the same object file are +# applied correctly + +.LBB0: +.space 1024 +js .LBB0 +# CHECK-FIXUP: fixup A - offset: 0, value: .LBB0, kind: fixup_cahp_pcrel_11 +# CHECK-INSTR: js -1024 + +.LBB1: +.space 1024 +jsal .LBB1 +# CHECK-FIXUP: fixup A - offset: 0, value: .LBB1, kind: fixup_cahp_pcrel_11 +# CHECK-INSTR: jsal -1024 + +.LBB2: +.space 512 +beq a0, a1, .LBB2 +# CHECK-FIXUP: fixup A - offset: 0, value: .LBB2, kind: fixup_cahp_pcrel_10 +# CHECK-INSTR: beq a0, a1, -512 + +.LBB3: +.space 512 +bne a0, a1, .LBB3 +# CHECK-FIXUP: fixup A - offset: 0, value: .LBB3, kind: fixup_cahp_pcrel_10 +# CHECK-INSTR: bne a0, a1, -512 + +.LBB4: +.space 512 +blt a0, a1, .LBB4 +# CHECK-FIXUP: fixup A - offset: 0, value: .LBB4, kind: fixup_cahp_pcrel_10 +# CHECK-INSTR: blt a0, a1, -512 + +.LBB5: +.space 512 +bltu a0, a1, .LBB5 +# CHECK-FIXUP: fixup A - offset: 0, value: .LBB5, kind: fixup_cahp_pcrel_10 +# CHECK-INSTR: bltu a0, a1, -512 + +.LBB6: +.space 512 +ble a0, a1, .LBB6 +# CHECK-FIXUP: fixup A - offset: 0, value: .LBB6, kind: fixup_cahp_pcrel_10 +# CHECK-INSTR: ble a0, a1, -512 + +.LBB7: +.space 512 +bleu a0, a1, .LBB7 +# CHECK-FIXUP: fixup A - offset: 0, value: .LBB7, kind: fixup_cahp_pcrel_10 +# CHECK-INSTR: bleu a0, a1, -512 + +addi a0, a1, %lo(val) +# CHECK-FIXUP: fixup A - offset: 0, value: %lo(val), kind: fixup_cahp_lo10 +# CHECK-INSTR: addi a0, a1, -460 + +lui a0, %hi(val) +# CHECK-FIXUP: fixup A - offset: 0, value: %hi(val), kind: fixup_cahp_hi6 +# CHECK-INSTR: lui a0, 5 + +.set val, 0x1234 + +# CHECK-REL-NOT: R_CAHP diff --git a/llvm/test/MC/CAHP/hilo-constaddr.s b/llvm/test/MC/CAHP/hilo-constaddr.s new file mode 100644 index 000000000000..b745ae9e5456 --- /dev/null +++ b/llvm/test/MC/CAHP/hilo-constaddr.s @@ -0,0 +1,39 @@ +# RUN: llvm-mc -filetype=obj -triple=cahp %s \ +# RUN: | llvm-objdump -d - | FileCheck %s -check-prefix=CHECK-INSTR + +# RUN: llvm-mc -filetype=obj -triple=cahp %s \ +# RUN: | llvm-readobj -r | FileCheck %s -check-prefix=CHECK-REL + +# Check the assembler can handle hi and lo expressions with a constant +# address, and constant expressions involving labels. Test case derived from +# test/MC/Mips/hilo-addressing.s + +# Check that 1 is added to the high 6 bits if bit 9 of the low part is 1. +.equ addr, 0x1234 + lui t0, %hi(addr) + lw ra, %lo(addr)(t0) +# CHECK-INSTR: lui t0, 5 +# CHECK-INSTR: lw ra, -460(t0) + +# Check that assembler can handle %hi(label1 - label2) and %lo(label1 - label2) +# expressions. + +tmp1: + # Emit zeros so that difference between tmp1 and tmp3 is 0x1234+5 bytes. + .fill 0x1234 +tmp2: + lui t0, %hi(tmp3-tmp1) + lw ra, %lo(tmp3-tmp1)(t0) +# CHECK-INSTR: lui t0, 5 +# CHECK-INSTR: lw ra, -455(t0) + +tmp3: + lui t1, %hi(tmp2-tmp3) + lw sp, %lo(tmp2-tmp3)(t1) +# CHECK-INSTR: lui t1, 0 +# CHECK-INSTR: lw sp, -5(t1) + +# Check that a relocation isn't emitted for %hi(label1 - label2) and +# %lo(label1 - label2) expressions. + +# CHECK-REL-NOT: R_CAHP diff --git a/llvm/test/MC/CAHP/hlt.s b/llvm/test/MC/CAHP/hlt.s new file mode 100644 index 000000000000..b4225aa568d3 --- /dev/null +++ b/llvm/test/MC/CAHP/hlt.s @@ -0,0 +1,9 @@ +# RUN: llvm-mc %s -triple=cahp -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s +# RUN: llvm-mc -filetype=obj -triple=cahp < %s \ +# RUN: | llvm-objdump -d - | FileCheck -check-prefix=CHECK-INSTDUMP %s + +# CHECK-INST: hlt +# CHECK-INSTDUMP: js 0 +# CHECK: encoding: [0x0e,0x00] +hlt diff --git a/llvm/test/MC/CAHP/lit.local.cfg b/llvm/test/MC/CAHP/lit.local.cfg new file mode 100644 index 000000000000..519647fc4da4 --- /dev/null +++ b/llvm/test/MC/CAHP/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'CAHP' in config.root.targets: + config.unsupported = True diff --git a/llvm/test/MC/CAHP/relocations.s b/llvm/test/MC/CAHP/relocations.s new file mode 100644 index 000000000000..f7001be75841 --- /dev/null +++ b/llvm/test/MC/CAHP/relocations.s @@ -0,0 +1,37 @@ +# RUN: llvm-mc -triple cahp < %s -show-encoding \ +# RUN: | FileCheck -check-prefix=INSTR -check-prefix=FIXUP %s +# RUN: llvm-mc -filetype=obj -triple cahp < %s \ +# RUN: | llvm-readobj -r | FileCheck -check-prefix=RELOC %s + +# Check prefixes: +# RELOC - Check the relocation in the object. +# FIXUP - Check the fixup on the instruction. +# INSTR - Check the instruction is handled properly by the ASMPrinter + +.2byte foo +# RELOC: R_CAHP_16 foo + +lui t1, %hi(foo) +# RELOC: R_CAHP_HI6 foo 0x0 +# INSTR: lui t1, %hi(foo) +# FIXUP: fixup A - offset: 0, value: %hi(foo), kind: fixup_cahp_hi6 + +lui t1, %hi(foo+4) +# RELOC: R_CAHP_HI6 foo 0x4 +# INSTR: lui t1, %hi(foo+4) +# FIXUP: fixup A - offset: 0, value: %hi(foo+4), kind: fixup_cahp_hi6 + +addi t1, t1, %lo(foo) +# RELOC: R_CAHP_LO10 foo 0x0 +# INSTR: addi t1, t1, %lo(foo) +# FIXUP: fixup A - offset: 0, value: %lo(foo), kind: fixup_cahp_lo10 + +addi t1, t1, %lo(foo+4) +# RELOC: R_CAHP_LO10 foo 0x4 +# INSTR: addi t1, t1, %lo(foo+4) +# FIXUP: fixup A - offset: 0, value: %lo(foo+4), kind: fixup_cahp_lo10 + +jsal foo +# RELOC: R_CAHP_PCREL_11 +# INSTR: jsal foo +# FIXUP: fixup A - offset: 0, value: foo, kind: fixup_cahp_pcrel_11 diff --git a/llvm/test/MC/Mips/mips-expansions.s b/llvm/test/MC/Mips/mips-expansions.s index 91a637bfe221..798461c5f99c 100644 --- a/llvm/test/MC/Mips/mips-expansions.s +++ b/llvm/test/MC/Mips/mips-expansions.s @@ -50,6 +50,7 @@ # CHECK-LE: lhu $4, 4($4) # LW/SW and LDC1/SDC1 of symbol address, done by MipsAsmParser::expandMemInst(): +# NON-PIC code .set noat lw $10, symbol($4) # CHECK-LE: lui $10, %hi(symbol) # encoding: [A,A,0x0a,0x3c] @@ -105,6 +106,64 @@ # CHECK-LE: lui $1, %hi(symbol) # CHECK-LE: sdc1 $f0, %lo(symbol)($1) +# PIC code + .option pic2 + .set noat + lw $10, symbol($4) +# CHECK-LE: lw $10, %got(symbol)($gp) # encoding: [A,A,0x8a,0x8f] +# CHECK-LE: # fixup A - offset: 0, value: %got(symbol), kind: fixup_Mips_GOT +# CHECK-LE-FIXME: addu $10, $10, $4 # encoding: [0x21,0x50,0x44,0x01] +# CHECK-LE: lw $10, 0($10) # encoding: [0x00,0x00,0x4a,0x8d] + .set at + sw $10, symbol($9) +# CHECK-LE: lw $1, %got(symbol)($gp) # encoding: [A,A,0x81,0x8f] +# CHECK-LE: # fixup A - offset: 0, value: %got(symbol), kind: fixup_Mips_GOT +# CHECK-LE-FIXME: addu $1, $1, $9 # encoding: [0x21,0x08,0x29,0x00] +# CHECK-LE: sw $10, 0($1) # encoding: [0x00,0x00,0x2a,0xac] + + lw $8, 1f+8 +# CHECK-LE: lw $8, %got(($tmp0)+8)($gp) # encoding: [A,A,0x88,0x8f] +# CHECK-LE: # fixup A - offset: 0, value: %got(($tmp0)+8), kind: fixup_Mips_GOT +# CHECK-LE: addiu $8, $8, %lo(($tmp0)+8) # encoding: [A,A,0x08,0x25] +# CHECK-LE: # fixup A - offset: 0, value: %lo(($tmp0)+8), kind: fixup_Mips_LO16 +# CHECK-LE: lw $8, 0($8) # encoding: [0x00,0x00,0x08,0x8d] + sw $8, 1f+8 +# CHECK-LE: lw $1, %got(($tmp0)+8)($gp) # encoding: [A,A,0x81,0x8f] +# CHECK-LE: # fixup A - offset: 0, value: %got(($tmp0)+8), kind: fixup_Mips_GOT +# CHECK-LE: addiu $1, $1, %lo(($tmp0)+8) # encoding: [A,A,0x21,0x24] +# CHECK-LE: # fixup A - offset: 0, value: %lo(($tmp0)+8), kind: fixup_Mips_LO16 +# CHECK-LE: sw $8, 0($1) # encoding: [0x00,0x00,0x28,0xac] + + lw $10, 655483($4) +# CHECK-LE: lui $10, 10 # encoding: [0x0a,0x00,0x0a,0x3c] +# CHECK-LE: addu $10, $10, $4 # encoding: [0x21,0x50,0x44,0x01] +# CHECK-LE: lw $10, 123($10) # encoding: [0x7b,0x00,0x4a,0x8d] + sw $10, 123456($9) +# CHECK-LE: lui $1, 2 # encoding: [0x02,0x00,0x01,0x3c] +# CHECK-LE: addu $1, $1, $9 # encoding: [0x21,0x08,0x29,0x00] +# CHECK-LE: sw $10, -7616($1) # encoding: [0x40,0xe2,0x2a,0xac] + + lw $8, symbol+8 +# CHECK-LE: lw $8, %got(symbol+8)($gp) # encoding: [A,A,0x88,0x8f] +# CHECK-LE: # fixup A - offset: 0, value: %got(symbol+8), kind: fixup_Mips_GOT +# CHECK-LE: addiu $8, $8, 8 # encoding: [0x08,0x00,0x08,0x25] +# CHECK-LE: lw $8, 0($8) # encoding: [0x00,0x00,0x08,0x8d] + sw $8, symbol+8 +# CHECK-LE: lw $1, %got(symbol+8)($gp) # encoding: [A,A,0x81,0x8f] +# CHECK-LE: # fixup A - offset: 0, value: %got(symbol+8), kind: fixup_Mips_GOT +# CHECK-LE: addiu $1, $1, 8 # encoding: [0x08,0x00,0x21,0x24] +# CHECK-LE: sw $8, 0($1) # encoding: [0x00,0x00,0x28,0xac] + + ldc1 $f0, symbol +# CHECK-LE: lw $1, %got(symbol)($gp) # encoding: [A,A,0x81,0x8f] +# CHECK-LE: # fixup A - offset: 0, value: %got(symbol), kind: fixup_Mips_GOT +# CHECK-LE: ldc1 $f0, 0($1) # encoding: [0x00,0x00,0x20,0xd4] + sdc1 $f0, symbol +# CHECK-LE: lw $1, %got(symbol)($gp) # encoding: [A,A,0x81,0x8f] +# CHECK-LE: # fixup A - offset: 0, value: %got(symbol), kind: fixup_Mips_GOT +# CHECK-LE: sdc1 $f0, 0($1) # encoding: [0x00,0x00,0x20,0xf4] + .option pic0 + # Test BNE with an immediate as the 2nd operand. bne $2, 0, 1332 # CHECK-LE: bnez $2, 1332 # encoding: [0x4d,0x01,0x40,0x14] diff --git a/llvm/test/MC/Mips/mips64-expansions.s b/llvm/test/MC/Mips/mips64-expansions.s index 4f0d3f15773c..4c24379f2dde 100644 --- a/llvm/test/MC/Mips/mips64-expansions.s +++ b/llvm/test/MC/Mips/mips64-expansions.s @@ -466,3 +466,56 @@ sym: # CHECK-NEXT: dsll $4, $4, 16 # CHECK-NEXT: daddu $4, $4, $3 # CHECK-NEXT: lhu $4, -32764($4) + +# LW/SW and LDC1/SDC1 of symbol address, done by MipsAsmParser::expandMemInst(): + .option pic2 + lw $10, symbol($4) +# CHECK: ld $10, %got_disp(symbol)($gp) # encoding: [A,A,0x8a,0xdf] +# CHECK: # fixup A - offset: 0, value: %got_disp(symbol), kind: fixup_Mips_GOT_DISP +# CHECK-FIXME: daddu $10, $10, $4 # encoding: [0x2d,0x50,0x44,0x01] +# CHECK: lw $10, 0($10) # encoding: [0x00,0x00,0x4a,0x8d] + sw $10, symbol($9) +# CHECK: ld $1, %got_disp(symbol)($gp) # encoding: [A,A,0x81,0xdf] +# CHECK: # fixup A - offset: 0, value: %got_disp(symbol), kind: fixup_Mips_GOT_DISP +# CHECK-FIXME: daddu $1, $1, $9 # encoding: [0x2d,0x08,0x29,0x00] +# CHECK: sw $10, 0($1) # encoding: [0x00,0x00,0x2a,0xac] + + lw $8, sym+8 +# CHECK: ld $8, %got_disp(sym)($gp) # encoding: [A,A,0x88,0xdf] +# CHECK: # fixup A - offset: 0, value: %got_disp(sym), kind: fixup_Mips_GOT_DISP +# CHECK: daddiu $8, $8, 8 # encoding: [0x08,0x00,0x08,0x65] +# CHECK: lw $8, 0($8) # encoding: [0x00,0x00,0x08,0x8d] + sw $8, sym+8 +# CHECK: ld $1, %got_disp(sym)($gp) # encoding: [A,A,0x81,0xdf] +# CHECK: # fixup A - offset: 0, value: %got_disp(sym), kind: fixup_Mips_GOT_DISP +# CHECK: daddiu $1, $1, 8 # encoding: [0x08,0x00,0x21,0x64] +# CHECK: sw $8, 0($1) # encoding: [0x00,0x00,0x28,0xac] + + lw $10, 655483($4) +# CHECK: lui $10, 10 # encoding: [0x0a,0x00,0x0a,0x3c] +# CHECK: daddu $10, $10, $4 # encoding: [0x2d,0x50,0x44,0x01] +# CHECK: lw $10, 123($10) # encoding: [0x7b,0x00,0x4a,0x8d] + sw $10, 123456($9) +# CHECK: lui $1, 2 # encoding: [0x02,0x00,0x01,0x3c] +# CHECK: daddu $1, $1, $9 # encoding: [0x2d,0x08,0x29,0x00] +# CHECK: sw $10, -7616($1) # encoding: [0x40,0xe2,0x2a,0xac] + + lw $8, symbol+8 +# CHECK: ld $8, %got_disp(symbol)($gp) # encoding: [A,A,0x88,0xdf] +# CHECK: # fixup A - offset: 0, value: %got_disp(symbol), kind: fixup_Mips_GOT_DISP +# CHECK: daddiu $8, $8, 8 # encoding: [0x08,0x00,0x08,0x65] +# CHECK: lw $8, 0($8) # encoding: [0x00,0x00,0x08,0x8d] + sw $8, symbol+8 +# CHECK: ld $1, %got_disp(symbol)($gp) # encoding: [A,A,0x81,0xdf] +# CHECK: # fixup A - offset: 0, value: %got_disp(symbol), kind: fixup_Mips_GOT_DISP +# CHECK: daddiu $1, $1, 8 # encoding: [0x08,0x00,0x21,0x64] +# CHECK: sw $8, 0($1) # encoding: [0x00,0x00,0x28,0xac] + + ldc1 $f0, symbol +# CHECK: ld $1, %got_disp(symbol)($gp) # encoding: [A,A,0x81,0xdf] +# CHECK: # fixup A - offset: 0, value: %got_disp(symbol), kind: fixup_Mips_GOT_DISP +# CHECK: ldc1 $f0, 0($1) # encoding: [0x00,0x00,0x20,0xd4] + sdc1 $f0, symbol +# CHECK: ld $1, %got_disp(symbol)($gp) # encoding: [A,A,0x81,0xdf] +# CHECK: # fixup A - offset: 0, value: %got_disp(symbol), kind: fixup_Mips_GOT_DISP +# CHECK: sdc1 $f0, 0($1) # encoding: [0x00,0x00,0x20,0xf4] diff --git a/llvm/test/MC/RISCV/rv32i-aliases-invalid.s b/llvm/test/MC/RISCV/rv32i-aliases-invalid.s index 4080d892a67e..ce603baa4fd0 100644 --- a/llvm/test/MC/RISCV/rv32i-aliases-invalid.s +++ b/llvm/test/MC/RISCV/rv32i-aliases-invalid.s @@ -1,3 +1,4 @@ +# UNSUPPORTED: linux, windows # RUN: not llvm-mc %s -triple=riscv32 -riscv-no-aliases 2>&1 | FileCheck %s # RUN: not llvm-mc %s -triple=riscv32 2>&1 | FileCheck %s diff --git a/llvm/test/MC/RISCV/rv64i-aliases-invalid.s b/llvm/test/MC/RISCV/rv64i-aliases-invalid.s index f3f2acc473dd..3e156b39f067 100644 --- a/llvm/test/MC/RISCV/rv64i-aliases-invalid.s +++ b/llvm/test/MC/RISCV/rv64i-aliases-invalid.s @@ -1,3 +1,4 @@ +# UNSUPPORTED: linux, windows # RUN: not llvm-mc %s -triple=riscv64 -riscv-no-aliases 2>&1 | FileCheck %s # RUN: not llvm-mc %s -triple=riscv64 2>&1 | FileCheck %s diff --git a/llvm/test/MC/RISCV/rvi-pseudos.s b/llvm/test/MC/RISCV/rvi-pseudos.s index 7ecdb8fb4ce1..37501a00e3ea 100644 --- a/llvm/test/MC/RISCV/rvi-pseudos.s +++ b/llvm/test/MC/RISCV/rvi-pseudos.s @@ -34,145 +34,150 @@ lla a3, ra lla a4, f1 # CHECK: .Lpcrel_hi5: +# CHECK: auipc a5, %pcrel_hi(a_symbol+2040) +# CHECK: addi a5, a5, %pcrel_lo(.Lpcrel_hi5) +lla a5, a_symbol + (0xFF << 3) + +# CHECK: .Lpcrel_hi6: # CHECK-NOPIC: auipc a0, %pcrel_hi(a_symbol) -# CHECK-NOPIC: addi a0, a0, %pcrel_lo(.Lpcrel_hi5) +# CHECK-NOPIC: addi a0, a0, %pcrel_lo(.Lpcrel_hi6) # CHECK-PIC: auipc a0, %got_pcrel_hi(a_symbol) -# CHECK-PIC-RV32: lw a0, %pcrel_lo(.Lpcrel_hi5)(a0) -# CHECK-PIC-RV64: ld a0, %pcrel_lo(.Lpcrel_hi5)(a0) +# CHECK-PIC-RV32: lw a0, %pcrel_lo(.Lpcrel_hi6)(a0) +# CHECK-PIC-RV64: ld a0, %pcrel_lo(.Lpcrel_hi6)(a0) la a0, a_symbol -# CHECK: .Lpcrel_hi6: +# CHECK: .Lpcrel_hi7: # CHECK-NOPIC: auipc a1, %pcrel_hi(another_symbol) -# CHECK-NOPIC: addi a1, a1, %pcrel_lo(.Lpcrel_hi6) +# CHECK-NOPIC: addi a1, a1, %pcrel_lo(.Lpcrel_hi7) # CHECK-PIC: auipc a1, %got_pcrel_hi(another_symbol) -# CHECK-PIC-RV32: lw a1, %pcrel_lo(.Lpcrel_hi6)(a1) -# CHECK-PIC-RV64: ld a1, %pcrel_lo(.Lpcrel_hi6)(a1) +# CHECK-PIC-RV32: lw a1, %pcrel_lo(.Lpcrel_hi7)(a1) +# CHECK-PIC-RV64: ld a1, %pcrel_lo(.Lpcrel_hi7)(a1) la a1, another_symbol # Check that we can load the address of symbols that are spelled like a register -# CHECK: .Lpcrel_hi7: +# CHECK: .Lpcrel_hi8: # CHECK-NOPIC: auipc a2, %pcrel_hi(zero) -# CHECK-NOPIC: addi a2, a2, %pcrel_lo(.Lpcrel_hi7) +# CHECK-NOPIC: addi a2, a2, %pcrel_lo(.Lpcrel_hi8) # CHECK-PIC: auipc a2, %got_pcrel_hi(zero) -# CHECK-PIC-RV32: lw a2, %pcrel_lo(.Lpcrel_hi7)(a2) -# CHECK-PIC-RV64: ld a2, %pcrel_lo(.Lpcrel_hi7)(a2) +# CHECK-PIC-RV32: lw a2, %pcrel_lo(.Lpcrel_hi8)(a2) +# CHECK-PIC-RV64: ld a2, %pcrel_lo(.Lpcrel_hi8)(a2) la a2, zero -# CHECK: .Lpcrel_hi8: +# CHECK: .Lpcrel_hi9: # CHECK-NOPIC: auipc a3, %pcrel_hi(ra) -# CHECK-NOPIC: addi a3, a3, %pcrel_lo(.Lpcrel_hi8) +# CHECK-NOPIC: addi a3, a3, %pcrel_lo(.Lpcrel_hi9) # CHECK-PIC: auipc a3, %got_pcrel_hi(ra) -# CHECK-PIC-RV32: lw a3, %pcrel_lo(.Lpcrel_hi8)(a3) -# CHECK-PIC-RV64: ld a3, %pcrel_lo(.Lpcrel_hi8)(a3) +# CHECK-PIC-RV32: lw a3, %pcrel_lo(.Lpcrel_hi9)(a3) +# CHECK-PIC-RV64: ld a3, %pcrel_lo(.Lpcrel_hi9)(a3) la a3, ra -# CHECK: .Lpcrel_hi9: +# CHECK: .Lpcrel_hi10: # CHECK-NOPIC: auipc a4, %pcrel_hi(f1) -# CHECK-NOPIC: addi a4, a4, %pcrel_lo(.Lpcrel_hi9) +# CHECK-NOPIC: addi a4, a4, %pcrel_lo(.Lpcrel_hi10) # CHECK-PIC: auipc a4, %got_pcrel_hi(f1) -# CHECK-PIC-RV32: lw a4, %pcrel_lo(.Lpcrel_hi9)(a4) -# CHECK-PIC-RV64: ld a4, %pcrel_lo(.Lpcrel_hi9)(a4) +# CHECK-PIC-RV32: lw a4, %pcrel_lo(.Lpcrel_hi10)(a4) +# CHECK-PIC-RV64: ld a4, %pcrel_lo(.Lpcrel_hi10)(a4) la a4, f1 -# CHECK: .Lpcrel_hi10: +# CHECK: .Lpcrel_hi11: # CHECK: auipc a0, %tls_ie_pcrel_hi(a_symbol) -# CHECK-RV32: lw a0, %pcrel_lo(.Lpcrel_hi10)(a0) -# CHECK-RV64: ld a0, %pcrel_lo(.Lpcrel_hi10)(a0) +# CHECK-RV32: lw a0, %pcrel_lo(.Lpcrel_hi11)(a0) +# CHECK-RV64: ld a0, %pcrel_lo(.Lpcrel_hi11)(a0) la.tls.ie a0, a_symbol -# CHECK: .Lpcrel_hi11: +# CHECK: .Lpcrel_hi12: # CHECK: auipc a1, %tls_ie_pcrel_hi(another_symbol) -# CHECK-RV32: lw a1, %pcrel_lo(.Lpcrel_hi11)(a1) -# CHECK-RV64: ld a1, %pcrel_lo(.Lpcrel_hi11)(a1) +# CHECK-RV32: lw a1, %pcrel_lo(.Lpcrel_hi12)(a1) +# CHECK-RV64: ld a1, %pcrel_lo(.Lpcrel_hi12)(a1) la.tls.ie a1, another_symbol # Check that we can load the address of symbols that are spelled like a register -# CHECK: .Lpcrel_hi12: +# CHECK: .Lpcrel_hi13: # CHECK: auipc a2, %tls_ie_pcrel_hi(zero) -# CHECK-RV32: lw a2, %pcrel_lo(.Lpcrel_hi12)(a2) -# CHECK-RV64: ld a2, %pcrel_lo(.Lpcrel_hi12)(a2) +# CHECK-RV32: lw a2, %pcrel_lo(.Lpcrel_hi13)(a2) +# CHECK-RV64: ld a2, %pcrel_lo(.Lpcrel_hi13)(a2) la.tls.ie a2, zero -# CHECK: .Lpcrel_hi13: +# CHECK: .Lpcrel_hi14: # CHECK: auipc a3, %tls_ie_pcrel_hi(ra) -# CHECK-RV32: lw a3, %pcrel_lo(.Lpcrel_hi13)(a3) -# CHECK-RV64: ld a3, %pcrel_lo(.Lpcrel_hi13)(a3) +# CHECK-RV32: lw a3, %pcrel_lo(.Lpcrel_hi14)(a3) +# CHECK-RV64: ld a3, %pcrel_lo(.Lpcrel_hi14)(a3) la.tls.ie a3, ra -# CHECK: .Lpcrel_hi14: +# CHECK: .Lpcrel_hi15: # CHECK: auipc a4, %tls_ie_pcrel_hi(f1) -# CHECK-RV32: lw a4, %pcrel_lo(.Lpcrel_hi14)(a4) -# CHECK-RV64: ld a4, %pcrel_lo(.Lpcrel_hi14)(a4) +# CHECK-RV32: lw a4, %pcrel_lo(.Lpcrel_hi15)(a4) +# CHECK-RV64: ld a4, %pcrel_lo(.Lpcrel_hi15)(a4) la.tls.ie a4, f1 -# CHECK: .Lpcrel_hi15: +# CHECK: .Lpcrel_hi16: # CHECK: auipc a0, %tls_gd_pcrel_hi(a_symbol) -# CHECK: addi a0, a0, %pcrel_lo(.Lpcrel_hi15) +# CHECK: addi a0, a0, %pcrel_lo(.Lpcrel_hi16) la.tls.gd a0, a_symbol -# CHECK: .Lpcrel_hi16: +# CHECK: .Lpcrel_hi17: # CHECK: auipc a1, %tls_gd_pcrel_hi(another_symbol) -# CHECK: addi a1, a1, %pcrel_lo(.Lpcrel_hi16) +# CHECK: addi a1, a1, %pcrel_lo(.Lpcrel_hi17) la.tls.gd a1, another_symbol # Check that we can load the address of symbols that are spelled like a register -# CHECK: .Lpcrel_hi17: +# CHECK: .Lpcrel_hi18: # CHECK: auipc a2, %tls_gd_pcrel_hi(zero) -# CHECK: addi a2, a2, %pcrel_lo(.Lpcrel_hi17) +# CHECK: addi a2, a2, %pcrel_lo(.Lpcrel_hi18) la.tls.gd a2, zero -# CHECK: .Lpcrel_hi18: +# CHECK: .Lpcrel_hi19: # CHECK: auipc a3, %tls_gd_pcrel_hi(ra) -# CHECK: addi a3, a3, %pcrel_lo(.Lpcrel_hi18) +# CHECK: addi a3, a3, %pcrel_lo(.Lpcrel_hi19) la.tls.gd a3, ra -# CHECK: .Lpcrel_hi19: +# CHECK: .Lpcrel_hi20: # CHECK: auipc a4, %tls_gd_pcrel_hi(f1) -# CHECK: addi a4, a4, %pcrel_lo(.Lpcrel_hi19) +# CHECK: addi a4, a4, %pcrel_lo(.Lpcrel_hi20) la.tls.gd a4, f1 -# CHECK: .Lpcrel_hi20: +# CHECK: .Lpcrel_hi21: # CHECK: auipc a0, %pcrel_hi(a_symbol) -# CHECK: lb a0, %pcrel_lo(.Lpcrel_hi20)(a0) +# CHECK: lb a0, %pcrel_lo(.Lpcrel_hi21)(a0) lb a0, a_symbol -# CHECK: .Lpcrel_hi21: +# CHECK: .Lpcrel_hi22: # CHECK: auipc a1, %pcrel_hi(a_symbol) -# CHECK: lh a1, %pcrel_lo(.Lpcrel_hi21)(a1) +# CHECK: lh a1, %pcrel_lo(.Lpcrel_hi22)(a1) lh a1, a_symbol -# CHECK: .Lpcrel_hi22: +# CHECK: .Lpcrel_hi23: # CHECK: auipc a2, %pcrel_hi(a_symbol) -# CHECK: lhu a2, %pcrel_lo(.Lpcrel_hi22)(a2) +# CHECK: lhu a2, %pcrel_lo(.Lpcrel_hi23)(a2) lhu a2, a_symbol -# CHECK: .Lpcrel_hi23: +# CHECK: .Lpcrel_hi24: # CHECK: auipc a3, %pcrel_hi(a_symbol) -# CHECK: lw a3, %pcrel_lo(.Lpcrel_hi23)(a3) +# CHECK: lw a3, %pcrel_lo(.Lpcrel_hi24)(a3) lw a3, a_symbol -# CHECK: .Lpcrel_hi24: +# CHECK: .Lpcrel_hi25: # CHECK: auipc a4, %pcrel_hi(a_symbol) -# CHECK: sb a3, %pcrel_lo(.Lpcrel_hi24)(a4) +# CHECK: sb a3, %pcrel_lo(.Lpcrel_hi25)(a4) sb a3, a_symbol, a4 -# CHECK: .Lpcrel_hi25: +# CHECK: .Lpcrel_hi26: # CHECK: auipc a4, %pcrel_hi(a_symbol) -# CHECK: sh a3, %pcrel_lo(.Lpcrel_hi25)(a4) +# CHECK: sh a3, %pcrel_lo(.Lpcrel_hi26)(a4) sh a3, a_symbol, a4 -# CHECK: .Lpcrel_hi26: +# CHECK: .Lpcrel_hi27: # CHECK: auipc a4, %pcrel_hi(a_symbol) -# CHECK: sw a3, %pcrel_lo(.Lpcrel_hi26)(a4) +# CHECK: sw a3, %pcrel_lo(.Lpcrel_hi27)(a4) sw a3, a_symbol, a4 # Check that we can load the address of symbols that are spelled like a register -# CHECK: .Lpcrel_hi27: +# CHECK: .Lpcrel_hi28: # CHECK: auipc a2, %pcrel_hi(zero) -# CHECK: lw a2, %pcrel_lo(.Lpcrel_hi27)(a2) +# CHECK: lw a2, %pcrel_lo(.Lpcrel_hi28)(a2) lw a2, zero -# CHECK: .Lpcrel_hi28: +# CHECK: .Lpcrel_hi29: # CHECK: auipc a4, %pcrel_hi(zero) -# CHECK: sw a3, %pcrel_lo(.Lpcrel_hi28)(a4) +# CHECK: sw a3, %pcrel_lo(.Lpcrel_hi29)(a4) sw a3, zero, a4 diff --git a/llvm/test/Transforms/CodeGenPrepare/sink-shift-and-trunc.ll b/llvm/test/Transforms/CodeGenPrepare/sink-shift-and-trunc.ll index 20a436edd105..609b6bf679a2 100644 --- a/llvm/test/Transforms/CodeGenPrepare/sink-shift-and-trunc.ll +++ b/llvm/test/Transforms/CodeGenPrepare/sink-shift-and-trunc.ll @@ -58,6 +58,23 @@ return: ; preds = %if.then17, %if.end1 ret i32 %retval.0, !dbg !63 } +; CodeGenPrepare was erasing the unused lshr instruction, but then further +; processing the instruction after it was freed. If this bug is still present, +; this test will always crash in an LLVM built with ASAN enabled, and may +; crash even if ASAN is not enabled. + +define i32 @shift_unused(i32 %a) { +; CHECK-LABEL: @shift_unused( +; CHECK-NEXT: BB2: +; CHECK-NEXT: ret i32 [[A:%.*]] +; + %as = lshr i32 %a, 3 + br label %BB2 + +BB2: + ret i32 %a +} + ; CHECK: [[shift1_loc]] = !DILocation(line: 1 ; CHECK: [[trunc1_loc]] = !DILocation(line: 2 ; CHECK: [[shift2_loc]] = !DILocation(line: 3 diff --git a/llvm/test/Transforms/DivRemPairs/PowerPC/div-expanded-rem-pair.ll b/llvm/test/Transforms/DivRemPairs/PowerPC/div-expanded-rem-pair.ll new file mode 100644 index 000000000000..04a8a7721e91 --- /dev/null +++ b/llvm/test/Transforms/DivRemPairs/PowerPC/div-expanded-rem-pair.ll @@ -0,0 +1,172 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -div-rem-pairs -S -mtriple=powerpc64-unknown-unknown | FileCheck %s + +declare void @foo(i32, i32) + +define void @decompose_illegal_srem_same_block(i32 %a, i32 %b) { +; CHECK-LABEL: @decompose_illegal_srem_same_block( +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[T0:%.*]] = mul i32 [[DIV]], [[B]] +; CHECK-NEXT: [[REM:%.*]] = sub i32 [[A]], [[T0]] +; CHECK-NEXT: call void @foo(i32 [[REM]], i32 [[DIV]]) +; CHECK-NEXT: ret void +; + %div = sdiv i32 %a, %b + %t0 = mul i32 %div, %b + %rem = sub i32 %a, %t0 + call void @foo(i32 %rem, i32 %div) + ret void +} + +define void @decompose_illegal_urem_same_block(i32 %a, i32 %b) { +; CHECK-LABEL: @decompose_illegal_urem_same_block( +; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[T0:%.*]] = mul i32 [[DIV]], [[B]] +; CHECK-NEXT: [[REM:%.*]] = sub i32 [[A]], [[T0]] +; CHECK-NEXT: call void @foo(i32 [[REM]], i32 [[DIV]]) +; CHECK-NEXT: ret void +; + %div = udiv i32 %a, %b + %t0 = mul i32 %div, %b + %rem = sub i32 %a, %t0 + call void @foo(i32 %rem, i32 %div) + ret void +} + +; Recompose and hoist the srem if it's safe and free, otherwise keep as-is.. + +define i16 @hoist_srem(i16 %a, i16 %b) { +; CHECK-LABEL: @hoist_srem( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[DIV:%.*]] = sdiv i16 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[DIV]], 42 +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] +; CHECK: if: +; CHECK-NEXT: [[T0:%.*]] = mul i16 [[DIV]], [[B]] +; CHECK-NEXT: [[REM:%.*]] = sub i16 [[A]], [[T0]] +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: [[RET:%.*]] = phi i16 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] +; CHECK-NEXT: ret i16 [[RET]] +; +entry: + %div = sdiv i16 %a, %b + %cmp = icmp eq i16 %div, 42 + br i1 %cmp, label %if, label %end + +if: + %t0 = mul i16 %div, %b + %rem = sub i16 %a, %t0 + br label %end + +end: + %ret = phi i16 [ %rem, %if ], [ 3, %entry ] + ret i16 %ret +} + +; Recompose and hoist the urem if it's safe and free, otherwise keep as-is.. + +define i8 @hoist_urem(i8 %a, i8 %b) { +; CHECK-LABEL: @hoist_urem( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[DIV]], 42 +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] +; CHECK: if: +; CHECK-NEXT: [[T0:%.*]] = mul i8 [[DIV]], [[B]] +; CHECK-NEXT: [[REM:%.*]] = sub i8 [[A]], [[T0]] +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: [[RET:%.*]] = phi i8 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] +; CHECK-NEXT: ret i8 [[RET]] +; +entry: + %div = udiv i8 %a, %b + %cmp = icmp eq i8 %div, 42 + br i1 %cmp, label %if, label %end + +if: + %t0 = mul i8 %div, %b + %rem = sub i8 %a, %t0 + br label %end + +end: + %ret = phi i8 [ %rem, %if ], [ 3, %entry ] + ret i8 %ret +} + +; Be careful with RAUW/invalidation if this is a srem-of-srem. + +define i32 @srem_of_srem_unexpanded(i32 %X, i32 %Y, i32 %Z) { +; CHECK-LABEL: @srem_of_srem_unexpanded( +; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]] +; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]] +; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[T1]], [[T0]] +; CHECK-NEXT: [[T3_DECOMPOSED:%.*]] = sub i32 [[X]], [[TMP1]] +; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3_DECOMPOSED]], [[Y]] +; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]] +; CHECK-NEXT: [[TMP2:%.*]] = mul i32 [[T4]], [[Y]] +; CHECK-NEXT: [[T6_DECOMPOSED:%.*]] = sub i32 [[T3_DECOMPOSED]], [[TMP2]] +; CHECK-NEXT: ret i32 [[T6_DECOMPOSED]] +; + %t0 = mul nsw i32 %Z, %Y + %t1 = sdiv i32 %X, %t0 + %t2 = mul nsw i32 %t0, %t1 + %t3 = srem i32 %X, %t0 + %t4 = sdiv i32 %t3, %Y + %t5 = mul nsw i32 %t4, %Y + %t6 = srem i32 %t3, %Y + ret i32 %t6 +} +define i32 @srem_of_srem_expanded(i32 %X, i32 %Y, i32 %Z) { +; CHECK-LABEL: @srem_of_srem_expanded( +; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]] +; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]] +; CHECK-NEXT: [[T3:%.*]] = sub nsw i32 [[X]], [[T2]] +; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3]], [[Y]] +; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]] +; CHECK-NEXT: [[T6:%.*]] = sub nsw i32 [[T3]], [[T5]] +; CHECK-NEXT: ret i32 [[T6]] +; + %t0 = mul nsw i32 %Z, %Y + %t1 = sdiv i32 %X, %t0 + %t2 = mul nsw i32 %t0, %t1 + %t3 = sub nsw i32 %X, %t2 + %t4 = sdiv i32 %t3, %Y + %t5 = mul nsw i32 %t4, %Y + %t6 = sub nsw i32 %t3, %t5 + ret i32 %t6 +} + +; If the target doesn't have a unified div/rem op for the type, keep decomposed rem + +define i128 @dont_hoist_urem(i128 %a, i128 %b) { +; CHECK-LABEL: @dont_hoist_urem( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[DIV:%.*]] = udiv i128 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i128 [[DIV]], 42 +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] +; CHECK: if: +; CHECK-NEXT: [[T0:%.*]] = mul i128 [[DIV]], [[B]] +; CHECK-NEXT: [[REM:%.*]] = sub i128 [[A]], [[T0]] +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: [[RET:%.*]] = phi i128 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] +; CHECK-NEXT: ret i128 [[RET]] +; +entry: + %div = udiv i128 %a, %b + %cmp = icmp eq i128 %div, 42 + br i1 %cmp, label %if, label %end + +if: + %t0 = mul i128 %div, %b + %rem = sub i128 %a, %t0 + br label %end + +end: + %ret = phi i128 [ %rem, %if ], [ 3, %entry ] + ret i128 %ret +} diff --git a/llvm/test/Transforms/DivRemPairs/PowerPC/div-rem-pairs.ll b/llvm/test/Transforms/DivRemPairs/PowerPC/div-rem-pairs.ll index c82360c9ba05..4e95e0e399ef 100644 --- a/llvm/test/Transforms/DivRemPairs/PowerPC/div-rem-pairs.ll +++ b/llvm/test/Transforms/DivRemPairs/PowerPC/div-rem-pairs.ll @@ -1,13 +1,14 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -div-rem-pairs -S -mtriple=powerpc64-unknown-unknown | FileCheck %s declare void @foo(i32, i32) define void @decompose_illegal_srem_same_block(i32 %a, i32 %b) { ; CHECK-LABEL: @decompose_illegal_srem_same_block( -; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 %a, %b -; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[DIV]], %b -; CHECK-NEXT: [[TMP2:%.*]] = sub i32 %a, [[TMP1]] -; CHECK-NEXT: call void @foo(i32 [[TMP2]], i32 [[DIV]]) +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[DIV]], [[B]] +; CHECK-NEXT: [[REM_DECOMPOSED:%.*]] = sub i32 [[A]], [[TMP1]] +; CHECK-NEXT: call void @foo(i32 [[REM_DECOMPOSED]], i32 [[DIV]]) ; CHECK-NEXT: ret void ; %rem = srem i32 %a, %b @@ -18,10 +19,10 @@ define void @decompose_illegal_srem_same_block(i32 %a, i32 %b) { define void @decompose_illegal_urem_same_block(i32 %a, i32 %b) { ; CHECK-LABEL: @decompose_illegal_urem_same_block( -; CHECK-NEXT: [[DIV:%.*]] = udiv i32 %a, %b -; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[DIV]], %b -; CHECK-NEXT: [[TMP2:%.*]] = sub i32 %a, [[TMP1]] -; CHECK-NEXT: call void @foo(i32 [[TMP2]], i32 [[DIV]]) +; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[DIV]], [[B]] +; CHECK-NEXT: [[REM_DECOMPOSED:%.*]] = sub i32 [[A]], [[TMP1]] +; CHECK-NEXT: call void @foo(i32 [[REM_DECOMPOSED]], i32 [[DIV]]) ; CHECK-NEXT: ret void ; %div = udiv i32 %a, %b @@ -36,15 +37,15 @@ define void @decompose_illegal_urem_same_block(i32 %a, i32 %b) { define i32 @hoist_sdiv(i32 %a, i32 %b) { ; CHECK-LABEL: @hoist_sdiv( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 %a, %b -; CHECK-NEXT: [[TMP0:%.*]] = mul i32 [[DIV]], %b -; CHECK-NEXT: [[TMP1:%.*]] = sub i32 %a, [[TMP0]] -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 42 -; CHECK-NEXT: br i1 [[CMP]], label %if, label %end +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[TMP0:%.*]] = mul i32 [[DIV]], [[B]] +; CHECK-NEXT: [[REM_DECOMPOSED:%.*]] = sub i32 [[A]], [[TMP0]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM_DECOMPOSED]], 42 +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] ; CHECK: if: -; CHECK-NEXT: br label %end +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], %if ], [ 3, %entry ] +; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i32 [[RET]] ; entry: @@ -66,15 +67,15 @@ end: define i64 @hoist_udiv(i64 %a, i64 %b) { ; CHECK-LABEL: @hoist_udiv( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[DIV:%.*]] = udiv i64 %a, %b -; CHECK-NEXT: [[TMP0:%.*]] = mul i64 [[DIV]], %b -; CHECK-NEXT: [[TMP1:%.*]] = sub i64 %a, [[TMP0]] -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[TMP1]], 42 -; CHECK-NEXT: br i1 [[CMP]], label %if, label %end +; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[TMP0:%.*]] = mul i64 [[DIV]], [[B]] +; CHECK-NEXT: [[REM_DECOMPOSED:%.*]] = sub i64 [[A]], [[TMP0]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[REM_DECOMPOSED]], 42 +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] ; CHECK: if: -; CHECK-NEXT: br label %end +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i64 [ [[DIV]], %if ], [ 3, %entry ] +; CHECK-NEXT: [[RET:%.*]] = phi i64 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i64 [[RET]] ; entry: @@ -96,15 +97,15 @@ end: define i16 @hoist_srem(i16 %a, i16 %b) { ; CHECK-LABEL: @hoist_srem( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[DIV:%.*]] = sdiv i16 %a, %b +; CHECK-NEXT: [[DIV:%.*]] = sdiv i16 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[DIV]], 42 -; CHECK-NEXT: br i1 [[CMP]], label %if, label %end +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] ; CHECK: if: -; CHECK-NEXT: [[TMP0:%.*]] = mul i16 [[DIV]], %b -; CHECK-NEXT: [[TMP1:%.*]] = sub i16 %a, [[TMP0]] -; CHECK-NEXT: br label %end +; CHECK-NEXT: [[TMP0:%.*]] = mul i16 [[DIV]], [[B]] +; CHECK-NEXT: [[REM_DECOMPOSED:%.*]] = sub i16 [[A]], [[TMP0]] +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i16 [ [[TMP1]], %if ], [ 3, %entry ] +; CHECK-NEXT: [[RET:%.*]] = phi i16 [ [[REM_DECOMPOSED]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i16 [[RET]] ; entry: @@ -126,15 +127,15 @@ end: define i8 @hoist_urem(i8 %a, i8 %b) { ; CHECK-LABEL: @hoist_urem( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[DIV:%.*]] = udiv i8 %a, %b +; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[DIV]], 42 -; CHECK-NEXT: br i1 [[CMP]], label %if, label %end +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] ; CHECK: if: -; CHECK-NEXT: [[TMP0:%.*]] = mul i8 [[DIV]], %b -; CHECK-NEXT: [[TMP1:%.*]] = sub i8 %a, [[TMP0]] -; CHECK-NEXT: br label %end +; CHECK-NEXT: [[TMP0:%.*]] = mul i8 [[DIV]], [[B]] +; CHECK-NEXT: [[REM_DECOMPOSED:%.*]] = sub i8 [[A]], [[TMP0]] +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i8 [ [[TMP1]], %if ], [ 3, %entry ] +; CHECK-NEXT: [[RET:%.*]] = phi i8 [ [[REM_DECOMPOSED]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i8 [[RET]] ; entry: @@ -151,19 +152,64 @@ end: ret i8 %ret } +; Be careful with RAUW/invalidation if this is a srem-of-srem. + +define i32 @srem_of_srem_unexpanded(i32 %X, i32 %Y, i32 %Z) { +; CHECK-LABEL: @srem_of_srem_unexpanded( +; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]] +; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]] +; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[T1]], [[T0]] +; CHECK-NEXT: [[T3_DECOMPOSED:%.*]] = sub i32 [[X]], [[TMP1]] +; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3_DECOMPOSED]], [[Y]] +; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]] +; CHECK-NEXT: [[TMP2:%.*]] = mul i32 [[T4]], [[Y]] +; CHECK-NEXT: [[T6_DECOMPOSED:%.*]] = sub i32 [[T3_DECOMPOSED]], [[TMP2]] +; CHECK-NEXT: ret i32 [[T6_DECOMPOSED]] +; + %t0 = mul nsw i32 %Z, %Y + %t1 = sdiv i32 %X, %t0 + %t2 = mul nsw i32 %t0, %t1 + %t3 = srem i32 %X, %t0 + %t4 = sdiv i32 %t3, %Y + %t5 = mul nsw i32 %t4, %Y + %t6 = srem i32 %t3, %Y + ret i32 %t6 +} +define i32 @srem_of_srem_expanded(i32 %X, i32 %Y, i32 %Z) { +; CHECK-LABEL: @srem_of_srem_expanded( +; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]] +; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]] +; CHECK-NEXT: [[T3:%.*]] = sub nsw i32 [[X]], [[T2]] +; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3]], [[Y]] +; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]] +; CHECK-NEXT: [[T6:%.*]] = sub nsw i32 [[T3]], [[T5]] +; CHECK-NEXT: ret i32 [[T6]] +; + %t0 = mul nsw i32 %Z, %Y + %t1 = sdiv i32 %X, %t0 + %t2 = mul nsw i32 %t0, %t1 + %t3 = sub nsw i32 %X, %t2 + %t4 = sdiv i32 %t3, %Y + %t5 = mul nsw i32 %t4, %Y + %t6 = sub nsw i32 %t3, %t5 + ret i32 %t6 +} + ; If the ops don't match, don't do anything: signedness. define i32 @dont_hoist_udiv(i32 %a, i32 %b) { ; CHECK-LABEL: @dont_hoist_udiv( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[REM:%.*]] = srem i32 %a, %b +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM]], 42 -; CHECK-NEXT: br i1 [[CMP]], label %if, label %end +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] ; CHECK: if: -; CHECK-NEXT: [[DIV:%.*]] = udiv i32 %a, %b -; CHECK-NEXT: br label %end +; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[A]], [[B]] +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], %if ], [ 3, %entry ] +; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i32 [[RET]] ; entry: @@ -185,14 +231,14 @@ end: define i32 @dont_hoist_srem(i32 %a, i32 %b) { ; CHECK-LABEL: @dont_hoist_srem( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[REM:%.*]] = urem i32 %a, %b +; CHECK-NEXT: [[REM:%.*]] = urem i32 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM]], 42 -; CHECK-NEXT: br i1 [[CMP]], label %if, label %end +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] ; CHECK: if: -; CHECK-NEXT: [[REM2:%.*]] = srem i32 %a, %b -; CHECK-NEXT: br label %end +; CHECK-NEXT: [[REM2:%.*]] = srem i32 [[A]], [[B]] +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[REM2]], %if ], [ 3, %entry ] +; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[REM2]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i32 [[RET]] ; entry: @@ -214,14 +260,14 @@ end: define i32 @dont_hoist_sdiv(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @dont_hoist_sdiv( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[REM:%.*]] = srem i32 %a, %b +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM]], 42 -; CHECK-NEXT: br i1 [[CMP]], label %if, label %end +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] ; CHECK: if: -; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 %a, %c -; CHECK-NEXT: br label %end +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A]], [[C:%.*]] +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], %if ], [ 3, %entry ] +; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i32 [[RET]] ; entry: @@ -243,15 +289,15 @@ end: define i128 @dont_hoist_urem(i128 %a, i128 %b) { ; CHECK-LABEL: @dont_hoist_urem( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[DIV:%.*]] = udiv i128 %a, %b +; CHECK-NEXT: [[DIV:%.*]] = udiv i128 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i128 [[DIV]], 42 -; CHECK-NEXT: br i1 [[CMP]], label %if, label %end +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] ; CHECK: if: -; CHECK-NEXT: [[TMP0:%.*]] = mul i128 [[DIV]], %b -; CHECK-NEXT: [[TMP1:%.*]] = sub i128 %a, [[TMP0]] -; CHECK-NEXT: br label %end +; CHECK-NEXT: [[TMP0:%.*]] = mul i128 [[DIV]], [[B]] +; CHECK-NEXT: [[REM_DECOMPOSED:%.*]] = sub i128 [[A]], [[TMP0]] +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i128 [ [[TMP1]], %if ], [ 3, %entry ] +; CHECK-NEXT: [[RET:%.*]] = phi i128 [ [[REM_DECOMPOSED]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i128 [[RET]] ; entry: @@ -274,15 +320,15 @@ end: define i32 @no_domination(i1 %cmp, i32 %a, i32 %b) { ; CHECK-LABEL: @no_domination( ; CHECK-NEXT: entry: -; CHECK-NEXT: br i1 %cmp, label %if, label %else +; CHECK-NEXT: br i1 [[CMP:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] ; CHECK: if: -; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 %a, %b -; CHECK-NEXT: br label %end +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: br label [[END:%.*]] ; CHECK: else: -; CHECK-NEXT: [[REM:%.*]] = srem i32 %a, %b -; CHECK-NEXT: br label %end +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A]], [[B]] +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], %if ], [ [[REM]], %else ] +; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ [[REM]], [[ELSE]] ] ; CHECK-NEXT: ret i32 [[RET]] ; entry: diff --git a/llvm/test/Transforms/DivRemPairs/X86/div-expanded-rem-pair.ll b/llvm/test/Transforms/DivRemPairs/X86/div-expanded-rem-pair.ll new file mode 100644 index 000000000000..b0cb92a394fd --- /dev/null +++ b/llvm/test/Transforms/DivRemPairs/X86/div-expanded-rem-pair.ll @@ -0,0 +1,170 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -div-rem-pairs -S -mtriple=x86_64-unknown-unknown | FileCheck %s + +declare void @foo(i32, i32) + +define void @decompose_illegal_srem_same_block(i32 %a, i32 %b) { +; CHECK-LABEL: @decompose_illegal_srem_same_block( +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[T0:%.*]] = mul i32 [[DIV]], [[B]] +; CHECK-NEXT: [[REM:%.*]] = sub i32 [[A]], [[T0]] +; CHECK-NEXT: call void @foo(i32 [[REM]], i32 [[DIV]]) +; CHECK-NEXT: ret void +; + %div = sdiv i32 %a, %b + %t0 = mul i32 %div, %b + %rem = sub i32 %a, %t0 + call void @foo(i32 %rem, i32 %div) + ret void +} + +define void @decompose_illegal_urem_same_block(i32 %a, i32 %b) { +; CHECK-LABEL: @decompose_illegal_urem_same_block( +; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[T0:%.*]] = mul i32 [[DIV]], [[B]] +; CHECK-NEXT: [[REM:%.*]] = sub i32 [[A]], [[T0]] +; CHECK-NEXT: call void @foo(i32 [[REM]], i32 [[DIV]]) +; CHECK-NEXT: ret void +; + %div = udiv i32 %a, %b + %t0 = mul i32 %div, %b + %rem = sub i32 %a, %t0 + call void @foo(i32 %rem, i32 %div) + ret void +} + +; Recompose and hoist the srem if it's safe and free, otherwise keep as-is.. + +define i16 @hoist_srem(i16 %a, i16 %b) { +; CHECK-LABEL: @hoist_srem( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[DIV:%.*]] = sdiv i16 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[DIV]], 42 +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] +; CHECK: if: +; CHECK-NEXT: [[T0:%.*]] = mul i16 [[DIV]], [[B]] +; CHECK-NEXT: [[REM:%.*]] = sub i16 [[A]], [[T0]] +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: [[RET:%.*]] = phi i16 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] +; CHECK-NEXT: ret i16 [[RET]] +; +entry: + %div = sdiv i16 %a, %b + %cmp = icmp eq i16 %div, 42 + br i1 %cmp, label %if, label %end + +if: + %t0 = mul i16 %div, %b + %rem = sub i16 %a, %t0 + br label %end + +end: + %ret = phi i16 [ %rem, %if ], [ 3, %entry ] + ret i16 %ret +} + +; Recompose and hoist the urem if it's safe and free, otherwise keep as-is.. + +define i8 @hoist_urem(i8 %a, i8 %b) { +; CHECK-LABEL: @hoist_urem( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[DIV]], 42 +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] +; CHECK: if: +; CHECK-NEXT: [[T0:%.*]] = mul i8 [[DIV]], [[B]] +; CHECK-NEXT: [[REM:%.*]] = sub i8 [[A]], [[T0]] +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: [[RET:%.*]] = phi i8 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] +; CHECK-NEXT: ret i8 [[RET]] +; +entry: + %div = udiv i8 %a, %b + %cmp = icmp eq i8 %div, 42 + br i1 %cmp, label %if, label %end + +if: + %t0 = mul i8 %div, %b + %rem = sub i8 %a, %t0 + br label %end + +end: + %ret = phi i8 [ %rem, %if ], [ 3, %entry ] + ret i8 %ret +} + +; Be careful with RAUW/invalidation if this is a srem-of-srem. + +define i32 @srem_of_srem_unexpanded(i32 %X, i32 %Y, i32 %Z) { +; CHECK-LABEL: @srem_of_srem_unexpanded( +; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]] +; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]] +; CHECK-NEXT: [[T3:%.*]] = srem i32 [[X]], [[T0]] +; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3]], [[Y]] +; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]] +; CHECK-NEXT: [[T6:%.*]] = srem i32 [[T3]], [[Y]] +; CHECK-NEXT: ret i32 [[T6]] +; + %t0 = mul nsw i32 %Z, %Y + %t1 = sdiv i32 %X, %t0 + %t2 = mul nsw i32 %t0, %t1 + %t3 = srem i32 %X, %t0 + %t4 = sdiv i32 %t3, %Y + %t5 = mul nsw i32 %t4, %Y + %t6 = srem i32 %t3, %Y + ret i32 %t6 +} +define i32 @srem_of_srem_expanded(i32 %X, i32 %Y, i32 %Z) { +; CHECK-LABEL: @srem_of_srem_expanded( +; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]] +; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]] +; CHECK-NEXT: [[T3:%.*]] = sub nsw i32 [[X]], [[T2]] +; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3]], [[Y]] +; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]] +; CHECK-NEXT: [[T6:%.*]] = sub nsw i32 [[T3]], [[T5]] +; CHECK-NEXT: ret i32 [[T6]] +; + %t0 = mul nsw i32 %Z, %Y + %t1 = sdiv i32 %X, %t0 + %t2 = mul nsw i32 %t0, %t1 + %t3 = sub nsw i32 %X, %t2 + %t4 = sdiv i32 %t3, %Y + %t5 = mul nsw i32 %t4, %Y + %t6 = sub nsw i32 %t3, %t5 + ret i32 %t6 +} + +; If the target doesn't have a unified div/rem op for the type, keep decomposed rem + +define i128 @dont_hoist_urem(i128 %a, i128 %b) { +; CHECK-LABEL: @dont_hoist_urem( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[DIV:%.*]] = udiv i128 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i128 [[DIV]], 42 +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] +; CHECK: if: +; CHECK-NEXT: [[T0:%.*]] = mul i128 [[DIV]], [[B]] +; CHECK-NEXT: [[REM:%.*]] = sub i128 [[A]], [[T0]] +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: [[RET:%.*]] = phi i128 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] +; CHECK-NEXT: ret i128 [[RET]] +; +entry: + %div = udiv i128 %a, %b + %cmp = icmp eq i128 %div, 42 + br i1 %cmp, label %if, label %end + +if: + %t0 = mul i128 %div, %b + %rem = sub i128 %a, %t0 + br label %end + +end: + %ret = phi i128 [ %rem, %if ], [ 3, %entry ] + ret i128 %ret +} diff --git a/llvm/test/Transforms/DivRemPairs/X86/div-rem-pairs.ll b/llvm/test/Transforms/DivRemPairs/X86/div-rem-pairs.ll index 74c8e6e209d4..711790004c15 100644 --- a/llvm/test/Transforms/DivRemPairs/X86/div-rem-pairs.ll +++ b/llvm/test/Transforms/DivRemPairs/X86/div-rem-pairs.ll @@ -1,11 +1,12 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -div-rem-pairs -S -mtriple=x86_64-unknown-unknown | FileCheck %s declare void @foo(i32, i32) define void @decompose_illegal_srem_same_block(i32 %a, i32 %b) { ; CHECK-LABEL: @decompose_illegal_srem_same_block( -; CHECK-NEXT: [[REM:%.*]] = srem i32 %a, %b -; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 %a, %b +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A]], [[B]] ; CHECK-NEXT: call void @foo(i32 [[REM]], i32 [[DIV]]) ; CHECK-NEXT: ret void ; @@ -17,8 +18,8 @@ define void @decompose_illegal_srem_same_block(i32 %a, i32 %b) { define void @decompose_illegal_urem_same_block(i32 %a, i32 %b) { ; CHECK-LABEL: @decompose_illegal_urem_same_block( -; CHECK-NEXT: [[DIV:%.*]] = udiv i32 %a, %b -; CHECK-NEXT: [[REM:%.*]] = urem i32 %a, %b +; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[REM:%.*]] = urem i32 [[A]], [[B]] ; CHECK-NEXT: call void @foo(i32 [[REM]], i32 [[DIV]]) ; CHECK-NEXT: ret void ; @@ -34,14 +35,14 @@ define void @decompose_illegal_urem_same_block(i32 %a, i32 %b) { define i32 @hoist_sdiv(i32 %a, i32 %b) { ; CHECK-LABEL: @hoist_sdiv( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[REM:%.*]] = srem i32 %a, %b -; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 %a, %b +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A]], [[B]] ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM]], 42 -; CHECK-NEXT: br i1 [[CMP]], label %if, label %end +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] ; CHECK: if: -; CHECK-NEXT: br label %end +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], %if ], [ 3, %entry ] +; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i32 [[RET]] ; entry: @@ -63,14 +64,14 @@ end: define i64 @hoist_udiv(i64 %a, i64 %b) { ; CHECK-LABEL: @hoist_udiv( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[REM:%.*]] = urem i64 %a, %b -; CHECK-NEXT: [[DIV:%.*]] = udiv i64 %a, %b +; CHECK-NEXT: [[REM:%.*]] = urem i64 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[DIV:%.*]] = udiv i64 [[A]], [[B]] ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[REM]], 42 -; CHECK-NEXT: br i1 [[CMP]], label %if, label %end +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] ; CHECK: if: -; CHECK-NEXT: br label %end +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i64 [ [[DIV]], %if ], [ 3, %entry ] +; CHECK-NEXT: [[RET:%.*]] = phi i64 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i64 [[RET]] ; entry: @@ -92,14 +93,14 @@ end: define i16 @hoist_srem(i16 %a, i16 %b) { ; CHECK-LABEL: @hoist_srem( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[DIV:%.*]] = sdiv i16 %a, %b -; CHECK-NEXT: [[REM:%.*]] = srem i16 %a, %b +; CHECK-NEXT: [[DIV:%.*]] = sdiv i16 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[REM:%.*]] = srem i16 [[A]], [[B]] ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i16 [[DIV]], 42 -; CHECK-NEXT: br i1 [[CMP]], label %if, label %end +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] ; CHECK: if: -; CHECK-NEXT: br label %end +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i16 [ [[REM]], %if ], [ 3, %entry ] +; CHECK-NEXT: [[RET:%.*]] = phi i16 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i16 [[RET]] ; entry: @@ -121,14 +122,14 @@ end: define i8 @hoist_urem(i8 %a, i8 %b) { ; CHECK-LABEL: @hoist_urem( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[DIV:%.*]] = udiv i8 %a, %b -; CHECK-NEXT: [[REM:%.*]] = urem i8 %a, %b +; CHECK-NEXT: [[DIV:%.*]] = udiv i8 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[REM:%.*]] = urem i8 [[A]], [[B]] ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[DIV]], 42 -; CHECK-NEXT: br i1 [[CMP]], label %if, label %end +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] ; CHECK: if: -; CHECK-NEXT: br label %end +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i8 [ [[REM]], %if ], [ 3, %entry ] +; CHECK-NEXT: [[RET:%.*]] = phi i8 [ [[REM]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i8 [[RET]] ; entry: @@ -145,19 +146,62 @@ end: ret i8 %ret } +; Be careful with RAUW/invalidation if this is a srem-of-srem. + +define i32 @srem_of_srem_unexpanded(i32 %X, i32 %Y, i32 %Z) { +; CHECK-LABEL: @srem_of_srem_unexpanded( +; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]] +; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]] +; CHECK-NEXT: [[T3:%.*]] = srem i32 [[X]], [[T0]] +; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3]], [[Y]] +; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]] +; CHECK-NEXT: [[T6:%.*]] = srem i32 [[T3]], [[Y]] +; CHECK-NEXT: ret i32 [[T6]] +; + %t0 = mul nsw i32 %Z, %Y + %t1 = sdiv i32 %X, %t0 + %t2 = mul nsw i32 %t0, %t1 + %t3 = srem i32 %X, %t0 + %t4 = sdiv i32 %t3, %Y + %t5 = mul nsw i32 %t4, %Y + %t6 = srem i32 %t3, %Y + ret i32 %t6 +} +define i32 @srem_of_srem_expanded(i32 %X, i32 %Y, i32 %Z) { +; CHECK-LABEL: @srem_of_srem_expanded( +; CHECK-NEXT: [[T0:%.*]] = mul nsw i32 [[Z:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[T1:%.*]] = sdiv i32 [[X:%.*]], [[T0]] +; CHECK-NEXT: [[T2:%.*]] = mul nsw i32 [[T0]], [[T1]] +; CHECK-NEXT: [[T3:%.*]] = sub nsw i32 [[X]], [[T2]] +; CHECK-NEXT: [[T4:%.*]] = sdiv i32 [[T3]], [[Y]] +; CHECK-NEXT: [[T5:%.*]] = mul nsw i32 [[T4]], [[Y]] +; CHECK-NEXT: [[T6:%.*]] = sub nsw i32 [[T3]], [[T5]] +; CHECK-NEXT: ret i32 [[T6]] +; + %t0 = mul nsw i32 %Z, %Y + %t1 = sdiv i32 %X, %t0 + %t2 = mul nsw i32 %t0, %t1 + %t3 = sub nsw i32 %X, %t2 + %t4 = sdiv i32 %t3, %Y + %t5 = mul nsw i32 %t4, %Y + %t6 = sub nsw i32 %t3, %t5 + ret i32 %t6 +} + ; If the ops don't match, don't do anything: signedness. define i32 @dont_hoist_udiv(i32 %a, i32 %b) { ; CHECK-LABEL: @dont_hoist_udiv( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[REM:%.*]] = srem i32 %a, %b +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM]], 42 -; CHECK-NEXT: br i1 [[CMP]], label %if, label %end +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] ; CHECK: if: -; CHECK-NEXT: [[DIV:%.*]] = udiv i32 %a, %b -; CHECK-NEXT: br label %end +; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[A]], [[B]] +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], %if ], [ 3, %entry ] +; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i32 [[RET]] ; entry: @@ -179,14 +223,14 @@ end: define i32 @dont_hoist_srem(i32 %a, i32 %b) { ; CHECK-LABEL: @dont_hoist_srem( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[REM:%.*]] = urem i32 %a, %b +; CHECK-NEXT: [[REM:%.*]] = urem i32 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM]], 42 -; CHECK-NEXT: br i1 [[CMP]], label %if, label %end +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] ; CHECK: if: -; CHECK-NEXT: [[REM2:%.*]] = srem i32 %a, %b -; CHECK-NEXT: br label %end +; CHECK-NEXT: [[REM2:%.*]] = srem i32 [[A]], [[B]] +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[REM2]], %if ], [ 3, %entry ] +; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[REM2]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i32 [[RET]] ; entry: @@ -208,14 +252,14 @@ end: define i32 @dont_hoist_sdiv(i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: @dont_hoist_sdiv( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[REM:%.*]] = srem i32 %a, %b +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM]], 42 -; CHECK-NEXT: br i1 [[CMP]], label %if, label %end +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] ; CHECK: if: -; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 %a, %c -; CHECK-NEXT: br label %end +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A]], [[C:%.*]] +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], %if ], [ 3, %entry ] +; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i32 [[RET]] ; entry: @@ -237,15 +281,15 @@ end: define i128 @dont_hoist_urem(i128 %a, i128 %b) { ; CHECK-LABEL: @dont_hoist_urem( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[DIV:%.*]] = udiv i128 %a, %b +; CHECK-NEXT: [[DIV:%.*]] = udiv i128 [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i128 [[DIV]], 42 -; CHECK-NEXT: br i1 [[CMP]], label %if, label %end +; CHECK-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[END:%.*]] ; CHECK: if: -; CHECK-NEXT: [[TMP0:%.*]] = mul i128 [[DIV]], %b -; CHECK-NEXT: [[TMP1:%.*]] = sub i128 %a, [[TMP0]] -; CHECK-NEXT: br label %end +; CHECK-NEXT: [[TMP0:%.*]] = mul i128 [[DIV]], [[B]] +; CHECK-NEXT: [[REM_DECOMPOSED:%.*]] = sub i128 [[A]], [[TMP0]] +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i128 [ [[TMP1]], %if ], [ 3, %entry ] +; CHECK-NEXT: [[RET:%.*]] = phi i128 [ [[REM_DECOMPOSED]], [[IF]] ], [ 3, [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i128 [[RET]] ; entry: @@ -268,15 +312,15 @@ end: define i32 @no_domination(i1 %cmp, i32 %a, i32 %b) { ; CHECK-LABEL: @no_domination( ; CHECK-NEXT: entry: -; CHECK-NEXT: br i1 %cmp, label %if, label %else +; CHECK-NEXT: br i1 [[CMP:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] ; CHECK: if: -; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 %a, %b -; CHECK-NEXT: br label %end +; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: br label [[END:%.*]] ; CHECK: else: -; CHECK-NEXT: [[REM:%.*]] = srem i32 %a, %b -; CHECK-NEXT: br label %end +; CHECK-NEXT: [[REM:%.*]] = srem i32 [[A]], [[B]] +; CHECK-NEXT: br label [[END]] ; CHECK: end: -; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], %if ], [ [[REM]], %else ] +; CHECK-NEXT: [[RET:%.*]] = phi i32 [ [[DIV]], [[IF]] ], [ [[REM]], [[ELSE]] ] ; CHECK-NEXT: ret i32 [[RET]] ; entry: diff --git a/llvm/test/Transforms/InstCombine/pow-0.ll b/llvm/test/Transforms/InstCombine/pow-0.ll new file mode 100644 index 000000000000..8de8e12a2d10 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/pow-0.ll @@ -0,0 +1,60 @@ +; RUN: opt < %s -instcombine -S | FileCheck %s + +; CHECK-LABEL: @zero( +; CHECK-NEXT: ret double 1.000000e+00 +define double @zero(double %value) { + %res = call double @llvm.pow.f64(double %value, double 0.000000e+00) + ret double %res +} + +; CHECK-LABEL: @minus_zero( +; CHECK-NEXT: ret double 1.000000e+00 +define double @minus_zero(double %value) { + %res = call double @llvm.pow.f64(double %value, double -0.000000e+00) + ret double %res +} + +; CHECK-LABEL: @fast_zero( +; CHECK-NEXT: ret double 1.000000e+00 +define double @fast_zero(double %value) { + %res = call fast double @llvm.pow.f64(double %value, double 0.000000e+00) + ret double %res +} + +; CHECK-LABEL: @fast_minus_zero( +; CHECK-NEXT: ret double 1.000000e+00 +define double @fast_minus_zero(double %value) { + %res = call fast double @llvm.pow.f64(double %value, double -0.000000e+00) + ret double %res +} + +; CHECK-LABEL: @vec_zero( +; CHECK-NEXT: ret <2 x double> +define <2 x double> @vec_zero(<2 x double> %value) { + %res = call <2 x double> @llvm.pow.v2f64(<2 x double> %value, <2 x double> ) + ret <2 x double> %res +} + +; CHECK-LABEL: @vec_minus_zero( +; CHECK-NEXT: ret <2 x double> +define <2 x double> @vec_minus_zero(<2 x double> %value) { + %res = call <2 x double> @llvm.pow.v2f64(<2 x double> %value, <2 x double> ) + ret <2 x double> %res +} + +; CHECK-LABEL: @vec_fast_zero( +; CHECK-NEXT: ret <2 x double> +define <2 x double> @vec_fast_zero(<2 x double> %value) { + %res = call fast <2 x double> @llvm.pow.v2f64(<2 x double> %value, <2 x double> ) + ret <2 x double> %res +} + +; CHECK-LABEL: @vec_fast_minus_zero( +; CHECK-NEXT: ret <2 x double> +define <2 x double> @vec_fast_minus_zero(<2 x double> %value) { + %res = call fast <2 x double> @llvm.pow.v2f64(<2 x double> %value, <2 x double> ) + ret <2 x double> %res +} + +declare double @llvm.pow.f64(double, double) +declare <2 x double> @llvm.pow.v2f64(<2 x double>, <2 x double>) diff --git a/llvm/test/Transforms/InstCombine/pow-4.ll b/llvm/test/Transforms/InstCombine/pow-4.ll index e4352392e229..4aac27fe72f0 100644 --- a/llvm/test/Transforms/InstCombine/pow-4.ll +++ b/llvm/test/Transforms/InstCombine/pow-4.ll @@ -223,3 +223,13 @@ define <4 x float> @test_simplify_3_5(<4 x float> %x) { ret <4 x float> %1 } +; Make sure that -0.0 exponent is always simplified. + +define double @PR43233(double %x) { +; CHECK-LABEL: @PR43233( +; CHECK-NEXT: ret double 1.000000e+00 +; + %r = call fast double @llvm.pow.f64(double %x, double -0.0) + ret double %r +} + diff --git a/llvm/test/Transforms/InstCombine/pow-exp.ll b/llvm/test/Transforms/InstCombine/pow-exp.ll index d5ed51117812..f352c3a88138 100644 --- a/llvm/test/Transforms/InstCombine/pow-exp.ll +++ b/llvm/test/Transforms/InstCombine/pow-exp.ll @@ -212,7 +212,7 @@ declare void @use_f(float) define double @pow_ok_base(double %e) { ; CHECK-LABEL: @pow_ok_base( -; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn double [[E:%.*]], 0xBFE0776228967D13 +; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn double [[E:%.*]], 0xBFE0776{{.*}} ; CHECK-NEXT: [[EXP2:%.*]] = call nnan ninf afn double @exp2(double [[MUL]]) ; CHECK-NEXT: ret double [[EXP2]] ; @@ -222,7 +222,7 @@ define double @pow_ok_base(double %e) { define double @pow_ok_base_fast(double %e) { ; CHECK-LABEL: @pow_ok_base_fast( -; CHECK-NEXT: [[MUL:%.*]] = fmul fast double [[E:%.*]], 0xBFE0776228967D13 +; CHECK-NEXT: [[MUL:%.*]] = fmul fast double [[E:%.*]], 0xBFE0776{{.*}} ; CHECK-NEXT: [[EXP2:%.*]] = call fast double @exp2(double [[MUL]]) ; CHECK-NEXT: ret double [[EXP2]] ; @@ -232,7 +232,7 @@ define double @pow_ok_base_fast(double %e) { define double @pow_ok_base2(double %e) { ; CHECK-LABEL: @pow_ok_base2( -; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn double [[E:%.*]], 0x4010952C788751AC +; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn double [[E:%.*]], 0x4010952{{.*}} ; CHECK-NEXT: [[EXP2:%.*]] = call nnan ninf afn double @exp2(double [[MUL]]) ; CHECK-NEXT: ret double [[EXP2]] ; @@ -242,7 +242,7 @@ define double @pow_ok_base2(double %e) { define double @pow_ok_base3(double %e) { ; CHECK-LABEL: @pow_ok_base3( -; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn double [[E:%.*]], 0x400AB0B5584886CD +; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn double [[E:%.*]], 0x400AB0B5{{.*}} ; CHECK-NEXT: [[EXP2:%.*]] = call nnan ninf afn double @exp2(double [[MUL]]) ; CHECK-NEXT: ret double [[EXP2]] ; @@ -252,7 +252,7 @@ define double @pow_ok_base3(double %e) { define double @pow_ok_ten_base(double %e) { ; CHECK-LABEL: @pow_ok_ten_base( -; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn double [[E:%.*]], 0x400A934F0979A371 +; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn double [[E:%.*]], 0x400A934F{{.*}} ; CHECK-NEXT: [[EXP2:%.*]] = call nnan ninf afn double @exp2(double [[MUL]]) ; CHECK-NEXT: ret double [[EXP2]] ; @@ -262,7 +262,7 @@ define double @pow_ok_ten_base(double %e) { define float @powf_ok_base(float %e) { ; CHECK-LABEL: @powf_ok_base( -; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn float [[E:%.*]], 0xBFE0776240000000 +; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn float [[E:%.*]], 0xBFE07762{{.*}} ; CHECK-NEXT: [[EXP2F:%.*]] = call nnan ninf afn float @exp2f(float [[MUL]]) ; CHECK-NEXT: ret float [[EXP2F]] ; @@ -272,7 +272,7 @@ define float @powf_ok_base(float %e) { define float @powf_ok_base2(float %e) { ; CHECK-LABEL: @powf_ok_base2( -; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn float [[E:%.*]], 0x4010952C80000000 +; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn float [[E:%.*]], 0x4010952{{.*}} ; CHECK-NEXT: [[EXP2F:%.*]] = call nnan ninf afn float @exp2f(float [[MUL]]) ; CHECK-NEXT: ret float [[EXP2F]] ; @@ -282,7 +282,7 @@ define float @powf_ok_base2(float %e) { define float @powf_ok_base3(float %e) { ; CHECK-LABEL: @powf_ok_base3( -; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn float [[E:%.*]], 0x400AB0B560000000 +; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn float [[E:%.*]], 0x400AB0B5{{.*}} ; CHECK-NEXT: [[EXP2F:%.*]] = call nnan ninf afn float @exp2f(float [[MUL]]) ; CHECK-NEXT: ret float [[EXP2F]] ; @@ -292,7 +292,7 @@ define float @powf_ok_base3(float %e) { define float @powf_ok_ten_base(float %e) { ; CHECK-LABEL: @powf_ok_ten_base( -; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn float [[E:%.*]], 0x400A934F00000000 +; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn float [[E:%.*]], 0x400A934{{.*}} ; CHECK-NEXT: [[EXP2F:%.*]] = call nnan ninf afn float @exp2f(float [[MUL]]) ; CHECK-NEXT: ret float [[EXP2F]] ; diff --git a/llvm/test/Transforms/InstCombine/pow_fp_int.ll b/llvm/test/Transforms/InstCombine/pow_fp_int.ll index 372a9e11c1eb..b0cb836da942 100644 --- a/llvm/test/Transforms/InstCombine/pow_fp_int.ll +++ b/llvm/test/Transforms/InstCombine/pow_fp_int.ll @@ -199,7 +199,7 @@ define double @powf_exp_const2_int_fast(double %base) { define double @pow_uitofp_const_base_fast_i32(i32 %x) { ; CHECK-LABEL: @pow_uitofp_const_base_fast_i32( ; CHECK-NEXT: [[SUBFP:%.*]] = uitofp i32 [[X:%.*]] to float -; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[SUBFP]], 0x4006757680000000 +; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[SUBFP]], 0x4006757{{.*}} ; CHECK-NEXT: [[EXP2:%.*]] = call fast float @llvm.exp2.f32(float [[MUL]]) ; CHECK-NEXT: [[RES:%.*]] = fpext float [[EXP2]] to double ; CHECK-NEXT: ret double [[RES]] @@ -251,7 +251,7 @@ define double @pow_uitofp_double_base_fast_i32(double %base, i32 %x) { define double @pow_sitofp_const_base_fast_i64(i64 %x) { ; CHECK-LABEL: @pow_sitofp_const_base_fast_i64( ; CHECK-NEXT: [[SUBFP:%.*]] = sitofp i64 [[X:%.*]] to float -; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[SUBFP]], 0x4006757680000000 +; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[SUBFP]], 0x400675{{.*}} ; CHECK-NEXT: [[EXP2:%.*]] = call fast float @llvm.exp2.f32(float [[MUL]]) ; CHECK-NEXT: [[RES:%.*]] = fpext float [[EXP2]] to double ; CHECK-NEXT: ret double [[RES]] @@ -265,7 +265,7 @@ define double @pow_sitofp_const_base_fast_i64(i64 %x) { define double @pow_uitofp_const_base_fast_i64(i64 %x) { ; CHECK-LABEL: @pow_uitofp_const_base_fast_i64( ; CHECK-NEXT: [[SUBFP:%.*]] = uitofp i64 [[X:%.*]] to float -; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[SUBFP]], 0x4006757680000000 +; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[SUBFP]], 0x400675{{.*}} ; CHECK-NEXT: [[EXP2:%.*]] = call fast float @llvm.exp2.f32(float [[MUL]]) ; CHECK-NEXT: [[RES:%.*]] = fpext float [[EXP2]] to double ; CHECK-NEXT: ret double [[RES]] diff --git a/llvm/test/Transforms/InstCombine/shift-amount-reassociation-in-bittest.ll b/llvm/test/Transforms/InstCombine/shift-amount-reassociation-in-bittest.ll index c0bce48b3bed..9a2cfa5977a2 100644 --- a/llvm/test/Transforms/InstCombine/shift-amount-reassociation-in-bittest.ll +++ b/llvm/test/Transforms/InstCombine/shift-amount-reassociation-in-bittest.ll @@ -279,8 +279,8 @@ define i1 @t18_const_oneuse0(i32 %x, i32 %y) { ; CHECK-LABEL: @t18_const_oneuse0( ; CHECK-NEXT: [[T0:%.*]] = lshr i32 [[X:%.*]], 1 ; CHECK-NEXT: call void @use32(i32 [[T0]]) -; CHECK-NEXT: [[TMP1:%.*]] = shl i32 [[Y:%.*]], 2 -; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[X]] +; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[X]], 2 +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[Y:%.*]] ; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 0 ; CHECK-NEXT: ret i1 [[TMP3]] ; @@ -521,15 +521,70 @@ define i1 @t31_var_oneuse6(i32 %x, i32 %y, i32 %shamt0, i32 %shamt1) { ret i1 %t3 } +; Shift-of-const + +; Ok, non-truncated shift is of constant; +define i1 @t32_shift_of_const_oneuse0(i32 %x, i32 %y, i32 %len) { +; CHECK-LABEL: @t32_shift_of_const_oneuse0( +; CHECK-NEXT: [[T0:%.*]] = sub i32 32, [[LEN:%.*]] +; CHECK-NEXT: call void @use32(i32 [[T0]]) +; CHECK-NEXT: [[T1:%.*]] = lshr i32 -52543054, [[T0]] +; CHECK-NEXT: call void @use32(i32 [[T1]]) +; CHECK-NEXT: [[T2:%.*]] = add i32 [[LEN]], -1 +; CHECK-NEXT: call void @use32(i32 [[T2]]) +; CHECK-NEXT: [[T3:%.*]] = shl i32 [[Y:%.*]], [[T2]] +; CHECK-NEXT: call void @use32(i32 [[T3]]) +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[Y]], 1 +; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i32 [[TMP1]], 0 +; CHECK-NEXT: ret i1 [[TMP2]] +; + %t0 = sub i32 32, %len + call void @use32(i32 %t0) + %t1 = lshr i32 4242424242, %t0 ; shift-of-constant + call void @use32(i32 %t1) + %t2 = add i32 %len, -1 + call void @use32(i32 %t2) + %t3 = shl i32 %y, %t2 + call void @use32(i32 %t3) + %t4 = and i32 %t1, %t3 ; no extra uses + %t5 = icmp ne i32 %t4, 0 + ret i1 %t5 +} +; Ok, truncated shift is of constant; +define i1 @t33_shift_of_const_oneuse1(i32 %x, i32 %y, i32 %len) { +; CHECK-LABEL: @t33_shift_of_const_oneuse1( +; CHECK-NEXT: [[T0:%.*]] = sub i32 32, [[LEN:%.*]] +; CHECK-NEXT: call void @use32(i32 [[T0]]) +; CHECK-NEXT: [[T1:%.*]] = lshr i32 [[X:%.*]], [[T0]] +; CHECK-NEXT: call void @use32(i32 [[T1]]) +; CHECK-NEXT: [[T2:%.*]] = add i32 [[LEN]], -1 +; CHECK-NEXT: call void @use32(i32 [[T2]]) +; CHECK-NEXT: [[T3:%.*]] = shl i32 -52543054, [[T2]] +; CHECK-NEXT: call void @use32(i32 [[T3]]) +; CHECK-NEXT: ret i1 false +; + %t0 = sub i32 32, %len + call void @use32(i32 %t0) + %t1 = lshr i32 %x, %t0 ; shift-of-constant + call void @use32(i32 %t1) + %t2 = add i32 %len, -1 + call void @use32(i32 %t2) + %t3 = shl i32 4242424242, %t2 + call void @use32(i32 %t3) + %t4 = and i32 %t1, %t3 ; no extra uses + %t5 = icmp ne i32 %t4, 0 + ret i1 %t5 +} + ; Commutativity with extra uses -define i1 @t32_commutativity0_oneuse0(i32 %x) { -; CHECK-LABEL: @t32_commutativity0_oneuse0( +define i1 @t34_commutativity0_oneuse0(i32 %x) { +; CHECK-LABEL: @t34_commutativity0_oneuse0( ; CHECK-NEXT: [[Y:%.*]] = call i32 @gen32() ; CHECK-NEXT: [[T0:%.*]] = lshr i32 [[X:%.*]], 1 ; CHECK-NEXT: call void @use32(i32 [[T0]]) -; CHECK-NEXT: [[TMP1:%.*]] = shl i32 [[Y]], 2 -; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[X]] +; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[X]], 2 +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[Y]] ; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 0 ; CHECK-NEXT: ret i1 [[TMP3]] ; @@ -541,8 +596,8 @@ define i1 @t32_commutativity0_oneuse0(i32 %x) { %t3 = icmp ne i32 %t2, 0 ret i1 %t3 } -define i1 @t33_commutativity0_oneuse1(i32 %x) { -; CHECK-LABEL: @t33_commutativity0_oneuse1( +define i1 @t35_commutativity0_oneuse1(i32 %x) { +; CHECK-LABEL: @t35_commutativity0_oneuse1( ; CHECK-NEXT: [[Y:%.*]] = call i32 @gen32() ; CHECK-NEXT: [[T1:%.*]] = shl i32 [[Y]], 1 ; CHECK-NEXT: call void @use32(i32 [[T1]]) @@ -560,13 +615,13 @@ define i1 @t33_commutativity0_oneuse1(i32 %x) { ret i1 %t3 } -define i1 @t34_commutativity1_oneuse0(i32 %y) { -; CHECK-LABEL: @t34_commutativity1_oneuse0( +define i1 @t36_commutativity1_oneuse0(i32 %y) { +; CHECK-LABEL: @t36_commutativity1_oneuse0( ; CHECK-NEXT: [[X:%.*]] = call i32 @gen32() ; CHECK-NEXT: [[T0:%.*]] = lshr i32 [[X]], 1 ; CHECK-NEXT: call void @use32(i32 [[T0]]) -; CHECK-NEXT: [[TMP1:%.*]] = shl i32 [[Y:%.*]], 2 -; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[X]] +; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[X]], 2 +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[Y:%.*]] ; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP2]], 0 ; CHECK-NEXT: ret i1 [[TMP3]] ; @@ -578,8 +633,8 @@ define i1 @t34_commutativity1_oneuse0(i32 %y) { %t3 = icmp ne i32 %t2, 0 ret i1 %t3 } -define i1 @t35_commutativity1_oneuse1(i32 %y) { -; CHECK-LABEL: @t35_commutativity1_oneuse1( +define i1 @t37_commutativity1_oneuse1(i32 %y) { +; CHECK-LABEL: @t37_commutativity1_oneuse1( ; CHECK-NEXT: [[X:%.*]] = call i32 @gen32() ; CHECK-NEXT: [[T1:%.*]] = shl i32 [[Y:%.*]], 1 ; CHECK-NEXT: call void @use32(i32 [[T1]]) @@ -598,8 +653,8 @@ define i1 @t35_commutativity1_oneuse1(i32 %y) { } ; Negative tests -define <2 x i1> @n36_overshift(<2 x i32> %x, <2 x i32> %y) { -; CHECK-LABEL: @n36_overshift( +define <2 x i1> @n38_overshift(<2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: @n38_overshift( ; CHECK-NEXT: [[T0:%.*]] = lshr <2 x i32> [[X:%.*]], ; CHECK-NEXT: [[T1:%.*]] = shl <2 x i32> [[Y:%.*]], ; CHECK-NEXT: [[T2:%.*]] = and <2 x i32> [[T1]], [[T0]] @@ -612,3 +667,15 @@ define <2 x i1> @n36_overshift(<2 x i32> %x, <2 x i32> %y) { %t3 = icmp ne <2 x i32> %t2, ret <2 x i1> %t3 } + +; As usual, don't crash given constantexpr's :/ +@f.a = internal global i16 0 +define i1 @constantexpr() { +entry: + %0 = load i16, i16* @f.a + %shr = ashr i16 %0, 1 + %shr1 = ashr i16 %shr, zext (i1 icmp ne (i16 ptrtoint (i16* @f.a to i16), i16 1) to i16) + %and = and i16 %shr1, 1 + %tobool = icmp ne i16 %and, 0 + ret i1 %tobool +} diff --git a/llvm/test/Transforms/LoopUnroll/unroll-header-exiting-with-phis.ll b/llvm/test/Transforms/LoopUnroll/unroll-header-exiting-with-phis.ll new file mode 100644 index 000000000000..e1fba5f6689c --- /dev/null +++ b/llvm/test/Transforms/LoopUnroll/unroll-header-exiting-with-phis.ll @@ -0,0 +1,107 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -S -loop-unroll -unroll-allow-partial | FileCheck %s + +; The phi which acts as input to func should not be undef. It should +; have its loop-carried value (the load in for.cond) replaced accordingly +; after unrolling the loop. + +define i16 @full_unroll(i16* %A) { +; CHECK-LABEL: @full_unroll( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_COND:%.*]] +; CHECK: for.cond: +; CHECK-NEXT: [[TMP2:%.*]] = load i16, i16* [[A:%.*]] +; CHECK-NEXT: br label [[FOR_COND_CLEANUP3:%.*]] +; CHECK: for.cond.cleanup: +; CHECK-NEXT: [[DOTLCSSA10_LCSSA:%.*]] = phi i16 [ [[TMP2_2:%.*]], [[FOR_COND_CLEANUP3_2:%.*]] ] +; CHECK-NEXT: [[TMP3:%.*]] = call i16 @func(i16 [[DOTLCSSA10_LCSSA]]) +; CHECK-NEXT: ret i16 0 +; CHECK: for.cond.cleanup3: +; CHECK-NEXT: [[PTR_1:%.*]] = getelementptr inbounds i16, i16* [[A]], i64 1 +; CHECK-NEXT: [[TMP2_1:%.*]] = load i16, i16* [[PTR_1]] +; CHECK-NEXT: br label [[FOR_COND_CLEANUP3_1:%.*]] +; CHECK: for.cond.cleanup3.1: +; CHECK-NEXT: [[PTR_2:%.*]] = getelementptr inbounds i16, i16* [[A]], i64 2 +; CHECK-NEXT: [[TMP2_2]] = load i16, i16* [[PTR_2]] +; CHECK-NEXT: br label [[FOR_COND_CLEANUP3_2]] +; CHECK: for.cond.cleanup3.2: +; CHECK-NEXT: [[PTR_3:%.*]] = getelementptr inbounds i16, i16* [[A]], i64 3 +; CHECK-NEXT: [[TMP2_3:%.*]] = load i16, i16* [[PTR_3]] +; CHECK-NEXT: br i1 false, label [[FOR_COND_CLEANUP3_3:%.*]], label [[FOR_COND_CLEANUP:%.*]] +; CHECK: for.cond.cleanup3.3: +; CHECK-NEXT: unreachable +; +entry: + br label %for.cond + +for.cond: ; preds = %for.cond.cleanup3, %entry + %.lcssa10 = phi i16 [ 123, %entry ], [ %.lcssa, %for.cond.cleanup3 ] + %i.0 = phi i64 [ 0, %entry ], [ %inc9, %for.cond.cleanup3 ] + %ptr = getelementptr inbounds i16, i16* %A, i64 %i.0 + %tmp2 = load i16, i16* %ptr + %cmp = icmp ult i64 %i.0, 3 + br i1 %cmp, label %for.cond.cleanup3, label %for.cond.cleanup + +for.cond.cleanup: ; preds = %for.cond + %.lcssa10.lcssa = phi i16 [ %.lcssa10, %for.cond ] + %tmp3 = call i16 (i16) @func(i16 %.lcssa10.lcssa) + ret i16 0 + +for.cond.cleanup3: ; preds = %for.cond + %.lcssa = phi i16 [ %tmp2, %for.cond ] + %inc9 = add i64 %i.0, 1 + br label %for.cond +} + +define i16 @partial_unroll(i16* %A) { +; CHECK-LABEL: @partial_unroll( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_COND:%.*]] +; CHECK: for.cond: +; CHECK-NEXT: [[I_0:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[INC9_2:%.*]], [[FOR_COND_CLEANUP3_2:%.*]] ] +; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds i16, i16* [[A:%.*]], i64 [[I_0]] +; CHECK-NEXT: [[TMP2:%.*]] = load i16, i16* [[PTR]] +; CHECK-NEXT: br label [[FOR_COND_CLEANUP3:%.*]] +; CHECK: for.cond.cleanup: +; CHECK-NEXT: [[DOTLCSSA10_LCSSA:%.*]] = phi i16 [ [[TMP2_1:%.*]], [[FOR_COND_CLEANUP3_1:%.*]] ] +; CHECK-NEXT: [[TMP3:%.*]] = call i16 @func(i16 [[DOTLCSSA10_LCSSA]]) +; CHECK-NEXT: ret i16 0 +; CHECK: for.cond.cleanup3: +; CHECK-NEXT: [[INC9:%.*]] = add nuw nsw i64 [[I_0]], 1 +; CHECK-NEXT: [[PTR_1:%.*]] = getelementptr inbounds i16, i16* [[A]], i64 [[INC9]] +; CHECK-NEXT: [[TMP2_1]] = load i16, i16* [[PTR_1]] +; CHECK-NEXT: br label [[FOR_COND_CLEANUP3_1]] +; CHECK: for.cond.cleanup3.1: +; CHECK-NEXT: [[INC9_1:%.*]] = add nuw nsw i64 [[INC9]], 1 +; CHECK-NEXT: [[PTR_2:%.*]] = getelementptr inbounds i16, i16* [[A]], i64 [[INC9_1]] +; CHECK-NEXT: [[TMP2_2:%.*]] = load i16, i16* [[PTR_2]] +; CHECK-NEXT: [[CMP_2:%.*]] = icmp ult i64 [[INC9_1]], 200 +; CHECK-NEXT: br i1 [[CMP_2]], label [[FOR_COND_CLEANUP3_2]], label [[FOR_COND_CLEANUP:%.*]] +; CHECK: for.cond.cleanup3.2: +; CHECK-NEXT: [[INC9_2]] = add nuw nsw i64 [[INC9_1]], 1 +; CHECK-NEXT: br label [[FOR_COND]] +; +entry: + br label %for.cond + +for.cond: ; preds = %for.cond.cleanup3, %entry + %.lcssa10 = phi i16 [ 123, %entry ], [ %.lcssa, %for.cond.cleanup3 ] + %i.0 = phi i64 [ 0, %entry ], [ %inc9, %for.cond.cleanup3 ] + %ptr = getelementptr inbounds i16, i16* %A, i64 %i.0 + %tmp2 = load i16, i16* %ptr + %cmp = icmp ult i64 %i.0, 200 + br i1 %cmp, label %for.cond.cleanup3, label %for.cond.cleanup + +for.cond.cleanup: ; preds = %for.cond + %.lcssa10.lcssa = phi i16 [ %.lcssa10, %for.cond ] + %tmp3 = call i16 (i16) @func(i16 %.lcssa10.lcssa) + ret i16 0 + +for.cond.cleanup3: ; preds = %for.cond + %.lcssa = phi i16 [ %tmp2, %for.cond ] + %inc9 = add i64 %i.0, 1 + br label %for.cond +} + +declare i16 @func(i16) + diff --git a/llvm/test/Transforms/LoopVectorize/pr43166-fold-tail-by-masking.ll b/llvm/test/Transforms/LoopVectorize/pr43166-fold-tail-by-masking.ll new file mode 100644 index 000000000000..d3a8b91ec8e7 --- /dev/null +++ b/llvm/test/Transforms/LoopVectorize/pr43166-fold-tail-by-masking.ll @@ -0,0 +1,165 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -loop-vectorize -force-vector-width=4 -S | FileCheck %s + + +; Test cases below are reduced (and slightly modified) reproducers based on a +; problem seen when compiling a C program like this: +; +; #include +; #include +; +; int y = 0; +; int b = 1; +; int d = 1; +; +; int main() { +; #pragma clang loop vectorize_width(4) +; for (int i = 0; i < 3; ++i) { +; b = (y == 0) ? d : (d / y); +; } +; +; if (b == 1) +; printf("GOOD!\n"); +; else +; printf("BAD!\n"); +; } +; +; When compiled+executed using +; build-all/bin/clang -O1 lv-bug.c && ./a.out +; the result is "GOOD!" +; +; When compiled+executed using +; build-all/bin/clang -O1 lv-bug.c -fvectorize && ./a.out +; the result is "BAD!" + + +; This test case miscompiled with clang 8.0.0 (see PR43166), now we get +; loop not vectorized: Cannot fold tail by masking in the presence of live outs. +; instead. +define i64 @test1(i64 %y) { +; CHECK-LABEL: @test1( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[COND_END:%.*]] ] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[Y:%.*]], 0 +; CHECK-NEXT: br i1 [[CMP]], label [[COND_END]], label [[COND_FALSE:%.*]] +; CHECK: cond.false: +; CHECK-NEXT: [[DIV:%.*]] = xor i64 3, [[Y]] +; CHECK-NEXT: br label [[COND_END]] +; CHECK: cond.end: +; CHECK-NEXT: [[COND:%.*]] = phi i64 [ [[DIV]], [[COND_FALSE]] ], [ 77, [[FOR_BODY]] ] +; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], 3 +; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY]] +; CHECK: for.cond.cleanup: +; CHECK-NEXT: [[COND_LCSSA:%.*]] = phi i64 [ [[COND]], [[COND_END]] ] +; CHECK-NEXT: ret i64 [[COND_LCSSA]] +; +entry: + br label %for.body + +for.body: + %i = phi i32 [ 0, %entry ], [ %inc, %cond.end ] + %cmp = icmp eq i64 %y, 0 + br i1 %cmp, label %cond.end, label %cond.false + +cond.false: + %div = xor i64 3, %y + br label %cond.end + +cond.end: + %cond = phi i64 [ %div, %cond.false ], [ 77, %for.body ] + %inc = add nuw nsw i32 %i, 1 + %exitcond = icmp eq i32 %inc, 3 + br i1 %exitcond, label %for.cond.cleanup, label %for.body + +for.cond.cleanup: + ret i64 %cond +} + +; This test case miscompiled with clang 8.0.0 (see PR43166), now we get +; loop not vectorized: Cannot fold tail by masking in the presence of live outs. +; instead. +define i64 @test2(i64 %y) { +; CHECK-LABEL: @test2( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[COND_END:%.*]] ] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[Y:%.*]], 0 +; CHECK-NEXT: br i1 [[CMP]], label [[COND_END]], label [[COND_FALSE:%.*]] +; CHECK: cond.false: +; CHECK-NEXT: br label [[COND_END]] +; CHECK: cond.end: +; CHECK-NEXT: [[COND:%.*]] = phi i64 [ 55, [[COND_FALSE]] ], [ 77, [[FOR_BODY]] ] +; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], 3 +; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY]] +; CHECK: for.cond.cleanup: +; CHECK-NEXT: [[COND_LCSSA:%.*]] = phi i64 [ [[COND]], [[COND_END]] ] +; CHECK-NEXT: ret i64 [[COND_LCSSA]] +; +entry: + br label %for.body + +for.body: + %i = phi i32 [ 0, %entry ], [ %inc, %cond.end ] + %cmp = icmp eq i64 %y, 0 + br i1 %cmp, label %cond.end, label %cond.false + +cond.false: + br label %cond.end + +cond.end: + %cond = phi i64 [ 55, %cond.false ], [ 77, %for.body ] + %inc = add nuw nsw i32 %i, 1 + %exitcond = icmp eq i32 %inc, 3 + br i1 %exitcond, label %for.cond.cleanup, label %for.body + +for.cond.cleanup: + ret i64 %cond +} + +; This test case miscompiled with clang 8.0.0 (see PR43166), now we get +; loop not vectorized: Cannot fold tail by masking in the presence of live outs. +; instead. +define i32 @test3(i64 %y) { +; CHECK-LABEL: @test3( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[FOR_BODY:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[COND_END:%.*]] ] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[Y:%.*]], 0 +; CHECK-NEXT: br i1 [[CMP]], label [[COND_END]], label [[COND_FALSE:%.*]] +; CHECK: cond.false: +; CHECK-NEXT: br label [[COND_END]] +; CHECK: cond.end: +; CHECK-NEXT: [[COND:%.*]] = phi i32 [ 55, [[COND_FALSE]] ], [ [[I]], [[FOR_BODY]] ] +; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I]], 1 +; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], 3 +; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY]] +; CHECK: for.cond.cleanup: +; CHECK-NEXT: [[COND_LCSSA:%.*]] = phi i32 [ [[COND]], [[COND_END]] ] +; CHECK-NEXT: ret i32 [[COND_LCSSA]] +; +entry: + br label %for.body + +for.body: + %i = phi i32 [ 0, %entry ], [ %inc, %cond.end ] + %cmp = icmp eq i64 %y, 0 + br i1 %cmp, label %cond.end, label %cond.false + +cond.false: + br label %cond.end + +cond.end: + %cond = phi i32 [ 55, %cond.false ], [ %i, %for.body ] + %inc = add nuw nsw i32 %i, 1 + %exitcond = icmp eq i32 %inc, 3 + br i1 %exitcond, label %for.cond.cleanup, label %for.body + +for.cond.cleanup: + ret i32 %cond +} diff --git a/llvm/test/Transforms/SpeculateAroundPHIs/pr42991.ll b/llvm/test/Transforms/SpeculateAroundPHIs/pr42991.ll new file mode 100644 index 000000000000..4aef689f53de --- /dev/null +++ b/llvm/test/Transforms/SpeculateAroundPHIs/pr42991.ll @@ -0,0 +1,44 @@ +; RUN: opt -S -passes=spec-phis %s + +; This testcase crashes during the speculate around PHIs pass. The pass however +; results in no changes. + +define i32 @test1() { +entry: + callbr void asm sideeffect "", "X,X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@test1, %return), i8* blockaddress(@test1, %f)) + to label %asm.fallthrough [label %return, label %f] + +asm.fallthrough: + br label %return + +f: + br label %return + +return: + %retval.0 = phi i32 [ 0, %f ], [ 1, %asm.fallthrough ], [ 1, %entry ] + ret i32 %retval.0 +} + +define void @test2() { +entry: + br label %tailrecurse + +tailrecurse: + %call = tail call i32 @test3() + %tobool1 = icmp eq i32 %call, 0 + callbr void asm sideeffect "", "X,X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@test2, %test1.exit), i8* blockaddress(@test2, %f.i)) + to label %if.end6 [label %test1.exit, label %f.i] + +f.i: + br label %test1.exit + +test1.exit: + %retval.0.i = phi i1 [ false, %f.i ], [ true, %tailrecurse ] + %brmerge = or i1 %tobool1, %retval.0.i + br i1 %brmerge, label %if.end6, label %tailrecurse + +if.end6: + ret void +} + +declare i32 @test3() diff --git a/llvm/test/tools/llvm-objcopy/ELF/respect-umask.test b/llvm/test/tools/llvm-objcopy/ELF/respect-umask.test index 03f97cdae9b9..f4d309905616 100644 --- a/llvm/test/tools/llvm-objcopy/ELF/respect-umask.test +++ b/llvm/test/tools/llvm-objcopy/ELF/respect-umask.test @@ -9,18 +9,25 @@ # RUN: touch %t # RUN: chmod 0755 %t # RUN: ls -l %t | cut -f 1 -d ' ' > %t.0755 -# RUN: chmod 0500 %t -# RUN: ls -l %t | cut -f 1 -d ' ' > %t.0500 -# RUN: chmod 0555 %t -# RUN: ls -l %t | cut -f 1 -d ' ' > %t.0555 +# RUN: chmod 0600 %t +# RUN: ls -l %t | cut -f 1 -d ' ' > %t.0600 +# RUN: chmod 0655 %t +# RUN: ls -l %t | cut -f 1 -d ' ' > %t.0655 -# RUN: rm -f %t; yaml2obj %s -o %t +# RUN: yaml2obj %s -o %t # RUN: umask 0022 # RUN: chmod 0777 %t -# RUN: rm -f %t1; llvm-objcopy %t %t1 -# RUN: ls -l %t1 | cut -f 1 -d ' ' > %t1.perms -# RUN: cmp %t1.perms %t.0755 +# RUN: llvm-objcopy %t %t1 +# RUN: ls -l %t1 | cut -f 1 -d ' ' | cmp - %t.0755 + +# RUN: umask 0177 +# RUN: llvm-objcopy %t %t2 +# RUN: ls -l %t2 | cut -f 1 -d ' ' | cmp - %t.0600 + +# RUN: umask 0122 +# RUN: llvm-objcopy %t %t3 +# RUN: ls -l %t3 | cut -f 1 -d ' ' | cmp - %t.0655 --- !ELF FileHeader: diff --git a/llvm/test/tools/llvm-objdump/CAHP/disassemble-invalid-byte-sequences.test b/llvm/test/tools/llvm-objdump/CAHP/disassemble-invalid-byte-sequences.test new file mode 100644 index 000000000000..15edf5135619 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/CAHP/disassemble-invalid-byte-sequences.test @@ -0,0 +1,20 @@ +## Show that llvm-objdump handles invalid byte sequences, and continues. + +# RUN: yaml2obj %s -o %t.o +# RUN: llvm-objdump %t.o -d | FileCheck %s + +# CHECK: 00000000 .text: +# CHECK-NEXT: 0: 73 68 69 +# CHECK-NEXT: 3: 72 61 + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_CAHP +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [SHF_ALLOC, SHF_EXECINSTR] + Content: '7368697261' diff --git a/llvm/test/tools/llvm-objdump/CAHP/lit.local.cfg b/llvm/test/tools/llvm-objdump/CAHP/lit.local.cfg new file mode 100644 index 000000000000..9c4893bff785 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/CAHP/lit.local.cfg @@ -0,0 +1,2 @@ +if "CAHP" not in config.root.targets: + config.unsupported = True diff --git a/llvm/tools/lli/CMakeLists.txt b/llvm/tools/lli/CMakeLists.txt index 42f6c2b2ede4..476c09229e63 100644 --- a/llvm/tools/lli/CMakeLists.txt +++ b/llvm/tools/lli/CMakeLists.txt @@ -12,6 +12,7 @@ set(LLVM_LINK_COMPONENTS MCJIT Object OrcJIT + Passes RuntimeDyld SelectionDAG Support diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index 4e1cb7d544e7..cce77cd8ffcd 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -1032,6 +1032,7 @@ static const EnumEntry ElfMachineType[] = { ENUM_ENT(EM_RISCV, "RISC-V"), ENUM_ENT(EM_LANAI, "EM_LANAI"), ENUM_ENT(EM_BPF, "EM_BPF"), + ENUM_ENT(EM_CAHP, "CAHP"), }; static const EnumEntry ElfSymbolBindings[] = { diff --git a/llvm/tools/llvm-shlib/CMakeLists.txt b/llvm/tools/llvm-shlib/CMakeLists.txt index 4905ed08157f..901f55c99d59 100644 --- a/llvm/tools/llvm-shlib/CMakeLists.txt +++ b/llvm/tools/llvm-shlib/CMakeLists.txt @@ -182,6 +182,6 @@ if(MSVC) VERBATIM ) # Finally link the target. - add_llvm_library(LLVM-C SHARED ${SOURCES} DEPENDS intrinsics_gen) + add_llvm_library(LLVM-C SHARED INSTALL_WITH_TOOLCHAIN ${SOURCES} DEPENDS intrinsics_gen) endif() diff --git a/llvm/unittests/ADT/TripleTest.cpp b/llvm/unittests/ADT/TripleTest.cpp index 37ebe5dbcb28..7a3ac70ef615 100644 --- a/llvm/unittests/ADT/TripleTest.cpp +++ b/llvm/unittests/ADT/TripleTest.cpp @@ -560,6 +560,18 @@ TEST(TripleTest, ParsedIDs) { EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment()); EXPECT_TRUE(T.isArch32Bit()); + T = Triple("cahp-unknown-unknown"); + EXPECT_EQ(Triple::cahp, T.getArch()); + EXPECT_EQ(Triple::UnknownVendor, T.getVendor()); + EXPECT_EQ(Triple::UnknownOS, T.getOS()); + EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment()); + + T = Triple("cahp"); + EXPECT_EQ(Triple::cahp, T.getArch()); + EXPECT_EQ(Triple::UnknownVendor, T.getVendor()); + EXPECT_EQ(Triple::UnknownOS, T.getOS()); + EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment()); + T = Triple("huh"); EXPECT_EQ(Triple::UnknownArch, T.getArch()); } @@ -883,6 +895,11 @@ TEST(TripleTest, BitWidthPredicates) { EXPECT_FALSE(T.isArch32Bit()); EXPECT_TRUE(T.isArch64Bit()); EXPECT_TRUE(T.isRISCV()); + + T.setArch(Triple::cahp); + EXPECT_TRUE(T.isArch16Bit()); + EXPECT_FALSE(T.isArch32Bit()); + EXPECT_FALSE(T.isArch64Bit()); } TEST(TripleTest, BitWidthArchVariants) { diff --git a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt index 76b18fd1ba9a..945c9926d26e 100644 --- a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt +++ b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt @@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS ExecutionEngine Object OrcJIT + Passes RuntimeDyld Support native diff --git a/llvm/unittests/IR/InstructionsTest.cpp b/llvm/unittests/IR/InstructionsTest.cpp index 9b9efe33cfed..b2ea3844d335 100644 --- a/llvm/unittests/IR/InstructionsTest.cpp +++ b/llvm/unittests/IR/InstructionsTest.cpp @@ -1061,5 +1061,56 @@ TEST(InstructionsTest, FNegInstruction) { FNeg->deleteValue(); } +TEST(InstructionsTest, CallBrInstruction) { + LLVMContext Context; + std::unique_ptr M = parseIR(Context, R"( +define void @foo() { +entry: + callbr void asm sideeffect "// XXX: ${0:l}", "X"(i8* blockaddress(@foo, %branch_test.exit)) + to label %land.rhs.i [label %branch_test.exit] + +land.rhs.i: + br label %branch_test.exit + +branch_test.exit: + %0 = phi i1 [ true, %entry ], [ false, %land.rhs.i ] + br i1 %0, label %if.end, label %if.then + +if.then: + ret void + +if.end: + ret void +} +)"); + Function *Foo = M->getFunction("foo"); + auto BBs = Foo->getBasicBlockList().begin(); + CallBrInst &CBI = cast(BBs->front()); + ++BBs; + ++BBs; + BasicBlock &BranchTestExit = *BBs; + ++BBs; + BasicBlock &IfThen = *BBs; + + // Test that setting the first indirect destination of callbr updates the dest + EXPECT_EQ(&BranchTestExit, CBI.getIndirectDest(0)); + CBI.setIndirectDest(0, &IfThen); + EXPECT_EQ(&IfThen, CBI.getIndirectDest(0)); + + // Further, test that changing the indirect destination updates the arg + // operand to use the block address of the new indirect destination basic + // block. This is a critical invariant of CallBrInst. + BlockAddress *IndirectBA = BlockAddress::get(CBI.getIndirectDest(0)); + BlockAddress *ArgBA = cast(CBI.getArgOperand(0)); + EXPECT_EQ(IndirectBA, ArgBA) + << "After setting the indirect destination, callbr had an indirect " + "destination of '" + << CBI.getIndirectDest(0)->getName() << "', but a argument of '" + << ArgBA->getBasicBlock()->getName() << "'. These should always match:\n" + << CBI; + EXPECT_EQ(IndirectBA->getBasicBlock(), &IfThen); + EXPECT_EQ(ArgBA->getBasicBlock(), &IfThen); +} + } // end anonymous namespace } // end namespace llvm diff --git a/llvm/unittests/Support/TargetParserTest.cpp b/llvm/unittests/Support/TargetParserTest.cpp index 34c7a8a4fd1c..04ee379d344a 100644 --- a/llvm/unittests/Support/TargetParserTest.cpp +++ b/llvm/unittests/Support/TargetParserTest.cpp @@ -1048,7 +1048,7 @@ TEST(TargetParserTest, AArch64ExtensionFeatures) { AArch64::AEK_RDM, AArch64::AEK_DOTPROD, AArch64::AEK_SVE, AArch64::AEK_SVE2, AArch64::AEK_SVE2AES, AArch64::AEK_SVE2SM4, - AArch64::AEK_SVE2SHA3, AArch64::AEK_BITPERM, + AArch64::AEK_SVE2SHA3, AArch64::AEK_SVE2BITPERM, AArch64::AEK_RCPC, AArch64::AEK_FP16FML }; std::vector Features; @@ -1083,7 +1083,7 @@ TEST(TargetParserTest, AArch64ExtensionFeatures) { EXPECT_TRUE(std::find(B, E, "+sve2-aes") != E); EXPECT_TRUE(std::find(B, E, "+sve2-sm4") != E); EXPECT_TRUE(std::find(B, E, "+sve2-sha3") != E); - EXPECT_TRUE(std::find(B, E, "+bitperm") != E); + EXPECT_TRUE(std::find(B, E, "+sve2-bitperm") != E); } TEST(TargetParserTest, AArch64ArchFeatures) { @@ -1114,7 +1114,8 @@ TEST(TargetParserTest, AArch64ArchExtFeature) { "-sve2-sm4"}, {"sve2-sha3", "nosve2-sha3", "+sve2-sha3", "-sve2-sha3"}, - {"bitperm", "nobitperm", "+bitperm", "-bitperm"}, + {"sve2-bitperm", "nosve2-bitperm", + "+sve2-bitperm", "-sve2-bitperm"}, {"dotprod", "nodotprod", "+dotprod", "-dotprod"}, {"rcpc", "norcpc", "+rcpc", "-rcpc" }, {"rng", "norng", "+rand", "-rand"}, diff --git a/llvm/utils/TableGen/CAHPCompressInstEmitter.cpp b/llvm/utils/TableGen/CAHPCompressInstEmitter.cpp new file mode 100644 index 000000000000..4120d3e44c56 --- /dev/null +++ b/llvm/utils/TableGen/CAHPCompressInstEmitter.cpp @@ -0,0 +1,760 @@ +// This file is copied and modified from The LLVM Compiler Infrastructure, which +// is distributed under the Apache License v2.0 with LLVM Exceptions (see +// LICENSE.TXT for details). This file is licensed under the same license. + +#include "CodeGenInstruction.h" +#include "CodeGenTarget.h" +#include "llvm/ADT/IndexedMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include +#include +using namespace llvm; + +#define DEBUG_TYPE "cahp-compress-inst-emitter" + +namespace { +class CAHPCompressInstEmitter { + struct OpData { + enum MapKind { Operand, Imm, Reg }; + MapKind Kind; + union { + unsigned Operand; // Operand number mapped to. + uint64_t Imm; // Integer immediate value. + Record *Reg; // Physical register. + } Data; + int TiedOpIdx = -1; // Tied operand index within the instruction. + }; + struct CompressPat { + CodeGenInstruction Source; // The source instruction definition. + CodeGenInstruction Dest; // The destination instruction to transform to. + std::vector + PatReqFeatures; // Required target features to enable pattern. + IndexedMap + SourceOperandMap; // Maps operands in the Source Instruction to + // the corresponding Dest instruction operand. + IndexedMap + DestOperandMap; // Maps operands in the Dest Instruction + // to the corresponding Source instruction operand. + CompressPat(CodeGenInstruction &S, CodeGenInstruction &D, + std::vector RF, IndexedMap &SourceMap, + IndexedMap &DestMap) + : Source(S), Dest(D), PatReqFeatures(RF), SourceOperandMap(SourceMap), + DestOperandMap(DestMap) {} + }; + + RecordKeeper &Records; + CodeGenTarget Target; + SmallVector CompressPatterns; + + void addDagOperandMapping(Record *Rec, DagInit *Dag, CodeGenInstruction &Inst, + IndexedMap &OperandMap, bool IsSourceInst); + void evaluateCompressPat(Record *Compress); + void emitCompressInstEmitter(raw_ostream &o, bool Compress); + bool validateTypes(Record *SubType, Record *Type, bool IsSourceInst); + bool validateRegister(Record *Reg, Record *RegClass); + void createDagOperandMapping(Record *Rec, StringMap &SourceOperands, + StringMap &DestOperands, + DagInit *SourceDag, DagInit *DestDag, + IndexedMap &SourceOperandMap); + + void createInstOperandMapping(Record *Rec, DagInit *SourceDag, + DagInit *DestDag, + IndexedMap &SourceOperandMap, + IndexedMap &DestOperandMap, + StringMap &SourceOperands, + CodeGenInstruction &DestInst); + +public: + CAHPCompressInstEmitter(RecordKeeper &R) : Records(R), Target(R) {} + + void run(raw_ostream &o); +}; +} // End anonymous namespace. + +bool CAHPCompressInstEmitter::validateRegister(Record *Reg, Record *RegClass) { + assert(Reg->isSubClassOf("Register") && "Reg record should be a Register\n"); + assert(RegClass->isSubClassOf("RegisterClass") && "RegClass record should be" + " a RegisterClass\n"); + CodeGenRegisterClass RC = Target.getRegisterClass(RegClass); + const CodeGenRegister *R = Target.getRegisterByName(Reg->getName().lower()); + assert((R != nullptr) && + ("Register" + Reg->getName().str() + " not defined!!\n").c_str()); + return RC.contains(R); +} + +bool CAHPCompressInstEmitter::validateTypes(Record *DagOpType, + Record *InstOpType, + bool IsSourceInst) { + if (DagOpType == InstOpType) + return true; + // Only source instruction operands are allowed to not match Input Dag + // operands. + if (!IsSourceInst) + return false; + + if (DagOpType->isSubClassOf("RegisterClass") && + InstOpType->isSubClassOf("RegisterClass")) { + CodeGenRegisterClass RC = Target.getRegisterClass(InstOpType); + CodeGenRegisterClass SubRC = Target.getRegisterClass(DagOpType); + return RC.hasSubClass(&SubRC); + } + + // At this point either or both types are not registers, reject the pattern. + if (DagOpType->isSubClassOf("RegisterClass") || + InstOpType->isSubClassOf("RegisterClass")) + return false; + + // Let further validation happen when compress()/uncompress() functions are + // invoked. + LLVM_DEBUG(dbgs() << (IsSourceInst ? "Input" : "Output") + << " Dag Operand Type: '" << DagOpType->getName() + << "' and " + << "Instruction Operand Type: '" << InstOpType->getName() + << "' can't be checked at pattern validation time!\n"); + return true; +} + +/// The patterns in the Dag contain different types of operands: +/// Register operands, e.g.: GPR:$rs1; Fixed registers, e.g: X1; Immediate +/// operands, e.g.: simm6:$imm; Fixed immediate operands, e.g.: 0. This function +/// maps Dag operands to its corresponding instruction operands. For register +/// operands and fixed registers it expects the Dag operand type to be contained +/// in the instantiated instruction operand type. For immediate operands and +/// immediates no validation checks are enforced at pattern validation time. +void CAHPCompressInstEmitter::addDagOperandMapping( + Record *Rec, DagInit *Dag, CodeGenInstruction &Inst, + IndexedMap &OperandMap, bool IsSourceInst) { + // TiedCount keeps track of the number of operands skipped in Inst + // operands list to get to the corresponding Dag operand. This is + // necessary because the number of operands in Inst might be greater + // than number of operands in the Dag due to how tied operands + // are represented. + unsigned TiedCount = 0; + for (unsigned i = 0, e = Inst.Operands.size(); i != e; ++i) { + int TiedOpIdx = Inst.Operands[i].getTiedRegister(); + if (-1 != TiedOpIdx) { + // Set the entry in OperandMap for the tied operand we're skipping. + OperandMap[i].Kind = OperandMap[TiedOpIdx].Kind; + OperandMap[i].Data = OperandMap[TiedOpIdx].Data; + TiedCount++; + continue; + } + if (DefInit *DI = dyn_cast(Dag->getArg(i - TiedCount))) { + if (DI->getDef()->isSubClassOf("Register")) { + // Check if the fixed register belongs to the Register class. + if (!validateRegister(DI->getDef(), Inst.Operands[i].Rec)) + PrintFatalError(Rec->getLoc(), + "Error in Dag '" + Dag->getAsString() + + "'Register: '" + DI->getDef()->getName() + + "' is not in register class '" + + Inst.Operands[i].Rec->getName() + "'"); + OperandMap[i].Kind = OpData::Reg; + OperandMap[i].Data.Reg = DI->getDef(); + continue; + } + // Validate that Dag operand type matches the type defined in the + // corresponding instruction. Operands in the input Dag pattern are + // allowed to be a subclass of the type specified in corresponding + // instruction operand instead of being an exact match. + if (!validateTypes(DI->getDef(), Inst.Operands[i].Rec, IsSourceInst)) + PrintFatalError(Rec->getLoc(), + "Error in Dag '" + Dag->getAsString() + "'. Operand '" + + Dag->getArgNameStr(i - TiedCount) + "' has type '" + + DI->getDef()->getName() + + "' which does not match the type '" + + Inst.Operands[i].Rec->getName() + + "' in the corresponding instruction operand!"); + + OperandMap[i].Kind = OpData::Operand; + } else if (IntInit *II = dyn_cast(Dag->getArg(i - TiedCount))) { + // Validate that corresponding instruction operand expects an immediate. + if (Inst.Operands[i].Rec->isSubClassOf("RegisterClass")) + PrintFatalError( + Rec->getLoc(), + ("Error in Dag '" + Dag->getAsString() + "' Found immediate: '" + + II->getAsString() + + "' but corresponding instruction operand expected a register!")); + // No pattern validation check possible for values of fixed immediate. + OperandMap[i].Kind = OpData::Imm; + OperandMap[i].Data.Imm = II->getValue(); + LLVM_DEBUG( + dbgs() << " Found immediate '" << II->getValue() << "' at " + << (IsSourceInst ? "input " : "output ") + << "Dag. No validation time check possible for values of " + "fixed immediate.\n"); + } else + llvm_unreachable("Unhandled CompressPat argument type!"); + } +} + +// Verify the Dag operand count is enough to build an instruction. +static bool verifyDagOpCount(CodeGenInstruction &Inst, DagInit *Dag, + bool IsSource) { + if (Dag->getNumArgs() == Inst.Operands.size()) + return true; + // Source instructions are non compressed instructions and don't have tied + // operands. + if (IsSource) + PrintFatalError(Inst.TheDef->getLoc(), + "Input operands for Inst '" + Inst.TheDef->getName() + + "' and input Dag operand count mismatch"); + // The Dag can't have more arguments than the Instruction. + if (Dag->getNumArgs() > Inst.Operands.size()) + PrintFatalError(Inst.TheDef->getLoc(), + "Inst '" + Inst.TheDef->getName() + + "' and Dag operand count mismatch"); + + // The Instruction might have tied operands so the Dag might have + // a fewer operand count. + unsigned RealCount = Inst.Operands.size(); + for (unsigned i = 0; i < Inst.Operands.size(); i++) + if (Inst.Operands[i].getTiedRegister() != -1) + --RealCount; + + if (Dag->getNumArgs() != RealCount) + PrintFatalError(Inst.TheDef->getLoc(), + "Inst '" + Inst.TheDef->getName() + + "' and Dag operand count mismatch"); + return true; +} + +static bool validateArgsTypes(Init *Arg1, Init *Arg2) { + DefInit *Type1 = dyn_cast(Arg1); + DefInit *Type2 = dyn_cast(Arg2); + assert(Type1 && ("Arg1 type not found\n")); + assert(Type2 && ("Arg2 type not found\n")); + return Type1->getDef() == Type2->getDef(); +} + +// Creates a mapping between the operand name in the Dag (e.g. $rs1) and +// its index in the list of Dag operands and checks that operands with the same +// name have the same types. For example in 'ADD2 $rs1, $rs2' we generate the +// mapping $rs1 --> 0, $rs2 ---> 1. If the operand appears twice in the (tied) +// same Dag we use the last occurrence for indexing. +void CAHPCompressInstEmitter::createDagOperandMapping( + Record *Rec, StringMap &SourceOperands, + StringMap &DestOperands, DagInit *SourceDag, DagInit *DestDag, + IndexedMap &SourceOperandMap) { + for (unsigned i = 0; i < DestDag->getNumArgs(); ++i) { + // Skip fixed immediates and registers, they were handled in + // addDagOperandMapping. + if ("" == DestDag->getArgNameStr(i)) + continue; + DestOperands[DestDag->getArgNameStr(i)] = i; + } + + for (unsigned i = 0; i < SourceDag->getNumArgs(); ++i) { + // Skip fixed immediates and registers, they were handled in + // addDagOperandMapping. + if ("" == SourceDag->getArgNameStr(i)) + continue; + + StringMap::iterator it = + SourceOperands.find(SourceDag->getArgNameStr(i)); + if (it != SourceOperands.end()) { + // Operand sharing the same name in the Dag should be mapped as tied. + SourceOperandMap[i].TiedOpIdx = it->getValue(); + if (!validateArgsTypes(SourceDag->getArg(it->getValue()), + SourceDag->getArg(i))) + PrintFatalError(Rec->getLoc(), + "Input Operand '" + SourceDag->getArgNameStr(i) + + "' has a mismatched tied operand!\n"); + } + it = DestOperands.find(SourceDag->getArgNameStr(i)); + if (it == DestOperands.end()) + PrintFatalError(Rec->getLoc(), "Operand " + SourceDag->getArgNameStr(i) + + " defined in Input Dag but not used in" + " Output Dag!\n"); + // Input Dag operand types must match output Dag operand type. + if (!validateArgsTypes(DestDag->getArg(it->getValue()), + SourceDag->getArg(i))) + PrintFatalError(Rec->getLoc(), "Type mismatch between Input and " + "Output Dag operand '" + + SourceDag->getArgNameStr(i) + "'!"); + SourceOperands[SourceDag->getArgNameStr(i)] = i; + } +} + +/// Map operand names in the Dag to their index in both corresponding input and +/// output instructions. Validate that operands defined in the input are +/// used in the output pattern while populating the maps. +void CAHPCompressInstEmitter::createInstOperandMapping( + Record *Rec, DagInit *SourceDag, DagInit *DestDag, + IndexedMap &SourceOperandMap, IndexedMap &DestOperandMap, + StringMap &SourceOperands, CodeGenInstruction &DestInst) { + // TiedCount keeps track of the number of operands skipped in Inst + // operands list to get to the corresponding Dag operand. + unsigned TiedCount = 0; + LLVM_DEBUG(dbgs() << " Operand mapping:\n Source Dest\n"); + for (unsigned i = 0, e = DestInst.Operands.size(); i != e; ++i) { + int TiedInstOpIdx = DestInst.Operands[i].getTiedRegister(); + if (TiedInstOpIdx != -1) { + ++TiedCount; + DestOperandMap[i].Data = DestOperandMap[TiedInstOpIdx].Data; + DestOperandMap[i].Kind = DestOperandMap[TiedInstOpIdx].Kind; + if (DestOperandMap[i].Kind == OpData::Operand) + // No need to fill the SourceOperandMap here since it was mapped to + // destination operand 'TiedInstOpIdx' in a previous iteration. + LLVM_DEBUG(dbgs() << " " << DestOperandMap[i].Data.Operand + << " ====> " << i + << " Dest operand tied with operand '" + << TiedInstOpIdx << "'\n"); + continue; + } + // Skip fixed immediates and registers, they were handled in + // addDagOperandMapping. + if (DestOperandMap[i].Kind != OpData::Operand) + continue; + + unsigned DagArgIdx = i - TiedCount; + StringMap::iterator SourceOp = + SourceOperands.find(DestDag->getArgNameStr(DagArgIdx)); + if (SourceOp == SourceOperands.end()) + PrintFatalError(Rec->getLoc(), + "Output Dag operand '" + + DestDag->getArgNameStr(DagArgIdx) + + "' has no matching input Dag operand."); + + assert(DestDag->getArgNameStr(DagArgIdx) == + SourceDag->getArgNameStr(SourceOp->getValue()) && + "Incorrect operand mapping detected!\n"); + DestOperandMap[i].Data.Operand = SourceOp->getValue(); + SourceOperandMap[SourceOp->getValue()].Data.Operand = i; + LLVM_DEBUG(dbgs() << " " << SourceOp->getValue() << " ====> " << i + << "\n"); + } +} + +/// Validates the CompressPattern and create operand mapping. +/// These are the checks to validate a CompressPat pattern declarations. +/// Error out with message under these conditions: +/// - Dag Input opcode is an expanded instruction and Dag Output opcode is a +/// compressed instruction. +/// - Operands in Dag Input must be all used in Dag Output. +/// Register Operand type in Dag Input Type must be contained in the +/// corresponding Source Instruction type. +/// - Register Operand type in Dag Input must be the same as in Dag Ouput. +/// - Register Operand type in Dag Output must be the same as the +/// corresponding Destination Inst type. +/// - Immediate Operand type in Dag Input must be the same as in Dag Ouput. +/// - Immediate Operand type in Dag Ouput must be the same as the corresponding +/// Destination Instruction type. +/// - Fixed register must be contained in the corresponding Source Instruction +/// type. +/// - Fixed register must be contained in the corresponding Destination +/// Instruction type. Warning message printed under these conditions: +/// - Fixed immediate in Dag Input or Dag Ouput cannot be checked at this time +/// and generate warning. +/// - Immediate operand type in Dag Input differs from the corresponding Source +/// Instruction type and generate a warning. +void CAHPCompressInstEmitter::evaluateCompressPat(Record *Rec) { + // Validate input Dag operands. + DagInit *SourceDag = Rec->getValueAsDag("Input"); + assert(SourceDag && "Missing 'Input' in compress pattern!"); + LLVM_DEBUG(dbgs() << "Input: " << *SourceDag << "\n"); + + DefInit *OpDef = dyn_cast(SourceDag->getOperator()); + if (!OpDef) + PrintFatalError(Rec->getLoc(), + Rec->getName() + " has unexpected operator type!"); + // Checking we are transforming from compressed to uncompressed instructions. + Record *Operator = OpDef->getDef(); + if (!Operator->isSubClassOf("CAHPInst24")) + PrintFatalError(Rec->getLoc(), "Input instruction '" + Operator->getName() + + "' is not a 24 bit wide instruction!"); + CodeGenInstruction SourceInst(Operator); + verifyDagOpCount(SourceInst, SourceDag, true); + + // Validate output Dag operands. + DagInit *DestDag = Rec->getValueAsDag("Output"); + assert(DestDag && "Missing 'Output' in compress pattern!"); + LLVM_DEBUG(dbgs() << "Output: " << *DestDag << "\n"); + + DefInit *DestOpDef = dyn_cast(DestDag->getOperator()); + if (!DestOpDef) + PrintFatalError(Rec->getLoc(), + Rec->getName() + " has unexpected operator type!"); + + Record *DestOperator = DestOpDef->getDef(); + if (!DestOperator->isSubClassOf("CAHPInst16")) + PrintFatalError(Rec->getLoc(), "Output instruction '" + + DestOperator->getName() + + "' is not a 16 bit wide instruction!"); + CodeGenInstruction DestInst(DestOperator); + verifyDagOpCount(DestInst, DestDag, false); + + // Fill the mapping from the source to destination instructions. + + IndexedMap SourceOperandMap; + SourceOperandMap.grow(SourceInst.Operands.size()); + // Create a mapping between source Dag operands and source Inst operands. + addDagOperandMapping(Rec, SourceDag, SourceInst, SourceOperandMap, + /*IsSourceInst*/ true); + + IndexedMap DestOperandMap; + DestOperandMap.grow(DestInst.Operands.size()); + // Create a mapping between destination Dag operands and destination Inst + // operands. + addDagOperandMapping(Rec, DestDag, DestInst, DestOperandMap, + /*IsSourceInst*/ false); + + StringMap SourceOperands; + StringMap DestOperands; + createDagOperandMapping(Rec, SourceOperands, DestOperands, SourceDag, DestDag, + SourceOperandMap); + // Create operand mapping between the source and destination instructions. + createInstOperandMapping(Rec, SourceDag, DestDag, SourceOperandMap, + DestOperandMap, SourceOperands, DestInst); + + // Get the target features for the CompressPat. + std::vector PatReqFeatures; + std::vector RF = Rec->getValueAsListOfDefs("Predicates"); + copy_if(RF, std::back_inserter(PatReqFeatures), [](Record *R) { + return R->getValueAsBit("AssemblerMatcherPredicate"); + }); + + CompressPatterns.push_back(CompressPat(SourceInst, DestInst, PatReqFeatures, + SourceOperandMap, DestOperandMap)); +} + +static void getReqFeatures(std::set &FeaturesSet, + const std::vector &ReqFeatures) { + for (auto &R : ReqFeatures) { + StringRef AsmCondString = R->getValueAsString("AssemblerCondString"); + + // AsmCondString has syntax [!]F(,[!]F)* + SmallVector Ops; + SplitString(AsmCondString, Ops, ","); + assert(!Ops.empty() && "AssemblerCondString cannot be empty"); + for (auto &Op : Ops) { + assert(!Op.empty() && "Empty operator"); + FeaturesSet.insert(Op); + } + } +} + +static unsigned +getMCOpPredicate(DenseMap &MCOpPredicateMap, + std::vector &MCOpPredicates, Record *Rec) { + unsigned Entry = MCOpPredicateMap[Rec]; + if (Entry) + return Entry; + + if (!Rec->isValueUnset("MCOperandPredicate")) { + MCOpPredicates.push_back(Rec); + Entry = MCOpPredicates.size(); + MCOpPredicateMap[Rec] = Entry; + return Entry; + } + + PrintFatalError(Rec->getLoc(), + "No MCOperandPredicate on this operand at all: " + + Rec->getName().str() + "'"); + return 0; +} + +static std::string mergeCondAndCode(raw_string_ostream &CondStream, + raw_string_ostream &CodeStream) { + std::string S; + raw_string_ostream CombinedStream(S); + CombinedStream.indent(4) + << "if (" + << CondStream.str().substr( + 6, CondStream.str().length() - + 10) // remove first indentation and last '&&'. + << ") {\n"; + CombinedStream << CodeStream.str(); + CombinedStream.indent(4) << " return true;\n"; + CombinedStream.indent(4) << "} // if\n"; + return CombinedStream.str(); +} + +void CAHPCompressInstEmitter::emitCompressInstEmitter(raw_ostream &o, + bool Compress) { + Record *AsmWriter = Target.getAsmWriter(); + if (!AsmWriter->getValueAsInt("PassSubtarget")) + PrintFatalError(AsmWriter->getLoc(), + "'PassSubtarget' is false. SubTargetInfo object is needed " + "for target features.\n"); + + std::string Namespace = Target.getName(); + + // Sort entries in CompressPatterns to handle instructions that can have more + // than one candidate for compression\uncompression, e.g ADD can be + // transformed to a C_ADD or a C_MV. When emitting 'uncompress()' function the + // source and destination are flipped and the sort key needs to change + // accordingly. + llvm::stable_sort(CompressPatterns, + [Compress](const CompressPat &LHS, const CompressPat &RHS) { + if (Compress) + return (LHS.Source.TheDef->getName().str() < + RHS.Source.TheDef->getName().str()); + else + return (LHS.Dest.TheDef->getName().str() < + RHS.Dest.TheDef->getName().str()); + }); + + // A list of MCOperandPredicates for all operands in use, and the reverse map. + std::vector MCOpPredicates; + DenseMap MCOpPredicateMap; + + std::string F; + std::string FH; + raw_string_ostream Func(F); + raw_string_ostream FuncH(FH); + bool NeedMRI = false; + + if (Compress) + o << "\n#ifdef GEN_COMPRESS_INSTR\n" + << "#undef GEN_COMPRESS_INSTR\n\n"; + else + o << "\n#ifdef GEN_UNCOMPRESS_INSTR\n" + << "#undef GEN_UNCOMPRESS_INSTR\n\n"; + + if (Compress) { + FuncH << "static bool compressInst(MCInst& OutInst,\n"; + FuncH.indent(25) << "const MCInst &MI,\n"; + FuncH.indent(25) << "const MCSubtargetInfo &STI,\n"; + FuncH.indent(25) << "MCContext &Context) {\n"; + } else { + FuncH << "static bool uncompressInst(MCInst& OutInst,\n"; + FuncH.indent(27) << "const MCInst &MI,\n"; + FuncH.indent(27) << "const MCRegisterInfo &MRI,\n"; + FuncH.indent(27) << "const MCSubtargetInfo &STI) {\n"; + } + + if (CompressPatterns.empty()) { + o << FuncH.str(); + o.indent(2) << "return false;\n}\n"; + if (Compress) + o << "\n#endif //GEN_COMPRESS_INSTR\n"; + else + o << "\n#endif //GEN_UNCOMPRESS_INSTR\n\n"; + return; + } + + std::string CaseString(""); + raw_string_ostream CaseStream(CaseString); + std::string PrevOp(""); + std::string CurOp(""); + CaseStream << " switch (MI.getOpcode()) {\n"; + CaseStream << " default: return false;\n"; + + for (auto &CompressPat : CompressPatterns) { + std::string CondString; + std::string CodeString; + raw_string_ostream CondStream(CondString); + raw_string_ostream CodeStream(CodeString); + CodeGenInstruction &Source = + Compress ? CompressPat.Source : CompressPat.Dest; + CodeGenInstruction &Dest = Compress ? CompressPat.Dest : CompressPat.Source; + IndexedMap SourceOperandMap = + Compress ? CompressPat.SourceOperandMap : CompressPat.DestOperandMap; + IndexedMap &DestOperandMap = + Compress ? CompressPat.DestOperandMap : CompressPat.SourceOperandMap; + + CurOp = Source.TheDef->getName().str(); + // Check current and previous opcode to decide to continue or end a case. + if (CurOp != PrevOp) { + if (PrevOp != "") + CaseStream.indent(6) << "break;\n } // case " + PrevOp + "\n"; + CaseStream.indent(4) << "case " + Namespace + "::" + CurOp + ": {\n"; + } + + std::set FeaturesSet; + // Add CompressPat required features. + getReqFeatures(FeaturesSet, CompressPat.PatReqFeatures); + + // Add Dest instruction required features. + std::vector ReqFeatures; + std::vector RF = Dest.TheDef->getValueAsListOfDefs("Predicates"); + copy_if(RF, std::back_inserter(ReqFeatures), [](Record *R) { + return R->getValueAsBit("AssemblerMatcherPredicate"); + }); + getReqFeatures(FeaturesSet, ReqFeatures); + + // Emit checks for all required features. + for (auto &Op : FeaturesSet) { + if (Op[0] == '!') + CondStream.indent(6) << ("!STI.getFeatureBits()[" + Namespace + + "::" + Op.substr(1) + "]") + .str() + + " &&\n"; + else + CondStream.indent(6) + << ("STI.getFeatureBits()[" + Namespace + "::" + Op + "]").str() + + " &&\n"; + } + + // Start Source Inst operands validation. + unsigned OpNo = 0; + for (OpNo = 0; OpNo < Source.Operands.size(); ++OpNo) { + if (SourceOperandMap[OpNo].TiedOpIdx != -1) { + if (Source.Operands[OpNo].Rec->isSubClassOf("RegisterClass")) + CondStream.indent(6) + << "(MI.getOperand(" + << std::to_string(OpNo) + ").getReg() == MI.getOperand(" + << std::to_string(SourceOperandMap[OpNo].TiedOpIdx) + << ").getReg()) &&\n"; + else + PrintFatalError("Unexpected tied operand types!\n"); + } + // Check for fixed immediates\registers in the source instruction. + switch (SourceOperandMap[OpNo].Kind) { + case OpData::Operand: + // We don't need to do anything for source instruction operand checks. + break; + case OpData::Imm: + CondStream.indent(6) + << "(MI.getOperand(" + std::to_string(OpNo) + ").isImm()) &&\n" + + " (MI.getOperand(" + std::to_string(OpNo) + + ").getImm() == " + + std::to_string(SourceOperandMap[OpNo].Data.Imm) + ") &&\n"; + break; + case OpData::Reg: { + Record *Reg = SourceOperandMap[OpNo].Data.Reg; + CondStream.indent(6) << "(MI.getOperand(" + std::to_string(OpNo) + + ").getReg() == " + Namespace + + "::" + Reg->getName().str() + ") &&\n"; + break; + } + } + } + CodeStream.indent(6) << "// " + Dest.AsmString + "\n"; + CodeStream.indent(6) << "OutInst.setOpcode(" + Namespace + + "::" + Dest.TheDef->getName().str() + ");\n"; + OpNo = 0; + for (const auto &DestOperand : Dest.Operands) { + CodeStream.indent(6) << "// Operand: " + DestOperand.Name + "\n"; + switch (DestOperandMap[OpNo].Kind) { + case OpData::Operand: { + unsigned OpIdx = DestOperandMap[OpNo].Data.Operand; + // Check that the operand in the Source instruction fits + // the type for the Dest instruction. + if (DestOperand.Rec->isSubClassOf("RegisterClass")) { + NeedMRI = true; + // This is a register operand. Check the register class. + // Don't check register class if this is a tied operand, it was done + // for the operand its tied to. + if (DestOperand.getTiedRegister() == -1) + CondStream.indent(6) + << "(MRI.getRegClass(" + Namespace + + "::" + DestOperand.Rec->getName().str() + + "RegClassID).contains(" + "MI.getOperand(" + + std::to_string(OpIdx) + ").getReg())) &&\n"; + + CodeStream.indent(6) << "OutInst.addOperand(MI.getOperand(" + + std::to_string(OpIdx) + "));\n"; + } else { + // Handling immediate operands. + unsigned Entry = getMCOpPredicate(MCOpPredicateMap, MCOpPredicates, + DestOperand.Rec); + CondStream.indent(6) << Namespace + "ValidateMCOperand(" + + "MI.getOperand(" + std::to_string(OpIdx) + + "), STI, " + std::to_string(Entry) + + ") &&\n"; + CodeStream.indent(6) << "OutInst.addOperand(MI.getOperand(" + + std::to_string(OpIdx) + "));\n"; + } + break; + } + case OpData::Imm: { + unsigned Entry = + getMCOpPredicate(MCOpPredicateMap, MCOpPredicates, DestOperand.Rec); + CondStream.indent(6) + << Namespace + "ValidateMCOperand(" + "MCOperand::createImm(" + + std::to_string(DestOperandMap[OpNo].Data.Imm) + "), STI, " + + std::to_string(Entry) + ") &&\n"; + CodeStream.indent(6) + << "OutInst.addOperand(MCOperand::createImm(" + + std::to_string(DestOperandMap[OpNo].Data.Imm) + "));\n"; + } break; + case OpData::Reg: { + // Fixed register has been validated at pattern validation time. + Record *Reg = DestOperandMap[OpNo].Data.Reg; + CodeStream.indent(6) << "OutInst.addOperand(MCOperand::createReg(" + + Namespace + "::" + Reg->getName().str() + + "));\n"; + } break; + } + ++OpNo; + } + CaseStream << mergeCondAndCode(CondStream, CodeStream); + PrevOp = CurOp; + } + Func << CaseStream.str() << "\n"; + // Close brace for the last case. + Func.indent(4) << "} // case " + CurOp + "\n"; + Func.indent(2) << "} // switch\n"; + Func.indent(2) << "return false;\n}\n"; + + if (!MCOpPredicates.empty()) { + o << "static bool " << Namespace + << "ValidateMCOperand(const MCOperand &MCOp,\n" + << " const MCSubtargetInfo &STI,\n" + << " unsigned PredicateIndex) {\n" + << " switch (PredicateIndex) {\n" + << " default:\n" + << " llvm_unreachable(\"Unknown MCOperandPredicate kind\");\n" + << " break;\n"; + + for (unsigned i = 0; i < MCOpPredicates.size(); ++i) { + Init *MCOpPred = MCOpPredicates[i]->getValueInit("MCOperandPredicate"); + if (CodeInit *SI = dyn_cast(MCOpPred)) + o << " case " << i + 1 << ": {\n" + << " // " << MCOpPredicates[i]->getName().str() << SI->getValue() + << "\n" + << " }\n"; + else + llvm_unreachable("Unexpected MCOperandPredicate field!"); + } + o << " }\n" + << "}\n\n"; + } + + o << FuncH.str(); + if (NeedMRI && Compress) + o.indent(2) << "const MCRegisterInfo &MRI = *Context.getRegisterInfo();\n"; + o << Func.str(); + + if (Compress) + o << "\n#endif //GEN_COMPRESS_INSTR\n"; + else + o << "\n#endif //GEN_UNCOMPRESS_INSTR\n\n"; +} + +void CAHPCompressInstEmitter::run(raw_ostream &o) { + Record *CompressClass = Records.getClass("CompressPat"); + assert(CompressClass && "Compress class definition missing!"); + std::vector Insts; + for (const auto &D : Records.getDefs()) { + if (D.second->isSubClassOf(CompressClass)) + Insts.push_back(D.second.get()); + } + + // Process the CompressPat definitions, validating them as we do so. + for (unsigned i = 0, e = Insts.size(); i != e; ++i) + evaluateCompressPat(Insts[i]); + + // Emit file header. + emitSourceFileHeader("Compress instruction Source Fragment", o); + // Generate compressInst() function. + emitCompressInstEmitter(o, true); + // Generate uncompressInst() function. + emitCompressInstEmitter(o, false); +} + +namespace llvm { + +void EmitCAHPCompressInst(RecordKeeper &RK, raw_ostream &OS) { + CAHPCompressInstEmitter(RK).run(OS); +} + +} // namespace llvm diff --git a/llvm/utils/TableGen/CMakeLists.txt b/llvm/utils/TableGen/CMakeLists.txt index c88365a2b8ce..07907f62e09b 100644 --- a/llvm/utils/TableGen/CMakeLists.txt +++ b/llvm/utils/TableGen/CMakeLists.txt @@ -6,6 +6,7 @@ add_tablegen(llvm-tblgen LLVM AsmWriterInst.cpp Attributes.cpp CallingConvEmitter.cpp + CAHPCompressInstEmitter.cpp CodeEmitterGen.cpp CodeGenDAGPatterns.cpp CodeGenHwModes.cpp diff --git a/llvm/utils/TableGen/TableGen.cpp b/llvm/utils/TableGen/TableGen.cpp index c485ed2feb7a..5129feb34dfe 100644 --- a/llvm/utils/TableGen/TableGen.cpp +++ b/llvm/utils/TableGen/TableGen.cpp @@ -33,6 +33,7 @@ enum ActionType { GenDisassembler, GenPseudoLowering, GenCompressInst, + GenCAHPCompressInst, GenCallingConv, GenDAGISel, GenDFAPacketizer, @@ -86,6 +87,8 @@ namespace { "Generate pseudo instruction lowering"), clEnumValN(GenCompressInst, "gen-compress-inst-emitter", "Generate RISCV compressed instructions."), + clEnumValN(GenCAHPCompressInst, "gen-cahp-compress-inst-emitter", + "Generate CAHP compressed instructions."), clEnumValN(GenAsmMatcher, "gen-asm-matcher", "Generate assembly instruction matcher"), clEnumValN(GenDAGISel, "gen-dag-isel", @@ -175,6 +178,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenCompressInst: EmitCompressInst(Records, OS); break; + case GenCAHPCompressInst: + EmitCAHPCompressInst(Records, OS); + break; case GenDAGISel: EmitDAGISel(Records, OS); break; diff --git a/llvm/utils/TableGen/TableGenBackends.h b/llvm/utils/TableGen/TableGenBackends.h index 135ec65c0f95..ca41bcf2810d 100644 --- a/llvm/utils/TableGen/TableGenBackends.h +++ b/llvm/utils/TableGen/TableGenBackends.h @@ -77,6 +77,7 @@ void EmitInstrInfo(RecordKeeper &RK, raw_ostream &OS); void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS); void EmitPseudoLowering(RecordKeeper &RK, raw_ostream &OS); void EmitCompressInst(RecordKeeper &RK, raw_ostream &OS); +void EmitCAHPCompressInst(RecordKeeper &RK, raw_ostream &OS); void EmitRegisterInfo(RecordKeeper &RK, raw_ostream &OS); void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS); void EmitMapTable(RecordKeeper &RK, raw_ostream &OS); diff --git a/llvm/utils/UpdateTestChecks/asm.py b/llvm/utils/UpdateTestChecks/asm.py index 9c250cd9898a..1bb29b0a03d5 100644 --- a/llvm/utils/UpdateTestChecks/asm.py +++ b/llvm/utils/UpdateTestChecks/asm.py @@ -42,6 +42,12 @@ class string: r'^\s*(\.Lfunc_end[0-9]+:\n|\.section)', flags=(re.M | re.S)) +ASM_FUNCTION_CAHP_RE = re.compile( + r'^_?(?P[^:]+):[ \t]*#+[ \t]*@(?P=func)\n(?:\s*\.?Lfunc_begin[^:\n]*:\n)?[^:]*?' + r'(?P^##?[ \t]+[^:]+:.*?)\s*' + r'.Lfunc_end[0-9]+:\n', + flags=(re.M | re.S)) + ASM_FUNCTION_HEXAGON_RE = re.compile( r'^_?(?P[^:]+):[ \t]*//[ \t]*@(?P=func)\n[^:]*?' r'(?P.*?)\n' # (body of the function) @@ -281,6 +287,16 @@ def scrub_asm_wasm32(asm, args): asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) return asm +def scrub_asm_cahp(asm, args): + # Scrub runs of whitespace out of the assembly, but leave the leading + # whitespace in place. + asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) + # Expand the tabs used for indentation. + asm = string.expandtabs(asm, 2) + # Strip trailing whitespace. + asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) + return asm + def get_triple_from_march(march): triples = { 'amdgcn': 'amdgcn', @@ -323,6 +339,7 @@ def build_function_body_dictionary_for_triple(args, raw_tool_output, triple, pre 'sparc': (scrub_asm_sparc, ASM_FUNCTION_SPARC_RE), 's390x': (scrub_asm_systemz, ASM_FUNCTION_SYSTEMZ_RE), 'wasm32': (scrub_asm_wasm32, ASM_FUNCTION_WASM32_RE), + 'cahp': (scrub_asm_cahp, ASM_FUNCTION_CAHP_RE), } handler = None best_prefix = '' diff --git a/llvm/utils/benchmark/README.LLVM b/llvm/utils/benchmark/README.LLVM index c493ff4f5c64..d2aa87e86e79 100644 --- a/llvm/utils/benchmark/README.LLVM +++ b/llvm/utils/benchmark/README.LLVM @@ -23,3 +23,5 @@ Changes: is applied to disable exceptions in Microsoft STL when exceptions are disabled * Disabled CMake get_git_version as it is meaningless for this in-tree build, and hardcoded a null version +* https://github.com/google/benchmark/commit/4abdfbb802d1b514703223f5f852ce4a507d32d2 + is applied on top of v1.4.1 to add RISC-V timer support. diff --git a/llvm/utils/benchmark/src/cycleclock.h b/llvm/utils/benchmark/src/cycleclock.h index e1f18cc64d20..7b54b2530378 100644 --- a/llvm/utils/benchmark/src/cycleclock.h +++ b/llvm/utils/benchmark/src/cycleclock.h @@ -164,6 +164,21 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { uint64_t tsc; asm("stck %0" : "=Q" (tsc) : : "cc"); return tsc; +#elif defined(__riscv) // RISC-V + // Use RDCYCLE (and RDCYCLEH on riscv32) +#if __riscv_xlen == 32 + uint64_t cycles_low, cycles_hi0, cycles_hi1; + asm("rdcycleh %0" : "=r"(cycles_hi0)); + asm("rdcycle %0" : "=r"(cycles_lo)); + asm("rdcycleh %0" : "=r"(cycles_hi1)); + // This matches the PowerPC overflow detection, above + cycles_lo &= -static_cast(cycles_hi0 == cycles_hi1); + return (cycles_hi1 << 32) | cycles_lo; +#else + uint64_t cycles; + asm("rdcycle %0" : "=r"(cycles)); + return cycles; +#endif #else // The soft failover to a generic implementation is automatic only for ARM. // For other platforms the developer is expected to make an attempt to create diff --git a/llvm/utils/gn/secondary/clang-tools-extra/clang-include-fixer/plugin/BUILD.gn b/llvm/utils/gn/secondary/clang-tools-extra/clang-include-fixer/plugin/BUILD.gn new file mode 100644 index 000000000000..ce4617556bff --- /dev/null +++ b/llvm/utils/gn/secondary/clang-tools-extra/clang-include-fixer/plugin/BUILD.gn @@ -0,0 +1,18 @@ +static_library("plugin") { + output_name = "clangIncludeFixerPlugin" + configs += [ "//llvm/utils/gn/build:clang_code" ] + deps = [ + "//clang-tools-extra/clang-include-fixer", + "//clang/lib/AST", + "//clang/lib/Basic", + "//clang/lib/Frontend", + "//clang/lib/Parse", + "//clang/lib/Sema", + "//clang/lib/Tooling", + "//llvm/utils/gn/build/libs/pthread", + ] + + sources = [ + "IncludeFixerPlugin.cpp", + ] +} diff --git a/llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/plugin/BUILD.gn b/llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/plugin/BUILD.gn index 1d033e87ee52..ec6d4ce78871 100644 --- a/llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/plugin/BUILD.gn +++ b/llvm/utils/gn/secondary/clang-tools-extra/clang-tidy/plugin/BUILD.gn @@ -1,3 +1,5 @@ +import("//clang/lib/StaticAnalyzer/Frontend/enable.gni") + static_library("plugin") { output_name = "clangTidyPlugin" configs += [ "//llvm/utils/gn/build:clang_code" ] @@ -16,6 +18,7 @@ static_library("plugin") { "//clang-tools-extra/clang-tidy/misc", "//clang-tools-extra/clang-tidy/modernize", "//clang-tools-extra/clang-tidy/objc", + "//clang-tools-extra/clang-tidy/openmp", "//clang-tools-extra/clang-tidy/performance", "//clang-tools-extra/clang-tidy/portability", "//clang-tools-extra/clang-tidy/readability", diff --git a/llvm/utils/gn/secondary/clang-tools-extra/clangd/BUILD.gn b/llvm/utils/gn/secondary/clang-tools-extra/clangd/BUILD.gn index e21727d22e34..44ebf4052388 100644 --- a/llvm/utils/gn/secondary/clang-tools-extra/clangd/BUILD.gn +++ b/llvm/utils/gn/secondary/clang-tools-extra/clangd/BUILD.gn @@ -105,6 +105,7 @@ static_library("clangd") { "URI.cpp", "XRefs.cpp", "index/Background.cpp", + "index/BackgroundIndexLoader.cpp", "index/BackgroundIndexStorage.cpp", "index/BackgroundQueue.cpp", "index/BackgroundRebuild.cpp", diff --git a/llvm/utils/gn/secondary/clang/tools/libclang/BUILD.gn b/llvm/utils/gn/secondary/clang/tools/libclang/BUILD.gn index 567588478e63..eb04b3071fad 100644 --- a/llvm/utils/gn/secondary/clang/tools/libclang/BUILD.gn +++ b/llvm/utils/gn/secondary/clang/tools/libclang/BUILD.gn @@ -3,8 +3,6 @@ import("//llvm/version.gni") # This build file is just enough to get check-clang to pass, it's missing # several things from the CMake build: -# - linking in clangTidyPlugin and clangIncludeFixerPlugin from -# clang-tools-extra (which doesn't have any GN build files yet) # - using libclang.exports # - a build target copying the Python bindings # - the GN linux build always builds without -fPIC (as if LLVM_ENABLE_PIC=OFF @@ -39,8 +37,22 @@ target(libclang_target_type, "libclang") { deps += [ "//clang/lib/ARCMigrate" ] } + defines = [] + + # FIXME: Once the GN build has a way to select which bits to build, + # only include this dependency if clang-tools-extra is part of the build. + # FIXME: libclang depending on anything in clang-tools-extra seems like + # a layering violation. + if (true) { + defines += [ "CLANG_TOOL_EXTRA_BUILD" ] + deps += [ + "//clang-tools-extra/clang-include-fixer/plugin", + "//clang-tools-extra/clang-tidy/plugin", + ] + } + if (host_os == "win") { - defines = [ "_CINDEX_LIB_" ] + defines += [ "_CINDEX_LIB_" ] } sources = [ diff --git a/llvm/utils/gn/secondary/libcxx/src/BUILD.gn b/llvm/utils/gn/secondary/libcxx/src/BUILD.gn index 09b8947765be..8f5c1c31fbea 100644 --- a/llvm/utils/gn/secondary/libcxx/src/BUILD.gn +++ b/llvm/utils/gn/secondary/libcxx/src/BUILD.gn @@ -236,9 +236,9 @@ if (libcxx_enable_shared) { ] args = [ "--input", - "$runtimes_dir/libc++.so.0", + rebase_path("$runtimes_dir/libc++.so.0", root_build_dir), "--output", - "$runtimes_dir/libc++.so", + rebase_path("$runtimes_dir/libc++.so", root_build_dir), "c++abi", "unwind", ] diff --git a/llvm/utils/lit/lit/__init__.py b/llvm/utils/lit/lit/__init__.py index 0d849d16f076..8c4586ccbc4d 100644 --- a/llvm/utils/lit/lit/__init__.py +++ b/llvm/utils/lit/lit/__init__.py @@ -2,7 +2,7 @@ __author__ = 'Daniel Dunbar' __email__ = 'daniel@minormatter.com' -__versioninfo__ = (0, 8, 0) +__versioninfo__ = (0, 9, 0) __version__ = '.'.join(str(v) for v in __versioninfo__) + 'dev' __all__ = [] diff --git a/llvm/utils/lit/setup.py b/llvm/utils/lit/setup.py index 10b75e7fe6ee..9d26b2ed71c7 100644 --- a/llvm/utils/lit/setup.py +++ b/llvm/utils/lit/setup.py @@ -60,7 +60,7 @@ 'Development Status :: 3 - Alpha', 'Environment :: Console', 'Intended Audience :: Developers', - 'License :: OSI Approved :: Apache-2.0 with LLVM exception', + 'License :: OSI Approved :: Apache Software License', 'Natural Language :: English', 'Operating System :: OS Independent', 'Programming Language :: Python', diff --git a/llvm/utils/lit/tests/lit.cfg b/llvm/utils/lit/tests/lit.cfg index 4648b1bfc9c3..56670323474d 100644 --- a/llvm/utils/lit/tests/lit.cfg +++ b/llvm/utils/lit/tests/lit.cfg @@ -35,9 +35,13 @@ else: lit_path = os.path.join(config.test_source_root, '..') # Required because some tests import the lit module -llvm_config.with_environment('PYTHONPATH', lit_path, append_path=True) +if llvm_config: + llvm_config.with_environment('PYTHONPATH', lit_path, append_path=True) +else: + config.environment['PYTHONPATH'] = os.pathsep.join([lit_path]) # Add llvm and lit tools directories if this config is being loaded indirectly. +# In this case, we can also expect llvm_config to have been imported correctly. for attribute in ('llvm_tools_dir', 'lit_tools_dir'): directory = getattr(config, attribute, None) if directory: @@ -63,3 +67,10 @@ try: except ImportError: lit_config.warning('Could not import psutil. Some tests will be skipped and' ' the --timeout command line argument will not work.') + +# When running the lit tests standalone, we want to define the same features +# that the llvm_config defines. This means that the 'system-windows' feature +# (and any others) need to match the names in llvm_config for consistency +if not llvm_config: + if sys.platform.startswith('win') or sys.platform.startswith('cygwin'): + config.available_features.add('system-windows') diff --git a/llvm/utils/llvm-build/llvmbuild/main.py b/llvm/utils/llvm-build/llvmbuild/main.py index 9a9726424d40..99b82ad5e20c 100644 --- a/llvm/utils/llvm-build/llvmbuild/main.py +++ b/llvm/utils/llvm-build/llvmbuild/main.py @@ -359,7 +359,7 @@ def write_library_table(self, output_path, enabled_optional_components): root_entries = set(e[0] for e in entries) for _,_,deps,_ in entries: root_entries -= set(deps) - entries.append(('all', None, root_entries, True)) + entries.append(('all', None, sorted(root_entries), True)) entries.sort() diff --git a/llvm/utils/release/test-release.sh b/llvm/utils/release/test-release.sh index 558e01d2eabc..8f691ccfb87a 100755 --- a/llvm/utils/release/test-release.sh +++ b/llvm/utils/release/test-release.sh @@ -591,11 +591,12 @@ for Flavor in $Flavors ; do for p2 in `find $llvmCore_phase2_objdir -name '*.o'` ; do p3=`echo $p2 | sed -e 's,Phase2,Phase3,'` # Substitute 'Phase2' for 'Phase3' in the Phase 2 object file in - # case there are build paths in the debug info. On some systems, - # sed adds a newline to the output, so pass $p3 through sed too. + # case there are build paths in the debug info. Do the same sub- + # stitution on both files in case the string occurrs naturally. if ! cmp -s \ - <(env LC_CTYPE=C sed -e 's,Phase2,Phase3,g' -e 's,Phase1,Phase2,g' $p2) \ - <(env LC_CTYPE=C sed -e '' $p3) 16 16; then + <(env LC_CTYPE=C sed -e 's,Phase1,Phase2,g' -e 's,Phase2,Phase3,g' $p2) \ + <(env LC_CTYPE=C sed -e 's,Phase1,Phase2,g' -e 's,Phase2,Phase3,g' $p3) \ + 16 16; then echo "file `basename $p2` differs between phase 2 and phase 3" fi done diff --git a/polly/test/DeLICM/reduction_looprotate_hoisted.ll b/polly/test/DeLICM/reduction_looprotate_hoisted.ll index 47f449564508..3a96ff6138b9 100644 --- a/polly/test/DeLICM/reduction_looprotate_hoisted.ll +++ b/polly/test/DeLICM/reduction_looprotate_hoisted.ll @@ -70,7 +70,7 @@ return: ; CHECK-NEXT: Stmt_reduction_preheader ; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1] ; CHECK-NEXT: [Start] -> { Stmt_reduction_preheader[i0] -> MemRef_phi__phi[] }; -; CHECK-NEXT: new: [Start] -> { Stmt_reduction_preheader[i0] -> MemRef_A[i0] : Start >= 2147483648 or Start <= 2147483646 }; +; CHECK-NEXT: new: [Start] -> { Stmt_reduction_preheader[i0] -> MemRef_A[i0] }; ; CHECK-NEXT: Stmt_reduction_for ; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 1] ; CHECK-NEXT: [Start] -> { Stmt_reduction_for[i0, i1] -> MemRef_phi__phi[] };