From 57b8a407493c34c3680e7e1e4cb82e097f43744a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20Umann?= Date: Fri, 28 Feb 2020 15:07:50 +0100 Subject: [PATCH 01/59] [analyzer][NFC] Tie CheckerRegistry to CheckerManager, allow CheckerManager to be constructed for non-analysis purposes Its been a while since my CheckerRegistry related patches landed, allow me to refresh your memory: During compilation, TblGen turns clang/include/clang/StaticAnalyzer/Checkers/Checkers.td into (build directory)/tools/clang/include/clang/StaticAnalyzer/Checkers/Checkers.inc. This is a file that contains the full name of the checkers, their options, etc. The class that is responsible for parsing this file is CheckerRegistry. The job of this class is to establish what checkers are available for the analyzer (even from plugins and statically linked but non-tblgen generated files!), and calculate which ones should be turned on according to the analyzer's invocation. CheckerManager is the class that is responsible for the construction and storage of checkers. This process works by first creating a CheckerRegistry object, and passing itself to CheckerRegistry::initializeManager(CheckerManager&), which will call the checker registry functions (for example registerMallocChecker) on it. The big problem here is that these two classes lie in two different libraries, so their interaction is pretty awkward. This used to be far worse, but I refactored much of it, which made things better but nowhere near perfect. --- This patch changes how the above mentioned two classes interact. CheckerRegistry is mainly used by CheckerManager, and they are so intertwined, it makes a lot of sense to turn in into a field, instead of a one-time local variable. This has additional benefits: much of the information that CheckerRegistry conveniently holds is no longer thrown away right after the analyzer's initialization, and opens the possibility to pass CheckerManager in the shouldRegister* function rather then LangOptions (D75271). There are a few problems with this. CheckerManager isn't the only user, when we honor help flags like -analyzer-checker-help, we only have access to a CompilerInstance class, that is before the point of parsing the AST. CheckerManager makes little sense without ASTContext, so I made some changes and added new constructors to make it constructible for the use of help flags. Differential Revision: https://reviews.llvm.org/D75360 --- .../StaticAnalyzer/Core/CheckerManager.h | 42 +++++++- .../Frontend/AnalysisConsumer.h | 2 +- .../Frontend/AnalyzerHelpFlags.h | 30 ++++++ .../Frontend/CheckerRegistration.h | 38 ------- .../StaticAnalyzer/Frontend/CheckerRegistry.h | 38 ++++--- .../StaticAnalyzer/Frontend/FrontendActions.h | 17 +-- .../ExecuteCompilerInvocation.cpp | 20 +--- .../StaticAnalyzer/Core/CheckerManager.cpp | 7 +- .../Frontend/AnalysisConsumer.cpp | 5 +- ...Registration.cpp => AnalyzerHelpFlags.cpp} | 60 ++++------- .../StaticAnalyzer/Frontend/CMakeLists.txt | 2 +- .../Frontend/CheckerRegistry.cpp | 101 +++++++++--------- 12 files changed, 176 insertions(+), 186 deletions(-) create mode 100644 clang/include/clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h delete mode 100644 clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h rename clang/lib/StaticAnalyzer/Frontend/{CheckerRegistration.cpp => AnalyzerHelpFlags.cpp} (69%) diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h index 4454d7603b27..6faf0f2e0afd 100644 --- a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -14,9 +14,11 @@ #define LLVM_CLANG_STATICANALYZER_CORE_CHECKERMANAGER_H #include "clang/Analysis/ProgramPoint.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/LangOptions.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" +#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" @@ -40,7 +42,6 @@ class BugReporter; class CallEvent; class CheckerBase; class CheckerContext; -class CheckerRegistry; class ExplodedGraph; class ExplodedNode; class ExplodedNodeSet; @@ -121,14 +122,42 @@ enum class ObjCMessageVisitKind { }; class CheckerManager { - ASTContext &Context; + ASTContext *Context; const LangOptions LangOpts; AnalyzerOptions &AOptions; CheckerNameRef CurrentCheckerName; + DiagnosticsEngine &Diags; + CheckerRegistry Registry; public: + CheckerManager( + ASTContext &Context, AnalyzerOptions &AOptions, + ArrayRef plugins, + ArrayRef> checkerRegistrationFns) + : Context(&Context), LangOpts(Context.getLangOpts()), AOptions(AOptions), + Diags(Context.getDiagnostics()), + Registry(plugins, Context.getDiagnostics(), AOptions, + checkerRegistrationFns) { + Registry.initializeRegistry(*this); + Registry.initializeManager(*this); + finishedCheckerRegistration(); + } + + /// Constructs a CheckerManager that ignores all non TblGen-generated + /// checkers. Useful for unit testing, unless the checker infrastructure + /// itself is tested. CheckerManager(ASTContext &Context, AnalyzerOptions &AOptions) - : Context(Context), LangOpts(Context.getLangOpts()), AOptions(AOptions) {} + : CheckerManager(Context, AOptions, {}, {}) {} + + /// Constructs a CheckerManager without requiring an AST. No checker + /// registration will take place. Only useful for retrieving the + /// CheckerRegistry and print for help flags where the AST is unavalaible. + CheckerManager(AnalyzerOptions &AOptions, const LangOptions &LangOpts, + DiagnosticsEngine &Diags, ArrayRef plugins) + : LangOpts(LangOpts), AOptions(AOptions), Diags(Diags), + Registry(plugins, Diags, AOptions) { + Registry.initializeRegistry(*this); + } ~CheckerManager(); @@ -141,7 +170,12 @@ class CheckerManager { const LangOptions &getLangOpts() const { return LangOpts; } AnalyzerOptions &getAnalyzerOptions() const { return AOptions; } - ASTContext &getASTContext() const { return Context; } + const CheckerRegistry &getCheckerRegistry() const { return Registry; } + DiagnosticsEngine &getDiagnostics() const { return Diags; } + ASTContext &getASTContext() const { + assert(Context); + return *Context; + } /// Emits an error through a DiagnosticsEngine about an invalid user supplied /// checker option value. diff --git a/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h b/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h index 2d24e6a9586b..bcc29a60ad70 100644 --- a/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h +++ b/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h @@ -55,7 +55,7 @@ class AnalysisASTConsumer : public ASTConsumer { std::unique_ptr CreateAnalysisConsumer(CompilerInstance &CI); -} // end GR namespace +} // namespace ento } // end clang namespace diff --git a/clang/include/clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h b/clang/include/clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h new file mode 100644 index 000000000000..a30c241e1350 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h @@ -0,0 +1,30 @@ +//===-- AnalyzerHelpFlags.h - Query functions for --help flags --*- 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_STATICANALYZER_FRONTEND_ANALYZERHELPFLAGS_H +#define LLVM_CLANG_STATICANALYZER_FRONTEND_ANALYZERHELPFLAGS_H + +namespace llvm { +class raw_ostream; +} // namespace llvm + +namespace clang { + +class CompilerInstance; + +namespace ento { + +void printCheckerHelp(llvm::raw_ostream &OS, CompilerInstance &CI); +void printEnabledCheckerList(llvm::raw_ostream &OS, CompilerInstance &CI); +void printAnalyzerConfigList(llvm::raw_ostream &OS); +void printCheckerConfigList(llvm::raw_ostream &OS, CompilerInstance &CI); + +} // namespace ento +} // namespace clang + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h deleted file mode 100644 index 52a534499002..000000000000 --- a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h +++ /dev/null @@ -1,38 +0,0 @@ -//===-- CheckerRegistration.h - Checker Registration Function ---*- 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_STATICANALYZER_FRONTEND_CHECKERREGISTRATION_H -#define LLVM_CLANG_STATICANALYZER_FRONTEND_CHECKERREGISTRATION_H - -#include "clang/AST/ASTContext.h" -#include "clang/Basic/LLVM.h" -#include -#include -#include - -namespace clang { - class AnalyzerOptions; - class LangOptions; - class DiagnosticsEngine; - -namespace ento { - class CheckerManager; - class CheckerRegistry; - - std::unique_ptr createCheckerManager( - ASTContext &context, - AnalyzerOptions &opts, - ArrayRef plugins, - ArrayRef> checkerRegistrationFns, - DiagnosticsEngine &diags); - -} // end ento namespace - -} // end namespace clang - -#endif diff --git a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h index 8830542f27d8..dde2409ed72c 100644 --- a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h +++ b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h @@ -10,7 +10,6 @@ #define LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H #include "clang/Basic/LLVM.h" -#include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" @@ -74,6 +73,8 @@ class LangOptions; namespace ento { +class CheckerManager; + /// Manages a set of available checkers for running a static analysis. /// The checkers are organized into packages by full name, where including /// a package will recursively include all subpackages and checkers within it. @@ -83,10 +84,15 @@ namespace ento { class CheckerRegistry { public: CheckerRegistry(ArrayRef plugins, DiagnosticsEngine &diags, - AnalyzerOptions &AnOpts, const LangOptions &LangOpts, + AnalyzerOptions &AnOpts, ArrayRef> checkerRegistrationFns = {}); + /// Collects all enabled checkers in the field EnabledCheckers. It preserves + /// the order of insertion, as dependencies have to be enabled before the + /// checkers that depend on them. + void initializeRegistry(const CheckerManager &Mgr); + /// Initialization functions perform any necessary setup for a checker. /// They should include a call to CheckerManager::registerChecker. using InitializationFunction = void (*)(CheckerManager &); @@ -205,14 +211,20 @@ class CheckerRegistry { using PackageInfoList = llvm::SmallVector; - template static void addToCheckerMgr(CheckerManager &mgr) { - mgr.registerChecker(); +private: + /// Default initialization function for checkers -- since CheckerManager + /// includes this header, we need to make it a template parameter, and since + /// the checker must be a template parameter as well, we can't put this in the + /// cpp file. + template static void initializeManager(MGR &mgr) { + mgr.template registerChecker(); } - static bool returnTrue(const LangOptions &LO) { + template static bool returnTrue(const LangOptions &) { return true; } +public: /// Adds a checker to the registry. Use this non-templated overload when your /// checker requires custom initialization. void addChecker(InitializationFunction Fn, ShouldRegisterFunction sfn, @@ -221,13 +233,16 @@ class CheckerRegistry { /// Adds a checker to the registry. Use this templated overload when your /// checker does not require any custom initialization. + /// This function isn't really needed and probably causes more headaches than + /// the tiny convenience that it provides, but external plugins might use it, + /// and there isn't a strong incentive to remove it. template void addChecker(StringRef FullName, StringRef Desc, StringRef DocsUri, bool IsHidden = false) { // Avoid MSVC's Compiler Error C2276: // http://msdn.microsoft.com/en-us/library/850cstw1(v=VS.80).aspx - addChecker(&CheckerRegistry::addToCheckerMgr, - &CheckerRegistry::returnTrue, FullName, Desc, DocsUri, IsHidden); + addChecker(&initializeManager, &returnTrue, FullName, + Desc, DocsUri, IsHidden); } /// Makes the checker with the full name \p fullName depends on the checker @@ -263,7 +278,7 @@ class CheckerRegistry { void addPackageOption(StringRef OptionType, StringRef PackageFullName, StringRef OptionName, StringRef DefaultValStr, StringRef Description, StringRef DevelopmentStatus, - bool IsHidden = false); + bool IsHidden = false); // FIXME: This *really* should be added to the frontend flag descriptions. /// Initializes a CheckerManager by calling the initialization functions for @@ -283,11 +298,6 @@ class CheckerRegistry { void printCheckerOptionList(raw_ostream &Out) const; private: - /// Collect all enabled checkers. The returned container preserves the order - /// of insertion, as dependencies have to be enabled before the checkers that - /// depend on them. - CheckerInfoSet getEnabledCheckers() const; - /// Return an iterator range of mutable CheckerInfos \p CmdLineArg applies to. /// For example, it'll return the checkers for the core package, if /// \p CmdLineArg is "core". @@ -314,7 +324,7 @@ class CheckerRegistry { DiagnosticsEngine &Diags; AnalyzerOptions &AnOpts; - const LangOptions &LangOpts; + CheckerInfoSet EnabledCheckers; }; } // namespace ento diff --git a/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h b/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h index 878b65a1b143..6b6a395a1884 100644 --- a/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h +++ b/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h @@ -51,22 +51,7 @@ class ParseModelFileAction : public ASTFrontendAction { llvm::StringMap &Bodies; }; -void printCheckerHelp(raw_ostream &OS, - ArrayRef plugins, - AnalyzerOptions &opts, - DiagnosticsEngine &diags, - const LangOptions &LangOpts); -void printEnabledCheckerList(raw_ostream &OS, ArrayRef plugins, - AnalyzerOptions &opts, - DiagnosticsEngine &diags, - const LangOptions &LangOpts); -void printAnalyzerConfigList(raw_ostream &OS); -void printCheckerConfigList(raw_ostream &OS, ArrayRef plugins, - AnalyzerOptions &opts, - DiagnosticsEngine &diags, - const LangOptions &LangOpts); - -} // end GR namespace +} // namespace ento } // end namespace clang diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 70735ab2d7b2..ab7a1e32e301 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -23,6 +23,7 @@ #include "clang/Frontend/Utils.h" #include "clang/FrontendTool/Utils.h" #include "clang/Rewrite/Frontend/FrontendActions.h" +#include "clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h" #include "clang/StaticAnalyzer/Frontend/FrontendActions.h" #include "llvm/Option/OptTable.h" #include "llvm/Option/Option.h" @@ -243,35 +244,24 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) { // These should happen AFTER plugins have been loaded! AnalyzerOptions &AnOpts = *Clang->getAnalyzerOpts(); + // Honor -analyzer-checker-help and -analyzer-checker-help-hidden. if (AnOpts.ShowCheckerHelp || AnOpts.ShowCheckerHelpAlpha || AnOpts.ShowCheckerHelpDeveloper) { - ento::printCheckerHelp(llvm::outs(), - Clang->getFrontendOpts().Plugins, - AnOpts, - Clang->getDiagnostics(), - Clang->getLangOpts()); + ento::printCheckerHelp(llvm::outs(), *Clang); return true; } // Honor -analyzer-checker-option-help. if (AnOpts.ShowCheckerOptionList || AnOpts.ShowCheckerOptionAlphaList || AnOpts.ShowCheckerOptionDeveloperList) { - ento::printCheckerConfigList(llvm::outs(), - Clang->getFrontendOpts().Plugins, - *Clang->getAnalyzerOpts(), - Clang->getDiagnostics(), - Clang->getLangOpts()); + ento::printCheckerConfigList(llvm::outs(), *Clang); return true; } // Honor -analyzer-list-enabled-checkers. if (AnOpts.ShowEnabledCheckerList) { - ento::printEnabledCheckerList(llvm::outs(), - Clang->getFrontendOpts().Plugins, - AnOpts, - Clang->getDiagnostics(), - Clang->getLangOpts()); + ento::printEnabledCheckerList(llvm::outs(), *Clang); return true; } diff --git a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp index ce5e4a46d3e2..081a31009235 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -64,10 +64,9 @@ void CheckerManager::reportInvalidCheckerOptionValue( const CheckerBase *C, StringRef OptionName, StringRef ExpectedValueDesc) const { - Context.getDiagnostics() - .Report(diag::err_analyzer_checker_option_invalid_input) - << (llvm::Twine() + C->getTagDescription() + ":" + OptionName).str() - << ExpectedValueDesc; + getDiagnostics().Report(diag::err_analyzer_checker_option_invalid_input) + << (llvm::Twine() + C->getTagDescription() + ":" + OptionName).str() + << ExpectedValueDesc; } //===----------------------------------------------------------------------===// diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index a908aede68bb..1ef6c477bba5 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -33,7 +33,6 @@ #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" -#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h" #include "clang/Tooling/Core/Replacement.h" #include "clang/Tooling/Tooling.h" #include "llvm/ADT/PostOrderIterator.h" @@ -348,8 +347,8 @@ class AnalysisConsumer : public AnalysisASTConsumer, void Initialize(ASTContext &Context) override { Ctx = &Context; - checkerMgr = createCheckerManager( - *Ctx, *Opts, Plugins, CheckerRegistrationFns, PP.getDiagnostics()); + checkerMgr = std::make_unique(*Ctx, *Opts, Plugins, + CheckerRegistrationFns); Mgr = std::make_unique(*Ctx, PP, PathConsumers, CreateStoreMgr, CreateConstraintMgr, diff --git a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp similarity index 69% rename from clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp rename to clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp index f4f06e32cd1d..d589e69bdf34 100644 --- a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp @@ -10,8 +10,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h" +#include "clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" @@ -24,53 +25,34 @@ using namespace clang; using namespace ento; -std::unique_ptr ento::createCheckerManager( - ASTContext &context, - AnalyzerOptions &opts, - ArrayRef plugins, - ArrayRef> checkerRegistrationFns, - DiagnosticsEngine &diags) { - auto checkerMgr = std::make_unique(context, opts); - - CheckerRegistry allCheckers(plugins, diags, opts, context.getLangOpts(), - checkerRegistrationFns); - - allCheckers.initializeManager(*checkerMgr); - allCheckers.validateCheckerOptions(); - checkerMgr->finishedCheckerRegistration(); - - return checkerMgr; -} - -void ento::printCheckerHelp(raw_ostream &out, ArrayRef plugins, - AnalyzerOptions &anopts, - DiagnosticsEngine &diags, - const LangOptions &langOpts) { +void ento::printCheckerHelp(raw_ostream &out, CompilerInstance &CI) { out << "OVERVIEW: Clang Static Analyzer Checkers List\n\n"; out << "USAGE: -analyzer-checker \n\n"; - CheckerRegistry(plugins, diags, anopts, langOpts) - .printCheckerWithDescList(out); + auto CheckerMgr = std::make_unique( + *CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(), + CI.getFrontendOpts().Plugins); + + CheckerMgr->getCheckerRegistry().printCheckerWithDescList(out); } -void ento::printEnabledCheckerList(raw_ostream &out, - ArrayRef plugins, - AnalyzerOptions &anopts, - DiagnosticsEngine &diags, - const LangOptions &langOpts) { +void ento::printEnabledCheckerList(raw_ostream &out, CompilerInstance &CI) { out << "OVERVIEW: Clang Static Analyzer Enabled Checkers List\n\n"; - CheckerRegistry(plugins, diags, anopts, langOpts) - .printEnabledCheckerList(out); + auto CheckerMgr = std::make_unique( + *CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(), + CI.getFrontendOpts().Plugins); + + CheckerMgr->getCheckerRegistry().printEnabledCheckerList(out); } -void ento::printCheckerConfigList(raw_ostream &OS, - ArrayRef plugins, - AnalyzerOptions &opts, - DiagnosticsEngine &diags, - const LangOptions &LangOpts) { - CheckerRegistry(plugins, diags, opts, LangOpts) - .printCheckerOptionList(OS); +void ento::printCheckerConfigList(raw_ostream &out, CompilerInstance &CI) { + + auto CheckerMgr = std::make_unique( + *CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(), + CI.getFrontendOpts().Plugins); + + CheckerMgr->getCheckerRegistry().printCheckerOptionList(out); } void ento::printAnalyzerConfigList(raw_ostream &out) { diff --git a/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt b/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt index 6f1151ab0c11..055878aee0a5 100644 --- a/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt @@ -6,7 +6,7 @@ set(LLVM_LINK_COMPONENTS add_clang_library(clangStaticAnalyzerFrontend AnalysisConsumer.cpp - CheckerRegistration.cpp + AnalyzerHelpFlags.cpp CheckerRegistry.cpp FrontendActions.cpp ModelConsumer.cpp diff --git a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp index 4af204474494..db09ca4e625e 100644 --- a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp @@ -109,9 +109,9 @@ CheckerRegistry::getMutableCheckersForCmdLineArg(StringRef CmdLineArg) { CheckerRegistry::CheckerRegistry( ArrayRef Plugins, DiagnosticsEngine &Diags, - AnalyzerOptions &AnOpts, const LangOptions &LangOpts, + AnalyzerOptions &AnOpts, ArrayRef> CheckerRegistrationFns) - : Diags(Diags), AnOpts(AnOpts), LangOpts(LangOpts) { + : Diags(Diags), AnOpts(AnOpts) { // Register builtin checkers. #define GET_CHECKERS @@ -179,12 +179,16 @@ CheckerRegistry::CheckerRegistry( addDependency(FULLNAME, DEPENDENCY); #define GET_CHECKER_OPTIONS -#define CHECKER_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, DEVELOPMENT_STATUS, IS_HIDDEN) \ - addCheckerOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, DEVELOPMENT_STATUS, IS_HIDDEN); +#define CHECKER_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \ + DEVELOPMENT_STATUS, IS_HIDDEN) \ + addCheckerOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \ + DEVELOPMENT_STATUS, IS_HIDDEN); #define GET_PACKAGE_OPTIONS -#define PACKAGE_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, DEVELOPMENT_STATUS, IS_HIDDEN) \ - addPackageOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, DEVELOPMENT_STATUS, IS_HIDDEN); +#define PACKAGE_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \ + DEVELOPMENT_STATUS, IS_HIDDEN) \ + addPackageOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \ + DEVELOPMENT_STATUS, IS_HIDDEN); #include "clang/StaticAnalyzer/Checkers/Checkers.inc" #undef CHECKER_DEPENDENCY @@ -213,24 +217,53 @@ CheckerRegistry::CheckerRegistry( : StateFromCmdLine::State_Disabled; } } + validateCheckerOptions(); +} + +/// Collects dependenies in \p enabledCheckers. Return None on failure. +LLVM_NODISCARD +static llvm::Optional +collectDependencies(const CheckerRegistry::CheckerInfo &checker, + const CheckerManager &Mgr); + +void CheckerRegistry::initializeRegistry(const CheckerManager &Mgr) { + for (const CheckerInfo &Checker : Checkers) { + if (!Checker.isEnabled(Mgr.getLangOpts())) + continue; + + // Recursively enable its dependencies. + llvm::Optional Deps = collectDependencies(Checker, Mgr); + + if (!Deps) { + // If we failed to enable any of the dependencies, don't enable this + // checker. + continue; + } + + // Note that set_union also preserves the order of insertion. + EnabledCheckers.set_union(*Deps); + + // Enable the checker. + EnabledCheckers.insert(&Checker); + } } /// Collects dependencies in \p ret, returns false on failure. static bool collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps, - const LangOptions &LO, + const CheckerManager &Mgr, CheckerRegistry::CheckerInfoSet &Ret); /// Collects dependenies in \p enabledCheckers. Return None on failure. LLVM_NODISCARD static llvm::Optional collectDependencies(const CheckerRegistry::CheckerInfo &checker, - const LangOptions &LO) { + const CheckerManager &Mgr) { CheckerRegistry::CheckerInfoSet Ret; // Add dependencies to the enabled checkers only if all of them can be // enabled. - if (!collectDependenciesImpl(checker.Dependencies, LO, Ret)) + if (!collectDependenciesImpl(checker.Dependencies, Mgr, Ret)) return None; return Ret; @@ -238,16 +271,16 @@ collectDependencies(const CheckerRegistry::CheckerInfo &checker, static bool collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps, - const LangOptions &LO, + const CheckerManager &Mgr, CheckerRegistry::CheckerInfoSet &Ret) { for (const CheckerRegistry::CheckerInfo *Dependency : Deps) { - if (Dependency->isDisabled(LO)) + if (Dependency->isDisabled(Mgr.getLangOpts())) return false; // Collect dependencies recursively. - if (!collectDependenciesImpl(Dependency->Dependencies, LO, Ret)) + if (!collectDependenciesImpl(Dependency->Dependencies, Mgr, Ret)) return false; Ret.insert(Dependency); @@ -256,34 +289,6 @@ collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps, return true; } -CheckerRegistry::CheckerInfoSet CheckerRegistry::getEnabledCheckers() const { - - CheckerInfoSet EnabledCheckers; - - for (const CheckerInfo &Checker : Checkers) { - if (!Checker.isEnabled(LangOpts)) - continue; - - // Recursively enable its dependencies. - llvm::Optional Deps = - collectDependencies(Checker, LangOpts); - - if (!Deps) { - // If we failed to enable any of the dependencies, don't enable this - // checker. - continue; - } - - // Note that set_union also preserves the order of insertion. - EnabledCheckers.set_union(*Deps); - - // Enable the checker. - EnabledCheckers.insert(&Checker); - } - - return EnabledCheckers; -} - void CheckerRegistry::resolveDependencies() { for (const std::pair &Entry : Dependencies) { auto CheckerIt = binaryFind(Checkers, Entry.first); @@ -298,8 +303,6 @@ void CheckerRegistry::resolveDependencies() { CheckerIt->Dependencies.emplace_back(&*DependencyIt); } - - Dependencies.clear(); } void CheckerRegistry::addDependency(StringRef FullName, StringRef Dependency) { @@ -378,14 +381,12 @@ void CheckerRegistry::resolveCheckerAndPackageOptions() { insertOptionToCollection(CheckerOptEntry.first, Checkers, CheckerOptEntry.second, AnOpts, Diags); } - CheckerOptions.clear(); for (const std::pair &PackageOptEntry : PackageOptions) { insertOptionToCollection(PackageOptEntry.first, Packages, PackageOptEntry.second, AnOpts, Diags); } - PackageOptions.clear(); } void CheckerRegistry::addPackage(StringRef FullName) { @@ -432,11 +433,8 @@ void CheckerRegistry::addCheckerOption(StringRef OptionType, } void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const { - // Collect checkers enabled by the options. - CheckerInfoSet enabledCheckers = getEnabledCheckers(); - // Initialize the CheckerManager with all enabled checkers. - for (const auto *Checker : enabledCheckers) { + for (const auto *Checker : EnabledCheckers) { CheckerMgr.setCurrentCheckerName(CheckerNameRef(Checker->FullName)); Checker->Initialize(CheckerMgr); } @@ -505,6 +503,10 @@ void CheckerRegistry::validateCheckerOptions() const { } } +//===----------------------------------------------------------------------===// +// Printing functions. +//===----------------------------------------------------------------------===// + void CheckerRegistry::printCheckerWithDescList(raw_ostream &Out, size_t MaxNameChars) const { // FIXME: Print available packages. @@ -556,9 +558,6 @@ void CheckerRegistry::printCheckerWithDescList(raw_ostream &Out, } void CheckerRegistry::printEnabledCheckerList(raw_ostream &Out) const { - // Collect checkers enabled by the options. - CheckerInfoSet EnabledCheckers = getEnabledCheckers(); - for (const auto *i : EnabledCheckers) Out << i->FullName << '\n'; } From 0ca19efe7b557cc833c0d665f76a3c0d49421f86 Mon Sep 17 00:00:00 2001 From: Ram Nalamothu Date: Mon, 23 Mar 2020 21:26:02 +0530 Subject: [PATCH 02/59] Add AMDGPU MC unittests only when AMDGPU target is being built Fixes the build failures introduced by 24698e526f619271705fe72bcaa928be9bc82484 --- llvm/unittests/MC/CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/llvm/unittests/MC/CMakeLists.txt b/llvm/unittests/MC/CMakeLists.txt index 05d6410bd8f7..48c06183ab99 100644 --- a/llvm/unittests/MC/CMakeLists.txt +++ b/llvm/unittests/MC/CMakeLists.txt @@ -1,3 +1,9 @@ +foreach(t ${LLVM_TARGETS_TO_BUILD}) + if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${t}) + add_subdirectory(${t}) + endif() +endforeach() + set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} MC @@ -13,4 +19,3 @@ add_llvm_unittest(MCTests TargetRegistry.cpp ) -add_subdirectory(AMDGPU) From 7e10581e8c15af39e6f0820768c5d43587f9088d Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Mon, 23 Mar 2020 09:13:40 -0700 Subject: [PATCH 03/59] [lldb/testsuite] Skip part of TestSettings.py on windows The newly introduced tests for unsetting environment variables is failing on Windows. Skip the test there to allow investigation. It seems like setting inherit-env to false was never tested before. Could it be that the Windows process launcher doesn't honor this setting? --- lldb/test/API/commands/settings/TestSettings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/test/API/commands/settings/TestSettings.py b/lldb/test/API/commands/settings/TestSettings.py index 29360856a735..c0cdc085f129 100644 --- a/lldb/test/API/commands/settings/TestSettings.py +++ b/lldb/test/API/commands/settings/TestSettings.py @@ -286,6 +286,7 @@ def do_test_run_args_and_env_vars(self, use_launchsimple): "Environment variable 'MY_ENV_VAR' successfully passed."]) @skipIfRemote # it doesn't make sense to send host env to remote target + @skipIf(oslist=["windows"]) def test_pass_host_env_vars(self): """Test that the host env vars are passed to the launched process.""" self.build() From 3c84aca9b357f8c49eacf69a72c9281fb96dd72f Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Mon, 23 Mar 2020 11:37:40 -0400 Subject: [PATCH 04/59] [libc++] Bump Clang support for Clang 4 It's hard to imagine someone using a recent version of libc++ with a roughly 3 years old Clang. Since we're not testing libc++ with Clang 3.5 anyway, claiming support for it is somewhat of a lie. Note that we don't test Clang 4 either, however I have no reason to bump the requirement beyond Clang 4 at the moment, whereas removing Clang 3.5 allows simplifying the test suite. Differential Revision: https://reviews.llvm.org/D76618 --- libcxx/docs/index.rst | 2 +- .../new.delete/new.delete.array/new_align_val_t.pass.cpp | 3 --- .../new.delete.array/new_align_val_t_nothrow.pass.cpp | 3 --- .../new.delete.array/new_align_val_t_nothrow_replace.pass.cpp | 2 -- .../new.delete.array/new_align_val_t_replace.pass.cpp | 3 --- .../new.delete/new.delete.single/new_align_val_t.pass.cpp | 3 --- .../new.delete.single/new_align_val_t_nothrow.pass.cpp | 3 --- .../new_align_val_t_nothrow_replace.pass.cpp | 3 --- .../new.delete.single/new_align_val_t_replace.pass.cpp | 3 --- libcxx/utils/libcxx/test/config.py | 4 ---- 10 files changed, 1 insertion(+), 28 deletions(-) diff --git a/libcxx/docs/index.rst b/libcxx/docs/index.rst index 7abdb10cb77d..f763f3aa0f60 100644 --- a/libcxx/docs/index.rst +++ b/libcxx/docs/index.rst @@ -100,7 +100,7 @@ Linux i386, x86_64 Clang, GCC libc++abi The following minimum compiler versions are strongly recommended. -* Clang 3.5 and above +* Clang 4.0 and above * GCC 5.0 and above. The C++03 dialect is only supported for Clang compilers. diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t.pass.cpp index e303c820847f..edd4e52fe3be 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t.pass.cpp @@ -11,9 +11,6 @@ // asan and msan will not call the new handler. // UNSUPPORTED: sanitizer-new-delete -// FIXME change this to XFAIL. -// UNSUPPORTED: no-aligned-allocation && !gcc - // Aligned allocation was not provided before macosx10.14 and as a result we // get availability errors when the deployment target is older than macosx10.14. // However, AppleClang 10 (and older) don't trigger availability errors, and diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow.pass.cpp index ed7a53743f0e..91e3a1bf0654 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow.pass.cpp @@ -11,9 +11,6 @@ // asan and msan will not call the new handler. // UNSUPPORTED: sanitizer-new-delete -// FIXME turn this into an XFAIL -// UNSUPPORTED: no-aligned-allocation && !gcc - // Aligned allocation was not provided before macosx10.14 and as a result we // get availability errors when the deployment target is older than macosx10.14. // However, AppleClang 10 (and older) don't trigger availability errors, and diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow_replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow_replace.pass.cpp index 49aa2bce3ea2..5aa47a5bc236 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow_replace.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow_replace.pass.cpp @@ -31,8 +31,6 @@ // XFAIL: (apple-clang-9 || apple-clang-10) && with_system_cxx_lib=macosx10.8 // XFAIL: (apple-clang-9 || apple-clang-10) && with_system_cxx_lib=macosx10.7 -// XFAIL: no-aligned-allocation && !gcc - // On Windows libc++ doesn't provide its own definitions for new/delete // but instead depends on the ones in VCRuntime. However VCRuntime does not // yet provide aligned new/delete definitions so this test fails. diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_replace.pass.cpp index cb9a2ef7f6ca..3cc153ecb2a2 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_replace.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_replace.pass.cpp @@ -9,9 +9,6 @@ // UNSUPPORTED: c++98, c++03, c++11, c++14 // UNSUPPORTED: sanitizer-new-delete -// NOTE: GCC doesn't provide the -faligned-allocation flag to test for -// XFAIL: no-aligned-allocation && !gcc - // test operator new replacement #include diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t.pass.cpp index 0d96db5de485..f0da4d674615 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t.pass.cpp @@ -33,9 +33,6 @@ // asan and msan will not call the new handler. // UNSUPPORTED: sanitizer-new-delete -// FIXME turn this into an XFAIL -// UNSUPPORTED: no-aligned-allocation && !gcc - // On Windows libc++ doesn't provide its own definitions for new/delete // but instead depends on the ones in VCRuntime. However VCRuntime does not // yet provide aligned new/delete definitions so this test fails to compile/link. diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow.pass.cpp index 4b621f78a726..7edb003c2581 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow.pass.cpp @@ -33,9 +33,6 @@ // asan and msan will not call the new handler. // UNSUPPORTED: sanitizer-new-delete -// FIXME turn this into an XFAIL -// UNSUPPORTED: no-aligned-allocation && !gcc - // On Windows libc++ doesn't provide its own definitions for new/delete // but instead depends on the ones in VCRuntime. However VCRuntime does not // yet provide aligned new/delete definitions so this test fails to compile/link. diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow_replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow_replace.pass.cpp index 892eac205826..95931b715d9d 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow_replace.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow_replace.pass.cpp @@ -31,9 +31,6 @@ // XFAIL: (apple-clang-9 || apple-clang-10) && with_system_cxx_lib=macosx10.8 // XFAIL: (apple-clang-9 || apple-clang-10) && with_system_cxx_lib=macosx10.7 -// NOTE: gcc doesn't provide -faligned-allocation flag to test for -// XFAIL: no-aligned-allocation && !gcc - // On Windows libc++ doesn't provide its own definitions for new/delete // but instead depends on the ones in VCRuntime. However VCRuntime does not // yet provide aligned new/delete definitions so this test fails. diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_replace.pass.cpp index 32c27d5899ec..3a17266d1756 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_replace.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_replace.pass.cpp @@ -9,9 +9,6 @@ // UNSUPPORTED: c++98, c++03, c++11, c++14 // UNSUPPORTED: sanitizer-new-delete -// NOTE: GCC doesn't provide a -faligned-allocation flag -// XFAIL: no-aligned-allocation && !gcc - // test operator new replacement #include diff --git a/libcxx/utils/libcxx/test/config.py b/libcxx/utils/libcxx/test/config.py index cc7691402f2a..a9a353916a9c 100644 --- a/libcxx/utils/libcxx/test/config.py +++ b/libcxx/utils/libcxx/test/config.py @@ -452,10 +452,6 @@ def configure_features(self): if self.cxx.hasCompileFlag('-faligned-allocation'): self.config.available_features.add('-faligned-allocation') - else: - # FIXME remove this once more than just clang-4.0 support - # C++17 aligned allocation. - self.config.available_features.add('no-aligned-allocation') if self.cxx.hasCompileFlag('-fdelayed-template-parsing'): self.config.available_features.add('fdelayed-template-parsing') From e10af89d9917e934c44d0ae21af60cf2b68999bc Mon Sep 17 00:00:00 2001 From: David Green Date: Mon, 23 Mar 2020 12:39:00 +0000 Subject: [PATCH 05/59] [ARM] Extra VMOVN and VMULL tests. NFC --- llvm/test/CodeGen/Thumb2/mve-vmovnstore.ll | 541 +++++++++++++++++++++ llvm/test/CodeGen/Thumb2/mve-vmull.ll | 99 ++++ 2 files changed, 640 insertions(+) create mode 100644 llvm/test/CodeGen/Thumb2/mve-vmovnstore.ll diff --git a/llvm/test/CodeGen/Thumb2/mve-vmovnstore.ll b/llvm/test/CodeGen/Thumb2/mve-vmovnstore.ll new file mode 100644 index 000000000000..d8c8c48f3ba8 --- /dev/null +++ b/llvm/test/CodeGen/Thumb2/mve-vmovnstore.ll @@ -0,0 +1,541 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=thumbv8.1m.main-arm-none-eabi -mattr=+mve -verify-machineinstrs %s -o - | FileCheck %s + +define arm_aapcs_vfpcc void @vmovn32_trunc1(<4 x i32> %src1, <4 x i32> %src2, <8 x i16> *%dest) { +; CHECK-LABEL: vmovn32_trunc1: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s8, s2 +; CHECK-NEXT: vmov.f32 s9, s6 +; CHECK-NEXT: vmov.f32 s10, s3 +; CHECK-NEXT: vmov.f32 s11, s7 +; CHECK-NEXT: vstrh.32 q2, [r0, #8] +; CHECK-NEXT: vmov.f32 s8, s0 +; CHECK-NEXT: vmov.f32 s9, s4 +; CHECK-NEXT: vmov.f32 s10, s1 +; CHECK-NEXT: vmov.f32 s11, s5 +; CHECK-NEXT: vstrh.32 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %strided.vec = shufflevector <4 x i32> %src1, <4 x i32> %src2, <8 x i32> + %out = trunc <8 x i32> %strided.vec to <8 x i16> + store <8 x i16> %out, <8 x i16> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn32_trunc2(<4 x i32> %src1, <4 x i32> %src2, <8 x i16> *%dest) { +; CHECK-LABEL: vmovn32_trunc2: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s8, s6 +; CHECK-NEXT: vmov.f32 s9, s2 +; CHECK-NEXT: vmov.f32 s10, s7 +; CHECK-NEXT: vmov.f32 s11, s3 +; CHECK-NEXT: vstrh.32 q2, [r0, #8] +; CHECK-NEXT: vmov.f32 s8, s4 +; CHECK-NEXT: vmov.f32 s9, s0 +; CHECK-NEXT: vmov.f32 s10, s5 +; CHECK-NEXT: vmov.f32 s11, s1 +; CHECK-NEXT: vstrh.32 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %strided.vec = shufflevector <4 x i32> %src1, <4 x i32> %src2, <8 x i32> + %out = trunc <8 x i32> %strided.vec to <8 x i16> + store <8 x i16> %out, <8 x i16> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn16_trunc1(<8 x i16> %src1, <8 x i16> %src2, <16 x i8> *%dest) { +; CHECK-LABEL: vmovn16_trunc1: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.u16 r1, q0[4] +; CHECK-NEXT: vmov.16 q2[0], r1 +; CHECK-NEXT: vmov.u16 r1, q1[4] +; CHECK-NEXT: vmov.16 q2[1], r1 +; CHECK-NEXT: vmov.u16 r1, q0[5] +; CHECK-NEXT: vmov.16 q2[2], r1 +; CHECK-NEXT: vmov.u16 r1, q1[5] +; CHECK-NEXT: vmov.16 q2[3], r1 +; CHECK-NEXT: vmov.u16 r1, q0[6] +; CHECK-NEXT: vmov.16 q2[4], r1 +; CHECK-NEXT: vmov.u16 r1, q1[6] +; CHECK-NEXT: vmov.16 q2[5], r1 +; CHECK-NEXT: vmov.u16 r1, q0[7] +; CHECK-NEXT: vmov.16 q2[6], r1 +; CHECK-NEXT: vmov.u16 r1, q1[7] +; CHECK-NEXT: vmov.16 q2[7], r1 +; CHECK-NEXT: vmov.u16 r1, q0[0] +; CHECK-NEXT: vstrb.16 q2, [r0, #8] +; CHECK-NEXT: vmov.16 q2[0], r1 +; CHECK-NEXT: vmov.u16 r1, q1[0] +; CHECK-NEXT: vmov.16 q2[1], r1 +; CHECK-NEXT: vmov.u16 r1, q0[1] +; CHECK-NEXT: vmov.16 q2[2], r1 +; CHECK-NEXT: vmov.u16 r1, q1[1] +; CHECK-NEXT: vmov.16 q2[3], r1 +; CHECK-NEXT: vmov.u16 r1, q0[2] +; CHECK-NEXT: vmov.16 q2[4], r1 +; CHECK-NEXT: vmov.u16 r1, q1[2] +; CHECK-NEXT: vmov.16 q2[5], r1 +; CHECK-NEXT: vmov.u16 r1, q0[3] +; CHECK-NEXT: vmov.16 q2[6], r1 +; CHECK-NEXT: vmov.u16 r1, q1[3] +; CHECK-NEXT: vmov.16 q2[7], r1 +; CHECK-NEXT: vstrb.16 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %strided.vec = shufflevector <8 x i16> %src1, <8 x i16> %src2, <16 x i32> + %out = trunc <16 x i16> %strided.vec to <16 x i8> + store <16 x i8> %out, <16 x i8> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn16_trunc2(<8 x i16> %src1, <8 x i16> %src2, <16 x i8> *%dest) { +; CHECK-LABEL: vmovn16_trunc2: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.u16 r1, q1[4] +; CHECK-NEXT: vmov.16 q2[0], r1 +; CHECK-NEXT: vmov.u16 r1, q0[4] +; CHECK-NEXT: vmov.16 q2[1], r1 +; CHECK-NEXT: vmov.u16 r1, q1[5] +; CHECK-NEXT: vmov.16 q2[2], r1 +; CHECK-NEXT: vmov.u16 r1, q0[5] +; CHECK-NEXT: vmov.16 q2[3], r1 +; CHECK-NEXT: vmov.u16 r1, q1[6] +; CHECK-NEXT: vmov.16 q2[4], r1 +; CHECK-NEXT: vmov.u16 r1, q0[6] +; CHECK-NEXT: vmov.16 q2[5], r1 +; CHECK-NEXT: vmov.u16 r1, q1[7] +; CHECK-NEXT: vmov.16 q2[6], r1 +; CHECK-NEXT: vmov.u16 r1, q0[7] +; CHECK-NEXT: vmov.16 q2[7], r1 +; CHECK-NEXT: vmov.u16 r1, q1[0] +; CHECK-NEXT: vstrb.16 q2, [r0, #8] +; CHECK-NEXT: vmov.16 q2[0], r1 +; CHECK-NEXT: vmov.u16 r1, q0[0] +; CHECK-NEXT: vmov.16 q2[1], r1 +; CHECK-NEXT: vmov.u16 r1, q1[1] +; CHECK-NEXT: vmov.16 q2[2], r1 +; CHECK-NEXT: vmov.u16 r1, q0[1] +; CHECK-NEXT: vmov.16 q2[3], r1 +; CHECK-NEXT: vmov.u16 r1, q1[2] +; CHECK-NEXT: vmov.16 q2[4], r1 +; CHECK-NEXT: vmov.u16 r1, q0[2] +; CHECK-NEXT: vmov.16 q2[5], r1 +; CHECK-NEXT: vmov.u16 r1, q1[3] +; CHECK-NEXT: vmov.16 q2[6], r1 +; CHECK-NEXT: vmov.u16 r1, q0[3] +; CHECK-NEXT: vmov.16 q2[7], r1 +; CHECK-NEXT: vstrb.16 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %strided.vec = shufflevector <8 x i16> %src1, <8 x i16> %src2, <16 x i32> + %out = trunc <16 x i16> %strided.vec to <16 x i8> + store <16 x i8> %out, <16 x i8> *%dest, align 8 + ret void +} + + +define arm_aapcs_vfpcc void @vmovn64_t1(<2 x i64> %src1, <2 x i64> %src2, <2 x i64> *%dest) { +; CHECK-LABEL: vmovn64_t1: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s2, s4 +; CHECK-NEXT: vmov.f32 s3, s5 +; CHECK-NEXT: vstrw.32 q0, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <2 x i64> %src1, <2 x i64> %src2, <2 x i32> + store <2 x i64> %out, <2 x i64> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn64_t2(<2 x i64> %src1, <2 x i64> %src2, <2 x i64> *%dest) { +; CHECK-LABEL: vmovn64_t2: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s6, s0 +; CHECK-NEXT: vmov.f32 s7, s1 +; CHECK-NEXT: vstrw.32 q1, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <2 x i64> %src1, <2 x i64> %src2, <2 x i32> + store <2 x i64> %out, <2 x i64> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn64_b1(<2 x i64> %src1, <2 x i64> %src2, <2 x i64> *%dest) { +; CHECK-LABEL: vmovn64_b1: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s2, s6 +; CHECK-NEXT: vmov.f32 s3, s7 +; CHECK-NEXT: vstrw.32 q0, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <2 x i64> %src1, <2 x i64> %src2, <2 x i32> + store <2 x i64> %out, <2 x i64> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn64_b2(<2 x i64> %src1, <2 x i64> %src2, <2 x i64> *%dest) { +; CHECK-LABEL: vmovn64_b2: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s8, s6 +; CHECK-NEXT: vmov.f32 s9, s7 +; CHECK-NEXT: vmov.f32 s10, s0 +; CHECK-NEXT: vmov.f32 s11, s1 +; CHECK-NEXT: vstrw.32 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <2 x i64> %src1, <2 x i64> %src2, <2 x i32> + store <2 x i64> %out, <2 x i64> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn64_b3(<2 x i64> %src1, <2 x i64> %src2, <2 x i64> *%dest) { +; CHECK-LABEL: vmovn64_b3: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s8, s2 +; CHECK-NEXT: vmov.f32 s9, s3 +; CHECK-NEXT: vmov.f32 s10, s4 +; CHECK-NEXT: vmov.f32 s11, s5 +; CHECK-NEXT: vstrw.32 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <2 x i64> %src1, <2 x i64> %src2, <2 x i32> + store <2 x i64> %out, <2 x i64> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn64_b4(<2 x i64> %src1, <2 x i64> %src2, <2 x i64> *%dest) { +; CHECK-LABEL: vmovn64_b4: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s6, s2 +; CHECK-NEXT: vmov.f32 s7, s3 +; CHECK-NEXT: vstrw.32 q1, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <2 x i64> %src1, <2 x i64> %src2, <2 x i32> + store <2 x i64> %out, <2 x i64> *%dest, align 8 + ret void +} + + + +define arm_aapcs_vfpcc void @vmovn32_t1(<4 x i32> %src1, <4 x i32> %src2, <4 x i32> *%dest) { +; CHECK-LABEL: vmovn32_t1: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s1, s4 +; CHECK-NEXT: vmov.f32 s3, s6 +; CHECK-NEXT: vstrw.32 q0, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <4 x i32> %src1, <4 x i32> %src2, <4 x i32> + store <4 x i32> %out, <4 x i32> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn32_t2(<4 x i32> %src1, <4 x i32> %src2, <4 x i32> *%dest) { +; CHECK-LABEL: vmovn32_t2: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s5, s0 +; CHECK-NEXT: vmov.f32 s7, s2 +; CHECK-NEXT: vstrw.32 q1, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <4 x i32> %src1, <4 x i32> %src2, <4 x i32> + store <4 x i32> %out, <4 x i32> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn32_b1(<4 x i32> %src1, <4 x i32> %src2, <4 x i32> *%dest) { +; CHECK-LABEL: vmovn32_b1: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s1, s5 +; CHECK-NEXT: vmov.f32 s3, s7 +; CHECK-NEXT: vstrw.32 q0, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <4 x i32> %src1, <4 x i32> %src2, <4 x i32> + store <4 x i32> %out, <4 x i32> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn32_b2(<4 x i32> %src1, <4 x i32> %src2, <4 x i32> *%dest) { +; CHECK-LABEL: vmovn32_b2: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s8, s5 +; CHECK-NEXT: vmov.f32 s9, s0 +; CHECK-NEXT: vmov.f32 s10, s7 +; CHECK-NEXT: vmov.f32 s11, s2 +; CHECK-NEXT: vstrw.32 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <4 x i32> %src1, <4 x i32> %src2, <4 x i32> + store <4 x i32> %out, <4 x i32> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn32_b3(<4 x i32> %src1, <4 x i32> %src2, <4 x i32> *%dest) { +; CHECK-LABEL: vmovn32_b3: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s8, s1 +; CHECK-NEXT: vmov.f32 s9, s4 +; CHECK-NEXT: vmov.f32 s10, s3 +; CHECK-NEXT: vmov.f32 s11, s6 +; CHECK-NEXT: vstrw.32 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <4 x i32> %src1, <4 x i32> %src2, <4 x i32> + store <4 x i32> %out, <4 x i32> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn32_b4(<4 x i32> %src1, <4 x i32> %src2, <4 x i32> *%dest) { +; CHECK-LABEL: vmovn32_b4: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s5, s1 +; CHECK-NEXT: vmov.f32 s7, s3 +; CHECK-NEXT: vstrw.32 q1, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <4 x i32> %src1, <4 x i32> %src2, <4 x i32> + store <4 x i32> %out, <4 x i32> *%dest, align 8 + ret void +} + + + + +define arm_aapcs_vfpcc void @vmovn16_t1(<8 x i16> %src1, <8 x i16> %src2, <8 x i16> *%dest) { +; CHECK-LABEL: vmovn16_t1: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmovnt.i32 q0, q1 +; CHECK-NEXT: vstrw.32 q0, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <8 x i16> %src1, <8 x i16> %src2, <8 x i32> + store <8 x i16> %out, <8 x i16> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn16_t2(<8 x i16> %src1, <8 x i16> %src2, <8 x i16> *%dest) { +; CHECK-LABEL: vmovn16_t2: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmovnt.i32 q1, q0 +; CHECK-NEXT: vstrw.32 q1, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <8 x i16> %src1, <8 x i16> %src2, <8 x i32> + store <8 x i16> %out, <8 x i16> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn16_b1(<8 x i16> %src1, <8 x i16> %src2, <8 x i16> *%dest) { +; CHECK-LABEL: vmovn16_b1: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmovnb.i32 q1, q0 +; CHECK-NEXT: vstrw.32 q1, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <8 x i16> %src1, <8 x i16> %src2, <8 x i32> + store <8 x i16> %out, <8 x i16> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn16_b2(<8 x i16> %src1, <8 x i16> %src2, <8 x i16> *%dest) { +; CHECK-LABEL: vmovn16_b2: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.u16 r1, q1[1] +; CHECK-NEXT: vmov.16 q2[0], r1 +; CHECK-NEXT: vmov.u16 r1, q0[0] +; CHECK-NEXT: vmov.16 q2[1], r1 +; CHECK-NEXT: vmov.u16 r1, q1[3] +; CHECK-NEXT: vmov.16 q2[2], r1 +; CHECK-NEXT: vmov.u16 r1, q0[2] +; CHECK-NEXT: vmov.16 q2[3], r1 +; CHECK-NEXT: vmov.u16 r1, q1[5] +; CHECK-NEXT: vmov.16 q2[4], r1 +; CHECK-NEXT: vmov.u16 r1, q0[4] +; CHECK-NEXT: vmov.16 q2[5], r1 +; CHECK-NEXT: vmov.u16 r1, q1[7] +; CHECK-NEXT: vmov.16 q2[6], r1 +; CHECK-NEXT: vmov.u16 r1, q0[6] +; CHECK-NEXT: vmov.16 q2[7], r1 +; CHECK-NEXT: vstrw.32 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <8 x i16> %src1, <8 x i16> %src2, <8 x i32> + store <8 x i16> %out, <8 x i16> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn16_b3(<8 x i16> %src1, <8 x i16> %src2, <8 x i16> *%dest) { +; CHECK-LABEL: vmovn16_b3: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.u16 r1, q0[1] +; CHECK-NEXT: vmov.16 q2[0], r1 +; CHECK-NEXT: vmov.u16 r1, q1[0] +; CHECK-NEXT: vmov.16 q2[1], r1 +; CHECK-NEXT: vmov.u16 r1, q0[3] +; CHECK-NEXT: vmov.16 q2[2], r1 +; CHECK-NEXT: vmov.u16 r1, q1[2] +; CHECK-NEXT: vmov.16 q2[3], r1 +; CHECK-NEXT: vmov.u16 r1, q0[5] +; CHECK-NEXT: vmov.16 q2[4], r1 +; CHECK-NEXT: vmov.u16 r1, q1[4] +; CHECK-NEXT: vmov.16 q2[5], r1 +; CHECK-NEXT: vmov.u16 r1, q0[7] +; CHECK-NEXT: vmov.16 q2[6], r1 +; CHECK-NEXT: vmov.u16 r1, q1[6] +; CHECK-NEXT: vmov.16 q2[7], r1 +; CHECK-NEXT: vstrw.32 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <8 x i16> %src1, <8 x i16> %src2, <8 x i32> + store <8 x i16> %out, <8 x i16> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn16_b4(<8 x i16> %src1, <8 x i16> %src2, <8 x i16> *%dest) { +; CHECK-LABEL: vmovn16_b4: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmovnb.i32 q0, q1 +; CHECK-NEXT: vstrw.32 q0, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <8 x i16> %src1, <8 x i16> %src2, <8 x i32> + store <8 x i16> %out, <8 x i16> *%dest, align 8 + ret void +} + + +define arm_aapcs_vfpcc void @vmovn8_b1(<16 x i8> %src1, <16 x i8> %src2, <16 x i8> *%dest) { +; CHECK-LABEL: vmovn8_b1: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmovnt.i16 q0, q1 +; CHECK-NEXT: vstrw.32 q0, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <16 x i8> %src1, <16 x i8> %src2, <16 x i32> + store <16 x i8> %out, <16 x i8> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn8_b2(<16 x i8> %src1, <16 x i8> %src2, <16 x i8> *%dest) { +; CHECK-LABEL: vmovn8_b2: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmovnt.i16 q1, q0 +; CHECK-NEXT: vstrw.32 q1, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <16 x i8> %src1, <16 x i8> %src2, <16 x i32> + store <16 x i8> %out, <16 x i8> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn8_t1(<16 x i8> %src1, <16 x i8> %src2, <16 x i8> *%dest) { +; CHECK-LABEL: vmovn8_t1: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmovnb.i16 q1, q0 +; CHECK-NEXT: vstrw.32 q1, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <16 x i8> %src1, <16 x i8> %src2, <16 x i32> + store <16 x i8> %out, <16 x i8> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn8_t2(<16 x i8> %src1, <16 x i8> %src2, <16 x i8> *%dest) { +; CHECK-LABEL: vmovn8_t2: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.u8 r1, q1[1] +; CHECK-NEXT: vmov.8 q2[0], r1 +; CHECK-NEXT: vmov.u8 r1, q0[0] +; CHECK-NEXT: vmov.8 q2[1], r1 +; CHECK-NEXT: vmov.u8 r1, q1[3] +; CHECK-NEXT: vmov.8 q2[2], r1 +; CHECK-NEXT: vmov.u8 r1, q0[2] +; CHECK-NEXT: vmov.8 q2[3], r1 +; CHECK-NEXT: vmov.u8 r1, q1[5] +; CHECK-NEXT: vmov.8 q2[4], r1 +; CHECK-NEXT: vmov.u8 r1, q0[4] +; CHECK-NEXT: vmov.8 q2[5], r1 +; CHECK-NEXT: vmov.u8 r1, q1[7] +; CHECK-NEXT: vmov.8 q2[6], r1 +; CHECK-NEXT: vmov.u8 r1, q0[6] +; CHECK-NEXT: vmov.8 q2[7], r1 +; CHECK-NEXT: vmov.u8 r1, q1[9] +; CHECK-NEXT: vmov.8 q2[8], r1 +; CHECK-NEXT: vmov.u8 r1, q0[8] +; CHECK-NEXT: vmov.8 q2[9], r1 +; CHECK-NEXT: vmov.u8 r1, q1[11] +; CHECK-NEXT: vmov.8 q2[10], r1 +; CHECK-NEXT: vmov.u8 r1, q0[10] +; CHECK-NEXT: vmov.8 q2[11], r1 +; CHECK-NEXT: vmov.u8 r1, q1[13] +; CHECK-NEXT: vmov.8 q2[12], r1 +; CHECK-NEXT: vmov.u8 r1, q0[12] +; CHECK-NEXT: vmov.8 q2[13], r1 +; CHECK-NEXT: vmov.u8 r1, q1[15] +; CHECK-NEXT: vmov.8 q2[14], r1 +; CHECK-NEXT: vmov.u8 r1, q0[14] +; CHECK-NEXT: vmov.8 q2[15], r1 +; CHECK-NEXT: vstrw.32 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <16 x i8> %src1, <16 x i8> %src2, <16 x i32> + store <16 x i8> %out, <16 x i8> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn8_t3(<16 x i8> %src1, <16 x i8> %src2, <16 x i8> *%dest) { +; CHECK-LABEL: vmovn8_t3: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.u8 r1, q0[1] +; CHECK-NEXT: vmov.8 q2[0], r1 +; CHECK-NEXT: vmov.u8 r1, q1[0] +; CHECK-NEXT: vmov.8 q2[1], r1 +; CHECK-NEXT: vmov.u8 r1, q0[3] +; CHECK-NEXT: vmov.8 q2[2], r1 +; CHECK-NEXT: vmov.u8 r1, q1[2] +; CHECK-NEXT: vmov.8 q2[3], r1 +; CHECK-NEXT: vmov.u8 r1, q0[5] +; CHECK-NEXT: vmov.8 q2[4], r1 +; CHECK-NEXT: vmov.u8 r1, q1[4] +; CHECK-NEXT: vmov.8 q2[5], r1 +; CHECK-NEXT: vmov.u8 r1, q0[7] +; CHECK-NEXT: vmov.8 q2[6], r1 +; CHECK-NEXT: vmov.u8 r1, q1[6] +; CHECK-NEXT: vmov.8 q2[7], r1 +; CHECK-NEXT: vmov.u8 r1, q0[9] +; CHECK-NEXT: vmov.8 q2[8], r1 +; CHECK-NEXT: vmov.u8 r1, q1[8] +; CHECK-NEXT: vmov.8 q2[9], r1 +; CHECK-NEXT: vmov.u8 r1, q0[11] +; CHECK-NEXT: vmov.8 q2[10], r1 +; CHECK-NEXT: vmov.u8 r1, q1[10] +; CHECK-NEXT: vmov.8 q2[11], r1 +; CHECK-NEXT: vmov.u8 r1, q0[13] +; CHECK-NEXT: vmov.8 q2[12], r1 +; CHECK-NEXT: vmov.u8 r1, q1[12] +; CHECK-NEXT: vmov.8 q2[13], r1 +; CHECK-NEXT: vmov.u8 r1, q0[15] +; CHECK-NEXT: vmov.8 q2[14], r1 +; CHECK-NEXT: vmov.u8 r1, q1[14] +; CHECK-NEXT: vmov.8 q2[15], r1 +; CHECK-NEXT: vstrw.32 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <16 x i8> %src1, <16 x i8> %src2, <16 x i32> + store <16 x i8> %out, <16 x i8> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn8_t4(<16 x i8> %src1, <16 x i8> %src2, <16 x i8> *%dest) { +; CHECK-LABEL: vmovn8_t4: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmovnb.i16 q0, q1 +; CHECK-NEXT: vstrw.32 q0, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <16 x i8> %src1, <16 x i8> %src2, <16 x i32> + store <16 x i8> %out, <16 x i8> *%dest, align 8 + ret void +} diff --git a/llvm/test/CodeGen/Thumb2/mve-vmull.ll b/llvm/test/CodeGen/Thumb2/mve-vmull.ll index b7b28068f528..c1e720fa3ab6 100644 --- a/llvm/test/CodeGen/Thumb2/mve-vmull.ll +++ b/llvm/test/CodeGen/Thumb2/mve-vmull.ll @@ -1,6 +1,105 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc -mtriple=thumbv8.1m.main-arm-none-eabi -mattr=+mve -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK +define arm_aapcs_vfpcc <2 x i64> @sext_02(<4 x i32> %src1, <4 x i32> %src2) { +; CHECK-LABEL: sext_02: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov r0, s4 +; CHECK-NEXT: vmov r1, s0 +; CHECK-NEXT: smull r0, r1, r1, r0 +; CHECK-NEXT: vmov.32 q2[0], r0 +; CHECK-NEXT: vmov r0, s6 +; CHECK-NEXT: vmov.32 q2[1], r1 +; CHECK-NEXT: vmov r1, s2 +; CHECK-NEXT: smull r0, r1, r1, r0 +; CHECK-NEXT: vmov.32 q2[2], r0 +; CHECK-NEXT: vmov.32 q2[3], r1 +; CHECK-NEXT: vmov q0, q2 +; CHECK-NEXT: bx lr +entry: + %shuf1 = shufflevector <4 x i32> %src1, <4 x i32> undef, <2 x i32> + %out1 = sext <2 x i32> %shuf1 to <2 x i64> + %shuf2 = shufflevector <4 x i32> %src2, <4 x i32> undef, <2 x i32> + %out2 = sext <2 x i32> %shuf2 to <2 x i64> + %out = mul <2 x i64> %out1, %out2 + ret <2 x i64> %out +} + +define arm_aapcs_vfpcc <2 x i64> @sext_13(<4 x i32> %src1, <4 x i32> %src2) { +; CHECK-LABEL: sext_13: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vrev64.32 q2, q1 +; CHECK-NEXT: vrev64.32 q1, q0 +; CHECK-NEXT: vmov r0, s8 +; CHECK-NEXT: vmov r1, s4 +; CHECK-NEXT: smull r0, r1, r1, r0 +; CHECK-NEXT: vmov.32 q0[0], r0 +; CHECK-NEXT: vmov r0, s10 +; CHECK-NEXT: vmov.32 q0[1], r1 +; CHECK-NEXT: vmov r1, s6 +; CHECK-NEXT: smull r0, r1, r1, r0 +; CHECK-NEXT: vmov.32 q0[2], r0 +; CHECK-NEXT: vmov.32 q0[3], r1 +; CHECK-NEXT: bx lr +entry: + %shuf1 = shufflevector <4 x i32> %src1, <4 x i32> undef, <2 x i32> + %out1 = sext <2 x i32> %shuf1 to <2 x i64> + %shuf2 = shufflevector <4 x i32> %src2, <4 x i32> undef, <2 x i32> + %out2 = sext <2 x i32> %shuf2 to <2 x i64> + %out = mul <2 x i64> %out1, %out2 + ret <2 x i64> %out +} + +define arm_aapcs_vfpcc <2 x i64> @zext_02(<4 x i32> %src1, <4 x i32> %src2) { +; CHECK-LABEL: zext_02: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov r0, s4 +; CHECK-NEXT: vmov r1, s0 +; CHECK-NEXT: umull r0, r1, r1, r0 +; CHECK-NEXT: vmov.32 q2[0], r0 +; CHECK-NEXT: vmov r0, s6 +; CHECK-NEXT: vmov.32 q2[1], r1 +; CHECK-NEXT: vmov r1, s2 +; CHECK-NEXT: umull r0, r1, r1, r0 +; CHECK-NEXT: vmov.32 q2[2], r0 +; CHECK-NEXT: vmov.32 q2[3], r1 +; CHECK-NEXT: vmov q0, q2 +; CHECK-NEXT: bx lr +entry: + %shuf1 = shufflevector <4 x i32> %src1, <4 x i32> undef, <2 x i32> + %out1 = zext <2 x i32> %shuf1 to <2 x i64> + %shuf2 = shufflevector <4 x i32> %src2, <4 x i32> undef, <2 x i32> + %out2 = zext <2 x i32> %shuf2 to <2 x i64> + %out = mul <2 x i64> %out1, %out2 + ret <2 x i64> %out +} + +define arm_aapcs_vfpcc <2 x i64> @zext_13(<4 x i32> %src1, <4 x i32> %src2) { +; CHECK-LABEL: zext_13: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vrev64.32 q2, q1 +; CHECK-NEXT: vrev64.32 q1, q0 +; CHECK-NEXT: vmov r0, s8 +; CHECK-NEXT: vmov r1, s4 +; CHECK-NEXT: umull r0, r1, r1, r0 +; CHECK-NEXT: vmov.32 q0[0], r0 +; CHECK-NEXT: vmov r0, s10 +; CHECK-NEXT: vmov.32 q0[1], r1 +; CHECK-NEXT: vmov r1, s6 +; CHECK-NEXT: umull r0, r1, r1, r0 +; CHECK-NEXT: vmov.32 q0[2], r0 +; CHECK-NEXT: vmov.32 q0[3], r1 +; CHECK-NEXT: bx lr +entry: + %shuf1 = shufflevector <4 x i32> %src1, <4 x i32> undef, <2 x i32> + %out1 = zext <2 x i32> %shuf1 to <2 x i64> + %shuf2 = shufflevector <4 x i32> %src2, <4 x i32> undef, <2 x i32> + %out2 = zext <2 x i32> %shuf2 to <2 x i64> + %out = mul <2 x i64> %out1, %out2 + ret <2 x i64> %out +} + + define arm_aapcs_vfpcc <4 x i32> @sext_0246(<8 x i16> %src1, <8 x i16> %src2) { ; CHECK-LABEL: sext_0246: ; CHECK: @ %bb.0: @ %entry From c1f8595fe5b856222418e2de547f0e346d84ac84 Mon Sep 17 00:00:00 2001 From: Alexandre Ganea Date: Mon, 23 Mar 2020 12:19:07 -0400 Subject: [PATCH 06/59] [Support] Silence warning in Path unittests when compiling with clang-cl warning: comparison of integers of different signs: 'const unsigned long long' and 'const int' [-Wsign-compare] --- llvm/unittests/Support/Path.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/unittests/Support/Path.cpp b/llvm/unittests/Support/Path.cpp index affba601a8bc..671966b52dd0 100644 --- a/llvm/unittests/Support/Path.cpp +++ b/llvm/unittests/Support/Path.cpp @@ -1895,7 +1895,7 @@ TEST_F(FileSystemTest, widenPath) { // Result should not start with the long path prefix. EXPECT_TRUE(std::wmemcmp(Result.data(), LongPathPrefix.c_str(), LongPathPrefix.size()) != 0); - EXPECT_EQ(Result.size(), MAX_PATH - 1); + EXPECT_EQ(Result.size(), (size_t)MAX_PATH - 1); // Add another Pi to exceed the MAX_PATH limit. Input += Pi; @@ -1921,7 +1921,7 @@ TEST_F(FileSystemTest, widenPath) { // Result should not start with the long path prefix. EXPECT_TRUE(std::wmemcmp(Result.data(), LongPathPrefix.c_str(), LongPathPrefix.size()) != 0); - EXPECT_EQ(Result.size(), MAX_PATH - 1); + EXPECT_EQ(Result.size(), (size_t)MAX_PATH - 1); // Extend the directory name so the input exceeds the MAX_PATH limit. DirName += DirChar; From ccc0d351817bedf3a979144238ffb8e2797285d4 Mon Sep 17 00:00:00 2001 From: Adam Balogh Date: Wed, 18 Mar 2020 20:15:20 +0100 Subject: [PATCH 07/59] [Analyzer] IteratorRangeChecker verify `std::advance()`, `std::prev()` and `std::next()` Upon calling one of the functions `std::advance()`, `std::prev()` and `std::next()` iterators could get out of their valid range which leads to undefined behavior. If all these funcions are inlined together with the functions they call internally (e.g. `__advance()` called by `std::advance()` in some implementations) the error is detected by `IteratorRangeChecker` but the bug location is inside the STL implementation. Even worse, if the budget runs out and one of the calls is not inlined the bug remains undetected. This patch fixes this behavior: all the bugs are detected at the point of the STL function invocation. Differential Revision: https://reviews.llvm.org/D76379 --- .../Checkers/IteratorRangeChecker.cpp | 70 ++- clang/test/Analysis/iterator-range.cpp | 417 ++++++++++++++++++ 2 files changed, 470 insertions(+), 17 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp index bd8b84d464b6..f9b493bf9bb0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp @@ -31,18 +31,30 @@ class IteratorRangeChecker std::unique_ptr OutOfRangeBugType; - void verifyDereference(CheckerContext &C, const SVal &Val) const; - void verifyIncrement(CheckerContext &C, const SVal &Iter) const; - void verifyDecrement(CheckerContext &C, const SVal &Iter) const; + void verifyDereference(CheckerContext &C, SVal Val) const; + void verifyIncrement(CheckerContext &C, SVal Iter) const; + void verifyDecrement(CheckerContext &C, SVal Iter) const; void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op, - const SVal &LHS, const SVal &RHS) const; - void reportBug(const StringRef &Message, const SVal &Val, - CheckerContext &C, ExplodedNode *ErrNode) const; + SVal LHS, SVal RHS) const; + void verifyAdvance(CheckerContext &C, SVal LHS, SVal RHS) const; + void verifyPrev(CheckerContext &C, SVal LHS, SVal RHS) const; + void verifyNext(CheckerContext &C, SVal LHS, SVal RHS) const; + void reportBug(const StringRef &Message, SVal Val, CheckerContext &C, + ExplodedNode *ErrNode) const; + public: IteratorRangeChecker(); void checkPreCall(const CallEvent &Call, CheckerContext &C) const; + using AdvanceFn = void (IteratorRangeChecker::*)(CheckerContext &, SVal, + SVal) const; + + CallDescriptionMap AdvanceFunctions = { + {{{"std", "advance"}, 2}, &IteratorRangeChecker::verifyAdvance}, + {{{"std", "prev"}, 2}, &IteratorRangeChecker::verifyPrev}, + {{{"std", "next"}, 2}, &IteratorRangeChecker::verifyNext}, + }; }; bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos); @@ -107,11 +119,23 @@ void IteratorRangeChecker::checkPreCall(const CallEvent &Call, verifyDereference(C, Call.getArgSVal(0)); } } + } else { + const AdvanceFn *Verifier = AdvanceFunctions.lookup(Call); + if (Verifier) { + if (Call.getNumArgs() > 1) { + (this->**Verifier)(C, Call.getArgSVal(0), Call.getArgSVal(1)); + } else { + auto &BVF = C.getSValBuilder().getBasicValueFactory(); + (this->**Verifier)( + C, Call.getArgSVal(0), + nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); + } + } } } void IteratorRangeChecker::verifyDereference(CheckerContext &C, - const SVal &Val) const { + SVal Val) const { auto State = C.getState(); const auto *Pos = getIteratorPosition(State, Val); if (Pos && isPastTheEnd(State, *Pos)) { @@ -123,24 +147,21 @@ void IteratorRangeChecker::verifyDereference(CheckerContext &C, } } -void IteratorRangeChecker::verifyIncrement(CheckerContext &C, - const SVal &Iter) const { +void IteratorRangeChecker::verifyIncrement(CheckerContext &C, SVal Iter) const { auto &BVF = C.getSValBuilder().getBasicValueFactory(); verifyRandomIncrOrDecr(C, OO_Plus, Iter, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); } -void IteratorRangeChecker::verifyDecrement(CheckerContext &C, - const SVal &Iter) const { +void IteratorRangeChecker::verifyDecrement(CheckerContext &C, SVal Iter) const { auto &BVF = C.getSValBuilder().getBasicValueFactory(); verifyRandomIncrOrDecr(C, OO_Minus, Iter, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); } void IteratorRangeChecker::verifyRandomIncrOrDecr(CheckerContext &C, - OverloadedOperatorKind Op, - const SVal &LHS, - const SVal &RHS) const { + OverloadedOperatorKind Op, + SVal LHS, SVal RHS) const { auto State = C.getState(); auto Value = RHS; @@ -180,9 +201,24 @@ void IteratorRangeChecker::verifyRandomIncrOrDecr(CheckerContext &C, } } -void IteratorRangeChecker::reportBug(const StringRef &Message, - const SVal &Val, CheckerContext &C, - ExplodedNode *ErrNode) const { +void IteratorRangeChecker::verifyAdvance(CheckerContext &C, SVal LHS, + SVal RHS) const { + verifyRandomIncrOrDecr(C, OO_PlusEqual, LHS, RHS); +} + +void IteratorRangeChecker::verifyPrev(CheckerContext &C, SVal LHS, + SVal RHS) const { + verifyRandomIncrOrDecr(C, OO_Minus, LHS, RHS); +} + +void IteratorRangeChecker::verifyNext(CheckerContext &C, SVal LHS, + SVal RHS) const { + verifyRandomIncrOrDecr(C, OO_Plus, LHS, RHS); +} + +void IteratorRangeChecker::reportBug(const StringRef &Message, SVal Val, + CheckerContext &C, + ExplodedNode *ErrNode) const { auto R = std::make_unique(*OutOfRangeBugType, Message, ErrNode); R->markInteresting(Val); diff --git a/clang/test/Analysis/iterator-range.cpp b/clang/test/Analysis/iterator-range.cpp index 71af17a1f3d0..babcfdec99d6 100644 --- a/clang/test/Analysis/iterator-range.cpp +++ b/clang/test/Analysis/iterator-range.cpp @@ -359,6 +359,423 @@ void subscript_positive_end(const std::vector &V) { auto j = i[1]; // expected-warning{{Past-the-end iterator dereferenced}} FIXME: expect warning Iterator incremented behind the past-the-end iterator } +// +// std::advance() +// + +// std::advance() by +1 + +void advance_plus_1_begin(const std::vector &V) { + auto i = V.begin(); + std::advance(i, 1); // no-warning +} + +void advance_plus_1_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + std::advance(i, 1); // no-warning +} + +void advance_plus_1_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + std::advance(i, 1); // no-warning +} + +void advance_plus_1_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + std::advance(i, 1); // no-warning +} + +void advance_plus_1_end(const std::vector &V) { + auto i = V.end(); + std::advance(i, 1); // expected-warning{{Iterator incremented behind the past-the-end iterator}} +} + +// std::advance() by -1 + +void advance_minus_1_begin(const std::vector &V) { + auto i = V.begin(); + std::advance(i, -1); // expected-warning{{Iterator decremented ahead of its valid range}} +} + +void advance_minus_1_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + std::advance(i, -1); // no-warning +} + +void advance_minus_1_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + std::advance(i, -1); // no-warning +} + +void advance_minus_1_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + std::advance(i, -1); // no-warning +} + +void advance_minus_1_end(const std::vector &V) { + auto i = V.end(); + std::advance(i, -1); // no-warning +} + +// std::advance() by +2 + +void advance_plus_2_begin(const std::vector &V) { + auto i = V.begin(); + std::advance(i, 2); // no-warning +} + +void advance_plus_2_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + std::advance(i, 2); // no-warning +} + +void advance_plus_2_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + std::advance(i, 2); // no-warning +} + +void advance_plus_2_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + std::advance(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}} +} + +void advance_plus_2_end(const std::vector &V) { + auto i = V.end(); + std::advance(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}} +} + +// std::advance() by -2 + +void advance_minus_2_begin(const std::vector &V) { + auto i = V.begin(); + std::advance(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}} +} + +void advance_minus_2_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + std::advance(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}} +} + +void advance_minus_2_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + std::advance(i, -2); // no-warning +} + +void advance_minus_2_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + std::advance(i, -2); // no-warning +} + +void advance_minus_2_end(const std::vector &V) { + auto i = V.end(); + std::advance(i, -2); // no-warning +} + +// std::advance() by 0 + +void advance_0_begin(const std::vector &V) { + auto i = V.begin(); + std::advance(i, 0); // no-warning +} + +void advance_0_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + std::advance(i, 0); // no-warning +} + +void advance_0_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + std::advance(i, 0); // no-warning +} + +void advance_0_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + std::advance(i, 0); // no-warning +} + +void advance_0_end(const std::vector &V) { + auto i = V.end(); + std::advance(i, 0); // no-warning +} + +// +// std::next() +// + +// std::next() by +1 (default) + +void next_plus_1_begin(const std::vector &V) { + auto i = V.begin(); + auto j = std::next(i); // no-warning +} + +void next_plus_1_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = std::next(i); // no-warning +} + +void next_plus_1_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = std::next(i); // no-warning +} + +void next_plus_1_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = std::next(i); // no-warning +} + +void next_plus_1_end(const std::vector &V) { + auto i = V.end(); + auto j = std::next(i); // expected-warning{{Iterator incremented behind the past-the-end iterator}} +} + +// std::next() by -1 + +void next_minus_1_begin(const std::vector &V) { + auto i = V.begin(); + auto j = std::next(i, -1); // expected-warning{{Iterator decremented ahead of its valid range}} +} + +void next_minus_1_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = std::next(i, -1); // no-warning +} + +void next_minus_1_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = std::next(i, -1); // no-warning +} + +void next_minus_1_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = std::next(i, -1); // no-warning +} + +void next_minus_1_end(const std::vector &V) { + auto i = V.end(); + auto j = std::next(i, -1); // no-warning +} + +// std::next() by +2 + +void next_plus_2_begin(const std::vector &V) { + auto i = V.begin(); + auto j = std::next(i, 2); // no-warning +} + +void next_plus_2_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = std::next(i, 2); // no-warning +} + +void next_plus_2_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = std::next(i, 2); // no-warning +} + +void next_plus_2_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = std::next(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}} +} + +void next_plus_2_end(const std::vector &V) { + auto i = V.end(); + auto j = std::next(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}} +} + +// std::next() by -2 + +void next_minus_2_begin(const std::vector &V) { + auto i = V.begin(); + auto j = std::next(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}} +} + +void next_minus_2_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = std::next(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}} +} + +void next_minus_2_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = std::next(i, -2); // no-warning +} + +void next_minus_2_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = std::next(i, -2); // no-warning +} + +void next_minus_2_end(const std::vector &V) { + auto i = V.end(); + auto j = std::next(i, -2); // no-warning +} + +// std::next() by 0 + +void next_0_begin(const std::vector &V) { + auto i = V.begin(); + auto j = std::next(i, 0); // no-warning +} + +void next_0_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = std::next(i, 0); // no-warning +} + +void next_0_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = std::next(i, 0); // no-warning +} + +void next_0_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = std::next(i, 0); // no-warning +} + +void next_0_end(const std::vector &V) { + auto i = V.end(); + auto j = std::next(i, 0); // no-warning +} + +// +// std::prev() +// + +// std::prev() by +1 (default) + +void prev_plus_1_begin(const std::vector &V) { + auto i = V.begin(); + auto j = std::prev(i); // expected-warning{{Iterator decremented ahead of its valid range}} +} + +void prev_plus_1_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = std::prev(i); // no-warning +} + +void prev_plus_1_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = std::prev(i); // no-warning +} + +void prev_plus_1_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = std::prev(i); // no-warning +} + +void prev_plus_1_end(const std::vector &V) { + auto i = V.end(); + auto j = std::prev(i); // no-warning +} + +// std::prev() by -1 + +void prev_minus_1_begin(const std::vector &V) { + auto i = V.begin(); + auto j = std::prev(i, -1); // no-warning +} + +void prev_minus_1_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = std::prev(i, -1); // no-warning +} + +void prev_minus_1_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = std::prev(i, -1); // no-warning +} + +void prev_minus_1_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = std::prev(i, -1); // no-warning +} + +void prev_minus_1_end(const std::vector &V) { + auto i = V.end(); + auto j = std::prev(i, -1); // expected-warning{{Iterator incremented behind the past-the-end iterator}} +} + +// std::prev() by +2 + +void prev_plus_2_begin(const std::vector &V) { + auto i = V.begin(); + auto j = std::prev(i, 2); // expected-warning{{Iterator decremented ahead of its valid range}} +} + +void prev_plus_2_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = std::prev(i, 2); // expected-warning{{Iterator decremented ahead of its valid range}} +} + +void prev_plus_2_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = std::prev(i, 2); // no-warning +} + +void prev_plus_2_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = std::prev(i, 2); // no-warning +} + +void prev_plus_2_end(const std::vector &V) { + auto i = V.end(); + auto j = std::prev(i, 2); // no-warning +} + +// std::prev() by -2 + +void prev_minus_2_begin(const std::vector &V) { + auto i = V.begin(); + auto j = std::prev(i, -2); // no-warning +} + +void prev_minus_2_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = std::prev(i, -2); // no-warning +} + +void prev_minus_2_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = std::prev(i, -2); // no-warning +} + +void prev_minus_2_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = std::prev(i, -2); // expected-warning{{Iterator incremented behind the past-the-end iterator}} +} + +void prev_minus_2_end(const std::vector &V) { + auto i = V.end(); + auto j = std::prev(i, -2); // expected-warning{{Iterator incremented behind the past-the-end iterator}} +} + +// std::prev() by 0 + +void prev_0_begin(const std::vector &V) { + auto i = V.begin(); + auto j = std::prev(i, 0); // no-warning +} + +void prev_0_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = std::prev(i, 0); // no-warning +} + +void prev_0_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = std::prev(i, 0); // no-warning +} + +void prev_0_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = std::prev(i, 0); // no-warning +} + +void prev_0_end(const std::vector &V) { + auto i = V.end(); + auto j = std::prev(i, 0); // no-warning +} + // // Structure member dereference operators // From 0a076f2660be13d2b5d0683f2dda2963317aecd3 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Mon, 23 Mar 2020 09:27:49 -0700 Subject: [PATCH 08/59] [ELF][test] Clean text-section-prefix.s --- lld/test/ELF/text-section-prefix.s | 42 ++++++++++++++++-------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/lld/test/ELF/text-section-prefix.s b/lld/test/ELF/text-section-prefix.s index e39536da387d..e20828ab26aa 100644 --- a/lld/test/ELF/text-section-prefix.s +++ b/lld/test/ELF/text-section-prefix.s @@ -1,39 +1,41 @@ # REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: ld.lld -z keep-text-section-prefix %t -o %t2 -# RUN: llvm-readelf -l %t2 | FileCheck %s -# RUN: ld.lld %t -o %t3 -# RUN: llvm-readelf -l %t3 | FileCheck --check-prefix=CHECKNO %s -# RUN: ld.lld -z nokeep-text-section-prefix %t -o %t4 -# RUN: llvm-readelf -l %t4 | FileCheck --check-prefix=CHECKNO %s - -# CHECK: .text -# CHECK: .text.hot -# CHECK: .text.startup -# CHECK: .text.exit -# CHECK: .text.unlikely -# CHECKNO: .text -# CHECKNO-NOT: .text.hot +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o +# RUN: ld.lld %t.o -o %t1 +# RUN: llvm-readelf -S %t1 | FileCheck --check-prefix=NOKEEP %s +# RUN: ld.lld -z nokeep-text-section-prefix %t.o -o %t2 +# RUN: cmp %t1 %t2 +# RUN: ld.lld -z keep-text-section-prefix %t.o -o %t.keep +# RUN: llvm-readelf -S %t.keep | FileCheck --check-prefix=KEEP %s + +# KEEP: [ 1] .text +# KEEP-NEXT: [ 2] .text.hot +# KEEP-NEXT: [ 3] .text.startup +# KEEP-NEXT: [ 4] .text.exit +# KEEP-NEXT: [ 5] .text.unlikely + +# NOKEEP: [ 1] .text +# NOKEEP-NOT: .text + +# RUN: echo 'SECTIONS {}' > %t.lds +# RUN: ld.lld -T %t.lds -z keep-text-section-prefix %t.o -o %t.script +# RUN: llvm-readelf -S %t.script | FileCheck --check-prefix=KEEP %s + +.globl _start _start: ret .section .text.f,"ax" -f: nop .section .text.hot.f_hot,"ax" -f_hot: nop .section .text.startup.f_startup,"ax" -f_startup: nop .section .text.exit.f_exit,"ax" -f_exit: nop .section .text.unlikely.f_unlikely,"ax" -f_unlikely: nop From ff2f5097ed448bb4fdd25c7f5ebf4ad70a8af484 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Mon, 23 Mar 2020 17:41:52 +0100 Subject: [PATCH 09/59] [Attributor] Fold single-use variable into assert Fixes unused variable warning in Release builds. --- llvm/lib/Transforms/IPO/Attributor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp index 2111f9ffac42..445ef3a5f4ce 100644 --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -8661,9 +8661,9 @@ static bool runAttributorOnFunctions(InformationCache &InfoCache, A.identifyDefaultAbstractAttributes(*F); } - Module &M = *Functions.front()->getParent(); ChangeStatus Changed = A.run(); - assert(!verifyModule(M, &errs()) && "Module verification failed!"); + assert(!verifyModule(*Functions.front()->getParent(), &errs()) && + "Module verification failed!"); LLVM_DEBUG(dbgs() << "[Attributor] Done with " << Functions.size() << " functions, result: " << Changed << ".\n"); return Changed == ChangeStatus::CHANGED; From 3f51c5d9caa84f974686d62c3978442385c9bf36 Mon Sep 17 00:00:00 2001 From: Johannes Doerfert Date: Mon, 23 Mar 2020 11:39:34 -0500 Subject: [PATCH 10/59] [OpenMPOpt][FIX] Resolve OpenMP runtime call type mismatches Exposed by D76058 and tested once that one lands. --- llvm/include/llvm/Frontend/OpenMP/OMPKinds.def | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def b/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def index d37c3911edf2..10ac5a759e77 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def +++ b/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def @@ -209,8 +209,8 @@ __OMP_RTL(omp_get_thread_limit, false, Int32, ) __OMP_RTL(omp_get_supported_active_levels, false, Int32, ) __OMP_RTL(omp_get_max_active_levels, false, Int32, ) __OMP_RTL(omp_get_level, false, Int32, ) -__OMP_RTL(omp_get_ancestor_thread_num, false, Int32, ) -__OMP_RTL(omp_get_team_size, false, Int32, ) +__OMP_RTL(omp_get_ancestor_thread_num, false, Int32, Int32) +__OMP_RTL(omp_get_team_size, false, Int32, Int32) __OMP_RTL(omp_get_active_level, false, Int32, ) __OMP_RTL(omp_in_final, false, Int32, ) __OMP_RTL(omp_get_proc_bind, false, Int32, ) @@ -219,7 +219,7 @@ __OMP_RTL(omp_get_num_procs, false, Int32, ) __OMP_RTL(omp_get_place_proc_ids, false, Void, Int32, Int32Ptr) __OMP_RTL(omp_get_place_num, false, Int32, ) __OMP_RTL(omp_get_partition_num_places, false, Int32, ) -__OMP_RTL(omp_get_partition_place_nums, false, Int32, ) +__OMP_RTL(omp_get_partition_place_nums, false, Void, Int32Ptr) __OMP_RTL(omp_set_num_threads, false, Void, Int32) __OMP_RTL(omp_set_dynamic, false, Void, Int32) From 9d38f98dc30bf9a2c2b6325817d3e08515b82892 Mon Sep 17 00:00:00 2001 From: Johannes Doerfert Date: Mon, 23 Mar 2020 10:47:06 -0500 Subject: [PATCH 11/59] [OpenMPOpt] Validate declaration types against the expected types Validation of the found runtime library functions declarations types (return and argument types) with the expected types. Reviewed By: jdoerfert Differential Revision: https://reviews.llvm.org/D76058 --- llvm/lib/Transforms/IPO/OpenMPOpt.cpp | 65 ++++++++++++++----- .../Transforms/OpenMP/rtf_type_checking.ll | 63 ++++++++++++++++++ 2 files changed, 110 insertions(+), 18 deletions(-) create mode 100644 llvm/test/Transforms/OpenMP/rtf_type_checking.ll diff --git a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp index a766513ded03..ca52a618be4c 100644 --- a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp +++ b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp @@ -119,7 +119,7 @@ struct OpenMPOpt { } private: - /// Try to delete parallel regions if possible + /// Try to delete parallel regions if possible. bool deleteParallelRegions() { const unsigned CallbackCalleeOperand = 2; @@ -385,6 +385,32 @@ struct OpenMPOpt { return nullptr; } + /// Returns true if the function declaration \p F matches the runtime + /// function types, that is, return type \p RTFRetType, and argument types + /// \p RTFArgTypes. + static bool declMatchesRTFTypes(Function *F, Type *RTFRetType, + SmallVector &RTFArgTypes) { + // TODO: We should output information to the user (under debug output + // and via remarks). + + if (!F) + return false; + if (F->getReturnType() != RTFRetType) + return false; + if (F->arg_size() != RTFArgTypes.size()) + return false; + + auto RTFTyIt = RTFArgTypes.begin(); + for (Argument &Arg : F->args()) { + if (Arg.getType() != *RTFTyIt) + return false; + + ++RTFTyIt; + } + + return true; + } + /// Helper to initialize all runtime function information for those defined in /// OpenMPKinds.def. void initializeRuntimeFunctions() { @@ -415,26 +441,29 @@ struct OpenMPOpt { #define OMP_RTL(_Enum, _Name, _IsVarArg, _ReturnType, ...) \ { \ - auto &RFI = RFIs[_Enum]; \ - RFI.Kind = _Enum; \ - RFI.Name = _Name; \ - RFI.IsVarArg = _IsVarArg; \ - RFI.ReturnType = _ReturnType; \ - RFI.ArgumentTypes = SmallVector({__VA_ARGS__}); \ - RFI.Declaration = M.getFunction(_Name); \ - unsigned NumUses = CollectUses(RFI); \ - (void)NumUses; \ - LLVM_DEBUG({ \ - dbgs() << TAG << RFI.Name << (RFI.Declaration ? "" : " not") \ - << " found\n"; \ - if (RFI.Declaration) \ - dbgs() << TAG << "-> got " << NumUses << " uses in " \ - << RFI.UsesMap.size() << " different functions.\n"; \ - }); \ + SmallVector ArgsTypes({__VA_ARGS__}); \ + Function *F = M.getFunction(_Name); \ + if (declMatchesRTFTypes(F, _ReturnType , ArgsTypes)) { \ + auto &RFI = RFIs[_Enum]; \ + RFI.Kind = _Enum; \ + RFI.Name = _Name; \ + RFI.IsVarArg = _IsVarArg; \ + RFI.ReturnType = _ReturnType; \ + RFI.ArgumentTypes = std::move(ArgsTypes); \ + RFI.Declaration = F; \ + unsigned NumUses = CollectUses(RFI); \ + (void)NumUses; \ + LLVM_DEBUG({ \ + dbgs() << TAG << RFI.Name << (RFI.Declaration ? "" : " not") \ + << " found\n"; \ + if (RFI.Declaration) \ + dbgs() << TAG << "-> got " << NumUses << " uses in " \ + << RFI.UsesMap.size() << " different functions.\n"; \ + }); \ + } \ } #include "llvm/Frontend/OpenMP/OMPKinds.def" - // TODO: We should validate the declaration agains the types we expect. // TODO: We should attach the attributes defined in OMPKinds.def. } diff --git a/llvm/test/Transforms/OpenMP/rtf_type_checking.ll b/llvm/test/Transforms/OpenMP/rtf_type_checking.ll new file mode 100644 index 000000000000..57c09bcc7e06 --- /dev/null +++ b/llvm/test/Transforms/OpenMP/rtf_type_checking.ll @@ -0,0 +1,63 @@ +; RUN: opt -S -openmpopt -stats < %s 2>&1 | FileCheck %s +; REQUIRES: asserts + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + +%struct.ident_t = type { i32, i32, i32, i32, i8* } + +@.str = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00", align 1 +@0 = private unnamed_addr global %struct.ident_t { i32 0, i32 2, i32 0, i32 0, i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.str, i32 0, i32 0) }, align 8 +@1 = private unnamed_addr global %struct.ident_t { i32 0, i32 322, i32 0, i32 0, i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.str, i32 0, i32 0) }, align 8 + +define i32 @main() { +entry: + + call void (%struct.ident_t*, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull @0, void (i32*, i32*, ...)* bitcast (void (i32*, i32*)* @.omp_outlined. to void (i32*, i32*, ...)*)) + ret i32 0 +} + +; Only the last runtime call will be matched due that the rest of the "runtime function" calls +; have some type mismatch compared to the real runtime function. See the check at bottom. +define internal void @.omp_outlined.(i32* noalias %.global_tid., i32* noalias %.bound_tid.) { +entry: + + call void @__kmpc_master(%struct.ident_t* nonnull @0) + call void @__kmpc_end_master(%struct.ident_t* nonnull @0, i32 0, i32 0) + call void @__kmpc_barrier(%struct.ident_t* nonnull @1, float 0.0) + call void @omp_get_thread_num() + call void @__kmpc_flush(%struct.ident_t* nonnull @0) + ret void +} +; Fewer arguments than expected in variadic function. +declare !callback !2 void @__kmpc_fork_call(%struct.ident_t*, void (i32*, i32*, ...)*, ...) + +; Fewer number of arguments in non variadic function. +declare void @__kmpc_master(%struct.ident_t*) + +; Bigger number of arguments in non variadic function. +declare void @__kmpc_end_master(%struct.ident_t*, i32, i32) + +; Different argument type than the expected. +declare void @__kmpc_barrier(%struct.ident_t*, float) + +; Proper use of runtime function. +declare void @__kmpc_flush(%struct.ident_t*) + +; Different return type. +declare void @omp_get_thread_num() + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang"} +!2 = !{!3} +!3 = !{i64 2, i64 -1, i64 -1, i1 true} +; ===-------------------------------------------------------------------------=== +; ... Statistics Collected ... +; ===-------------------------------------------------------------------------=== +; +; CHECK: 1 cgscc-passmgr - Maximum CGSCCPassMgr iterations on one SCC +; CHECK: 2 openmp-opt{{.*}}Number of OpenMP runtime functions identified +; +; There are two matches since the pass is run once per function. \ No newline at end of file From ae37e2285d233f28217e4e95a3ff71059c7ee8c7 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Mon, 23 Mar 2020 09:52:42 -0700 Subject: [PATCH 12/59] [lldb/Reproducers] Mark reproducer test directory as unsupported on Windows Reproducers are unsupported on Windows. Rather than having a UNSUPPORTED line in every test, just skip the whole subdirectory. --- .../Shell/Reproducer/Functionalities/TestDataFormatter.test | 2 +- .../Reproducer/Functionalities/TestExpressionEvaluation.test | 2 +- lldb/test/Shell/Reproducer/Functionalities/TestImageList.test | 2 +- lldb/test/Shell/Reproducer/Functionalities/TestStepping.test | 2 +- lldb/test/Shell/Reproducer/TestCaptureEnvOverride.test | 1 - lldb/test/Shell/Reproducer/TestCrash.test | 1 - lldb/test/Shell/Reproducer/TestDiscard.test | 1 - lldb/test/Shell/Reproducer/TestDump.test | 1 - lldb/test/Shell/Reproducer/TestGDBRemoteRepro.test | 2 +- lldb/test/Shell/Reproducer/TestMultipleTargets.test | 2 +- lldb/test/Shell/Reproducer/TestRelativePath.test | 1 - lldb/test/Shell/Reproducer/TestReuseDirectory.test | 2 +- lldb/test/Shell/Reproducer/TestSynchronous.test | 1 - lldb/test/Shell/Reproducer/TestWorkingDir.test | 2 -- lldb/test/Shell/Reproducer/lit.local.cfg | 3 +++ 15 files changed, 10 insertions(+), 15 deletions(-) diff --git a/lldb/test/Shell/Reproducer/Functionalities/TestDataFormatter.test b/lldb/test/Shell/Reproducer/Functionalities/TestDataFormatter.test index 7db8bc4b36cf..d133c8d3b9f9 100644 --- a/lldb/test/Shell/Reproducer/Functionalities/TestDataFormatter.test +++ b/lldb/test/Shell/Reproducer/Functionalities/TestDataFormatter.test @@ -1,4 +1,4 @@ -# UNSUPPORTED: system-windows, system-freebsd +# UNSUPPORTED: system-freebsd # This tests that data formatters continue to work when replaying a reproducer. diff --git a/lldb/test/Shell/Reproducer/Functionalities/TestExpressionEvaluation.test b/lldb/test/Shell/Reproducer/Functionalities/TestExpressionEvaluation.test index e2bcb2d96570..f400cef07a24 100644 --- a/lldb/test/Shell/Reproducer/Functionalities/TestExpressionEvaluation.test +++ b/lldb/test/Shell/Reproducer/Functionalities/TestExpressionEvaluation.test @@ -1,4 +1,4 @@ -# UNSUPPORTED: system-windows, system-freebsd +# UNSUPPORTED: system-freebsd # XFAIL: system-netbsd # Flaky diff --git a/lldb/test/Shell/Reproducer/Functionalities/TestImageList.test b/lldb/test/Shell/Reproducer/Functionalities/TestImageList.test index db319093f174..ec8b36ea9576 100644 --- a/lldb/test/Shell/Reproducer/Functionalities/TestImageList.test +++ b/lldb/test/Shell/Reproducer/Functionalities/TestImageList.test @@ -1,4 +1,4 @@ -# UNSUPPORTED: system-windows, system-freebsd +# UNSUPPORTED: system-freebsd # This tests that image list works when replaying. We arbitrarily assume # there's at least two entries and compare that they're identical. diff --git a/lldb/test/Shell/Reproducer/Functionalities/TestStepping.test b/lldb/test/Shell/Reproducer/Functionalities/TestStepping.test index 1dec9a077c7b..ba9164f4b43a 100644 --- a/lldb/test/Shell/Reproducer/Functionalities/TestStepping.test +++ b/lldb/test/Shell/Reproducer/Functionalities/TestStepping.test @@ -1,4 +1,4 @@ -# UNSUPPORTED: system-windows, system-freebsd +# UNSUPPORTED: system-freebsd # This tests that stepping continues to work when replaying a reproducer. diff --git a/lldb/test/Shell/Reproducer/TestCaptureEnvOverride.test b/lldb/test/Shell/Reproducer/TestCaptureEnvOverride.test index a8e7bdec250e..ef06bce8983f 100644 --- a/lldb/test/Shell/Reproducer/TestCaptureEnvOverride.test +++ b/lldb/test/Shell/Reproducer/TestCaptureEnvOverride.test @@ -1,4 +1,3 @@ -# UNSUPPORTED: system-windows # This tests the LLDB_CAPTURE_REPRODUCER override. # RUN: %lldb -b -o 'reproducer status' --capture --capture-path %t.repro /bin/ls | FileCheck %s --check-prefix CAPTURE diff --git a/lldb/test/Shell/Reproducer/TestCrash.test b/lldb/test/Shell/Reproducer/TestCrash.test index cb0c09aad141..1389a9b76ad3 100644 --- a/lldb/test/Shell/Reproducer/TestCrash.test +++ b/lldb/test/Shell/Reproducer/TestCrash.test @@ -1,4 +1,3 @@ -# UNSUPPORTED: system-windows # This tests that a reproducer is generated when LLDB crashes. # Start clean. diff --git a/lldb/test/Shell/Reproducer/TestDiscard.test b/lldb/test/Shell/Reproducer/TestDiscard.test index db9614aabb84..829aabbe2b03 100644 --- a/lldb/test/Shell/Reproducer/TestDiscard.test +++ b/lldb/test/Shell/Reproducer/TestDiscard.test @@ -1,4 +1,3 @@ -# UNSUPPORTED: system-windows # This ensures that the reproducer properly cleans up after itself. # Build the inferior. diff --git a/lldb/test/Shell/Reproducer/TestDump.test b/lldb/test/Shell/Reproducer/TestDump.test index c193b806b547..8300a97004bb 100644 --- a/lldb/test/Shell/Reproducer/TestDump.test +++ b/lldb/test/Shell/Reproducer/TestDump.test @@ -1,4 +1,3 @@ -# UNSUPPORTED: system-windows # This tests the reproducer dump functionality. # Generate a reproducer. diff --git a/lldb/test/Shell/Reproducer/TestGDBRemoteRepro.test b/lldb/test/Shell/Reproducer/TestGDBRemoteRepro.test index 609c83929292..683a7e2f5529 100644 --- a/lldb/test/Shell/Reproducer/TestGDBRemoteRepro.test +++ b/lldb/test/Shell/Reproducer/TestGDBRemoteRepro.test @@ -1,4 +1,4 @@ -# UNSUPPORTED: system-windows, system-freebsd +# UNSUPPORTED: system-freebsd # This tests the replaying of GDB remote packets. # diff --git a/lldb/test/Shell/Reproducer/TestMultipleTargets.test b/lldb/test/Shell/Reproducer/TestMultipleTargets.test index ce1a5ecdd4c8..7859480e2d04 100644 --- a/lldb/test/Shell/Reproducer/TestMultipleTargets.test +++ b/lldb/test/Shell/Reproducer/TestMultipleTargets.test @@ -1,4 +1,4 @@ -# UNSUPPORTED: system-windows, system-freebsd +# UNSUPPORTED: system-freebsd # This tests the replaying with multiple targets. diff --git a/lldb/test/Shell/Reproducer/TestRelativePath.test b/lldb/test/Shell/Reproducer/TestRelativePath.test index 2ee4bf0c9649..fa7518784550 100644 --- a/lldb/test/Shell/Reproducer/TestRelativePath.test +++ b/lldb/test/Shell/Reproducer/TestRelativePath.test @@ -1,4 +1,3 @@ -# UNSUPPORTED: system-windows # This tests relative capture paths. # RUN: mkdir -p %t diff --git a/lldb/test/Shell/Reproducer/TestReuseDirectory.test b/lldb/test/Shell/Reproducer/TestReuseDirectory.test index 31b71a0f2601..a3fecced2504 100644 --- a/lldb/test/Shell/Reproducer/TestReuseDirectory.test +++ b/lldb/test/Shell/Reproducer/TestReuseDirectory.test @@ -1,4 +1,4 @@ -# UNSUPPORTED: system-windows, system-freebsd +# UNSUPPORTED: system-freebsd # Test that we can capture twice to the same directory without breaking the # reproducer functionality. diff --git a/lldb/test/Shell/Reproducer/TestSynchronous.test b/lldb/test/Shell/Reproducer/TestSynchronous.test index c62cbe81aff3..f32ce8c57224 100644 --- a/lldb/test/Shell/Reproducer/TestSynchronous.test +++ b/lldb/test/Shell/Reproducer/TestSynchronous.test @@ -1,5 +1,4 @@ # REQUIRES: python -# UNSUPPORTED: system-windows # Ensure that replay happens in synchronous mode. # RUN: rm -rf %t.repro diff --git a/lldb/test/Shell/Reproducer/TestWorkingDir.test b/lldb/test/Shell/Reproducer/TestWorkingDir.test index 707916bae560..1d4c7694211a 100644 --- a/lldb/test/Shell/Reproducer/TestWorkingDir.test +++ b/lldb/test/Shell/Reproducer/TestWorkingDir.test @@ -1,5 +1,3 @@ -# XFAIL: system-windows - # This tests that the reproducer can deal with relative files. We create a # binary in a subdirectory and pass its relative path to LLDB. The subdirectory # is removed before replay so that it only exists in the reproducer's VFS. diff --git a/lldb/test/Shell/Reproducer/lit.local.cfg b/lldb/test/Shell/Reproducer/lit.local.cfg index 7f4022768c87..30f97f28279d 100644 --- a/lldb/test/Shell/Reproducer/lit.local.cfg +++ b/lldb/test/Shell/Reproducer/lit.local.cfg @@ -6,5 +6,8 @@ if 'LLVM_DISABLE_CRASH_REPORT' in config.environment: if 'LLDB_CAPTURE_REPRODUCER' in config.environment: del config.environment['LLDB_CAPTURE_REPRODUCER'] +if 'system-windows' in config.available_features: + config.unsupported = True + if 'lldb-repro' in config.available_features: config.unsupported = True From 552bd477f8ebef12ee5e50ab7150dd55890549e4 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Mon, 23 Mar 2020 09:55:39 -0700 Subject: [PATCH 13/59] [gn build] Port 24698e526f619271705fe72bcaa928be9bc82484 --- .../gn/secondary/llvm/lib/Target/targets.gni | 5 ++++- llvm/utils/gn/secondary/llvm/unittests/BUILD.gn | 6 ++++++ .../secondary/llvm/unittests/MC/AMDGPU/BUILD.gn | 14 ++++++++++++++ .../llvm/unittests/Target/AMDGPU/BUILD.gn | 15 +++++++++++++++ 4 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 llvm/utils/gn/secondary/llvm/unittests/MC/AMDGPU/BUILD.gn create mode 100644 llvm/utils/gn/secondary/llvm/unittests/Target/AMDGPU/BUILD.gn diff --git a/llvm/utils/gn/secondary/llvm/lib/Target/targets.gni b/llvm/utils/gn/secondary/llvm/lib/Target/targets.gni index 8306b5daabcc..0fb7f4c5daa2 100644 --- a/llvm/utils/gn/secondary/llvm/lib/Target/targets.gni +++ b/llvm/utils/gn/secondary/llvm/lib/Target/targets.gni @@ -45,6 +45,7 @@ if (llvm_targets_to_build == "host") { # unittest targets). llvm_build_AArch64 = false llvm_build_ARM = false +llvm_build_AMDGPU = false llvm_build_BPF = false llvm_build_Mips = false llvm_build_PowerPC = false @@ -53,6 +54,8 @@ llvm_build_X86 = false foreach(target, llvm_targets_to_build) { if (target == "AArch64") { llvm_build_AArch64 = true + } else if (target == "AMDGPU") { + llvm_build_AMDGPU = true } else if (target == "ARM") { llvm_build_ARM = true } else if (target == "BPF") { @@ -65,7 +68,7 @@ foreach(target, llvm_targets_to_build) { llvm_build_WebAssembly = true } else if (target == "X86") { llvm_build_X86 = true - } else if (target == "AMDGPU" || target == "AVR" || target == "Hexagon" || + } else if (target == "AVR" || target == "Hexagon" || target == "Lanai" || target == "NVPTX" || target == "RISCV" || target == "Sparc" || target == "SystemZ") { # Nothing to do. diff --git a/llvm/utils/gn/secondary/llvm/unittests/BUILD.gn b/llvm/utils/gn/secondary/llvm/unittests/BUILD.gn index fb951086571d..3d960d501e42 100644 --- a/llvm/utils/gn/secondary/llvm/unittests/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/unittests/BUILD.gn @@ -56,6 +56,12 @@ group("unittests") { "tools/llvm-exegesis/AArch64:LLVMExegesisAArch64Tests", ] } + if (llvm_build_AMDGPU) { + deps += [ + "MC/AMDGPU:AMDGPUDwarfTests", + "Target/AMDGPU:AMDGPUTests", + ] + } if (llvm_build_ARM) { deps += [ "Target/ARM:ARMTests", diff --git a/llvm/utils/gn/secondary/llvm/unittests/MC/AMDGPU/BUILD.gn b/llvm/utils/gn/secondary/llvm/unittests/MC/AMDGPU/BUILD.gn new file mode 100644 index 000000000000..8d1763e65f0c --- /dev/null +++ b/llvm/utils/gn/secondary/llvm/unittests/MC/AMDGPU/BUILD.gn @@ -0,0 +1,14 @@ +import("//llvm/utils/unittest/unittest.gni") + +unittest("AMDGPUDwarfTests") { + deps = [ + "//llvm/lib/MC", + "//llvm/lib/Support", + "//llvm/lib/Target/AMDGPU:LLVMAMDGPUCodeGen", + "//llvm/lib/Target/AMDGPU/MCTargetDesc", + "//llvm/lib/Target/AMDGPU/TargetInfo", + ] + sources = [ + "DwarfRegMappings.cpp", + ] +} diff --git a/llvm/utils/gn/secondary/llvm/unittests/Target/AMDGPU/BUILD.gn b/llvm/utils/gn/secondary/llvm/unittests/Target/AMDGPU/BUILD.gn new file mode 100644 index 000000000000..3e156fc6ee70 --- /dev/null +++ b/llvm/utils/gn/secondary/llvm/unittests/Target/AMDGPU/BUILD.gn @@ -0,0 +1,15 @@ +import("//llvm/utils/unittest/unittest.gni") + +unittest("AMDGPUTests") { + deps = [ + "//llvm/lib/Support", + "//llvm/lib/Target", + "//llvm/lib/Target/AMDGPU:LLVMAMDGPUCodeGen", + "//llvm/lib/Target/AMDGPU/MCTargetDesc", + "//llvm/lib/Target/AMDGPU/TargetInfo", + ] + sources = [ + # Make `gn format` not collapse this, for sync_source_lists_from_cmake.py. + "DwarfRegMappings.cpp", + ] +} From ae044467ede146556b6a424f4486ebbbc920e95f Mon Sep 17 00:00:00 2001 From: AndreyChurbanov Date: Mon, 23 Mar 2020 20:02:19 +0300 Subject: [PATCH 14/59] [openmp][runtime] Fixed hang for explicit task inside a taskloop. Added missed initialization of td_last_tied field for taskloop tasks. Differential Revision: https://reviews.llvm.org/D75673 --- openmp/runtime/src/kmp_tasking.cpp | 9 ++- .../test/tasking/omp_task_red_taskloop.c | 57 +++++++++++++++++++ 2 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 openmp/runtime/test/tasking/omp_task_red_taskloop.c diff --git a/openmp/runtime/src/kmp_tasking.cpp b/openmp/runtime/src/kmp_tasking.cpp index 15ffc1454fe9..6dae9dc73e7a 100644 --- a/openmp/runtime/src/kmp_tasking.cpp +++ b/openmp/runtime/src/kmp_tasking.cpp @@ -3923,9 +3923,12 @@ kmp_task_t *__kmp_task_dup_alloc(kmp_info_t *thread, kmp_task_t *task_src) { } taskdata->td_alloc_thread = thread; taskdata->td_parent = parent_task; - taskdata->td_taskgroup = - parent_task - ->td_taskgroup; // task inherits the taskgroup from the parent task + // task inherits the taskgroup from the parent task + taskdata->td_taskgroup = parent_task->td_taskgroup; + // tied task needs to initialize the td_last_tied at creation, + // untied one does this when it is scheduled for execution + if (taskdata->td_flags.tiedness == TASK_TIED) + taskdata->td_last_tied = taskdata; // Only need to keep track of child task counts if team parallel and tasking // not serialized diff --git a/openmp/runtime/test/tasking/omp_task_red_taskloop.c b/openmp/runtime/test/tasking/omp_task_red_taskloop.c new file mode 100644 index 000000000000..89c66256da73 --- /dev/null +++ b/openmp/runtime/test/tasking/omp_task_red_taskloop.c @@ -0,0 +1,57 @@ +// RUN: %libomp-compile-and-run + +#include +#include + +int r; + +int work(int k, int l) +{ + return k + l + 1; +} +void bar(int i) { + #pragma omp taskgroup task_reduction(+:r) + { int th_gen = omp_get_thread_num(); + #pragma omp task in_reduction(+:r) firstprivate(i, th_gen) + { + r += work(i, 0); +printf("executing task (%d, 0), th %d (gen by th %d)\n", i, omp_get_thread_num(), th_gen); + } + #pragma omp task in_reduction(+:r) firstprivate(i, th_gen) + { + r += work(i, 1); +printf("executing task (%d, 1), th %d (gen by th %d)\n", i, omp_get_thread_num(), th_gen); + } + } +} +int foo() { + int i; + int th_gen = omp_get_thread_num(); + #pragma omp taskgroup task_reduction(+:r) + { + bar(0); + } +printf("th %d passed bar0\n", th_gen); + #pragma omp taskloop reduction(+:r) firstprivate(th_gen) + for (i = 1; i < 4; ++i) { + bar(i); +printf("th %d (gen by th %d) passed bar%d in taskloop\n", omp_get_thread_num(), th_gen, i); +// #pragma omp task in_reduction(+:r) + r += i; + } + return 0; +} +// res = 2*((1+2)+(2+3)+(3+4)+(4+5)+1+2+3) = 60 +#define res 60 +int main() +{ + r = 0; + #pragma omp parallel num_threads(2) + foo(); + if (r == res) { + return 0; + } else { + printf("error r = %d (!= %d)\n", r, res); + return 1; + } +} From 63828a35da6f790f448b87b3eec61d294df31ccc Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Mon, 23 Mar 2020 10:41:08 -0400 Subject: [PATCH 15/59] [OPENMP50]Bassic support for exclusive clause. Added basic support (parsing/sema/serialization) for exclusive clause in scan directives. --- clang/include/clang/AST/OpenMPClause.h | 74 +++++++++++++++++++ clang/include/clang/AST/RecursiveASTVisitor.h | 7 ++ clang/include/clang/Basic/OpenMPKinds.def | 2 + clang/include/clang/Sema/Sema.h | 5 ++ clang/lib/AST/OpenMPClause.cpp | 28 +++++++ clang/lib/AST/StmtProfile.cpp | 3 + clang/lib/Basic/OpenMPKinds.cpp | 2 + clang/lib/CodeGen/CGStmtOpenMP.cpp | 1 + clang/lib/Parse/ParseOpenMP.cpp | 8 +- clang/lib/Sema/SemaOpenMP.cpp | 37 ++++++++++ clang/lib/Sema/TreeTransform.h | 27 +++++++ clang/lib/Serialization/ASTReader.cpp | 13 ++++ clang/lib/Serialization/ASTWriter.cpp | 7 ++ clang/test/OpenMP/scan_ast_print.cpp | 4 +- clang/test/OpenMP/scan_messages.cpp | 30 +++++--- clang/tools/libclang/CIndex.cpp | 3 + 16 files changed, 237 insertions(+), 14 deletions(-) diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index a781797c2d56..acf450f07e66 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -6985,6 +6985,80 @@ class OMPInclusiveClause final } }; +/// This represents clause 'exclusive' in the '#pragma omp scan' directive. +/// +/// \code +/// #pragma omp scan exclusive(a,b) +/// \endcode +/// In this example directive '#pragma omp scan' has clause 'exclusive' +/// with the variables 'a' and 'b'. +class OMPExclusiveClause final + : public OMPVarListClause, + private llvm::TrailingObjects { + friend class OMPClauseReader; + friend OMPVarListClause; + friend TrailingObjects; + + /// Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + OMPExclusiveClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, unsigned N) + : OMPVarListClause(OMPC_exclusive, StartLoc, + LParenLoc, EndLoc, N) {} + + /// Build an empty clause. + /// + /// \param N Number of variables. + explicit OMPExclusiveClause(unsigned N) + : OMPVarListClause(OMPC_exclusive, SourceLocation(), + SourceLocation(), SourceLocation(), + N) {} + +public: + /// Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param VL List of references to the original variables. + static OMPExclusiveClause *Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc, ArrayRef VL); + + /// Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + static OMPExclusiveClause *CreateEmpty(const ASTContext &C, unsigned N); + + child_range children() { + return child_range(reinterpret_cast(varlist_begin()), + reinterpret_cast(varlist_end())); + } + + const_child_range children() const { + auto Children = const_cast(this)->children(); + return const_child_range(Children.begin(), Children.end()); + } + + child_range used_children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range used_children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_exclusive; + } +}; + /// This class implements a simple visitor for OMPClause /// subclasses. template class Ptr, typename RetTy> diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 94f68f555fdf..4bd489f4ba6d 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -3190,6 +3190,13 @@ bool RecursiveASTVisitor::VisitOMPInclusiveClause( return true; } +template +bool RecursiveASTVisitor::VisitOMPExclusiveClause( + OMPExclusiveClause *C) { + TRY_TO(VisitOMPClauseList(C)); + return true; +} + template bool RecursiveASTVisitor::VisitOMPPrivateClause(OMPPrivateClause *C) { TRY_TO(VisitOMPClauseList(C)); diff --git a/clang/include/clang/Basic/OpenMPKinds.def b/clang/include/clang/Basic/OpenMPKinds.def index 1e4b2b116a98..ffffed50ef86 100644 --- a/clang/include/clang/Basic/OpenMPKinds.def +++ b/clang/include/clang/Basic/OpenMPKinds.def @@ -285,9 +285,11 @@ OPENMP_CLAUSE(depobj, OMPDepobjClause) OPENMP_CLAUSE(destroy, OMPDestroyClause) OPENMP_CLAUSE(detach, OMPDetachClause) OPENMP_CLAUSE(inclusive, OMPInclusiveClause) +OPENMP_CLAUSE(exclusive, OMPExclusiveClause) // Clauses allowed for OpenMP directive 'scan'. OPENMP_SCAN_CLAUSE(inclusive) +OPENMP_SCAN_CLAUSE(exclusive) // Clauses allowed for OpenMP directive 'parallel'. OPENMP_PARALLEL_CLAUSE(if) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 03f3a1b4bdc9..90ba85638f0b 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10506,6 +10506,11 @@ class Sema final { SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); + /// Called on well-formed 'exclusive' clause. + OMPClause *ActOnOpenMPExclusiveClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); /// Called on well-formed 'allocate' clause. OMPClause * ActOnOpenMPAllocateClause(Expr *Allocator, ArrayRef VarList, diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index de8fd67a0250..5f9da85a9f07 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -147,6 +147,7 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) { case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: break; } @@ -235,6 +236,7 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C) case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: break; } @@ -1268,6 +1270,24 @@ OMPInclusiveClause *OMPInclusiveClause::CreateEmpty(const ASTContext &C, return new (Mem) OMPInclusiveClause(N); } +OMPExclusiveClause *OMPExclusiveClause::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc, + ArrayRef VL) { + void *Mem = C.Allocate(totalSizeToAlloc(VL.size())); + auto *Clause = + new (Mem) OMPExclusiveClause(StartLoc, LParenLoc, EndLoc, VL.size()); + Clause->setVarRefs(VL); + return Clause; +} + +OMPExclusiveClause *OMPExclusiveClause::CreateEmpty(const ASTContext &C, + unsigned N) { + void *Mem = C.Allocate(totalSizeToAlloc(N)); + return new (Mem) OMPExclusiveClause(N); +} + //===----------------------------------------------------------------------===// // OpenMP clauses printing methods //===----------------------------------------------------------------------===// @@ -1833,6 +1853,14 @@ void OMPClausePrinter::VisitOMPInclusiveClause(OMPInclusiveClause *Node) { } } +void OMPClausePrinter::VisitOMPExclusiveClause(OMPExclusiveClause *Node) { + if (!Node->varlist_empty()) { + OS << "exclusive"; + VisitOMPClauseList(Node, '('); + OS << ")"; + } +} + void OMPTraitInfo::getAsVariantMatchInfo( ASTContext &ASTCtx, llvm::omp::VariantMatchInfo &VMI) const { for (const OMPTraitSet &Set : Sets) { diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index a31a65fad35f..cd39024cd838 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -798,6 +798,9 @@ void OMPClauseProfiler::VisitOMPNontemporalClause( void OMPClauseProfiler::VisitOMPInclusiveClause(const OMPInclusiveClause *C) { VisitOMPClauseList(C); } +void OMPClauseProfiler::VisitOMPExclusiveClause(const OMPExclusiveClause *C) { + VisitOMPClauseList(C); +} void OMPClauseProfiler::VisitOMPOrderClause(const OMPOrderClause *C) {} } // namespace diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index a905dff440d7..36e7f4583468 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -213,6 +213,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: break; } llvm_unreachable("Invalid OpenMP simple clause kind"); @@ -449,6 +450,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: break; } llvm_unreachable("Invalid OpenMP simple clause kind"); diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index e05829f0a890..bef36bf4693b 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -4617,6 +4617,7 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind, case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: llvm_unreachable("Clause is not allowed in 'omp atomic'."); } } diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index bb239c833b82..acc1e55eb721 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -2344,7 +2344,8 @@ bool Parser::ParseOpenMPSimpleVarList( /// from-clause | is_device_ptr-clause | task_reduction-clause | /// in_reduction-clause | allocator-clause | allocate-clause | /// acq_rel-clause | acquire-clause | release-clause | relaxed-clause | -/// depobj-clause | destroy-clause | detach-clause | inclusive-clause +/// depobj-clause | destroy-clause | detach-clause | inclusive-clause | +/// exclusive-clause /// OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, bool FirstClause) { @@ -2514,6 +2515,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_allocate: case OMPC_nontemporal: case OMPC_inclusive: + case OMPC_exclusive: Clause = ParseOpenMPVarListClause(DKind, CKind, WrongDirective); break; case OMPC_device_type: @@ -3239,7 +3241,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, /// Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate', /// 'shared', 'copyin', 'copyprivate', 'flush', 'reduction', 'task_reduction', -/// 'in_reduction', 'nontemporal' or 'inclusive'. +/// 'in_reduction', 'nontemporal', 'exclusive' or 'inclusive'. /// /// private-clause: /// 'private' '(' list ')' @@ -3283,6 +3285,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, /// 'nontemporal' '(' list ')' /// inclusive-clause: /// 'inclusive' '(' list ')' +/// exclusive-clause: +/// 'exclusive' '(' list ')' /// /// For 'linear' clause linear-list may have the following forms: /// list diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 8c488da6cf0f..d9a4a17f1866 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -5100,6 +5100,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPC_order: case OMPC_destroy: case OMPC_inclusive: + case OMPC_exclusive: continue; case OMPC_allocator: case OMPC_flush: @@ -11084,6 +11085,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_order: case OMPC_destroy: case OMPC_inclusive: + case OMPC_exclusive: llvm_unreachable("Clause is not allowed."); } return Res; @@ -11820,6 +11822,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: llvm_unreachable("Unexpected OpenMP clause."); } return CaptureRegion; @@ -12258,6 +12261,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: llvm_unreachable("Clause is not allowed."); } return Res; @@ -12482,6 +12486,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: llvm_unreachable("Clause is not allowed."); } return Res; @@ -12713,6 +12718,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_order: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: llvm_unreachable("Clause is not allowed."); } return Res; @@ -12923,6 +12929,9 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_inclusive: Res = ActOnOpenMPInclusiveClause(VarList, StartLoc, LParenLoc, EndLoc); break; + case OMPC_exclusive: + Res = ActOnOpenMPExclusiveClause(VarList, StartLoc, LParenLoc, EndLoc); + break; case OMPC_if: case OMPC_depobj: case OMPC_final: @@ -18008,3 +18017,31 @@ OMPClause *Sema::ActOnOpenMPInclusiveClause(ArrayRef VarList, return OMPInclusiveClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); } + +OMPClause *Sema::ActOnOpenMPExclusiveClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + SmallVector Vars; + for (Expr *RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP nontemporal clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/true); + if (Res.second) + // It will be analyzed later. + Vars.push_back(RefExpr); + ValueDecl *D = Res.first; + if (!D) + continue; + + Vars.push_back(RefExpr); + } + + if (Vars.empty()) + return nullptr; + + return OMPExclusiveClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); +} diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 8a22eb89d806..3e6d67d67845 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2065,6 +2065,18 @@ class TreeTransform { EndLoc); } + /// Build a new OpenMP 'exclusive' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPExclusiveClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPExclusiveClause(VarList, StartLoc, LParenLoc, + EndLoc); + } + /// Build a new OpenMP 'order' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. @@ -9548,6 +9560,21 @@ TreeTransform::TransformOMPInclusiveClause(OMPInclusiveClause *C) { Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } +template +OMPClause * +TreeTransform::TransformOMPExclusiveClause(OMPExclusiveClause *C) { + llvm::SmallVector Vars; + Vars.reserve(C->varlist_size()); + for (auto *VE : C->varlists()) { + ExprResult EVar = getDerived().TransformExpr(cast(VE)); + if (EVar.isInvalid()) + return nullptr; + Vars.push_back(EVar.get()); + } + return getDerived().RebuildOMPExclusiveClause( + Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); +} + template OMPClause * TreeTransform::TransformOMPOrderClause(OMPOrderClause *C) { diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index ac111776fe76..77f15bcd910a 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -11845,6 +11845,9 @@ OMPClause *OMPClauseReader::readClause() { case OMPC_inclusive: C = OMPInclusiveClause::CreateEmpty(Context, Record.readInt()); break; + case OMPC_exclusive: + C = OMPExclusiveClause::CreateEmpty(Context, Record.readInt()); + break; case OMPC_order: C = new (Context) OMPOrderClause(); break; @@ -12665,6 +12668,16 @@ void OMPClauseReader::VisitOMPInclusiveClause(OMPInclusiveClause *C) { C->setVarRefs(Vars); } +void OMPClauseReader::VisitOMPExclusiveClause(OMPExclusiveClause *C) { + C->setLParenLoc(Record.readSourceLocation()); + unsigned NumVars = C->varlist_size(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setVarRefs(Vars); +} + void OMPClauseReader::VisitOMPOrderClause(OMPOrderClause *C) { C->setKind(Record.readEnum()); C->setLParenLoc(Record.readSourceLocation()); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index a5d5b0f47144..9ccebae9567d 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -6611,6 +6611,13 @@ void OMPClauseWriter::VisitOMPInclusiveClause(OMPInclusiveClause *C) { Record.AddStmt(VE); } +void OMPClauseWriter::VisitOMPExclusiveClause(OMPExclusiveClause *C) { + Record.push_back(C->varlist_size()); + Record.AddSourceLocation(C->getLParenLoc()); + for (auto *VE : C->varlists()) + Record.AddStmt(VE); +} + void OMPClauseWriter::VisitOMPOrderClause(OMPOrderClause *C) { Record.writeEnum(C->getKind()); Record.AddSourceLocation(C->getLParenLoc()); diff --git a/clang/test/OpenMP/scan_ast_print.cpp b/clang/test/OpenMP/scan_ast_print.cpp index efcaa2da138a..4b9eca6f7ec9 100644 --- a/clang/test/OpenMP/scan_ast_print.cpp +++ b/clang/test/OpenMP/scan_ast_print.cpp @@ -39,11 +39,11 @@ int main(int argc, char **argv) { // CHECK: static int a; #pragma omp for simd for (int i = 0; i < 10; ++i) { -#pragma omp scan inclusive(a) +#pragma omp scan exclusive(a, argc) } // CHECK-NEXT: #pragma omp for simd // CHECK-NEXT: for (int i = 0; i < 10; ++i) { -// CHECK-NEXT: #pragma omp scan inclusive(a){{$}} +// CHECK-NEXT: #pragma omp scan exclusive(a,argc){{$}} return tmain(argc) + tmain(argv[0][0]) + a; } diff --git a/clang/test/OpenMP/scan_messages.cpp b/clang/test/OpenMP/scan_messages.cpp index 3be998d0f96e..9f093858c249 100644 --- a/clang/test/OpenMP/scan_messages.cpp +++ b/clang/test/OpenMP/scan_messages.cpp @@ -54,25 +54,25 @@ T tmain(T argc) { #pragma omp simd for (int i = 0; i < 10; ++i) switch (argc) { -#pragma omp scan inclusive(argc) // expected-note 2 {{previous 'scan' directive used here}} +#pragma omp scan exclusive(argc) // expected-note 2 {{previous 'scan' directive used here}} case 1: -#pragma omp scan inclusive(argc) // expected-error {{exactly one 'scan' directive must appear in the loop body of an enclosing directive}} +#pragma omp scan exclusive(argc) // expected-error {{exactly one 'scan' directive must appear in the loop body of an enclosing directive}} break; default: { -#pragma omp scan inclusive(argc) // expected-error {{exactly one 'scan' directive must appear in the loop body of an enclosing directive}} +#pragma omp scan exclusive(argc) // expected-error {{exactly one 'scan' directive must appear in the loop body of an enclosing directive}} } break; } #pragma omp simd for (int i = 0; i < 10; ++i) for (;;) -#pragma omp scan inclusive(argc) // expected-error {{'#pragma omp scan' cannot be an immediate substatement}} +#pragma omp scan exclusive(argc) // expected-error {{'#pragma omp scan' cannot be an immediate substatement}} for (;;) { -#pragma omp scan inclusive(argc) +#pragma omp scan exclusive(argc) } #pragma omp simd for (int i = 0; i < 10; ++i) { label: -#pragma omp scan inclusive(argc) +#pragma omp scan exclusive(argc) } #pragma omp simd for (int i = 0; i < 10; ++i) { @@ -91,6 +91,16 @@ int main(int argc, char **argv) { } #pragma omp simd for (int i = 0; i < 10; ++i) { +#pragma omp scan exclusive(argc) inclusive(argc) // expected-error {{exactly one of 'inclusive' or 'exclusive' clauses is expected}} + ; + } +#pragma omp simd + for (int i = 0; i < 10; ++i) { +#pragma omp scan exclusive(argc) exclusive(argc) // expected-error {{exactly one of 'inclusive' or 'exclusive' clauses is expected}} + ; + } +#pragma omp simd + for (int i = 0; i < 10; ++i) { #pragma omp scan untied // expected-error {{unexpected OpenMP clause 'untied' in directive '#pragma omp scan'}} expected-error {{exactly one of 'inclusive' or 'exclusive' clauses is expected}} #pragma omp scan unknown // expected-warning {{extra tokens at the end of '#pragma omp scan' are ignored}} expected-error {{exactly one of 'inclusive' or 'exclusive' clauses is expected}} } @@ -117,18 +127,18 @@ int main(int argc, char **argv) { #pragma omp simd for (int i = 0; i < 10; ++i) do { -#pragma omp scan inclusive(argc) +#pragma omp scan exclusive(argc) } while (argc); #pragma omp simd for (int i = 0; i < 10; ++i) switch (argc) -#pragma omp scan inclusive(argc) // expected-error {{'#pragma omp scan' cannot be an immediate substatement}} +#pragma omp scan exclusive(argc) // expected-error {{'#pragma omp scan' cannot be an immediate substatement}} switch (argc) case 1: -#pragma omp scan inclusive(argc) // expected-error {{'#pragma omp scan' cannot be an immediate substatement}} +#pragma omp scan exclusive(argc) // expected-error {{'#pragma omp scan' cannot be an immediate substatement}} switch (argc) case 1: { -#pragma omp scan inclusive(argc) +#pragma omp scan exclusive(argc) } #pragma omp simd for (int i = 0; i < 10; ++i) diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 31a0f364a348..ae7fd4271799 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -2312,6 +2312,9 @@ void OMPClauseEnqueue::VisitOMPClauseList(T *Node) { void OMPClauseEnqueue::VisitOMPInclusiveClause(const OMPInclusiveClause *C) { VisitOMPClauseList(C); } +void OMPClauseEnqueue::VisitOMPExclusiveClause(const OMPExclusiveClause *C) { + VisitOMPClauseList(C); +} void OMPClauseEnqueue::VisitOMPAllocateClause(const OMPAllocateClause *C) { VisitOMPClauseList(C); Visitor->AddStmt(C->getAllocator()); From 04336ada1756fea6ae0a6d86bd2d6bd35cdd19ad Mon Sep 17 00:00:00 2001 From: Jonathan Coe Date: Mon, 23 Mar 2020 17:17:27 +0000 Subject: [PATCH 16/59] [clang-format] No space inserted between commas in C# Reviewers: krasimir Reviewed By: krasimir Subscribers: cfe-commits, MyDeveloperDay Tags: #clang-format, #clang Differential Revision: https://reviews.llvm.org/D76621 --- clang/lib/Format/TokenAnnotator.cpp | 4 ++++ clang/unittests/Format/FormatTestCSharp.cpp | 3 +++ 2 files changed, 7 insertions(+) diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 685749fc31ab..f2666a8bd171 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -3015,6 +3015,10 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Right.is(TT_CSharpNullConditionalLSquare)) return false; + // No space between consecutive commas '[,,]'. + if (Left.is(tok::comma) && Right.is(tok::comma)) + return false; + // Possible space inside `?[ 0 ]`. if (Left.is(TT_CSharpNullConditionalLSquare)) return Style.SpacesInSquareBrackets; diff --git a/clang/unittests/Format/FormatTestCSharp.cpp b/clang/unittests/Format/FormatTestCSharp.cpp index 0b770b4dfd3c..17b8e070c36a 100644 --- a/clang/unittests/Format/FormatTestCSharp.cpp +++ b/clang/unittests/Format/FormatTestCSharp.cpp @@ -640,9 +640,12 @@ TEST_F(FormatTestCSharp, CSharpSpaces) { verifyFormat(R"(private float[,] Values;)", Style); verifyFormat(R"(Result this[Index x] => Foo(x);)", Style); + verifyFormat(R"(char[,,] rawCharArray = MakeCharacterGrid();)", Style); + Style.SpacesInSquareBrackets = true; verifyFormat(R"(private float[ , ] Values;)", Style); verifyFormat(R"(string dirPath = args?[ 0 ];)", Style); + verifyFormat(R"(char[ ,, ] rawCharArray = MakeCharacterGrid();)", Style); } TEST_F(FormatTestCSharp, CSharpNullableTypes) { From ff042de67d5a756e983b682b696a0c45b06cb62f Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Mon, 23 Mar 2020 10:22:07 -0700 Subject: [PATCH 17/59] [gn build] Port 24698e526f619271705fe72bcaa928be9bc82484. Fix AMDGPUTests --- llvm/utils/gn/secondary/llvm/lib/Target/targets.gni | 2 +- llvm/utils/gn/secondary/llvm/unittests/Target/AMDGPU/BUILD.gn | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/llvm/utils/gn/secondary/llvm/lib/Target/targets.gni b/llvm/utils/gn/secondary/llvm/lib/Target/targets.gni index 0fb7f4c5daa2..2590432529b6 100644 --- a/llvm/utils/gn/secondary/llvm/lib/Target/targets.gni +++ b/llvm/utils/gn/secondary/llvm/lib/Target/targets.gni @@ -44,8 +44,8 @@ if (llvm_targets_to_build == "host") { # and remember which targets are built where needed (for conditionally-built # unittest targets). llvm_build_AArch64 = false -llvm_build_ARM = false llvm_build_AMDGPU = false +llvm_build_ARM = false llvm_build_BPF = false llvm_build_Mips = false llvm_build_PowerPC = false diff --git a/llvm/utils/gn/secondary/llvm/unittests/Target/AMDGPU/BUILD.gn b/llvm/utils/gn/secondary/llvm/unittests/Target/AMDGPU/BUILD.gn index 3e156fc6ee70..238ff86b771c 100644 --- a/llvm/utils/gn/secondary/llvm/unittests/Target/AMDGPU/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/unittests/Target/AMDGPU/BUILD.gn @@ -7,7 +7,9 @@ unittest("AMDGPUTests") { "//llvm/lib/Target/AMDGPU:LLVMAMDGPUCodeGen", "//llvm/lib/Target/AMDGPU/MCTargetDesc", "//llvm/lib/Target/AMDGPU/TargetInfo", + "//llvm/lib/Target/AMDGPU/Utils", ] + include_dirs = [ "//llvm/lib/Target/AMDGPU" ] sources = [ # Make `gn format` not collapse this, for sync_source_lists_from_cmake.py. "DwarfRegMappings.cpp", From 9607a119bd5e01ccbbe45c2a5ae6bfbdd219e6c5 Mon Sep 17 00:00:00 2001 From: LLVM GN Syncbot Date: Mon, 23 Mar 2020 17:23:22 +0000 Subject: [PATCH 18/59] [gn build] Port 57b8a407493 --- .../gn/secondary/clang/lib/StaticAnalyzer/Frontend/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Frontend/BUILD.gn b/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Frontend/BUILD.gn index e4654bf14944..423ddbc68fc7 100644 --- a/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Frontend/BUILD.gn +++ b/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Frontend/BUILD.gn @@ -14,7 +14,7 @@ static_library("Frontend") { ] sources = [ "AnalysisConsumer.cpp", - "CheckerRegistration.cpp", + "AnalyzerHelpFlags.cpp", "CheckerRegistry.cpp", "FrontendActions.cpp", "ModelConsumer.cpp", From 9e33c096476ab5e02ab1c8442cc3cb4e32e29f17 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Tue, 25 Feb 2020 18:00:13 -0800 Subject: [PATCH 19/59] [ELF] Keep orphan section names (.rodata.foo .text.foo) unchanged if !hasSectionsCommand This behavior matches GNU ld and seems reasonable. ``` // If a SECTIONS command is not specified .text.* -> .text .rodata.* -> .rodata .init_array.* -> .init_array ``` A proposed Linux feature CONFIG_FG_KASLR may depend on the GNU ld behavior. Reword a comment about -z keep-text-section-prefix and a comment about CommonSection (deleted by rL286234). Reviewed By: grimar Differential Revision: https://reviews.llvm.org/D75225 --- lld/ELF/Writer.cpp | 26 ++++++++------ lld/test/ELF/linkerscript/data-commands-gc.s | 2 +- .../ELF/linkerscript/icf-output-sections.s | 14 +++++--- lld/test/ELF/linkerscript/linkorder.s | 4 +-- lld/test/ELF/linkerscript/linkorder2.s | 2 +- lld/test/ELF/linkerscript/memory3.s | 2 +- lld/test/ELF/linkerscript/orphan-report.s | 2 +- .../symbol-assign-many-passes2.test | 2 +- lld/test/ELF/mips-npic-call-pic-script.s | 34 +++++++++---------- lld/test/ELF/shuffle-sections-init-fini.s | 4 ++- lld/test/ELF/text-section-prefix.s | 14 +++++++- 11 files changed, 65 insertions(+), 41 deletions(-) diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index e172b708afcf..15b04d6fe332 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -108,12 +108,21 @@ StringRef getOutputSectionName(const InputSectionBase *s) { } } - // This check is for -z keep-text-section-prefix. This option separates text - // sections with prefix ".text.hot", ".text.unlikely", ".text.startup" or - // ".text.exit". - // When enabled, this allows identifying the hot code region (.text.hot) in - // the final binary which can be selectively mapped to huge pages or mlocked, - // for instance. + // A BssSection created for a common symbol is identified as "COMMON" in + // linker scripts. It should go to .bss section. + if (s->name == "COMMON") + return ".bss"; + + if (script->hasSectionsCommand) + return s->name; + + // When no SECTIONS is specified, emulate GNU ld's internal linker scripts + // by grouping sections with certain prefixes. + + // GNU ld places text sections with prefix ".text.hot.", ".text.unlikely.", + // ".text.startup." or ".text.exit." before others. We provide an option -z + // keep-text-section-prefix to group such sections into separate output + // sections. This is more flexible. See also sortISDBySectionOrder(). if (config->zKeepTextSectionPrefix) for (StringRef v : {".text.hot.", ".text.unlikely.", ".text.startup.", ".text.exit."}) @@ -127,11 +136,6 @@ StringRef getOutputSectionName(const InputSectionBase *s) { if (isSectionPrefix(v, s->name)) return v.drop_back(); - // CommonSection is identified as "COMMON" in linker scripts. - // By default, it should go to .bss section. - if (s->name == "COMMON") - return ".bss"; - return s->name; } diff --git a/lld/test/ELF/linkerscript/data-commands-gc.s b/lld/test/ELF/linkerscript/data-commands-gc.s index 0add6ba27e94..0262d7334e3e 100644 --- a/lld/test/ELF/linkerscript/data-commands-gc.s +++ b/lld/test/ELF/linkerscript/data-commands-gc.s @@ -4,7 +4,7 @@ # RUN: ld.lld --gc-sections -o %t %t.o --script %t.script # RUN: llvm-objdump -t %t | FileCheck %s -# CHECK: 0000000000000008 g .rodata 0000000000000000 bar +# CHECK: 0000000000000008 g .rodata.bar 0000000000000000 bar .section .rodata.bar .quad 0x1122334455667788 diff --git a/lld/test/ELF/linkerscript/icf-output-sections.s b/lld/test/ELF/linkerscript/icf-output-sections.s index f23d7fff06b0..ae9203abaea4 100644 --- a/lld/test/ELF/linkerscript/icf-output-sections.s +++ b/lld/test/ELF/linkerscript/icf-output-sections.s @@ -28,13 +28,19 @@ # SEC2: .text.foo PROGBITS 0000000000000000 001000 000001 # SEC2-NEXT: .text.bar PROGBITS 0000000000000001 001001 000001 -## .text.bar* are orphans that get assigned to .text. +## .text.bar* are orphan sections. # RUN: echo 'SECTIONS { .text.foo : {*(.text.foo*)} }' > %t3.script -# RUN: ld.lld %t.o --script %t3.script --icf=all --print-icf-sections -o %t | FileCheck --check-prefix=ICF2 %s -# RUN: llvm-readelf -S %t | FileCheck --check-prefix=SEC3 %s +# RUN: ld.lld %t.o -T %t3.script --icf=all --print-icf-sections -o %t3 | FileCheck --check-prefix=ICF3 %s +# RUN: llvm-readelf -S %t3 | FileCheck --check-prefix=SEC3 %s +# ICF3: selected section {{.*}}.o:(.text.foo0) +# ICF3-NEXT: removing identical section {{.*}}.o:(.text.foo1) + +# SEC3: Name Type Address Off Size # SEC3: .text.foo PROGBITS 0000000000000000 001000 000001 -# SEC3-NEXT: .text PROGBITS 0000000000000004 001004 000001 +# SEC3-NEXT: .text PROGBITS 0000000000000004 001004 000000 +# SEC3-NEXT: .text.bar0 PROGBITS 0000000000000004 001004 000001 +# SEC3-NEXT: .text.bar1 PROGBITS 0000000000000005 001005 000001 .section .text.foo0,"ax" ret diff --git a/lld/test/ELF/linkerscript/linkorder.s b/lld/test/ELF/linkerscript/linkorder.s index 44547b8ab002..042e8b3293fe 100644 --- a/lld/test/ELF/linkerscript/linkorder.s +++ b/lld/test/ELF/linkerscript/linkorder.s @@ -1,11 +1,11 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: echo "SECTIONS { .text : { *(.text.bar) *(.text.foo) } }" > %t.script +# RUN: echo "SECTIONS { .rodata : {*(.rodata*)} .text : {*(.text.bar) *(.text.foo)} }" > %t.script # RUN: ld.lld -o %t --script %t.script %t.o # RUN: llvm-objdump -s %t | FileCheck %s -# RUN: echo "SECTIONS { .text : { *(.text.foo) *(.text.bar) } }" > %t.script +# RUN: echo "SECTIONS { .rodata : {*(.rodata*)} .text : {*(.text.foo) *(.text.bar)} }" > %t.script # RUN: ld.lld -o %t --script %t.script %t.o # RUN: llvm-objdump -s %t | FileCheck --check-prefix=INV %s diff --git a/lld/test/ELF/linkerscript/linkorder2.s b/lld/test/ELF/linkerscript/linkorder2.s index 4a538b6190e7..5b2eeea08abb 100644 --- a/lld/test/ELF/linkerscript/linkorder2.s +++ b/lld/test/ELF/linkerscript/linkorder2.s @@ -1,6 +1,6 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: echo "SECTIONS { .text : { *(.text.*) } }" > %t.script +# RUN: echo 'SECTIONS { .rodata : {*(.rodata.*)} .text : {*(.text.*)} }' > %t.script # RUN: echo "_bar" > %t.ord # RUN: echo "_foo" >> %t.ord diff --git a/lld/test/ELF/linkerscript/memory3.s b/lld/test/ELF/linkerscript/memory3.s index b9d609e59e31..56fc36d67a31 100644 --- a/lld/test/ELF/linkerscript/memory3.s +++ b/lld/test/ELF/linkerscript/memory3.s @@ -18,6 +18,6 @@ # CHECK: 0 00000000 0000000000000000 # CHECK: 1 .text 00000001 0000000000001000 -.section .text.foo,"ax",%progbits +.section .text,"ax",%progbits foo: nop diff --git a/lld/test/ELF/linkerscript/orphan-report.s b/lld/test/ELF/linkerscript/orphan-report.s index 5203a6d20de2..3dca23267ec6 100644 --- a/lld/test/ELF/linkerscript/orphan-report.s +++ b/lld/test/ELF/linkerscript/orphan-report.s @@ -24,7 +24,7 @@ # RUN: %t.o 2>&1 | FileCheck %s --check-prefixes=COMMON,DYNSYM,SYMTAB # COMMON: {{.*}}.o:(.text) is being placed in '.text' -# COMMON-NEXT: {{.*}}.o:(.text.2) is being placed in '.text' +# COMMON-NEXT: {{.*}}.o:(.text.2) is being placed in '.text.2' # COMMON-NEXT: :(.comment) is being placed in '.comment' # DYNSYM-NEXT: :(.dynsym) is being placed in '.dynsym' # DYNSYM-NEXT: :(.gnu.hash) is being placed in '.gnu.hash' diff --git a/lld/test/ELF/linkerscript/symbol-assign-many-passes2.test b/lld/test/ELF/linkerscript/symbol-assign-many-passes2.test index 973a4881850e..18dc5019ee1e 100644 --- a/lld/test/ELF/linkerscript/symbol-assign-many-passes2.test +++ b/lld/test/ELF/linkerscript/symbol-assign-many-passes2.test @@ -22,7 +22,7 @@ SECTIONS { b = c + 1; c = d + 1; d = e + 1; - *(.text); + *(.text*); } e = .; } diff --git a/lld/test/ELF/mips-npic-call-pic-script.s b/lld/test/ELF/mips-npic-call-pic-script.s index 0ce1bfe94779..041c62101f7f 100644 --- a/lld/test/ELF/mips-npic-call-pic-script.s +++ b/lld/test/ELF/mips-npic-call-pic-script.s @@ -87,13 +87,13 @@ __start: # ORPH1: Disassembly of section .text: # ORPH1-EMPTY: # ORPH1-NEXT: <__start>: -# ORPH1-NEXT: 20000: jal 131156 <__LA25Thunk_foo1a> +# ORPH1-NEXT: 20000: jal 131168 <__LA25Thunk_foo1a> # ORPH1-NEXT: 20004: nop -# ORPH1-NEXT: 20008: jal 131208 <__LA25Thunk_foo2> +# ORPH1-NEXT: 20008: jal 131216 <__LA25Thunk_foo2> # ORPH1-NEXT: 2000c: nop -# ORPH1-NEXT: 20010: jal 131172 <__LA25Thunk_foo1b> +# ORPH1-NEXT: 20010: jal 131184 <__LA25Thunk_foo1b> # ORPH1-NEXT: 20014: nop -# ORPH1-NEXT: 20018: jal 131208 <__LA25Thunk_foo2> +# ORPH1-NEXT: 20018: jal 131216 <__LA25Thunk_foo2> # ORPH1-NEXT: 2001c: nop # ORPH1-NEXT: 20020: jal 131120 <__LA25Thunk_fpic> # ORPH1-NEXT: 20024: nop @@ -113,16 +113,16 @@ __start: # ORPH1-NEXT: 20050: nop # ORPH1: <__LA25Thunk_foo1a>: -# ORPH1-NEXT: 20054: lui $25, 2 -# ORPH1-NEXT: 20058: j 131200 -# ORPH1-NEXT: 2005c: addiu $25, $25, 128 -# ORPH1-NEXT: 20060: nop +# ORPH1-NEXT: 20060: lui $25, 2 +# ORPH1-NEXT: j 131200 +# ORPH1-NEXT: addiu $25, $25, 128 +# ORPH1-NEXT: nop # ORPH1: <__LA25Thunk_foo1b>: -# ORPH1-NEXT: 20064: lui $25, 2 -# ORPH1-NEXT: 20068: j 131204 -# ORPH1-NEXT: 2006c: addiu $25, $25, 132 -# ORPH1-NEXT: 20070: nop +# ORPH1-NEXT: 20070: lui $25, 2 +# ORPH1-NEXT: j 131204 +# ORPH1-NEXT: addiu $25, $25, 132 +# ORPH1-NEXT: nop # ORPH1: : # ORPH1-NEXT: 20080: nop @@ -131,17 +131,17 @@ __start: # ORPH1-NEXT: 20084: nop # ORPH1: <__LA25Thunk_foo2>: -# ORPH1-NEXT: 20088: lui $25, 2 -# ORPH1-NEXT: 2008c: j 131232 -# ORPH1-NEXT: 20090: addiu $25, $25, 160 -# ORPH1-NEXT: 20094: nop +# ORPH1-NEXT: 20090: lui $25, 2 +# ORPH1-NEXT: j 131232 +# ORPH1-NEXT: addiu $25, $25, 160 +# ORPH1-NEXT: nop # ORPH1: : # ORPH1-NEXT: 200a0: nop # Test script with orphans added to new OutputSection, the .text.1 and # .text.2 sections will form a new OutputSection .text -# RUN: echo "SECTIONS { .out 0x20000 : { *(.text) } }" > %t3.script +# RUN: echo "SECTIONS { .out 0x20000 : { *(.text) } .text : {*(.text*)} }" > %t3.script # RUN: ld.lld --script %t3.script %t-npic.o %t-pic.o %t-sto-pic.o -o %t3.exe # RUN: llvm-objdump -d --no-show-raw-insn %t3.exe | FileCheck --check-prefix=ORPH2 %s diff --git a/lld/test/ELF/shuffle-sections-init-fini.s b/lld/test/ELF/shuffle-sections-init-fini.s index 31d87bb32444..d98ca8d359de 100644 --- a/lld/test/ELF/shuffle-sections-init-fini.s +++ b/lld/test/ELF/shuffle-sections-init-fini.s @@ -30,7 +30,9 @@ ## With a SECTIONS command, SHT_INIT_ARRAY prirotities are ignored. ## All .init_array* are shuffled together. -# RUN: echo 'SECTIONS {}' > %t.script +# RUN: echo 'SECTIONS { \ +# RUN: .init_array : { *(.init_array*) } \ +# RUN: .fini_array : { *(.fini_array*) }}' > %t.script # RUN: ld.lld -T %t.script %t.o -o %t2 # RUN: llvm-readelf -x .init -x .fini -x .init_array -x .fini_array %t2 | \ # RUN: FileCheck --check-prefixes=CHECK2,ORDERED2 %s diff --git a/lld/test/ELF/text-section-prefix.s b/lld/test/ELF/text-section-prefix.s index e20828ab26aa..022b4167037d 100644 --- a/lld/test/ELF/text-section-prefix.s +++ b/lld/test/ELF/text-section-prefix.s @@ -1,4 +1,7 @@ # REQUIRES: x86 +## -z keep-text-section-prefix separates text sections with prefix .text.hot, +## .text.unlikely, .text.startup, or .text.exit, in the absence of a SECTIONS command. + # RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o # RUN: ld.lld %t.o -o %t1 # RUN: llvm-readelf -S %t1 | FileCheck --check-prefix=NOKEEP %s @@ -17,9 +20,18 @@ # NOKEEP: [ 1] .text # NOKEEP-NOT: .text +## With a SECTIONS command, orphan sections are created verbatim. +## No grouping is performed for them. # RUN: echo 'SECTIONS {}' > %t.lds # RUN: ld.lld -T %t.lds -z keep-text-section-prefix %t.o -o %t.script -# RUN: llvm-readelf -S %t.script | FileCheck --check-prefix=KEEP %s +# RUN: llvm-readelf -S %t.script | FileCheck --check-prefix=SCRIPT %s + +# SCRIPT: .text +# SCRIPT-NEXT: .text.f +# SCRIPT-NEXT: .text.hot.f_hot +# SCRIPT-NEXT: .text.startup.f_startup +# SCRIPT-NEXT: .text.exit.f_exit +# SCRIPT-NEXT: .text.unlikely.f_unlikely .globl _start _start: From a1fe6beb1ec3903e9c9351ae58c6747545189a58 Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Mon, 23 Mar 2020 13:56:07 -0400 Subject: [PATCH 20/59] [InstCombine] remove one-use check for ctpop -> cttz Two one-use checks were added with rGfdcb27105537, but only the first one is necessary to limit an increase in instruction count. The second transform only creates one instruction, so it is always a reasonable canonicalization/optimization. --- llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp | 3 +-- llvm/test/Transforms/InstCombine/ctpop-cttz.ll | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index a234779ba24f..b28da9464933 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1343,8 +1343,7 @@ static Instruction *foldCtpop(IntrinsicInst &II, InstCombiner &IC) { } // ctpop(~x & (x - 1)) -> cttz(x, false) - if (Op0->hasOneUse() && - match(Op0, + if (match(Op0, m_c_And(m_Not(m_Value(X)), m_Add(m_Deferred(X), m_AllOnes())))) { Function *F = Intrinsic::getDeclaration(II.getModule(), Intrinsic::cttz, Ty); diff --git a/llvm/test/Transforms/InstCombine/ctpop-cttz.ll b/llvm/test/Transforms/InstCombine/ctpop-cttz.ll index f1fe9384e3fe..6ac3cfe36bbc 100644 --- a/llvm/test/Transforms/InstCombine/ctpop-cttz.ll +++ b/llvm/test/Transforms/InstCombine/ctpop-cttz.ll @@ -78,7 +78,7 @@ define i32 @ctpop2_multiuse(i32 %0) { ; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP0:%.*]], -1 ; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[TMP0]], -1 ; CHECK-NEXT: [[TMP4:%.*]] = and i32 [[TMP3]], [[TMP2]] -; CHECK-NEXT: [[TMP5:%.*]] = tail call i32 @llvm.ctpop.i32(i32 [[TMP4]]), !range !0 +; CHECK-NEXT: [[TMP5:%.*]] = call i32 @llvm.cttz.i32(i32 [[TMP0]], i1 false), !range !0 ; CHECK-NEXT: [[TMP6:%.*]] = add i32 [[TMP5]], [[TMP4]] ; CHECK-NEXT: ret i32 [[TMP6]] ; From 42d8f48ccfcd48a1dba76a14a86d45eec27ca649 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Mon, 23 Mar 2020 09:51:07 -0700 Subject: [PATCH 21/59] Fix a warning building on my machine, NFC. warning: unused function 'compilePtxToCubinForTesting' Summary: Also eliminate the redunant anon namespace around the already static function. Reviewers: herhut Subscribers: hiraditya, steven_wu, dexonsmith, mehdi_amini, rriddle, jpienaar, burmako, shauheen, antiagainst, nicolasvasilache, csigg, arpith-jacob, mgester, lucyrfox, aartbik, liufengdb, Joonsoo, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D76627 --- mlir/test/lib/Transforms/TestConvertGPUKernelToCubin.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mlir/test/lib/Transforms/TestConvertGPUKernelToCubin.cpp b/mlir/test/lib/Transforms/TestConvertGPUKernelToCubin.cpp index 2a2259547b37..e0c4c1907c4f 100644 --- a/mlir/test/lib/Transforms/TestConvertGPUKernelToCubin.cpp +++ b/mlir/test/lib/Transforms/TestConvertGPUKernelToCubin.cpp @@ -9,18 +9,15 @@ #include "mlir/Conversion/GPUToCUDA/GPUToCUDAPass.h" #include "mlir/Pass/Pass.h" #include "mlir/Pass/PassManager.h" - using namespace mlir; -namespace { +#if MLIR_CUDA_CONVERSIONS_ENABLED static OwnedCubin compilePtxToCubinForTesting(const std::string &, Location, StringRef) { const char data[] = "CUBIN"; return std::make_unique>(data, data + sizeof(data) - 1); } -} // end anonymous namespace -#if MLIR_CUDA_CONVERSIONS_ENABLED namespace mlir { void registerTestConvertGPUKernelToCubinPass() { PassPipelineRegistration<>("test-kernel-to-cubin", From 1b9cd51d55b33cfaf68e21fa5396539ca54e5324 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Mon, 23 Mar 2020 11:12:10 -0700 Subject: [PATCH 22/59] [CMake] Fix AMDGPUTests -DBUILD_SHARED_LIBS=on builds and trim dependencies of AMDGPUTests and AMDDwarfTests after D76357/G24698e526f619271705fe72bcaa928be9bc82484 FAILED: unittests/Target/AMDGPU/AMDGPUTests ... ld.lld: error: undefined symbol: llvm::MCRegisterInfo::getLLVMRegNum(unsigned int, bool) const >>> referenced by DwarfRegMappings.cpp:60 (/usr/local/google/home/maskray/llvm/llvm/unittests/Target/AMDGPU/DwarfRegMappings.cpp:60) >>> unittests/Target/AMDGPU/CMakeFiles/AMDGPUTests.dir/DwarfRegMappings.cpp.o:(AMDGPUDwarfRegMappingTests_TestWave64DwarfRegMapping_Test::TestBody()) >>> referenced by DwarfRegMappings.cpp:82 (/usr/local/google/home/maskray/llvm/llvm/unittests/Target/AMDGPU/DwarfRegMappings.cpp:82) >>> unittests/Target/AMDGPU/CMakeFiles/AMDGPUTests.dir/DwarfRegMappings.cpp.o:(AMDGPUDwarfRegMappingTests_TestWave32DwarfRegMapping_Test::TestBody()) A -DBUILD_SHARED_LIBS=off build is good because AMDGPUCodeGen pulls in MC. A -DBUILD_SHARED_LIBS=on build requires all direct dependencies (MC) to be listed becuase llvm/cmake/modules/HandleLLVMOptions.cmake uses -Wl,-z,defs --- llvm/unittests/MC/AMDGPU/CMakeLists.txt | 4 +++- llvm/unittests/Target/AMDGPU/CMakeLists.txt | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/llvm/unittests/MC/AMDGPU/CMakeLists.txt b/llvm/unittests/MC/AMDGPU/CMakeLists.txt index b3581949a6da..9a77415590d7 100644 --- a/llvm/unittests/MC/AMDGPU/CMakeLists.txt +++ b/llvm/unittests/MC/AMDGPU/CMakeLists.txt @@ -1,5 +1,7 @@ set(LLVM_LINK_COMPONENTS - ${LLVM_TARGETS_TO_BUILD} + AMDGPUCodeGen + AMDGPUDesc + AMDGPUInfo MC Support ) diff --git a/llvm/unittests/Target/AMDGPU/CMakeLists.txt b/llvm/unittests/Target/AMDGPU/CMakeLists.txt index 3e8134708b4f..ba6b92f378a6 100644 --- a/llvm/unittests/Target/AMDGPU/CMakeLists.txt +++ b/llvm/unittests/Target/AMDGPU/CMakeLists.txt @@ -4,9 +4,11 @@ include_directories( ) set(LLVM_LINK_COMPONENTS - ${LLVM_TARGETS_TO_BUILD} + AMDGPUCodeGen + AMDGPUDesc + AMDGPUInfo + MC Support - Target ) add_llvm_target_unittest(AMDGPUTests From a567d6809e1514f34975d746bb1c93301792a74c Mon Sep 17 00:00:00 2001 From: shafik Date: Mon, 23 Mar 2020 11:42:41 -0700 Subject: [PATCH 23/59] [DataFormatters] Add formatter for libc++ std::unique_ptr This adds a formatter for libc++ std::unique_ptr. I also refactored GetValueOfCompressedPair(...) out of LibCxxList.cpp since I need the same functionality and it made sense to share it. Differential Revision: https://reviews.llvm.org/D76476 --- .../lldb/DataFormatters/FormattersHelpers.h | 2 + .../DataFormatters/FormattersHelpers.cpp | 11 +++ .../Language/CPlusPlus/CPlusPlusLanguage.cpp | 13 +++ .../Plugins/Language/CPlusPlus/LibCxx.cpp | 98 +++++++++++++++++++ .../Plugins/Language/CPlusPlus/LibCxx.h | 28 ++++++ .../Plugins/Language/CPlusPlus/LibCxxList.cpp | 13 +-- .../libcxx/unique_ptr/Makefile | 6 ++ .../TestDataFormatterLibcxxUniquePtr.py | 47 +++++++++ .../libcxx/unique_ptr/main.cpp | 13 +++ 9 files changed, 220 insertions(+), 11 deletions(-) create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/Makefile create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp diff --git a/lldb/include/lldb/DataFormatters/FormattersHelpers.h b/lldb/include/lldb/DataFormatters/FormattersHelpers.h index 93642e57fde0..a5b0da57e5d8 100644 --- a/lldb/include/lldb/DataFormatters/FormattersHelpers.h +++ b/lldb/include/lldb/DataFormatters/FormattersHelpers.h @@ -56,6 +56,8 @@ size_t ExtractIndexFromString(const char *item_name); lldb::addr_t GetArrayAddressOrPointerValue(ValueObject &valobj); +lldb::ValueObjectSP GetValueOfLibCXXCompressedPair(ValueObject &pair); + time_t GetOSXEpoch(); struct InferiorSizedWord { diff --git a/lldb/source/DataFormatters/FormattersHelpers.cpp b/lldb/source/DataFormatters/FormattersHelpers.cpp index 96e93808c18e..7944ff06eee5 100644 --- a/lldb/source/DataFormatters/FormattersHelpers.cpp +++ b/lldb/source/DataFormatters/FormattersHelpers.cpp @@ -142,3 +142,14 @@ lldb_private::formatters::GetArrayAddressOrPointerValue(ValueObject &valobj) { return data_addr; } + +lldb::ValueObjectSP +lldb_private::formatters::GetValueOfLibCXXCompressedPair(ValueObject &pair) { + ValueObjectSP value = + pair.GetChildMemberWithName(ConstString("__value_"), true); + if (!value) { + // pre-r300140 member name + value = pair.GetChildMemberWithName(ConstString("__first_"), true); + } + return value; +} diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index 97084da5fffa..ecb577e0c531 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -611,6 +611,15 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "shared_ptr synthetic children", ConstString("^(std::__[[:alnum:]]+::)shared_ptr<.+>(( )?&)?$"), stl_synth_flags, true); + + ConstString libcxx_std_unique_ptr_regex( + "^std::__[[:alnum:]]+::unique_ptr<.+>(( )?&)?$"); + AddCXXSynthetic( + cpp_category_sp, + lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator, + "unique_ptr synthetic children", libcxx_std_unique_ptr_regex, + stl_synth_flags, true); + AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, @@ -715,6 +724,10 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "libc++ std::weak_ptr summary provider", ConstString("^std::__[[:alnum:]]+::weak_ptr<.+>(( )?&)?$"), stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxUniquePointerSummaryProvider, + "libc++ std::unique_ptr summary provider", + libcxx_std_unique_ptr_regex, stl_summary_flags, true); AddCXXSynthetic( cpp_category_sp, diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp index 7152ff407f29..84dd09a47d8a 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp @@ -144,6 +144,43 @@ bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider( return true; } +bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider( + ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); + if (!valobj_sp) + return false; + + ValueObjectSP ptr_sp( + valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)); + if (!ptr_sp) + return false; + + ptr_sp = GetValueOfLibCXXCompressedPair(*ptr_sp); + if (!ptr_sp) + return false; + + if (ptr_sp->GetValueAsUnsigned(0) == 0) { + stream.Printf("nullptr"); + return true; + } else { + bool print_pointee = false; + Status error; + ValueObjectSP pointee_sp = ptr_sp->Dereference(error); + if (pointee_sp && error.Success()) { + if (pointee_sp->DumpPrintableRepresentation( + stream, ValueObject::eValueObjectRepresentationStyleSummary, + lldb::eFormatInvalid, + ValueObject::PrintableRepresentationSpecialCases::eDisable, + false)) + print_pointee = true; + } + if (!print_pointee) + stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0)); + } + + return true; +} + /* (lldb) fr var ibeg --raw --ptr-depth 1 (std::__1::__map_iteratorGetChildMemberWithName(ConstString("__ptr_"), true)); + if (!ptr_sp) + return false; + + m_compressed_pair_sp = GetValueOfLibCXXCompressedPair(*ptr_sp); + + return false; +} + +bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: + MightHaveChildren() { + return true; +} + +size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: + GetIndexOfChildWithName(ConstString name) { + if (name == "__value_") + return 0; + return UINT32_MAX; +} + bool lldb_private::formatters::LibcxxContainerSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { if (valobj.IsPointerType()) { diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h index a92e8be9abe9..ea5a7c178178 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h @@ -43,6 +43,10 @@ bool LibcxxSmartPointerSummaryProvider( const TypeSummaryOptions &options); // libc++ std::shared_ptr<> and std::weak_ptr<> +// libc++ std::unique_ptr<> +bool LibcxxUniquePointerSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); + bool LibcxxFunctionSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); // libc++ std::function<> @@ -107,6 +111,26 @@ class LibcxxSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd { lldb::ByteOrder m_byte_order; }; +class LibcxxUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); + + size_t CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + + bool Update() override; + + bool MightHaveChildren() override; + + size_t GetIndexOfChildWithName(ConstString name) override; + + ~LibcxxUniquePtrSyntheticFrontEnd() override; + +private: + lldb::ValueObjectSP m_compressed_pair_sp; +}; + SyntheticChildrenFrontEnd * LibcxxBitsetSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); @@ -115,6 +139,10 @@ SyntheticChildrenFrontEnd * LibcxxSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); +SyntheticChildrenFrontEnd * +LibcxxUniquePtrSyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP); + SyntheticChildrenFrontEnd * LibcxxStdVectorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp index 4c5940a45766..0d5ae16a0b29 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp @@ -290,15 +290,6 @@ ValueObjectSP ForwardListFrontEnd::GetChildAtIndex(size_t idx) { m_element_type); } -static ValueObjectSP GetValueOfCompressedPair(ValueObject &pair) { - ValueObjectSP value = pair.GetChildMemberWithName(ConstString("__value_"), true); - if (! value) { - // pre-r300140 member name - value = pair.GetChildMemberWithName(ConstString("__first_"), true); - } - return value; -} - bool ForwardListFrontEnd::Update() { AbstractListFrontEnd::Update(); @@ -311,7 +302,7 @@ bool ForwardListFrontEnd::Update() { m_backend.GetChildMemberWithName(ConstString("__before_begin_"), true)); if (!impl_sp) return false; - impl_sp = GetValueOfCompressedPair(*impl_sp); + impl_sp = GetValueOfLibCXXCompressedPair(*impl_sp); if (!impl_sp) return false; m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get(); @@ -332,7 +323,7 @@ size_t ListFrontEnd::CalculateNumChildren() { ValueObjectSP size_alloc( m_backend.GetChildMemberWithName(ConstString("__size_alloc_"), true)); if (size_alloc) { - ValueObjectSP value = GetValueOfCompressedPair(*size_alloc); + ValueObjectSP value = GetValueOfLibCXXCompressedPair(*size_alloc); if (value) { m_count = value->GetValueAsUnsigned(UINT32_MAX); } diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/Makefile new file mode 100644 index 000000000000..7e57f13aea55 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/Makefile @@ -0,0 +1,6 @@ +CXX_SOURCES := main.cpp + +USE_LIBCPP := 1 + +CXXFLAGS_EXTRAS := -std=c++14 +include Makefile.rules diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py new file mode 100644 index 000000000000..b91e494258bf --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py @@ -0,0 +1,47 @@ +""" +Test lldb data formatter for libc++ std::unique_ptr. +""" + + + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class LibcxUniquePtrDataFormatterTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @add_test_categories(["libc++"]) + def test_with_run_command(self): + """Test that that file and class static variables display correctly.""" + self.build() + + (self.target, self.process, _, bkpt) = lldbutil.run_to_source_breakpoint(self, '// break here', + lldb.SBFileSpec("main.cpp", False)) + + self.expect("frame variable up_empty", + substrs=['(std::unique_ptr >) up_empty = nullptr {', + '__value_ = ', + '}']) + + self.expect("frame variable up_int", + substrs=['(std::unique_ptr >) up_int = 10 {', + '__value_ = ', + '}']) + + self.expect("frame variable up_int_ref", + substrs=['(std::unique_ptr > &) up_int_ref = 10: {', + '__value_ = ', + '}']) + + self.expect("frame variable up_int_ref_ref", + substrs=['(std::unique_ptr > &&) up_int_ref_ref = 10: {', + '__value_ = ', + '}']) + + self.expect("frame variable up_str", + substrs=['up_str = "hello" {', + '__value_ = ', + '}']) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp new file mode 100644 index 000000000000..4ccffe2a006d --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp @@ -0,0 +1,13 @@ +#include +#include +#include + +int main() { + std::unique_ptr up_empty; + std::unique_ptr up_int = std::make_unique(10); + std::unique_ptr up_str = std::make_unique("hello"); + std::unique_ptr &up_int_ref = up_int; + std::unique_ptr &&up_int_ref_ref = std::make_unique(10); + + return 0; // break here +} From 04f2b717d23b17d3bd0a15f6b2b3c3c79a83b955 Mon Sep 17 00:00:00 2001 From: MaheshRavishankar Date: Thu, 19 Mar 2020 16:02:18 -0700 Subject: [PATCH 24/59] [mlir] Fix unsafe create operation in GreedyPatternRewriter When trying to fold an operation during operation creation check that the operation folding succeeds before inserting the op. Differential Revision: https://reviews.llvm.org/D76415 --- mlir/include/mlir/Transforms/FoldUtils.h | 19 ++++++++++++++----- mlir/lib/Transforms/Utils/FoldUtils.cpp | 20 ++++++++++++-------- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/mlir/include/mlir/Transforms/FoldUtils.h b/mlir/include/mlir/Transforms/FoldUtils.h index 83ce3bf0d072..0bab87c5e4e3 100644 --- a/mlir/include/mlir/Transforms/FoldUtils.h +++ b/mlir/include/mlir/Transforms/FoldUtils.h @@ -75,11 +75,20 @@ class OperationFolder { template void create(OpBuilder &builder, SmallVectorImpl &results, Location location, Args &&... args) { - Operation *op = builder.create(location, std::forward(args)...); - if (failed(tryToFold(op, results))) + // The op needs to be inserted only if the fold (below) fails, or the number + // of results of the op is zero (which is treated as an in-place + // fold). Using create methods of the builder will insert the op, so not + // using it here. + OperationState state(location, OpTy::getOperationName()); + OpTy::build(&builder, state, std::forward(args)...); + Operation *op = Operation::create(state); + + if (failed(tryToFold(builder, op, results)) || op->getNumResults() == 0) { + builder.insert(op); results.assign(op->result_begin(), op->result_end()); - else if (op->getNumResults() != 0) - op->erase(); + return; + } + op->destroy(); } /// Overload to create or fold a single result operation. @@ -120,7 +129,7 @@ class OperationFolder { /// Tries to perform folding on the given `op`. If successful, populates /// `results` with the results of the folding. LogicalResult tryToFold( - Operation *op, SmallVectorImpl &results, + OpBuilder &builder, Operation *op, SmallVectorImpl &results, function_ref processGeneratedConstants = nullptr); /// Try to get or create a new constant entry. On success this returns the diff --git a/mlir/lib/Transforms/Utils/FoldUtils.cpp b/mlir/lib/Transforms/Utils/FoldUtils.cpp index 7d209b2231a2..f2099bca75ea 100644 --- a/mlir/lib/Transforms/Utils/FoldUtils.cpp +++ b/mlir/lib/Transforms/Utils/FoldUtils.cpp @@ -24,8 +24,8 @@ using namespace mlir; /// inserted into. static Region *getInsertionRegion( DialectInterfaceCollection &interfaces, - Operation *op) { - while (Region *region = op->getParentRegion()) { + Block *insertionBlock) { + while (Region *region = insertionBlock->getParent()) { // Insert in this region for any of the following scenarios: // * The parent is unregistered, or is known to be isolated from above. // * The parent is a top-level operation. @@ -40,7 +40,7 @@ static Region *getInsertionRegion( return region; // Traverse up the parent looking for an insertion region. - op = parentOp; + insertionBlock = parentOp->getBlock(); } llvm_unreachable("expected valid insertion region"); } @@ -82,7 +82,8 @@ LogicalResult OperationFolder::tryToFold( // Try to fold the operation. SmallVector results; - if (failed(tryToFold(op, results, processGeneratedConstants))) + OpBuilder builder(op); + if (failed(tryToFold(builder, op, results, processGeneratedConstants))) return failure(); // Check to see if the operation was just updated in place. @@ -117,7 +118,8 @@ void OperationFolder::notifyRemoval(Operation *op) { assert(constValue); // Get the constant map that this operation was uniqued in. - auto &uniquedConstants = foldScopes[getInsertionRegion(interfaces, op)]; + auto &uniquedConstants = + foldScopes[getInsertionRegion(interfaces, op->getBlock())]; // Erase all of the references to this operation. auto type = op->getResult(0).getType(); @@ -135,7 +137,7 @@ void OperationFolder::clear() { /// Tries to perform folding on the given `op`. If successful, populates /// `results` with the results of the folding. LogicalResult OperationFolder::tryToFold( - Operation *op, SmallVectorImpl &results, + OpBuilder &builder, Operation *op, SmallVectorImpl &results, function_ref processGeneratedConstants) { SmallVector operandConstants; SmallVector foldResults; @@ -164,9 +166,11 @@ LogicalResult OperationFolder::tryToFold( // Create a builder to insert new operations into the entry block of the // insertion region. - auto *insertRegion = getInsertionRegion(interfaces, op); + auto *insertRegion = + getInsertionRegion(interfaces, builder.getInsertionBlock()); auto &entry = insertRegion->front(); - OpBuilder builder(&entry, entry.begin()); + OpBuilder::InsertionGuard foldGuard(builder); + builder.setInsertionPoint(&entry, entry.begin()); // Get the constant map for the insertion region of this operation. auto &uniquedConstants = foldScopes[insertRegion]; From 328b72dd8209fc447b5eac3106072561bb01dff3 Mon Sep 17 00:00:00 2001 From: Andrew Ng Date: Sat, 21 Mar 2020 12:06:06 +0000 Subject: [PATCH 25/59] [Support] Fix clang warning in widenPath NFC Differential Revision: https://reviews.llvm.org/D76544 --- llvm/lib/Support/Windows/Path.inc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc index ee199aa1d4b1..0eadefb689fd 100644 --- a/llvm/lib/Support/Windows/Path.inc +++ b/llvm/lib/Support/Windows/Path.inc @@ -75,8 +75,7 @@ std::error_code widenPath(const Twine &Path8, SmallVectorImpl &Path16, SmallString Path8Str; Path8.toVector(Path8Str); - std::error_code EC = UTF8ToUTF16(Path8Str, Path16); - if (EC) + if (std::error_code EC = UTF8ToUTF16(Path8Str, Path16)) return EC; const bool IsAbsolute = llvm::sys::path::is_absolute(Path8); @@ -97,7 +96,7 @@ std::error_code widenPath(const Twine &Path8, SmallVectorImpl &Path16, return std::error_code(); if (!IsAbsolute) { - if (EC = llvm::sys::fs::make_absolute(Path8Str)) + if (std::error_code EC = llvm::sys::fs::make_absolute(Path8Str)) return EC; } From aa63eb6a461dcfd9cd3f1c09de36e75e8394634f Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Wed, 22 Jan 2020 10:31:03 -0500 Subject: [PATCH 26/59] GlobalISel: Add computeKnownBitsForTargetInstr I think we can save the MRI argument from these since it's in GISelKnownBits already, but currently not accessible. Implementation deferred to avoid dependency on other patches. --- .../llvm/CodeGen/GlobalISel/GISelKnownBits.h | 3 ++ llvm/include/llvm/CodeGen/TargetLowering.h | 10 +++++ .../lib/CodeGen/GlobalISel/GISelKnownBits.cpp | 41 ++++++++++++++++--- .../CodeGen/SelectionDAG/TargetLowering.cpp | 6 +++ 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GISelKnownBits.h b/llvm/include/llvm/CodeGen/GlobalISel/GISelKnownBits.h index 906e8a9ac312..976d42d58846 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/GISelKnownBits.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/GISelKnownBits.h @@ -50,6 +50,9 @@ class GISelKnownBits : public GISelChangeObserver { // KnownBitsAPI KnownBits getKnownBits(Register R); + KnownBits getKnownBits(Register R, const APInt &DemandedElts, + unsigned Depth = 0); + // Calls getKnownBits for first operand def of MI. KnownBits getKnownBits(MachineInstr &MI); APInt getKnownZeroes(Register R); diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h index 0552420c3c33..fefa8daa60a1 100644 --- a/llvm/include/llvm/CodeGen/TargetLowering.h +++ b/llvm/include/llvm/CodeGen/TargetLowering.h @@ -3332,6 +3332,16 @@ class TargetLowering : public TargetLoweringBase { const SelectionDAG &DAG, unsigned Depth = 0) const; + /// This method can be implemented by targets that want to expose additional + /// information about sign bits to GlobalISel combiners. The DemandedElts + /// argument allows us to only collect the minimum sign bits that are shared + /// by the requested vector elements. + virtual unsigned computeNumSignBitsForTargetInstr(GISelKnownBits &Analysis, + Register R, + const APInt &DemandedElts, + const MachineRegisterInfo &MRI, + unsigned Depth = 0) const; + /// Attempt to simplify any target nodes based on the demanded vector /// elements, returning true on success. Otherwise, analyze the expression and /// return a mask of KnownUndef and KnownZero elements for the expression diff --git a/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp b/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp index 8e369fe9e31d..213af320531c 100644 --- a/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp +++ b/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp @@ -65,12 +65,18 @@ KnownBits GISelKnownBits::getKnownBits(MachineInstr &MI) { } KnownBits GISelKnownBits::getKnownBits(Register R) { - KnownBits Known; - LLT Ty = MRI.getType(R); + const LLT Ty = MRI.getType(R); APInt DemandedElts = Ty.isVector() ? APInt::getAllOnesValue(Ty.getNumElements()) : APInt(1, 1); + return getKnownBits(R, DemandedElts); +} + +KnownBits GISelKnownBits::getKnownBits(Register R, const APInt &DemandedElts, + unsigned Depth) { // For now, we only maintain the cache during one request. assert(ComputeKnownBitsCache.empty() && "Cache should have been cleared"); + + KnownBits Known; computeKnownBitsImpl(R, Known, DemandedElts); ComputeKnownBitsCache.clear(); return Known; @@ -428,6 +434,7 @@ unsigned GISelKnownBits::computeNumSignBits(Register R, return 1; // No demanded elts, better to assume we don't know anything. LLT DstTy = MRI.getType(R); + const unsigned TyBits = DstTy.getScalarSizeInBits(); // Handle the case where this is called on a register that does not have a // type constraint. This is unlikely to occur except by looking through copies @@ -436,6 +443,7 @@ unsigned GISelKnownBits::computeNumSignBits(Register R, if (!DstTy.isValid()) return 1; + unsigned FirstAnswer = 1; switch (Opcode) { case TargetOpcode::COPY: { MachineOperand &Src = MI.getOperand(1); @@ -465,13 +473,34 @@ unsigned GISelKnownBits::computeNumSignBits(Register R, return NumSrcSignBits - (NumSrcBits - DstTyBits); break; } - default: + case TargetOpcode::G_INTRINSIC: + case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS: + default: { + unsigned NumBits = + TL.computeNumSignBitsForTargetInstr(*this, R, DemandedElts, MRI, Depth); + if (NumBits > 1) + FirstAnswer = std::max(FirstAnswer, NumBits); break; } + } + + // Finally, if we can prove that the top bits of the result are 0's or 1's, + // use this information. + KnownBits Known = getKnownBits(R, DemandedElts, Depth); + APInt Mask; + if (Known.isNonNegative()) { // sign bit is 0 + Mask = Known.Zero; + } else if (Known.isNegative()) { // sign bit is 1; + Mask = Known.One; + } else { + // Nothing known. + return FirstAnswer; + } - // TODO: Handle target instructions - // TODO: Fall back to known bits - return 1; + // Okay, we know that the sign bit in Mask is set. Use CLO to determine + // the number of identical bits in the top of the input value. + Mask <<= Mask.getBitWidth() - TyBits; + return std::max(FirstAnswer, Mask.countLeadingOnes()); } unsigned GISelKnownBits::computeNumSignBits(Register R, unsigned Depth) { diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 70d8656d2875..3f0c6443211e 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -2783,6 +2783,12 @@ unsigned TargetLowering::ComputeNumSignBitsForTargetNode(SDValue Op, return 1; } +unsigned TargetLowering::computeNumSignBitsForTargetInstr( + GISelKnownBits &Analysis, Register R, const APInt &DemandedElts, + const MachineRegisterInfo &MRI, unsigned Depth) const { + return 1; +} + bool TargetLowering::SimplifyDemandedVectorEltsForTargetNode( SDValue Op, const APInt &DemandedElts, APInt &KnownUndef, APInt &KnownZero, TargetLoweringOpt &TLO, unsigned Depth) const { From 58f843a5b3d672f703c91af92cb2fd805f09ccbc Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Sun, 22 Mar 2020 18:12:25 -0400 Subject: [PATCH 27/59] GlobalISel: Prepare to allow other target unit tests Currently all GlobalISel unittests use a hardcoded AArch64 target machine. Factor this so I can write some for AMDGPU specific known bits unittests. --- llvm/unittests/CodeGen/GlobalISel/CSETest.cpp | 4 +- .../GlobalISel/ConstantFoldingTest.cpp | 4 +- .../CodeGen/GlobalISel/GISelMITest.cpp | 38 ++++++ .../CodeGen/GlobalISel/GISelMITest.h | 61 ++++------ .../CodeGen/GlobalISel/KnownBitsTest.cpp | 28 ++--- .../GlobalISel/LegalizerHelperTest.cpp | 114 +++++++++--------- .../CodeGen/GlobalISel/LegalizerTest.cpp | 6 +- .../GlobalISel/MachineIRBuilderTest.cpp | 27 ++--- .../CodeGen/GlobalISel/PatternMatchTest.cpp | 18 +-- 9 files changed, 160 insertions(+), 140 deletions(-) diff --git a/llvm/unittests/CodeGen/GlobalISel/CSETest.cpp b/llvm/unittests/CodeGen/GlobalISel/CSETest.cpp index 999220fd250d..1c86d5ff9943 100644 --- a/llvm/unittests/CodeGen/GlobalISel/CSETest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/CSETest.cpp @@ -11,7 +11,7 @@ namespace { -TEST_F(GISelMITest, TestCSE) { +TEST_F(AArch64GISelMITest, TestCSE) { setUp(); if (!TM) return; @@ -79,7 +79,7 @@ TEST_F(GISelMITest, TestCSE) { EXPECT_EQ(&*Undef0, &*Undef1); } -TEST_F(GISelMITest, TestCSEConstantConfig) { +TEST_F(AArch64GISelMITest, TestCSEConstantConfig) { setUp(); if (!TM) return; diff --git a/llvm/unittests/CodeGen/GlobalISel/ConstantFoldingTest.cpp b/llvm/unittests/CodeGen/GlobalISel/ConstantFoldingTest.cpp index 2f99005105fd..127aaffc2878 100644 --- a/llvm/unittests/CodeGen/GlobalISel/ConstantFoldingTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/ConstantFoldingTest.cpp @@ -17,7 +17,7 @@ using namespace llvm; namespace { -TEST_F(GISelMITest, FoldWithBuilder) { +TEST_F(AArch64GISelMITest, FoldWithBuilder) { setUp(); if (!TM) return; @@ -68,7 +68,7 @@ TEST_F(GISelMITest, FoldWithBuilder) { EXPECT_EQ(-0x80, Cst); } -TEST_F(GISelMITest, FoldBinOp) { +TEST_F(AArch64GISelMITest, FoldBinOp) { setUp(); if (!TM) return; diff --git a/llvm/unittests/CodeGen/GlobalISel/GISelMITest.cpp b/llvm/unittests/CodeGen/GlobalISel/GISelMITest.cpp index 0558c4121fdd..5b59ee74852a 100644 --- a/llvm/unittests/CodeGen/GlobalISel/GISelMITest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/GISelMITest.cpp @@ -28,3 +28,41 @@ operator<<(std::ostream &OS, const MachineFunction &MF) { } } + +std::unique_ptr +AArch64GISelMITest::createTargetMachine() const { + Triple TargetTriple("aarch64--"); + std::string Error; + const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error); + if (!T) + return nullptr; + + TargetOptions Options; + return std::unique_ptr( + static_cast(T->createTargetMachine( + "AArch64", "", "", Options, None, None, CodeGenOpt::Aggressive))); +} + +void AArch64GISelMITest::getTargetTestModuleString(SmallString<512> &S, + StringRef MIRFunc) const { + (Twine(R"MIR( +--- +... +name: func +tracksRegLiveness: true +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } + - { id: 3, class: _ } +body: | + bb.1: + liveins: $x0, $x1, $x2, $x4 + + %0(s64) = COPY $x0 + %1(s64) = COPY $x1 + %2(s64) = COPY $x2 +)MIR") + + Twine(MIRFunc) + Twine("...\n")) + .toNullTerminatedStringRef(S); +} diff --git a/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h b/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h index 4254f4f759e4..53f5a1c4cd8c 100644 --- a/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h +++ b/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h @@ -53,21 +53,6 @@ std::ostream & operator<<(std::ostream &OS, const MachineFunction &MF); } -/// Create a TargetMachine. As we lack a dedicated always available target for -/// unittests, we go for "AArch64". -static std::unique_ptr createTargetMachine() { - Triple TargetTriple("aarch64--"); - std::string Error; - const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error); - if (!T) - return nullptr; - - TargetOptions Options; - return std::unique_ptr( - static_cast(T->createTargetMachine( - "AArch64", "", "", Options, None, None, CodeGenOpt::Aggressive))); -} - static std::unique_ptr parseMIR(LLVMContext &Context, std::unique_ptr &MIR, const TargetMachine &TM, @@ -90,34 +75,13 @@ static std::unique_ptr parseMIR(LLVMContext &Context, return M; } - static std::pair, std::unique_ptr> createDummyModule(LLVMContext &Context, const LLVMTargetMachine &TM, - StringRef MIRFunc) { - SmallString<512> S; - StringRef MIRString = (Twine(R"MIR( ---- -... -name: func -tracksRegLiveness: true -registers: - - { id: 0, class: _ } - - { id: 1, class: _ } - - { id: 2, class: _ } - - { id: 3, class: _ } -body: | - bb.1: - liveins: $x0, $x1, $x2, $x4 - - %0(s64) = COPY $x0 - %1(s64) = COPY $x1 - %2(s64) = COPY $x2 -)MIR") + Twine(MIRFunc) + Twine("...\n")) - .toNullTerminatedStringRef(S); + StringRef MIRString, const char *FuncName) { std::unique_ptr MIR; auto MMI = std::make_unique(&TM); std::unique_ptr M = - parseMIR(Context, MIR, TM, MIRString, "func", *MMI); + parseMIR(Context, MIR, TM, MIRString, FuncName, *MMI); return make_pair(std::move(M), std::move(MMI)); } @@ -140,11 +104,23 @@ static void collectCopies(SmallVectorImpl &Copies, class GISelMITest : public ::testing::Test { protected: GISelMITest() : ::testing::Test() {} + + /// Prepare a target specific LLVMTargetMachine. + virtual std::unique_ptr createTargetMachine() const = 0; + + /// Get the stub sample MIR test function. + virtual void getTargetTestModuleString(SmallString<512> &S, + StringRef MIRFunc) const = 0; + void setUp(StringRef ExtraAssembly = "") { TM = createTargetMachine(); if (!TM) return; - ModuleMMIPair = createDummyModule(Context, *TM, ExtraAssembly); + + SmallString<512> MIRString; + getTargetTestModuleString(MIRString, ExtraAssembly); + + ModuleMMIPair = createDummyModule(Context, *TM, MIRString, "func"); MF = getMFFromMMI(ModuleMMIPair.first.get(), ModuleMMIPair.second.get()); collectCopies(Copies, MF); EntryMBB = &*MF->begin(); @@ -152,6 +128,7 @@ class GISelMITest : public ::testing::Test { MRI = &MF->getRegInfo(); B.setInsertPt(*EntryMBB, EntryMBB->end()); } + LLVMContext Context; std::unique_ptr TM; MachineFunction *MF; @@ -163,6 +140,12 @@ class GISelMITest : public ::testing::Test { MachineRegisterInfo *MRI; }; +class AArch64GISelMITest : public GISelMITest { + std::unique_ptr createTargetMachine() const override; + void getTargetTestModuleString(SmallString<512> &S, + StringRef MIRFunc) const override; +}; + #define DefineLegalizerInfo(Name, SettingUpActionsBlock) \ class Name##Info : public LegalizerInfo { \ public: \ diff --git a/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp b/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp index a5372511b051..e2479b93e730 100644 --- a/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp @@ -10,7 +10,7 @@ #include "llvm/CodeGen/GlobalISel/GISelKnownBits.h" #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" -TEST_F(GISelMITest, TestKnownBitsCst) { +TEST_F(AArch64GISelMITest, TestKnownBitsCst) { StringRef MIRString = " %3:_(s8) = G_CONSTANT i8 1\n" " %4:_(s8) = COPY %3\n"; setUp(MIRString); @@ -30,7 +30,7 @@ TEST_F(GISelMITest, TestKnownBitsCst) { EXPECT_EQ(Res.Zero.getZExtValue(), Res2.Zero.getZExtValue()); } -TEST_F(GISelMITest, TestKnownBitsCstWithClass) { +TEST_F(AArch64GISelMITest, TestKnownBitsCstWithClass) { StringRef MIRString = " %10:gpr32 = MOVi32imm 1\n" " %4:_(s32) = COPY %10\n"; setUp(MIRString); @@ -58,7 +58,7 @@ TEST_F(GISelMITest, TestKnownBitsCstWithClass) { // Check that we are able to track bits through PHIs // and get the intersections of everything we know on each operand. -TEST_F(GISelMITest, TestKnownBitsCstPHI) { +TEST_F(AArch64GISelMITest, TestKnownBitsCstPHI) { StringRef MIRString = " bb.10:\n" " %10:_(s8) = G_CONSTANT i8 3\n" " %11:_(s1) = G_IMPLICIT_DEF\n" @@ -92,7 +92,7 @@ TEST_F(GISelMITest, TestKnownBitsCstPHI) { // Check that we report we know nothing when we hit a // non-generic register. // Note: this could be improved though! -TEST_F(GISelMITest, TestKnownBitsCstPHIToNonGenericReg) { +TEST_F(AArch64GISelMITest, TestKnownBitsCstPHIToNonGenericReg) { StringRef MIRString = " bb.10:\n" " %10:gpr32 = MOVi32imm 3\n" " %11:_(s1) = G_IMPLICIT_DEF\n" @@ -129,7 +129,7 @@ TEST_F(GISelMITest, TestKnownBitsCstPHIToNonGenericReg) { // here to cover the code that stops the analysis of PHIs // earlier. In that case, we would not even look at the // second incoming value. -TEST_F(GISelMITest, TestKnownBitsUnknownPHI) { +TEST_F(AArch64GISelMITest, TestKnownBitsUnknownPHI) { StringRef MIRString = " bb.10:\n" " %10:_(s64) = COPY %0\n" @@ -165,7 +165,7 @@ TEST_F(GISelMITest, TestKnownBitsUnknownPHI) { // For now, the analysis just stops and assumes it knows nothing, // eventually we could teach it how to properly track phis that // loop back. -TEST_F(GISelMITest, TestKnownBitsCstPHIWithLoop) { +TEST_F(AArch64GISelMITest, TestKnownBitsCstPHIWithLoop) { StringRef MIRString = " bb.10:\n" " %10:_(s8) = G_CONSTANT i8 3\n" @@ -210,7 +210,7 @@ TEST_F(GISelMITest, TestKnownBitsCstPHIWithLoop) { // on PHIs, but eventually we could teach it how to properly track // phis that loop back without relying on the luck effect of max // depth. -TEST_F(GISelMITest, TestKnownBitsDecreasingCstPHIWithLoop) { +TEST_F(AArch64GISelMITest, TestKnownBitsDecreasingCstPHIWithLoop) { StringRef MIRString = " bb.10:\n" " %10:_(s8) = G_CONSTANT i8 5\n" " %11:_(s8) = G_CONSTANT i8 1\n" @@ -243,7 +243,7 @@ TEST_F(GISelMITest, TestKnownBitsDecreasingCstPHIWithLoop) { EXPECT_EQ(Res.Zero.getZExtValue(), Res2.Zero.getZExtValue()); } -TEST_F(GISelMITest, TestKnownBitsPtrToIntViceVersa) { +TEST_F(AArch64GISelMITest, TestKnownBitsPtrToIntViceVersa) { StringRef MIRString = " %3:_(s16) = G_CONSTANT i16 256\n" " %4:_(p0) = G_INTTOPTR %3\n" " %5:_(s32) = G_PTRTOINT %4\n" @@ -259,7 +259,7 @@ TEST_F(GISelMITest, TestKnownBitsPtrToIntViceVersa) { EXPECT_EQ(256u, Res.One.getZExtValue()); EXPECT_EQ(0xfffffeffu, Res.Zero.getZExtValue()); } -TEST_F(GISelMITest, TestKnownBitsXOR) { +TEST_F(AArch64GISelMITest, TestKnownBitsXOR) { StringRef MIRString = " %3:_(s8) = G_CONSTANT i8 4\n" " %4:_(s8) = G_CONSTANT i8 7\n" " %5:_(s8) = G_XOR %3, %4\n" @@ -276,7 +276,7 @@ TEST_F(GISelMITest, TestKnownBitsXOR) { EXPECT_EQ(252u, Res.Zero.getZExtValue()); } -TEST_F(GISelMITest, TestKnownBits) { +TEST_F(AArch64GISelMITest, TestKnownBits) { StringRef MIR = " %3:_(s32) = G_TRUNC %0\n" " %4:_(s32) = G_TRUNC %1\n" @@ -306,7 +306,7 @@ TEST_F(GISelMITest, TestKnownBits) { EXPECT_EQ(Known.Zero, Zeroes); } -TEST_F(GISelMITest, TestSignBitIsZero) { +TEST_F(AArch64GISelMITest, TestSignBitIsZero) { setUp(); if (!TM) return; @@ -321,7 +321,7 @@ TEST_F(GISelMITest, TestSignBitIsZero) { EXPECT_FALSE(KnownBits.signBitIsZero(SignBit.getReg(0))); } -TEST_F(GISelMITest, TestNumSignBitsConstant) { +TEST_F(AArch64GISelMITest, TestNumSignBitsConstant) { StringRef MIRString = " %3:_(s8) = G_CONSTANT i8 1\n" " %4:_(s8) = COPY %3\n" @@ -353,7 +353,7 @@ TEST_F(GISelMITest, TestNumSignBitsConstant) { EXPECT_EQ(3u, Info.computeNumSignBits(CopyRegNeg32)); } -TEST_F(GISelMITest, TestNumSignBitsSext) { +TEST_F(AArch64GISelMITest, TestNumSignBitsSext) { StringRef MIRString = " %3:_(p0) = G_IMPLICIT_DEF\n" " %4:_(s8) = G_LOAD %3 :: (load 1)\n" " %5:_(s32) = G_SEXT %4\n" @@ -373,7 +373,7 @@ TEST_F(GISelMITest, TestNumSignBitsSext) { EXPECT_EQ(32u, Info.computeNumSignBits(CopySextNeg1)); } -TEST_F(GISelMITest, TestNumSignBitsTrunc) { +TEST_F(AArch64GISelMITest, TestNumSignBitsTrunc) { StringRef MIRString = " %3:_(p0) = G_IMPLICIT_DEF\n" " %4:_(s32) = G_LOAD %3 :: (load 4)\n" " %5:_(s8) = G_TRUNC %4\n" diff --git a/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp b/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp index f47f9a364a73..3bc8f1f8f240 100644 --- a/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp @@ -25,7 +25,7 @@ class DummyGISelObserver : public GISelChangeObserver { // Test CTTZ expansion when CTTZ_ZERO_UNDEF is legal or custom, // in which case it becomes CTTZ_ZERO_UNDEF with select. -TEST_F(GISelMITest, LowerBitCountingCTTZ0) { +TEST_F(AArch64GISelMITest, LowerBitCountingCTTZ0) { setUp(); if (!TM) return; @@ -57,7 +57,7 @@ TEST_F(GISelMITest, LowerBitCountingCTTZ0) { } // CTTZ expansion in terms of CTLZ -TEST_F(GISelMITest, LowerBitCountingCTTZ1) { +TEST_F(AArch64GISelMITest, LowerBitCountingCTTZ1) { setUp(); if (!TM) return; @@ -91,7 +91,7 @@ TEST_F(GISelMITest, LowerBitCountingCTTZ1) { } // CTLZ scalar narrowing -TEST_F(GISelMITest, NarrowScalarCTLZ) { +TEST_F(AArch64GISelMITest, NarrowScalarCTLZ) { setUp(); if (!TM) return; @@ -126,7 +126,7 @@ TEST_F(GISelMITest, NarrowScalarCTLZ) { } // CTTZ scalar narrowing -TEST_F(GISelMITest, NarrowScalarCTTZ) { +TEST_F(AArch64GISelMITest, NarrowScalarCTTZ) { setUp(); if (!TM) return; @@ -161,7 +161,7 @@ TEST_F(GISelMITest, NarrowScalarCTTZ) { } // CTTZ expansion in terms of CTPOP -TEST_F(GISelMITest, LowerBitCountingCTTZ2) { +TEST_F(AArch64GISelMITest, LowerBitCountingCTTZ2) { setUp(); if (!TM) return; @@ -192,7 +192,7 @@ TEST_F(GISelMITest, LowerBitCountingCTTZ2) { } // CTPOP widening. -TEST_F(GISelMITest, WidenBitCountingCTPOP1) { +TEST_F(AArch64GISelMITest, WidenBitCountingCTPOP1) { if (!TM) return; @@ -224,7 +224,7 @@ TEST_F(GISelMITest, WidenBitCountingCTPOP1) { } // Test a strange case where the result is wider than the source -TEST_F(GISelMITest, WidenBitCountingCTPOP2) { +TEST_F(AArch64GISelMITest, WidenBitCountingCTPOP2) { if (!TM) return; @@ -257,7 +257,7 @@ TEST_F(GISelMITest, WidenBitCountingCTPOP2) { } // CTTZ_ZERO_UNDEF expansion in terms of CTTZ -TEST_F(GISelMITest, LowerBitCountingCTTZ3) { +TEST_F(AArch64GISelMITest, LowerBitCountingCTTZ3) { setUp(); if (!TM) return; @@ -284,7 +284,7 @@ TEST_F(GISelMITest, LowerBitCountingCTTZ3) { } // CTLZ expansion in terms of CTLZ_ZERO_UNDEF -TEST_F(GISelMITest, LowerBitCountingCTLZ0) { +TEST_F(AArch64GISelMITest, LowerBitCountingCTLZ0) { setUp(); if (!TM) return; @@ -315,7 +315,7 @@ TEST_F(GISelMITest, LowerBitCountingCTLZ0) { } // CTLZ expansion in terms of CTLZ_ZERO_UNDEF if the latter is a libcall -TEST_F(GISelMITest, LowerBitCountingCTLZLibcall) { +TEST_F(AArch64GISelMITest, LowerBitCountingCTLZLibcall) { setUp(); if (!TM) return; @@ -346,7 +346,7 @@ TEST_F(GISelMITest, LowerBitCountingCTLZLibcall) { } // CTLZ expansion -TEST_F(GISelMITest, LowerBitCountingCTLZ1) { +TEST_F(AArch64GISelMITest, LowerBitCountingCTLZ1) { setUp(); if (!TM) return; @@ -387,7 +387,7 @@ TEST_F(GISelMITest, LowerBitCountingCTLZ1) { } // CTLZ widening. -TEST_F(GISelMITest, WidenBitCountingCTLZ) { +TEST_F(AArch64GISelMITest, WidenBitCountingCTLZ) { setUp(); if (!TM) return; @@ -422,7 +422,7 @@ TEST_F(GISelMITest, WidenBitCountingCTLZ) { } // CTLZ_ZERO_UNDEF widening. -TEST_F(GISelMITest, WidenBitCountingCTLZZeroUndef) { +TEST_F(AArch64GISelMITest, WidenBitCountingCTLZZeroUndef) { setUp(); if (!TM) return; @@ -458,7 +458,7 @@ TEST_F(GISelMITest, WidenBitCountingCTLZZeroUndef) { } // CTPOP widening. -TEST_F(GISelMITest, WidenBitCountingCTPOP) { +TEST_F(AArch64GISelMITest, WidenBitCountingCTPOP) { setUp(); if (!TM) return; @@ -491,7 +491,7 @@ TEST_F(GISelMITest, WidenBitCountingCTPOP) { } // CTTZ_ZERO_UNDEF widening. -TEST_F(GISelMITest, WidenBitCountingCTTZ_ZERO_UNDEF) { +TEST_F(AArch64GISelMITest, WidenBitCountingCTTZ_ZERO_UNDEF) { setUp(); if (!TM) return; @@ -525,7 +525,7 @@ TEST_F(GISelMITest, WidenBitCountingCTTZ_ZERO_UNDEF) { } // CTTZ widening. -TEST_F(GISelMITest, WidenBitCountingCTTZ) { +TEST_F(AArch64GISelMITest, WidenBitCountingCTTZ) { setUp(); if (!TM) return; @@ -559,7 +559,7 @@ TEST_F(GISelMITest, WidenBitCountingCTTZ) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // UADDO widening. -TEST_F(GISelMITest, WidenUADDO) { +TEST_F(AArch64GISelMITest, WidenUADDO) { setUp(); if (!TM) return; @@ -598,7 +598,7 @@ TEST_F(GISelMITest, WidenUADDO) { } // USUBO widening. -TEST_F(GISelMITest, WidenUSUBO) { +TEST_F(AArch64GISelMITest, WidenUSUBO) { setUp(); if (!TM) return; @@ -636,7 +636,7 @@ TEST_F(GISelMITest, WidenUSUBO) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, FewerElementsAnd) { +TEST_F(AArch64GISelMITest, FewerElementsAnd) { if (!TM) return; @@ -683,7 +683,7 @@ TEST_F(GISelMITest, FewerElementsAnd) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, MoreElementsAnd) { +TEST_F(AArch64GISelMITest, MoreElementsAnd) { if (!TM) return; @@ -724,7 +724,7 @@ TEST_F(GISelMITest, MoreElementsAnd) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, FewerElementsPhi) { +TEST_F(AArch64GISelMITest, FewerElementsPhi) { if (!TM) return; @@ -819,7 +819,7 @@ TEST_F(GISelMITest, FewerElementsPhi) { } // FNEG expansion in terms of FSUB -TEST_F(GISelMITest, LowerFNEG) { +TEST_F(AArch64GISelMITest, LowerFNEG) { if (!TM) return; @@ -864,7 +864,7 @@ TEST_F(GISelMITest, LowerFNEG) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LowerMinMax) { +TEST_F(AArch64GISelMITest, LowerMinMax) { if (!TM) return; @@ -942,7 +942,7 @@ TEST_F(GISelMITest, LowerMinMax) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, WidenScalarBuildVector) { +TEST_F(AArch64GISelMITest, WidenScalarBuildVector) { if (!TM) return; @@ -988,7 +988,7 @@ TEST_F(GISelMITest, WidenScalarBuildVector) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LowerMergeValues) { +TEST_F(AArch64GISelMITest, LowerMergeValues) { if (!TM) return; @@ -1089,7 +1089,7 @@ TEST_F(GISelMITest, LowerMergeValues) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, WidenScalarMergeValuesPointer) { +TEST_F(AArch64GISelMITest, WidenScalarMergeValuesPointer) { if (!TM) return; @@ -1126,7 +1126,7 @@ TEST_F(GISelMITest, WidenScalarMergeValuesPointer) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, WidenSEXTINREG) { +TEST_F(AArch64GISelMITest, WidenSEXTINREG) { if (!TM) return; @@ -1157,7 +1157,7 @@ TEST_F(GISelMITest, WidenSEXTINREG) { ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr)); } -TEST_F(GISelMITest, NarrowSEXTINREG) { +TEST_F(AArch64GISelMITest, NarrowSEXTINREG) { if (!TM) return; @@ -1188,7 +1188,7 @@ TEST_F(GISelMITest, NarrowSEXTINREG) { ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr)); } -TEST_F(GISelMITest, NarrowSEXTINREG2) { +TEST_F(AArch64GISelMITest, NarrowSEXTINREG2) { if (!TM) return; @@ -1220,7 +1220,7 @@ TEST_F(GISelMITest, NarrowSEXTINREG2) { ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr)); } -TEST_F(GISelMITest, LowerSEXTINREG) { +TEST_F(AArch64GISelMITest, LowerSEXTINREG) { if (!TM) return; @@ -1250,7 +1250,7 @@ TEST_F(GISelMITest, LowerSEXTINREG) { ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr)); } -TEST_F(GISelMITest, LibcallFPExt) { +TEST_F(AArch64GISelMITest, LibcallFPExt) { setUp(); if (!TM) return; @@ -1289,7 +1289,7 @@ TEST_F(GISelMITest, LibcallFPExt) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFPTrunc) { +TEST_F(AArch64GISelMITest, LibcallFPTrunc) { setUp(); if (!TM) return; @@ -1331,7 +1331,7 @@ TEST_F(GISelMITest, LibcallFPTrunc) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallSimple) { +TEST_F(AArch64GISelMITest, LibcallSimple) { setUp(); if (!TM) return; @@ -1354,7 +1354,7 @@ TEST_F(GISelMITest, LibcallSimple) { Helper.libcall(*MIBFADD)); } -TEST_F(GISelMITest, LibcallSRem) { +TEST_F(AArch64GISelMITest, LibcallSRem) { setUp(); if (!TM) return; @@ -1411,7 +1411,7 @@ TEST_F(GISelMITest, LibcallSRem) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallURem) { +TEST_F(AArch64GISelMITest, LibcallURem) { setUp(); if (!TM) return; @@ -1468,7 +1468,7 @@ TEST_F(GISelMITest, LibcallURem) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallCtlzZeroUndef) { +TEST_F(AArch64GISelMITest, LibcallCtlzZeroUndef) { setUp(); if (!TM) return; @@ -1521,7 +1521,7 @@ TEST_F(GISelMITest, LibcallCtlzZeroUndef) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFAdd) { +TEST_F(AArch64GISelMITest, LibcallFAdd) { setUp(); if (!TM) return; @@ -1573,7 +1573,7 @@ TEST_F(GISelMITest, LibcallFAdd) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFSub) { +TEST_F(AArch64GISelMITest, LibcallFSub) { setUp(); if (!TM) return; @@ -1625,7 +1625,7 @@ TEST_F(GISelMITest, LibcallFSub) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFMul) { +TEST_F(AArch64GISelMITest, LibcallFMul) { setUp(); if (!TM) return; @@ -1677,7 +1677,7 @@ TEST_F(GISelMITest, LibcallFMul) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFDiv) { +TEST_F(AArch64GISelMITest, LibcallFDiv) { setUp(); if (!TM) return; @@ -1729,7 +1729,7 @@ TEST_F(GISelMITest, LibcallFDiv) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFExp) { +TEST_F(AArch64GISelMITest, LibcallFExp) { setUp(); if (!TM) return; @@ -1776,7 +1776,7 @@ TEST_F(GISelMITest, LibcallFExp) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFExp2) { +TEST_F(AArch64GISelMITest, LibcallFExp2) { setUp(); if (!TM) return; @@ -1823,7 +1823,7 @@ TEST_F(GISelMITest, LibcallFExp2) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFRem) { +TEST_F(AArch64GISelMITest, LibcallFRem) { setUp(); if (!TM) return; @@ -1870,7 +1870,7 @@ TEST_F(GISelMITest, LibcallFRem) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFPow) { +TEST_F(AArch64GISelMITest, LibcallFPow) { setUp(); if (!TM) return; @@ -1917,7 +1917,7 @@ TEST_F(GISelMITest, LibcallFPow) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFMa) { +TEST_F(AArch64GISelMITest, LibcallFMa) { setUp(); if (!TM) return; @@ -1965,7 +1965,7 @@ TEST_F(GISelMITest, LibcallFMa) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFCeil) { +TEST_F(AArch64GISelMITest, LibcallFCeil) { setUp(); if (!TM) return; @@ -2012,7 +2012,7 @@ TEST_F(GISelMITest, LibcallFCeil) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFFloor) { +TEST_F(AArch64GISelMITest, LibcallFFloor) { setUp(); if (!TM) return; @@ -2059,7 +2059,7 @@ TEST_F(GISelMITest, LibcallFFloor) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFMinNum) { +TEST_F(AArch64GISelMITest, LibcallFMinNum) { setUp(); if (!TM) return; @@ -2109,7 +2109,7 @@ TEST_F(GISelMITest, LibcallFMinNum) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFMaxNum) { +TEST_F(AArch64GISelMITest, LibcallFMaxNum) { setUp(); if (!TM) return; @@ -2159,7 +2159,7 @@ TEST_F(GISelMITest, LibcallFMaxNum) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFSqrt) { +TEST_F(AArch64GISelMITest, LibcallFSqrt) { setUp(); if (!TM) return; @@ -2206,7 +2206,7 @@ TEST_F(GISelMITest, LibcallFSqrt) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFRint) { +TEST_F(AArch64GISelMITest, LibcallFRint) { setUp(); if (!TM) return; @@ -2253,7 +2253,7 @@ TEST_F(GISelMITest, LibcallFRint) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFNearbyInt) { +TEST_F(AArch64GISelMITest, LibcallFNearbyInt) { setUp(); if (!TM) return; @@ -2303,7 +2303,7 @@ TEST_F(GISelMITest, LibcallFNearbyInt) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, NarrowScalarExtract) { +TEST_F(AArch64GISelMITest, NarrowScalarExtract) { setUp(); if (!TM) return; @@ -2342,7 +2342,7 @@ TEST_F(GISelMITest, NarrowScalarExtract) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LowerInsert) { +TEST_F(AArch64GISelMITest, LowerInsert) { setUp(); if (!TM) return; @@ -2443,7 +2443,7 @@ TEST_F(GISelMITest, LowerInsert) { } // Test lowering of G_FFLOOR -TEST_F(GISelMITest, LowerFFloor) { +TEST_F(AArch64GISelMITest, LowerFFloor) { setUp(); if (!TM) return; @@ -2475,7 +2475,7 @@ TEST_F(GISelMITest, LowerFFloor) { } // Test lowering of G_BSWAP -TEST_F(GISelMITest, LowerBSWAP) { +TEST_F(AArch64GISelMITest, LowerBSWAP) { setUp(); if (!TM) return; @@ -2517,7 +2517,7 @@ TEST_F(GISelMITest, LowerBSWAP) { } // Test widening of G_UNMERGE_VALUES -TEST_F(GISelMITest, WidenUnmerge) { +TEST_F(AArch64GISelMITest, WidenUnmerge) { setUp(); if (!TM) return; diff --git a/llvm/unittests/CodeGen/GlobalISel/LegalizerTest.cpp b/llvm/unittests/CodeGen/GlobalISel/LegalizerTest.cpp index afb4614f07e4..edae7f945712 100644 --- a/llvm/unittests/CodeGen/GlobalISel/LegalizerTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/LegalizerTest.cpp @@ -49,7 +49,7 @@ DefineLegalizerInfo(ALegalizer, { getActionDefinitionsBuilder(G_SHL).legalFor({{s32, s32}}); }) -TEST_F(GISelMITest, BasicLegalizerTest) { +TEST_F(AArch64GISelMITest, BasicLegalizerTest) { StringRef MIRString = R"( %vptr:_(p0) = COPY $x4 %v:_(<2 x s8>) = G_LOAD %vptr:_(p0) :: (load 2, align 1) @@ -85,7 +85,7 @@ TEST_F(GISelMITest, BasicLegalizerTest) { // Making sure the legalization finishes successfully w/o failure to combine // away all the legalization artifacts regardless of the order of their // creation. -TEST_F(GISelMITest, UnorderedArtifactCombiningTest) { +TEST_F(AArch64GISelMITest, UnorderedArtifactCombiningTest) { StringRef MIRString = R"( %vptr:_(p0) = COPY $x4 %v:_(<2 x s8>) = G_LOAD %vptr:_(p0) :: (load 2, align 1) @@ -169,7 +169,7 @@ TEST_F(GISelMITest, UnorderedArtifactCombiningTest) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckString)) << *MF; } -TEST_F(GISelMITest, UnorderedArtifactCombiningManyCopiesTest) { +TEST_F(AArch64GISelMITest, UnorderedArtifactCombiningManyCopiesTest) { StringRef MIRString = R"( %vptr:_(p0) = COPY $x4 %v:_(<2 x s8>) = G_LOAD %vptr:_(p0) :: (load 2, align 1) diff --git a/llvm/unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp b/llvm/unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp index f6fed8e75d2c..4d766cd42bee 100644 --- a/llvm/unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp @@ -9,7 +9,7 @@ #include "GISelMITest.h" #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" -TEST_F(GISelMITest, TestBuildConstantFConstant) { +TEST_F(AArch64GISelMITest, TestBuildConstantFConstant) { setUp(); if (!TM) return; @@ -37,11 +37,10 @@ TEST_F(GISelMITest, TestBuildConstantFConstant) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } - #ifdef GTEST_HAS_DEATH_TEST #ifndef NDEBUG -TEST_F(GISelMITest, TestBuildConstantFConstantDeath) { +TEST_F(AArch64GISelMITest, TestBuildConstantFConstantDeath) { setUp(); if (!TM) return; @@ -73,7 +72,7 @@ TEST_F(GISelMITest, TestBuildConstantFConstantDeath) { #endif #endif -TEST_F(GISelMITest, DstOpSrcOp) { +TEST_F(AArch64GISelMITest, DstOpSrcOp) { setUp(); if (!TM) return; @@ -99,7 +98,7 @@ TEST_F(GISelMITest, DstOpSrcOp) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, BuildUnmerge) { +TEST_F(AArch64GISelMITest, BuildUnmerge) { setUp(); if (!TM) return; @@ -120,7 +119,7 @@ TEST_F(GISelMITest, BuildUnmerge) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, TestBuildFPInsts) { +TEST_F(AArch64GISelMITest, TestBuildFPInsts) { setUp(); if (!TM) return; @@ -156,7 +155,7 @@ TEST_F(GISelMITest, TestBuildFPInsts) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, BuildIntrinsic) { +TEST_F(AArch64GISelMITest, BuildIntrinsic) { setUp(); if (!TM) return; @@ -185,7 +184,7 @@ TEST_F(GISelMITest, BuildIntrinsic) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, BuildXor) { +TEST_F(AArch64GISelMITest, BuildXor) { setUp(); if (!TM) return; @@ -214,7 +213,7 @@ TEST_F(GISelMITest, BuildXor) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, BuildBitCounts) { +TEST_F(AArch64GISelMITest, BuildBitCounts) { setUp(); if (!TM) return; @@ -242,7 +241,7 @@ TEST_F(GISelMITest, BuildBitCounts) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, BuildCasts) { +TEST_F(AArch64GISelMITest, BuildCasts) { setUp(); if (!TM) return; @@ -267,7 +266,7 @@ TEST_F(GISelMITest, BuildCasts) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, BuildMinMax) { +TEST_F(AArch64GISelMITest, BuildMinMax) { setUp(); if (!TM) return; @@ -293,7 +292,7 @@ TEST_F(GISelMITest, BuildMinMax) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, BuildAtomicRMW) { +TEST_F(AArch64GISelMITest, BuildAtomicRMW) { setUp(); if (!TM) return; @@ -324,7 +323,7 @@ TEST_F(GISelMITest, BuildAtomicRMW) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, BuildMerge) { +TEST_F(AArch64GISelMITest, BuildMerge) { setUp(); if (!TM) return; @@ -363,7 +362,7 @@ TEST_F(GISelMITest, BuildMerge) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, BuildAddoSubo) { +TEST_F(AArch64GISelMITest, BuildAddoSubo) { setUp(); if (!TM) return; diff --git a/llvm/unittests/CodeGen/GlobalISel/PatternMatchTest.cpp b/llvm/unittests/CodeGen/GlobalISel/PatternMatchTest.cpp index 66c1d6793a7a..172eca46b4a9 100644 --- a/llvm/unittests/CodeGen/GlobalISel/PatternMatchTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/PatternMatchTest.cpp @@ -30,7 +30,7 @@ using namespace MIPatternMatch; namespace { -TEST_F(GISelMITest, MatchIntConstant) { +TEST_F(AArch64GISelMITest, MatchIntConstant) { setUp(); if (!TM) return; @@ -41,7 +41,7 @@ TEST_F(GISelMITest, MatchIntConstant) { EXPECT_EQ(Cst, 42); } -TEST_F(GISelMITest, MatchBinaryOp) { +TEST_F(AArch64GISelMITest, MatchBinaryOp) { setUp(); if (!TM) return; @@ -139,7 +139,7 @@ TEST_F(GISelMITest, MatchBinaryOp) { EXPECT_EQ(Src1, TruncCopy1.getReg(0)); } -TEST_F(GISelMITest, MatchICmp) { +TEST_F(AArch64GISelMITest, MatchICmp) { setUp(); if (!TM) return; @@ -164,7 +164,7 @@ TEST_F(GISelMITest, MatchICmp) { EXPECT_EQ(Copies[1], Reg1); } -TEST_F(GISelMITest, MatchFCmp) { +TEST_F(AArch64GISelMITest, MatchFCmp) { setUp(); if (!TM) return; @@ -189,7 +189,7 @@ TEST_F(GISelMITest, MatchFCmp) { EXPECT_EQ(Copies[1], Reg1); } -TEST_F(GISelMITest, MatchFPUnaryOp) { +TEST_F(AArch64GISelMITest, MatchFPUnaryOp) { setUp(); if (!TM) return; @@ -251,7 +251,7 @@ TEST_F(GISelMITest, MatchFPUnaryOp) { EXPECT_NE(TmpFP16, TmpFP); } -TEST_F(GISelMITest, MatchExtendsTrunc) { +TEST_F(AArch64GISelMITest, MatchExtendsTrunc) { setUp(); if (!TM) return; @@ -298,7 +298,7 @@ TEST_F(GISelMITest, MatchExtendsTrunc) { EXPECT_EQ(Src0, Copies[0]); } -TEST_F(GISelMITest, MatchSpecificType) { +TEST_F(AArch64GISelMITest, MatchSpecificType) { setUp(); if (!TM) return; @@ -335,7 +335,7 @@ TEST_F(GISelMITest, MatchSpecificType) { EXPECT_EQ(Src0, Copies[0]); } -TEST_F(GISelMITest, MatchCombinators) { +TEST_F(AArch64GISelMITest, MatchCombinators) { setUp(); if (!TM) return; @@ -369,7 +369,7 @@ TEST_F(GISelMITest, MatchCombinators) { EXPECT_FALSE(match); } -TEST_F(GISelMITest, MatchMiscellaneous) { +TEST_F(AArch64GISelMITest, MatchMiscellaneous) { setUp(); if (!TM) return; From 2ad5fc1d9154807f7fe287139839099438fd54d4 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Sun, 22 Mar 2020 19:06:30 -0400 Subject: [PATCH 28/59] AMDGPU/GlobalISel: Implement computeNumSignBitsForTargetInstr --- llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp | 23 +++++++++++ llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h | 6 +++ .../CodeGen/GlobalISel/GISelMITest.cpp | 38 +++++++++++++++++++ .../CodeGen/GlobalISel/GISelMITest.h | 6 +++ .../CodeGen/GlobalISel/KnownBitsTest.cpp | 33 ++++++++++++++++ 5 files changed, 106 insertions(+) diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp index bee0605bd556..bdf5c3b03663 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp @@ -4587,6 +4587,29 @@ unsigned AMDGPUTargetLowering::ComputeNumSignBitsForTargetNode( } } +unsigned AMDGPUTargetLowering::computeNumSignBitsForTargetInstr( + GISelKnownBits &Analysis, Register R, + const APInt &DemandedElts, const MachineRegisterInfo &MRI, + unsigned Depth) const { + const MachineInstr *MI = MRI.getVRegDef(R); + if (!MI) + return 1; + + // TODO: Check range metadata on MMO. + switch (MI->getOpcode()) { + case AMDGPU::G_AMDGPU_BUFFER_LOAD_SBYTE: + return 25; + case AMDGPU::G_AMDGPU_BUFFER_LOAD_SSHORT: + return 17; + case AMDGPU::G_AMDGPU_BUFFER_LOAD_UBYTE: + return 24; + case AMDGPU::G_AMDGPU_BUFFER_LOAD_USHORT: + return 16; + default: + return 1; + } +} + bool AMDGPUTargetLowering::isKnownNeverNaNForTargetNode(SDValue Op, const SelectionDAG &DAG, bool SNaN, diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h index 54747b57f6f4..7d0b17f7e816 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h @@ -269,6 +269,12 @@ class AMDGPUTargetLowering : public TargetLowering { const SelectionDAG &DAG, unsigned Depth = 0) const override; + unsigned computeNumSignBitsForTargetInstr(GISelKnownBits &Analysis, + Register R, + const APInt &DemandedElts, + const MachineRegisterInfo &MRI, + unsigned Depth = 0) const override; + bool isKnownNeverNaNForTargetNode(SDValue Op, const SelectionDAG &DAG, bool SNaN = false, diff --git a/llvm/unittests/CodeGen/GlobalISel/GISelMITest.cpp b/llvm/unittests/CodeGen/GlobalISel/GISelMITest.cpp index 5b59ee74852a..ef50a0f281f0 100644 --- a/llvm/unittests/CodeGen/GlobalISel/GISelMITest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/GISelMITest.cpp @@ -66,3 +66,41 @@ body: | Twine(MIRFunc) + Twine("...\n")) .toNullTerminatedStringRef(S); } + +std::unique_ptr +AMDGPUGISelMITest::createTargetMachine() const { + Triple TargetTriple("amdgcn-amd-amdhsa"); + std::string Error; + const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error); + if (!T) + return nullptr; + + TargetOptions Options; + return std::unique_ptr( + static_cast(T->createTargetMachine( + "amdgcn-amd-amdhsa", "gfx900", "", Options, None, None, + CodeGenOpt::Aggressive))); +} + +void AMDGPUGISelMITest::getTargetTestModuleString( + SmallString<512> &S, StringRef MIRFunc) const { + (Twine(R"MIR( +--- +... +name: func +tracksRegLiveness: true +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } + - { id: 3, class: _ } +body: | + bb.1: + liveins: $vgpr0, $vgpr1, $vgpr2 + + %0(s32) = COPY $vgpr0 + %1(s32) = COPY $vgpr1 + %2(s32) = COPY $vgpr2 +)MIR") + Twine(MIRFunc) + Twine("...\n")) + .toNullTerminatedStringRef(S); +} diff --git a/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h b/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h index 53f5a1c4cd8c..db3f2b9531c9 100644 --- a/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h +++ b/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h @@ -146,6 +146,12 @@ class AArch64GISelMITest : public GISelMITest { StringRef MIRFunc) const override; }; +class AMDGPUGISelMITest : public GISelMITest { + std::unique_ptr createTargetMachine() const override; + void getTargetTestModuleString(SmallString<512> &S, + StringRef MIRFunc) const override; +}; + #define DefineLegalizerInfo(Name, SettingUpActionsBlock) \ class Name##Info : public LegalizerInfo { \ public: \ diff --git a/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp b/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp index e2479b93e730..fe0c14270ecf 100644 --- a/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp @@ -398,3 +398,36 @@ TEST_F(AArch64GISelMITest, TestNumSignBitsTrunc) { EXPECT_EQ(8u, Info.computeNumSignBits(CopyTruncNeg1)); EXPECT_EQ(5u, Info.computeNumSignBits(CopyTrunc7)); } + +TEST_F(AMDGPUGISelMITest, TestNumSignBitsTrunc) { + StringRef MIRString = + " %3:_(<4 x s32>) = G_IMPLICIT_DEF\n" + " %4:_(s32) = G_IMPLICIT_DEF\n" + " %5:_(s32) = G_AMDGPU_BUFFER_LOAD_UBYTE %3, %4, %4, %4, 0, 0, 0 :: (load 1)\n" + " %6:_(s32) = COPY %5\n" + + " %7:_(s32) = G_AMDGPU_BUFFER_LOAD_SBYTE %3, %4, %4, %4, 0, 0, 0 :: (load 1)\n" + " %8:_(s32) = COPY %7\n" + + " %9:_(s32) = G_AMDGPU_BUFFER_LOAD_USHORT %3, %4, %4, %4, 0, 0, 0 :: (load 2)\n" + " %10:_(s32) = COPY %9\n" + + " %11:_(s32) = G_AMDGPU_BUFFER_LOAD_SSHORT %3, %4, %4, %4, 0, 0, 0 :: (load 2)\n" + " %12:_(s32) = COPY %11\n"; + + setUp(MIRString); + if (!TM) + return; + + Register CopyLoadUByte = Copies[Copies.size() - 4]; + Register CopyLoadSByte = Copies[Copies.size() - 3]; + Register CopyLoadUShort = Copies[Copies.size() - 2]; + Register CopyLoadSShort = Copies[Copies.size() - 1]; + + GISelKnownBits Info(*MF); + + EXPECT_EQ(24u, Info.computeNumSignBits(CopyLoadUByte)); + EXPECT_EQ(25u, Info.computeNumSignBits(CopyLoadSByte)); + EXPECT_EQ(16u, Info.computeNumSignBits(CopyLoadUShort)); + EXPECT_EQ(17u, Info.computeNumSignBits(CopyLoadSShort)); +} From 56abcfad70ee679ad95ab41d934491ebcaebdf7d Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Mon, 23 Mar 2020 11:56:39 -0700 Subject: [PATCH 29/59] Revert "[analyzer][NFC] Tie CheckerRegistry to CheckerManager, allow CheckerManager to be constructed for non-analysis purposes" Temporarily reverting this patch because it breaks the modules build. --- .../StaticAnalyzer/Core/CheckerManager.h | 42 +------- .../Frontend/AnalysisConsumer.h | 2 +- .../Frontend/AnalyzerHelpFlags.h | 30 ------ .../Frontend/CheckerRegistration.h | 38 +++++++ .../StaticAnalyzer/Frontend/CheckerRegistry.h | 38 +++---- .../StaticAnalyzer/Frontend/FrontendActions.h | 17 ++- .../ExecuteCompilerInvocation.cpp | 20 +++- .../StaticAnalyzer/Core/CheckerManager.cpp | 7 +- .../Frontend/AnalysisConsumer.cpp | 5 +- .../StaticAnalyzer/Frontend/CMakeLists.txt | 2 +- ...rHelpFlags.cpp => CheckerRegistration.cpp} | 60 +++++++---- .../Frontend/CheckerRegistry.cpp | 101 +++++++++--------- 12 files changed, 186 insertions(+), 176 deletions(-) delete mode 100644 clang/include/clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h create mode 100644 clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h rename clang/lib/StaticAnalyzer/Frontend/{AnalyzerHelpFlags.cpp => CheckerRegistration.cpp} (69%) diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h index 6faf0f2e0afd..4454d7603b27 100644 --- a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -14,11 +14,9 @@ #define LLVM_CLANG_STATICANALYZER_CORE_CHECKERMANAGER_H #include "clang/Analysis/ProgramPoint.h" -#include "clang/Basic/Diagnostic.h" #include "clang/Basic/LangOptions.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" -#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" @@ -42,6 +40,7 @@ class BugReporter; class CallEvent; class CheckerBase; class CheckerContext; +class CheckerRegistry; class ExplodedGraph; class ExplodedNode; class ExplodedNodeSet; @@ -122,42 +121,14 @@ enum class ObjCMessageVisitKind { }; class CheckerManager { - ASTContext *Context; + ASTContext &Context; const LangOptions LangOpts; AnalyzerOptions &AOptions; CheckerNameRef CurrentCheckerName; - DiagnosticsEngine &Diags; - CheckerRegistry Registry; public: - CheckerManager( - ASTContext &Context, AnalyzerOptions &AOptions, - ArrayRef plugins, - ArrayRef> checkerRegistrationFns) - : Context(&Context), LangOpts(Context.getLangOpts()), AOptions(AOptions), - Diags(Context.getDiagnostics()), - Registry(plugins, Context.getDiagnostics(), AOptions, - checkerRegistrationFns) { - Registry.initializeRegistry(*this); - Registry.initializeManager(*this); - finishedCheckerRegistration(); - } - - /// Constructs a CheckerManager that ignores all non TblGen-generated - /// checkers. Useful for unit testing, unless the checker infrastructure - /// itself is tested. CheckerManager(ASTContext &Context, AnalyzerOptions &AOptions) - : CheckerManager(Context, AOptions, {}, {}) {} - - /// Constructs a CheckerManager without requiring an AST. No checker - /// registration will take place. Only useful for retrieving the - /// CheckerRegistry and print for help flags where the AST is unavalaible. - CheckerManager(AnalyzerOptions &AOptions, const LangOptions &LangOpts, - DiagnosticsEngine &Diags, ArrayRef plugins) - : LangOpts(LangOpts), AOptions(AOptions), Diags(Diags), - Registry(plugins, Diags, AOptions) { - Registry.initializeRegistry(*this); - } + : Context(Context), LangOpts(Context.getLangOpts()), AOptions(AOptions) {} ~CheckerManager(); @@ -170,12 +141,7 @@ class CheckerManager { const LangOptions &getLangOpts() const { return LangOpts; } AnalyzerOptions &getAnalyzerOptions() const { return AOptions; } - const CheckerRegistry &getCheckerRegistry() const { return Registry; } - DiagnosticsEngine &getDiagnostics() const { return Diags; } - ASTContext &getASTContext() const { - assert(Context); - return *Context; - } + ASTContext &getASTContext() const { return Context; } /// Emits an error through a DiagnosticsEngine about an invalid user supplied /// checker option value. diff --git a/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h b/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h index bcc29a60ad70..2d24e6a9586b 100644 --- a/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h +++ b/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h @@ -55,7 +55,7 @@ class AnalysisASTConsumer : public ASTConsumer { std::unique_ptr CreateAnalysisConsumer(CompilerInstance &CI); -} // namespace ento +} // end GR namespace } // end clang namespace diff --git a/clang/include/clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h b/clang/include/clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h deleted file mode 100644 index a30c241e1350..000000000000 --- a/clang/include/clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h +++ /dev/null @@ -1,30 +0,0 @@ -//===-- AnalyzerHelpFlags.h - Query functions for --help flags --*- 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_STATICANALYZER_FRONTEND_ANALYZERHELPFLAGS_H -#define LLVM_CLANG_STATICANALYZER_FRONTEND_ANALYZERHELPFLAGS_H - -namespace llvm { -class raw_ostream; -} // namespace llvm - -namespace clang { - -class CompilerInstance; - -namespace ento { - -void printCheckerHelp(llvm::raw_ostream &OS, CompilerInstance &CI); -void printEnabledCheckerList(llvm::raw_ostream &OS, CompilerInstance &CI); -void printAnalyzerConfigList(llvm::raw_ostream &OS); -void printCheckerConfigList(llvm::raw_ostream &OS, CompilerInstance &CI); - -} // namespace ento -} // namespace clang - -#endif diff --git a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h new file mode 100644 index 000000000000..52a534499002 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h @@ -0,0 +1,38 @@ +//===-- CheckerRegistration.h - Checker Registration Function ---*- 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_STATICANALYZER_FRONTEND_CHECKERREGISTRATION_H +#define LLVM_CLANG_STATICANALYZER_FRONTEND_CHECKERREGISTRATION_H + +#include "clang/AST/ASTContext.h" +#include "clang/Basic/LLVM.h" +#include +#include +#include + +namespace clang { + class AnalyzerOptions; + class LangOptions; + class DiagnosticsEngine; + +namespace ento { + class CheckerManager; + class CheckerRegistry; + + std::unique_ptr createCheckerManager( + ASTContext &context, + AnalyzerOptions &opts, + ArrayRef plugins, + ArrayRef> checkerRegistrationFns, + DiagnosticsEngine &diags); + +} // end ento namespace + +} // end namespace clang + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h index dde2409ed72c..8830542f27d8 100644 --- a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h +++ b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H #include "clang/Basic/LLVM.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" @@ -73,8 +74,6 @@ class LangOptions; namespace ento { -class CheckerManager; - /// Manages a set of available checkers for running a static analysis. /// The checkers are organized into packages by full name, where including /// a package will recursively include all subpackages and checkers within it. @@ -84,15 +83,10 @@ class CheckerManager; class CheckerRegistry { public: CheckerRegistry(ArrayRef plugins, DiagnosticsEngine &diags, - AnalyzerOptions &AnOpts, + AnalyzerOptions &AnOpts, const LangOptions &LangOpts, ArrayRef> checkerRegistrationFns = {}); - /// Collects all enabled checkers in the field EnabledCheckers. It preserves - /// the order of insertion, as dependencies have to be enabled before the - /// checkers that depend on them. - void initializeRegistry(const CheckerManager &Mgr); - /// Initialization functions perform any necessary setup for a checker. /// They should include a call to CheckerManager::registerChecker. using InitializationFunction = void (*)(CheckerManager &); @@ -211,20 +205,14 @@ class CheckerRegistry { using PackageInfoList = llvm::SmallVector; -private: - /// Default initialization function for checkers -- since CheckerManager - /// includes this header, we need to make it a template parameter, and since - /// the checker must be a template parameter as well, we can't put this in the - /// cpp file. - template static void initializeManager(MGR &mgr) { - mgr.template registerChecker(); + template static void addToCheckerMgr(CheckerManager &mgr) { + mgr.registerChecker(); } - template static bool returnTrue(const LangOptions &) { + static bool returnTrue(const LangOptions &LO) { return true; } -public: /// Adds a checker to the registry. Use this non-templated overload when your /// checker requires custom initialization. void addChecker(InitializationFunction Fn, ShouldRegisterFunction sfn, @@ -233,16 +221,13 @@ class CheckerRegistry { /// Adds a checker to the registry. Use this templated overload when your /// checker does not require any custom initialization. - /// This function isn't really needed and probably causes more headaches than - /// the tiny convenience that it provides, but external plugins might use it, - /// and there isn't a strong incentive to remove it. template void addChecker(StringRef FullName, StringRef Desc, StringRef DocsUri, bool IsHidden = false) { // Avoid MSVC's Compiler Error C2276: // http://msdn.microsoft.com/en-us/library/850cstw1(v=VS.80).aspx - addChecker(&initializeManager, &returnTrue, FullName, - Desc, DocsUri, IsHidden); + addChecker(&CheckerRegistry::addToCheckerMgr, + &CheckerRegistry::returnTrue, FullName, Desc, DocsUri, IsHidden); } /// Makes the checker with the full name \p fullName depends on the checker @@ -278,7 +263,7 @@ class CheckerRegistry { void addPackageOption(StringRef OptionType, StringRef PackageFullName, StringRef OptionName, StringRef DefaultValStr, StringRef Description, StringRef DevelopmentStatus, - bool IsHidden = false); + bool IsHidden = false); // FIXME: This *really* should be added to the frontend flag descriptions. /// Initializes a CheckerManager by calling the initialization functions for @@ -298,6 +283,11 @@ class CheckerRegistry { void printCheckerOptionList(raw_ostream &Out) const; private: + /// Collect all enabled checkers. The returned container preserves the order + /// of insertion, as dependencies have to be enabled before the checkers that + /// depend on them. + CheckerInfoSet getEnabledCheckers() const; + /// Return an iterator range of mutable CheckerInfos \p CmdLineArg applies to. /// For example, it'll return the checkers for the core package, if /// \p CmdLineArg is "core". @@ -324,7 +314,7 @@ class CheckerRegistry { DiagnosticsEngine &Diags; AnalyzerOptions &AnOpts; - CheckerInfoSet EnabledCheckers; + const LangOptions &LangOpts; }; } // namespace ento diff --git a/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h b/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h index 6b6a395a1884..878b65a1b143 100644 --- a/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h +++ b/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h @@ -51,7 +51,22 @@ class ParseModelFileAction : public ASTFrontendAction { llvm::StringMap &Bodies; }; -} // namespace ento +void printCheckerHelp(raw_ostream &OS, + ArrayRef plugins, + AnalyzerOptions &opts, + DiagnosticsEngine &diags, + const LangOptions &LangOpts); +void printEnabledCheckerList(raw_ostream &OS, ArrayRef plugins, + AnalyzerOptions &opts, + DiagnosticsEngine &diags, + const LangOptions &LangOpts); +void printAnalyzerConfigList(raw_ostream &OS); +void printCheckerConfigList(raw_ostream &OS, ArrayRef plugins, + AnalyzerOptions &opts, + DiagnosticsEngine &diags, + const LangOptions &LangOpts); + +} // end GR namespace } // end namespace clang diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index ab7a1e32e301..70735ab2d7b2 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -23,7 +23,6 @@ #include "clang/Frontend/Utils.h" #include "clang/FrontendTool/Utils.h" #include "clang/Rewrite/Frontend/FrontendActions.h" -#include "clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h" #include "clang/StaticAnalyzer/Frontend/FrontendActions.h" #include "llvm/Option/OptTable.h" #include "llvm/Option/Option.h" @@ -244,24 +243,35 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) { // These should happen AFTER plugins have been loaded! AnalyzerOptions &AnOpts = *Clang->getAnalyzerOpts(); - // Honor -analyzer-checker-help and -analyzer-checker-help-hidden. if (AnOpts.ShowCheckerHelp || AnOpts.ShowCheckerHelpAlpha || AnOpts.ShowCheckerHelpDeveloper) { - ento::printCheckerHelp(llvm::outs(), *Clang); + ento::printCheckerHelp(llvm::outs(), + Clang->getFrontendOpts().Plugins, + AnOpts, + Clang->getDiagnostics(), + Clang->getLangOpts()); return true; } // Honor -analyzer-checker-option-help. if (AnOpts.ShowCheckerOptionList || AnOpts.ShowCheckerOptionAlphaList || AnOpts.ShowCheckerOptionDeveloperList) { - ento::printCheckerConfigList(llvm::outs(), *Clang); + ento::printCheckerConfigList(llvm::outs(), + Clang->getFrontendOpts().Plugins, + *Clang->getAnalyzerOpts(), + Clang->getDiagnostics(), + Clang->getLangOpts()); return true; } // Honor -analyzer-list-enabled-checkers. if (AnOpts.ShowEnabledCheckerList) { - ento::printEnabledCheckerList(llvm::outs(), *Clang); + ento::printEnabledCheckerList(llvm::outs(), + Clang->getFrontendOpts().Plugins, + AnOpts, + Clang->getDiagnostics(), + Clang->getLangOpts()); return true; } diff --git a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp index 081a31009235..ce5e4a46d3e2 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -64,9 +64,10 @@ void CheckerManager::reportInvalidCheckerOptionValue( const CheckerBase *C, StringRef OptionName, StringRef ExpectedValueDesc) const { - getDiagnostics().Report(diag::err_analyzer_checker_option_invalid_input) - << (llvm::Twine() + C->getTagDescription() + ":" + OptionName).str() - << ExpectedValueDesc; + Context.getDiagnostics() + .Report(diag::err_analyzer_checker_option_invalid_input) + << (llvm::Twine() + C->getTagDescription() + ":" + OptionName).str() + << ExpectedValueDesc; } //===----------------------------------------------------------------------===// diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 1ef6c477bba5..a908aede68bb 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -33,6 +33,7 @@ #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" +#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h" #include "clang/Tooling/Core/Replacement.h" #include "clang/Tooling/Tooling.h" #include "llvm/ADT/PostOrderIterator.h" @@ -347,8 +348,8 @@ class AnalysisConsumer : public AnalysisASTConsumer, void Initialize(ASTContext &Context) override { Ctx = &Context; - checkerMgr = std::make_unique(*Ctx, *Opts, Plugins, - CheckerRegistrationFns); + checkerMgr = createCheckerManager( + *Ctx, *Opts, Plugins, CheckerRegistrationFns, PP.getDiagnostics()); Mgr = std::make_unique(*Ctx, PP, PathConsumers, CreateStoreMgr, CreateConstraintMgr, diff --git a/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt b/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt index 055878aee0a5..6f1151ab0c11 100644 --- a/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt @@ -6,7 +6,7 @@ set(LLVM_LINK_COMPONENTS add_clang_library(clangStaticAnalyzerFrontend AnalysisConsumer.cpp - AnalyzerHelpFlags.cpp + CheckerRegistration.cpp CheckerRegistry.cpp FrontendActions.cpp ModelConsumer.cpp diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp similarity index 69% rename from clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp rename to clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp index d589e69bdf34..f4f06e32cd1d 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp @@ -10,9 +10,8 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h" +#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h" #include "clang/Basic/Diagnostic.h" -#include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" @@ -25,34 +24,53 @@ using namespace clang; using namespace ento; -void ento::printCheckerHelp(raw_ostream &out, CompilerInstance &CI) { - out << "OVERVIEW: Clang Static Analyzer Checkers List\n\n"; - out << "USAGE: -analyzer-checker \n\n"; +std::unique_ptr ento::createCheckerManager( + ASTContext &context, + AnalyzerOptions &opts, + ArrayRef plugins, + ArrayRef> checkerRegistrationFns, + DiagnosticsEngine &diags) { + auto checkerMgr = std::make_unique(context, opts); - auto CheckerMgr = std::make_unique( - *CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(), - CI.getFrontendOpts().Plugins); + CheckerRegistry allCheckers(plugins, diags, opts, context.getLangOpts(), + checkerRegistrationFns); - CheckerMgr->getCheckerRegistry().printCheckerWithDescList(out); -} + allCheckers.initializeManager(*checkerMgr); + allCheckers.validateCheckerOptions(); + checkerMgr->finishedCheckerRegistration(); -void ento::printEnabledCheckerList(raw_ostream &out, CompilerInstance &CI) { - out << "OVERVIEW: Clang Static Analyzer Enabled Checkers List\n\n"; + return checkerMgr; +} - auto CheckerMgr = std::make_unique( - *CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(), - CI.getFrontendOpts().Plugins); +void ento::printCheckerHelp(raw_ostream &out, ArrayRef plugins, + AnalyzerOptions &anopts, + DiagnosticsEngine &diags, + const LangOptions &langOpts) { + out << "OVERVIEW: Clang Static Analyzer Checkers List\n\n"; + out << "USAGE: -analyzer-checker \n\n"; - CheckerMgr->getCheckerRegistry().printEnabledCheckerList(out); + CheckerRegistry(plugins, diags, anopts, langOpts) + .printCheckerWithDescList(out); } -void ento::printCheckerConfigList(raw_ostream &out, CompilerInstance &CI) { +void ento::printEnabledCheckerList(raw_ostream &out, + ArrayRef plugins, + AnalyzerOptions &anopts, + DiagnosticsEngine &diags, + const LangOptions &langOpts) { + out << "OVERVIEW: Clang Static Analyzer Enabled Checkers List\n\n"; - auto CheckerMgr = std::make_unique( - *CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(), - CI.getFrontendOpts().Plugins); + CheckerRegistry(plugins, diags, anopts, langOpts) + .printEnabledCheckerList(out); +} - CheckerMgr->getCheckerRegistry().printCheckerOptionList(out); +void ento::printCheckerConfigList(raw_ostream &OS, + ArrayRef plugins, + AnalyzerOptions &opts, + DiagnosticsEngine &diags, + const LangOptions &LangOpts) { + CheckerRegistry(plugins, diags, opts, LangOpts) + .printCheckerOptionList(OS); } void ento::printAnalyzerConfigList(raw_ostream &out) { diff --git a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp index db09ca4e625e..4af204474494 100644 --- a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp @@ -109,9 +109,9 @@ CheckerRegistry::getMutableCheckersForCmdLineArg(StringRef CmdLineArg) { CheckerRegistry::CheckerRegistry( ArrayRef Plugins, DiagnosticsEngine &Diags, - AnalyzerOptions &AnOpts, + AnalyzerOptions &AnOpts, const LangOptions &LangOpts, ArrayRef> CheckerRegistrationFns) - : Diags(Diags), AnOpts(AnOpts) { + : Diags(Diags), AnOpts(AnOpts), LangOpts(LangOpts) { // Register builtin checkers. #define GET_CHECKERS @@ -179,16 +179,12 @@ CheckerRegistry::CheckerRegistry( addDependency(FULLNAME, DEPENDENCY); #define GET_CHECKER_OPTIONS -#define CHECKER_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \ - DEVELOPMENT_STATUS, IS_HIDDEN) \ - addCheckerOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \ - DEVELOPMENT_STATUS, IS_HIDDEN); +#define CHECKER_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, DEVELOPMENT_STATUS, IS_HIDDEN) \ + addCheckerOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, DEVELOPMENT_STATUS, IS_HIDDEN); #define GET_PACKAGE_OPTIONS -#define PACKAGE_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \ - DEVELOPMENT_STATUS, IS_HIDDEN) \ - addPackageOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \ - DEVELOPMENT_STATUS, IS_HIDDEN); +#define PACKAGE_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, DEVELOPMENT_STATUS, IS_HIDDEN) \ + addPackageOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, DEVELOPMENT_STATUS, IS_HIDDEN); #include "clang/StaticAnalyzer/Checkers/Checkers.inc" #undef CHECKER_DEPENDENCY @@ -217,53 +213,24 @@ CheckerRegistry::CheckerRegistry( : StateFromCmdLine::State_Disabled; } } - validateCheckerOptions(); -} - -/// Collects dependenies in \p enabledCheckers. Return None on failure. -LLVM_NODISCARD -static llvm::Optional -collectDependencies(const CheckerRegistry::CheckerInfo &checker, - const CheckerManager &Mgr); - -void CheckerRegistry::initializeRegistry(const CheckerManager &Mgr) { - for (const CheckerInfo &Checker : Checkers) { - if (!Checker.isEnabled(Mgr.getLangOpts())) - continue; - - // Recursively enable its dependencies. - llvm::Optional Deps = collectDependencies(Checker, Mgr); - - if (!Deps) { - // If we failed to enable any of the dependencies, don't enable this - // checker. - continue; - } - - // Note that set_union also preserves the order of insertion. - EnabledCheckers.set_union(*Deps); - - // Enable the checker. - EnabledCheckers.insert(&Checker); - } } /// Collects dependencies in \p ret, returns false on failure. static bool collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps, - const CheckerManager &Mgr, + const LangOptions &LO, CheckerRegistry::CheckerInfoSet &Ret); /// Collects dependenies in \p enabledCheckers. Return None on failure. LLVM_NODISCARD static llvm::Optional collectDependencies(const CheckerRegistry::CheckerInfo &checker, - const CheckerManager &Mgr) { + const LangOptions &LO) { CheckerRegistry::CheckerInfoSet Ret; // Add dependencies to the enabled checkers only if all of them can be // enabled. - if (!collectDependenciesImpl(checker.Dependencies, Mgr, Ret)) + if (!collectDependenciesImpl(checker.Dependencies, LO, Ret)) return None; return Ret; @@ -271,16 +238,16 @@ collectDependencies(const CheckerRegistry::CheckerInfo &checker, static bool collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps, - const CheckerManager &Mgr, + const LangOptions &LO, CheckerRegistry::CheckerInfoSet &Ret) { for (const CheckerRegistry::CheckerInfo *Dependency : Deps) { - if (Dependency->isDisabled(Mgr.getLangOpts())) + if (Dependency->isDisabled(LO)) return false; // Collect dependencies recursively. - if (!collectDependenciesImpl(Dependency->Dependencies, Mgr, Ret)) + if (!collectDependenciesImpl(Dependency->Dependencies, LO, Ret)) return false; Ret.insert(Dependency); @@ -289,6 +256,34 @@ collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps, return true; } +CheckerRegistry::CheckerInfoSet CheckerRegistry::getEnabledCheckers() const { + + CheckerInfoSet EnabledCheckers; + + for (const CheckerInfo &Checker : Checkers) { + if (!Checker.isEnabled(LangOpts)) + continue; + + // Recursively enable its dependencies. + llvm::Optional Deps = + collectDependencies(Checker, LangOpts); + + if (!Deps) { + // If we failed to enable any of the dependencies, don't enable this + // checker. + continue; + } + + // Note that set_union also preserves the order of insertion. + EnabledCheckers.set_union(*Deps); + + // Enable the checker. + EnabledCheckers.insert(&Checker); + } + + return EnabledCheckers; +} + void CheckerRegistry::resolveDependencies() { for (const std::pair &Entry : Dependencies) { auto CheckerIt = binaryFind(Checkers, Entry.first); @@ -303,6 +298,8 @@ void CheckerRegistry::resolveDependencies() { CheckerIt->Dependencies.emplace_back(&*DependencyIt); } + + Dependencies.clear(); } void CheckerRegistry::addDependency(StringRef FullName, StringRef Dependency) { @@ -381,12 +378,14 @@ void CheckerRegistry::resolveCheckerAndPackageOptions() { insertOptionToCollection(CheckerOptEntry.first, Checkers, CheckerOptEntry.second, AnOpts, Diags); } + CheckerOptions.clear(); for (const std::pair &PackageOptEntry : PackageOptions) { insertOptionToCollection(PackageOptEntry.first, Packages, PackageOptEntry.second, AnOpts, Diags); } + PackageOptions.clear(); } void CheckerRegistry::addPackage(StringRef FullName) { @@ -433,8 +432,11 @@ void CheckerRegistry::addCheckerOption(StringRef OptionType, } void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const { + // Collect checkers enabled by the options. + CheckerInfoSet enabledCheckers = getEnabledCheckers(); + // Initialize the CheckerManager with all enabled checkers. - for (const auto *Checker : EnabledCheckers) { + for (const auto *Checker : enabledCheckers) { CheckerMgr.setCurrentCheckerName(CheckerNameRef(Checker->FullName)); Checker->Initialize(CheckerMgr); } @@ -503,10 +505,6 @@ void CheckerRegistry::validateCheckerOptions() const { } } -//===----------------------------------------------------------------------===// -// Printing functions. -//===----------------------------------------------------------------------===// - void CheckerRegistry::printCheckerWithDescList(raw_ostream &Out, size_t MaxNameChars) const { // FIXME: Print available packages. @@ -558,6 +556,9 @@ void CheckerRegistry::printCheckerWithDescList(raw_ostream &Out, } void CheckerRegistry::printEnabledCheckerList(raw_ostream &Out) const { + // Collect checkers enabled by the options. + CheckerInfoSet EnabledCheckers = getEnabledCheckers(); + for (const auto *i : EnabledCheckers) Out << i->FullName << '\n'; } From 75add0b2ef10cd4a791793b1ec6bc8db18bdebfe Mon Sep 17 00:00:00 2001 From: LLVM GN Syncbot Date: Mon, 23 Mar 2020 19:09:57 +0000 Subject: [PATCH 30/59] [gn build] Port 56abcfad70e --- .../gn/secondary/clang/lib/StaticAnalyzer/Frontend/BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Frontend/BUILD.gn b/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Frontend/BUILD.gn index 423ddbc68fc7..e4654bf14944 100644 --- a/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Frontend/BUILD.gn +++ b/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Frontend/BUILD.gn @@ -14,7 +14,7 @@ static_library("Frontend") { ] sources = [ "AnalysisConsumer.cpp", - "AnalyzerHelpFlags.cpp", + "CheckerRegistration.cpp", "CheckerRegistry.cpp", "FrontendActions.cpp", "ModelConsumer.cpp", From 896335bfb8ea2c09c361c4f1e5a9aa6fb78caf88 Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Fri, 20 Mar 2020 14:00:19 -0700 Subject: [PATCH 31/59] Don't export symbols from clang/opt/llc if plugins are disabled. The only reason we export symbols from these tools is to support plugins; if we don't have plugins, exporting symbols just bloats the executable and makes LTO less effective. See review of D75879 for the discussion that led to this patch. Differential Revision: https://reviews.llvm.org/D76527 --- clang/tools/driver/CMakeLists.txt | 2 +- llvm/cmake/modules/AddLLVM.cmake | 7 +++++++ llvm/tools/bugpoint/CMakeLists.txt | 2 +- llvm/tools/llc/CMakeLists.txt | 2 +- llvm/tools/llvm-stress/CMakeLists.txt | 1 - llvm/tools/opt/CMakeLists.txt | 2 +- llvm/unittests/Passes/CMakeLists.txt | 2 +- 7 files changed, 12 insertions(+), 6 deletions(-) diff --git a/clang/tools/driver/CMakeLists.txt b/clang/tools/driver/CMakeLists.txt index 2b783cff0955..c53485ef1957 100644 --- a/clang/tools/driver/CMakeLists.txt +++ b/clang/tools/driver/CMakeLists.txt @@ -57,7 +57,7 @@ endif() # Support plugins. if(CLANG_PLUGIN_SUPPORT) - export_executable_symbols(clang) + export_executable_symbols_for_plugins(clang) endif() add_dependencies(clang clang-resource-headers) diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake index 7b95d8be1b60..8cd71eef2332 100644 --- a/llvm/cmake/modules/AddLLVM.cmake +++ b/llvm/cmake/modules/AddLLVM.cmake @@ -1029,6 +1029,13 @@ function(export_executable_symbols target) endif() endfunction() +# Export symbols if LLVM plugins are enabled. +function(export_executable_symbols_for_plugins target) + if(LLVM_ENABLE_PLUGINS) + export_executable_symbols(${target}) + endif() +endfunction() + if(NOT LLVM_TOOLCHAIN_TOOLS) set (LLVM_TOOLCHAIN_TOOLS llvm-ar diff --git a/llvm/tools/bugpoint/CMakeLists.txt b/llvm/tools/bugpoint/CMakeLists.txt index 0b5998e181eb..8d2d5a06e664 100644 --- a/llvm/tools/bugpoint/CMakeLists.txt +++ b/llvm/tools/bugpoint/CMakeLists.txt @@ -38,4 +38,4 @@ add_llvm_tool(bugpoint intrinsics_gen SUPPORT_PLUGINS ) -export_executable_symbols(bugpoint) +export_executable_symbols_for_plugins(bugpoint) diff --git a/llvm/tools/llc/CMakeLists.txt b/llvm/tools/llc/CMakeLists.txt index 479bc6b55b27..2eecfca2e075 100644 --- a/llvm/tools/llc/CMakeLists.txt +++ b/llvm/tools/llc/CMakeLists.txt @@ -27,4 +27,4 @@ add_llvm_tool(llc SUPPORT_PLUGINS ) -export_executable_symbols(llc) +export_executable_symbols_for_plugins(llc) diff --git a/llvm/tools/llvm-stress/CMakeLists.txt b/llvm/tools/llvm-stress/CMakeLists.txt index 139ab9e0d8f9..e4d1ae65ee76 100644 --- a/llvm/tools/llvm-stress/CMakeLists.txt +++ b/llvm/tools/llvm-stress/CMakeLists.txt @@ -10,4 +10,3 @@ add_llvm_tool(llvm-stress DEPENDS intrinsics_gen ) -export_executable_symbols(llvm-stress) diff --git a/llvm/tools/opt/CMakeLists.txt b/llvm/tools/opt/CMakeLists.txt index 79613c836c53..8caa1b78b729 100644 --- a/llvm/tools/opt/CMakeLists.txt +++ b/llvm/tools/opt/CMakeLists.txt @@ -39,7 +39,7 @@ add_llvm_tool(opt intrinsics_gen SUPPORT_PLUGINS ) -export_executable_symbols(opt) +export_executable_symbols_for_plugins(opt) if(LLVM_BUILD_EXAMPLES) target_link_libraries(opt PRIVATE ExampleIRTransforms) diff --git a/llvm/unittests/Passes/CMakeLists.txt b/llvm/unittests/Passes/CMakeLists.txt index c04aa9f84458..823bc56851fa 100644 --- a/llvm/unittests/Passes/CMakeLists.txt +++ b/llvm/unittests/Passes/CMakeLists.txt @@ -16,7 +16,7 @@ if (NOT WIN32) add_llvm_unittest(PluginsTests PluginsTest.cpp ) - export_executable_symbols(PluginsTests) + export_executable_symbols_for_plugins(PluginsTests) target_link_libraries(PluginsTests PRIVATE LLVMTestingSupport) set(LLVM_LINK_COMPONENTS) From 6b57d7f57d2cec7ec717757a6a52f2203d6e9db7 Mon Sep 17 00:00:00 2001 From: Johannes Doerfert Date: Fri, 13 Mar 2020 19:39:09 -0500 Subject: [PATCH 32/59] [OpenMP][NFC] Reduce instantiation time with different data structure See rational here: https://reviews.llvm.org/D71847#1922648 Reviewed By: rnk Differential Revision: https://reviews.llvm.org/D76170 --- .../include/llvm/Frontend/OpenMP/OMPContext.h | 10 +++-- .../include/llvm/Frontend/OpenMP/OMPKinds.def | 7 ++++ llvm/lib/Frontend/OpenMP/OMPContext.cpp | 39 ++++++++++++------- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPContext.h b/llvm/include/llvm/Frontend/OpenMP/OMPContext.h index 960c557f55d4..0a9d9c277d99 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMPContext.h +++ b/llvm/include/llvm/Frontend/OpenMP/OMPContext.h @@ -16,6 +16,7 @@ #define LLVM_OPENMP_CONTEXT_H #include "llvm/ADT/APSInt.h" +#include "llvm/ADT/BitVector.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Triple.h" @@ -43,6 +44,7 @@ enum class TraitSelector { /// IDs for all OpenMP context trait properties (host/gpu/bsc/llvm/...) enum class TraitProperty { #define OMP_TRAIT_PROPERTY(Enum, ...) Enum, +#define OMP_LAST_TRAIT_PROPERTY(Enum) Last = Enum #include "llvm/Frontend/OpenMP/OMPKinds.def" }; @@ -122,12 +124,12 @@ struct VariantMatchInfo { void addTrait(TraitSet Set, TraitProperty Property, APInt *Score = nullptr) { if (Score) ScoreMap[Property] = *Score; - RequiredTraits.insert(Property); + RequiredTraits.set(unsigned(Property)); if (Set == TraitSet::construct) ConstructTraits.push_back(Property); } - SmallSet RequiredTraits; + BitVector RequiredTraits = BitVector(unsigned(TraitProperty::Last) + 1); SmallVector ConstructTraits; SmallDenseMap ScoreMap; }; @@ -142,12 +144,12 @@ struct OMPContext { addTrait(getOpenMPContextTraitSetForProperty(Property), Property); } void addTrait(TraitSet Set, TraitProperty Property) { - ActiveTraits.insert(Property); + ActiveTraits.set(unsigned(Property)); if (Set == TraitSet::construct) ConstructTraits.push_back(Property); } - SmallSet ActiveTraits; + BitVector ActiveTraits = BitVector(unsigned(TraitProperty::Last) + 1); SmallVector ConstructTraits; }; diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def b/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def index 10ac5a759e77..5d26f07a7f5a 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def +++ b/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def @@ -427,6 +427,9 @@ __OMP_PROC_BIND_KIND(unknown, 7) #ifndef OMP_TRAIT_PROPERTY #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str) #endif +#ifndef OMP_LAST_TRAIT_PROPERTY +#define OMP_LAST_TRAIT_PROPERTY(Enum) +#endif #define __OMP_TRAIT_SET(Name) OMP_TRAIT_SET(Name, #Name) #define __OMP_TRAIT_SELECTOR(TraitSet, Name, RequiresProperty) \ @@ -534,10 +537,14 @@ __OMP_REQUIRES_TRAIT(reverse_offload) __OMP_REQUIRES_TRAIT(dynamic_allocators) __OMP_REQUIRES_TRAIT(atomic_default_mem_order) +OMP_LAST_TRAIT_PROPERTY( + implementation_atomic_default_mem_order_atomic_default_mem_order) + #undef __OMP_TRAIT_SELECTOR_AND_PROPERTY #undef OMP_TRAIT_SELECTOR #undef __OMP_TRAIT_SELECTOR #undef OMP_TRAIT_PROPERTY +#undef OMP_LAST_TRAIT_PROPERTY #undef __OMP_TRAIT_PROPERTY #undef __OMP_REQUIRES_TRAIT #undef OMP_REQUIRES_TRAIT diff --git a/llvm/lib/Frontend/OpenMP/OMPContext.cpp b/llvm/lib/Frontend/OpenMP/OMPContext.cpp index 62e5d1d8c466..748caa645a37 100644 --- a/llvm/lib/Frontend/OpenMP/OMPContext.cpp +++ b/llvm/lib/Frontend/OpenMP/OMPContext.cpp @@ -26,8 +26,9 @@ using namespace omp; OMPContext::OMPContext(bool IsDeviceCompilation, Triple TargetTriple) { // Add the appropriate device kind trait based on the triple and the // IsDeviceCompilation flag. - ActiveTraits.insert(IsDeviceCompilation ? TraitProperty::device_kind_nohost - : TraitProperty::device_kind_host); + ActiveTraits.set(unsigned(IsDeviceCompilation + ? TraitProperty::device_kind_nohost + : TraitProperty::device_kind_host)); switch (TargetTriple.getArch()) { case Triple::arm: case Triple::armeb: @@ -43,12 +44,12 @@ OMPContext::OMPContext(bool IsDeviceCompilation, Triple TargetTriple) { case Triple::ppc64le: case Triple::x86: case Triple::x86_64: - ActiveTraits.insert(TraitProperty::device_kind_cpu); + ActiveTraits.set(unsigned(TraitProperty::device_kind_cpu)); break; case Triple::amdgcn: case Triple::nvptx: case Triple::nvptx64: - ActiveTraits.insert(TraitProperty::device_kind_gpu); + ActiveTraits.set(unsigned(TraitProperty::device_kind_gpu)); break; default: break; @@ -58,7 +59,7 @@ OMPContext::OMPContext(bool IsDeviceCompilation, Triple TargetTriple) { #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str) \ if (TraitSelector::TraitSelectorEnum == TraitSelector::device_arch) \ if (TargetTriple.getArch() == TargetTriple.getArchTypeForLLVMName(Str)) \ - ActiveTraits.insert(TraitProperty::Enum); + ActiveTraits.set(unsigned(TraitProperty::Enum)); #include "llvm/Frontend/OpenMP/OMPKinds.def" // TODO: What exactly do we want to see as device ISA trait? @@ -67,20 +68,22 @@ OMPContext::OMPContext(bool IsDeviceCompilation, Triple TargetTriple) { // LLVM is the "OpenMP vendor" but we could also interpret vendor as the // target vendor. - ActiveTraits.insert(TraitProperty::implementation_vendor_llvm); + ActiveTraits.set(unsigned(TraitProperty::implementation_vendor_llvm)); // The user condition true is accepted but not false. - ActiveTraits.insert(TraitProperty::user_condition_true); + ActiveTraits.set(unsigned(TraitProperty::user_condition_true)); // This is for sure some device. - ActiveTraits.insert(TraitProperty::device_kind_any); + ActiveTraits.set(unsigned(TraitProperty::device_kind_any)); LLVM_DEBUG({ dbgs() << "[" << DEBUG_TYPE << "] New OpenMP context with the following properties:\n"; - for (auto &Property : ActiveTraits) + for (const auto &SetBitsIt : ActiveTraits.set_bits()) { + TraitProperty Property = TraitProperty(SetBitsIt); dbgs() << "\t " << getOpenMPContextTraitPropertyFullName(Property) << "\n"; + } }); } @@ -122,17 +125,24 @@ static bool isStrictSubset(const VariantMatchInfo &VMI0, // If all required traits are a strict subset and the ordered vectors storing // the construct traits, we say it is a strict subset. Note that the latter // relation is not required to be strict. - return set_is_strict_subset(VMI0.RequiredTraits, VMI1.RequiredTraits) && - isSubset(VMI0.ConstructTraits, VMI1.ConstructTraits); + if (VMI0.RequiredTraits.count() >= VMI1.RequiredTraits.count()) + return false; + for (const auto &SetBitsIt : VMI0.RequiredTraits.set_bits()) + if (!VMI1.RequiredTraits.test(SetBitsIt)) + return false; + if (!isSubset(VMI0.ConstructTraits, VMI1.ConstructTraits)) + return false; + return true; } static int isVariantApplicableInContextHelper( const VariantMatchInfo &VMI, const OMPContext &Ctx, SmallVectorImpl *ConstructMatches) { - for (TraitProperty Property : VMI.RequiredTraits) { + for (const auto &SetBitsIt : VMI.RequiredTraits.set_bits()) { + TraitProperty Property = TraitProperty(SetBitsIt); - bool IsActiveTrait = Ctx.ActiveTraits.count(Property); + bool IsActiveTrait = Ctx.ActiveTraits.test(unsigned(Property)); if (!IsActiveTrait) { LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE << "] Property " << getOpenMPContextTraitPropertyName(Property) @@ -181,7 +191,8 @@ static APInt getVariantMatchScore(const VariantMatchInfo &VMI, APInt Score(64, 1); unsigned NoConstructTraits = VMI.ConstructTraits.size(); - for (TraitProperty Property : VMI.RequiredTraits) { + for (const auto &SetBitsIt : VMI.RequiredTraits.set_bits()) { + TraitProperty Property = TraitProperty(SetBitsIt); // If there is a user score attached, use it. if (VMI.ScoreMap.count(Property)) { const APInt &UserScore = VMI.ScoreMap.lookup(Property); From 55eca2853e4f096be189208770034a8a4fb72666 Mon Sep 17 00:00:00 2001 From: Johannes Doerfert Date: Fri, 13 Mar 2020 23:42:05 -0500 Subject: [PATCH 33/59] [OpenMP][NFC] Minimize memory usage and copying of `OMPTraitInfo`s See rational here: https://reviews.llvm.org/D71830#1922656 Reviewed By: rnk Differential Revision: https://reviews.llvm.org/D76173 --- clang/include/clang/AST/ASTContext.h | 9 +++++++++ clang/include/clang/AST/OpenMPClause.h | 14 ++++++++++---- clang/include/clang/Basic/Attr.td | 2 +- .../include/clang/Serialization/ASTRecordReader.h | 2 +- .../include/clang/Serialization/ASTRecordWriter.h | 2 +- clang/lib/AST/ASTContext.cpp | 8 ++++++++ clang/lib/AST/AttrImpl.cpp | 2 +- clang/lib/AST/OpenMPClause.cpp | 4 ++++ clang/lib/CodeGen/CGOpenMPRuntime.cpp | 2 +- clang/lib/Parse/ParseOpenMP.cpp | 2 +- clang/lib/Sema/SemaOpenMP.cpp | 2 +- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 3 ++- clang/lib/Serialization/ASTReader.cpp | 6 +++--- clang/lib/Serialization/ASTReaderDecl.cpp | 2 +- clang/lib/Serialization/ASTWriter.cpp | 6 +++--- clang/utils/TableGen/ClangAttrEmitter.cpp | 8 ++++---- 16 files changed, 51 insertions(+), 23 deletions(-) diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index d74edb8a8adb..d9e2945ebbea 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -116,6 +116,7 @@ class ObjCPropertyDecl; class ObjCPropertyImplDecl; class ObjCProtocolDecl; class ObjCTypeParamDecl; +struct OMPTraitInfo; struct ParsedTargetAttr; class Preprocessor; class Stmt; @@ -2962,6 +2963,14 @@ OPT_LIST(V) }; llvm::StringMap SectionInfos; + + /// Return a new OMPTraitInfo object owned by this context. + OMPTraitInfo &getNewOMPTraitInfo(); + +private: + /// All OMPTraitInfo objects live in this collection, one per + /// `pragma omp [begin] declare variant` directive. + SmallVector OMPTraitInfoVector; }; /// Utility function for constructing a nullary selector. diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index acf450f07e66..8b92cb62634a 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -7116,22 +7116,27 @@ class OMPClausePrinter final : public OMPClauseVisitor { /// collection of selector sets, each with an associated kind and an ordered /// collection of selectors. A selector has a kind, an optional score/condition, /// and an ordered collection of properties. -struct OMPTraitInfo { +class OMPTraitInfo { + /// Private constructor accesible only by ASTContext. + OMPTraitInfo() {} + friend class ASTContext; + +public: struct OMPTraitProperty { llvm::omp::TraitProperty Kind = llvm::omp::TraitProperty::invalid; }; struct OMPTraitSelector { Expr *ScoreOrCondition = nullptr; llvm::omp::TraitSelector Kind = llvm::omp::TraitSelector::invalid; - llvm::SmallVector Properties; + llvm::SmallVector Properties; }; struct OMPTraitSet { llvm::omp::TraitSet Kind = llvm::omp::TraitSet::invalid; - llvm::SmallVector Selectors; + llvm::SmallVector Selectors; }; /// The outermost level of selector sets. - llvm::SmallVector Sets; + llvm::SmallVector Sets; bool anyScoreOrCondition( llvm::function_ref Cond) { @@ -7157,6 +7162,7 @@ struct OMPTraitInfo { void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const; }; llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const OMPTraitInfo &TI); +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const OMPTraitInfo *TI); } // namespace clang diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index c8c35cbe5b70..db1589bea814 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3314,7 +3314,7 @@ def OMPDeclareVariant : InheritableAttr { OMPTraitInfoArgument<"TraitInfos">, ]; let AdditionalMembers = [{ - OMPTraitInfo &getTraitInfo() { return traitInfos; } + OMPTraitInfo &getTraitInfo() { return *traitInfos; } void printPrettyPragma(raw_ostream & OS, const PrintingPolicy &Policy) const; }]; diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h index 7d4ef7c43a9d..362296024a97 100644 --- a/clang/include/clang/Serialization/ASTRecordReader.h +++ b/clang/include/clang/Serialization/ASTRecordReader.h @@ -260,7 +260,7 @@ class ASTRecordReader } /// Read an OMPTraitInfo object, advancing Idx. - OMPTraitInfo readOMPTraitInfo(); + OMPTraitInfo *readOMPTraitInfo(); /// Read an OpenMP clause, advancing Idx. OMPClause *readOMPClause(); diff --git a/clang/include/clang/Serialization/ASTRecordWriter.h b/clang/include/clang/Serialization/ASTRecordWriter.h index 924aa5d4b758..491207c9de90 100644 --- a/clang/include/clang/Serialization/ASTRecordWriter.h +++ b/clang/include/clang/Serialization/ASTRecordWriter.h @@ -267,7 +267,7 @@ class ASTRecordWriter void AddCXXDefinitionData(const CXXRecordDecl *D); /// Write an OMPTraitInfo object. - void writeOMPTraitInfo(const OMPTraitInfo &TI); + void writeOMPTraitInfo(const OMPTraitInfo *TI); void writeOMPClause(OMPClause *C); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 77d5e59d9f0c..390abda466a2 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1005,6 +1005,9 @@ ASTContext::~ASTContext() { for (APValue *Value : APValueCleanups) Value->~APValue(); + + // Destroy the OMPTraitInfo objects that life here. + llvm::DeleteContainerPointers(OMPTraitInfoVector); } void ASTContext::setTraversalScope(const std::vector &TopLevelDecls) { @@ -10838,3 +10841,8 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap &FeatureMap, Target->getTargetOpts().Features); } } + +OMPTraitInfo &ASTContext::getNewOMPTraitInfo() { + OMPTraitInfoVector.push_back(new OMPTraitInfo()); + return *OMPTraitInfoVector.back(); +} diff --git a/clang/lib/AST/AttrImpl.cpp b/clang/lib/AST/AttrImpl.cpp index 2c76f86713fb..a5ff68c18778 100644 --- a/clang/lib/AST/AttrImpl.cpp +++ b/clang/lib/AST/AttrImpl.cpp @@ -159,7 +159,7 @@ void OMPDeclareVariantAttr::printPrettyPragma( OS << ")"; } OS << " match("; - traitInfos.print(OS, Policy); + traitInfos->print(OS, Policy); OS << ")"; } diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index 5f9da85a9f07..87ab3e333e22 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -1964,3 +1964,7 @@ llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS, TI.print(OS, Policy); return OS; } +llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS, + const OMPTraitInfo *TI) { + return TI ? OS << *TI : OS; +} diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index b00027586767..58c5334776f3 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -11393,7 +11393,7 @@ static const FunctionDecl *getDeclareVariantFunction(CodeGenModule &CGM, SmallVector VariantExprs; SmallVector VMIs; for (const auto *A : FD->specific_attrs()) { - const OMPTraitInfo &TI = A->getTraitInfos(); + const OMPTraitInfo &TI = *A->getTraitInfos(); VMIs.push_back(VariantMatchInfo()); TI.getAsVariantMatchInfo(CGM.getContext(), VMIs.back()); VariantExprs.push_back(A->getVariantFuncRef()); diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index acc1e55eb721..33b07bad8935 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -1365,7 +1365,7 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr, } // Parse inner context selectors. - OMPTraitInfo TI; + OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo(); parseOMPContextSelectors(Loc, TI); // Parse ')' diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index d9a4a17f1866..c9e2f395ec06 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -5703,7 +5703,7 @@ void Sema::ActOnOpenMPDeclareVariantDirective(FunctionDecl *FD, OMPTraitInfo &TI, SourceRange SR) { auto *NewAttr = - OMPDeclareVariantAttr::CreateImplicit(Context, VariantRef, TI, SR); + OMPDeclareVariantAttr::CreateImplicit(Context, VariantRef, &TI, SR); FD->addAttr(NewAttr); } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 875eb2bfb940..502c0babab8d 100755 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -398,7 +398,8 @@ static void instantiateOMPDeclareVariantAttr( // Copy the template version of the OMPTraitInfo and run substitute on all // score and condition expressiosn. - OMPTraitInfo TI = Attr.getTraitInfos(); + OMPTraitInfo &TI = S.getASTContext().getNewOMPTraitInfo(); + TI = *Attr.getTraitInfos(); // Try to substitute template parameters in score and condition expressions. auto SubstScoreOrConditionExpr = [&S, Subst](Expr *&E, bool) { diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 77f15bcd910a..fbd68929b2f1 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -12684,8 +12684,8 @@ void OMPClauseReader::VisitOMPOrderClause(OMPOrderClause *C) { C->setKindKwLoc(Record.readSourceLocation()); } -OMPTraitInfo ASTRecordReader::readOMPTraitInfo() { - OMPTraitInfo TI; +OMPTraitInfo *ASTRecordReader::readOMPTraitInfo() { + OMPTraitInfo &TI = getContext().getNewOMPTraitInfo(); TI.Sets.resize(readUInt32()); for (auto &Set : TI.Sets) { Set.Kind = readEnum(); @@ -12700,5 +12700,5 @@ OMPTraitInfo ASTRecordReader::readOMPTraitInfo() { Property.Kind = readEnum(); } } - return TI; + return &TI; } diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index bb2ecb53c7ce..3bd7b825cdc8 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2744,7 +2744,7 @@ class AttrReader { return Reader.readVersionTuple(); } - OMPTraitInfo readOMPTraitInfo() { return Reader.readOMPTraitInfo(); } + OMPTraitInfo *readOMPTraitInfo() { return Reader.readOMPTraitInfo(); } template T *GetLocalDeclAs(uint32_t LocalID) { return Reader.GetLocalDeclAs(LocalID); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 9ccebae9567d..f30824622346 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -6624,9 +6624,9 @@ void OMPClauseWriter::VisitOMPOrderClause(OMPOrderClause *C) { Record.AddSourceLocation(C->getKindKwLoc()); } -void ASTRecordWriter::writeOMPTraitInfo(const OMPTraitInfo &TI) { - writeUInt32(TI.Sets.size()); - for (const auto &Set : TI.Sets) { +void ASTRecordWriter::writeOMPTraitInfo(const OMPTraitInfo *TI) { + writeUInt32(TI->Sets.size()); + for (const auto &Set : TI->Sets) { writeEnum(Set.Kind); writeUInt32(Set.Selectors.size()); for (const auto &Selector : Set.Selectors) { diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index f640c9eecaee..dcb2f323122c 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -107,7 +107,7 @@ static std::string ReadPCHRecord(StringRef type) { .Case("IdentifierInfo *", "Record.readIdentifier()") .Case("StringRef", "Record.readString()") .Case("ParamIdx", "ParamIdx::deserialize(Record.readInt())") - .Case("OMPTraitInfo", "Record.readOMPTraitInfo()") + .Case("OMPTraitInfo *", "Record.readOMPTraitInfo()") .Default("Record.readInt()"); } @@ -131,7 +131,7 @@ static std::string WritePCHRecord(StringRef type, StringRef name) { .Case("StringRef", "AddString(" + std::string(name) + ");\n") .Case("ParamIdx", "push_back(" + std::string(name) + ".serialize());\n") - .Case("OMPTraitInfo", + .Case("OMPTraitInfo *", "writeOMPTraitInfo(" + std::string(name) + ");\n") .Default("push_back(" + std::string(name) + ");\n"); } @@ -363,7 +363,7 @@ namespace { OS << " if (SA->get" << getUpperName() << "().isValid())\n "; OS << " OS << \" \" << SA->get" << getUpperName() << "().getSourceIndex();\n"; - } else if (type == "OMPTraitInfo") { + } else if (type == "OMPTraitInfo *") { OS << " OS << \" \" << SA->get" << getUpperName() << "();\n"; } else { llvm_unreachable("Unknown SimpleArgument type!"); @@ -1331,7 +1331,7 @@ createArgument(const Record &Arg, StringRef Attr, else if (ArgName == "VersionArgument") Ptr = std::make_unique(Arg, Attr); else if (ArgName == "OMPTraitInfoArgument") - Ptr = std::make_unique(Arg, Attr, "OMPTraitInfo"); + Ptr = std::make_unique(Arg, Attr, "OMPTraitInfo *"); if (!Ptr) { // Search in reverse order so that the most-derived type is handled first. From 43d98a0ecfec7882419206673f04a9632c746057 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Wed, 13 Feb 2019 18:28:16 -0500 Subject: [PATCH 34/59] Allow replacing intrinsic operands with variables Since intrinsics can now specify when an argument is required to be constant, it is now OK to replace arguments with variables if they aren't. This means intrinsics must now be accurately marked with immarg. --- llvm/include/llvm/IR/CallSite.h | 7 + .../Transforms/Scalar/ConstantHoisting.cpp | 2 +- llvm/lib/Transforms/Utils/Local.cpp | 36 +++-- llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 13 +- llvm/test/Transforms/GVNSink/indirect-call.ll | 24 ++++ .../SimplifyCFG/sink-common-code.ll | 123 +++++++++++++++++- llvm/unittests/Transforms/Utils/LocalTest.cpp | 60 +++++++++ 7 files changed, 248 insertions(+), 17 deletions(-) diff --git a/llvm/include/llvm/IR/CallSite.h b/llvm/include/llvm/IR/CallSite.h index 0e957c4797e8..6a82e73537cf 100644 --- a/llvm/include/llvm/IR/CallSite.h +++ b/llvm/include/llvm/IR/CallSite.h @@ -146,6 +146,13 @@ class CallSiteBase { return static_cast(0); } + /// Return if this call is to an intrinsic. + bool isIntrinsic() const { + if (auto *F = getCalledFunction()) + return F->isIntrinsic(); + return false; + } + /// Determine whether the passed iterator points to the callee operand's Use. bool isCallee(Value::const_user_iterator UI) const { return isCallee(&UI.getUse()); diff --git a/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp b/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp index 5bfece010bec..0fc07fb9778d 100644 --- a/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp +++ b/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp @@ -491,7 +491,7 @@ void ConstantHoistingPass::collectConstantCandidates( // take constant variables is lower than `TargetTransformInfo::TCC_Basic`. // So it's safe for us to collect constant candidates from all // IntrinsicInsts. - if (canReplaceOperandWithVariable(Inst, Idx) || isa(Inst)) { + if (canReplaceOperandWithVariable(Inst, Idx)) { collectConstantCandidates(ConstCandMap, Inst, Idx); } } // end of for all operands diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index 1267226dfeb2..d5d9dff75ef0 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -2935,21 +2935,39 @@ bool llvm::canReplaceOperandWithVariable(const Instruction *I, unsigned OpIdx) { default: return true; case Instruction::Call: - case Instruction::Invoke: + case Instruction::Invoke: { + ImmutableCallSite CS(I); + // Can't handle inline asm. Skip it. - if (isa(ImmutableCallSite(I).getCalledValue())) - return false; - // Many arithmetic intrinsics have no issue taking a - // variable, however it's hard to distingish these from - // specials such as @llvm.frameaddress that require a constant. - if (isa(I)) + if (CS.isInlineAsm()) return false; // Constant bundle operands may need to retain their constant-ness for // correctness. - if (ImmutableCallSite(I).isBundleOperand(OpIdx)) + if (CS.isBundleOperand(OpIdx)) return false; - return true; + + if (OpIdx < CS.getNumArgOperands()) { + // Some variadic intrinsics require constants in the variadic arguments, + // which currently aren't markable as immarg. + if (CS.isIntrinsic() && OpIdx >= CS.getFunctionType()->getNumParams()) { + // This is known to be OK for stackmap. + return CS.getIntrinsicID() == Intrinsic::experimental_stackmap; + } + + // gcroot is a special case, since it requires a constant argument which + // isn't also required to be a simple ConstantInt. + if (CS.getIntrinsicID() == Intrinsic::gcroot) + return false; + + // Some intrinsic operands are required to be immediates. + return !CS.paramHasAttr(OpIdx, Attribute::ImmArg); + } + + // It is never allowed to replace the call argument to an intrinsic, but it + // may be possible for a call. + return !CS.isIntrinsic(); + } case Instruction::ShuffleVector: // Shufflevector masks are constant. return OpIdx != 2; diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index 36358ef34fd0..9a39df4c35f8 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -1445,6 +1445,13 @@ static bool isLifeTimeMarker(const Instruction *I) { return false; } +// TODO: Refine this. This should avoid cases like turning constant memcpy sizes +// into variables. +static bool replacingOperandWithVariableIsCheap(const Instruction *I, + int OpIdx) { + return !isa(I); +} + // All instructions in Insts belong to different blocks that all unconditionally // branch to a common successor. Analyze each instruction and return true if it // would be possible to sink them into their successor, creating one common @@ -1522,7 +1529,8 @@ static bool canSinkInstructions( return false; for (unsigned OI = 0, OE = I0->getNumOperands(); OI != OE; ++OI) { - if (I0->getOperand(OI)->getType()->isTokenTy()) + Value *Op = I0->getOperand(OI); + if (Op->getType()->isTokenTy()) // Don't touch any operand of token type. return false; @@ -1531,7 +1539,8 @@ static bool canSinkInstructions( return I->getOperand(OI) == I0->getOperand(OI); }; if (!all_of(Insts, SameAsI0)) { - if (!canReplaceOperandWithVariable(I0, OI)) + if ((isa(Op) && !replacingOperandWithVariableIsCheap(I0, OI)) || + !canReplaceOperandWithVariable(I0, OI)) // We can't create a PHI from this GEP. return false; // Don't create indirect calls! The called value is the final operand. diff --git a/llvm/test/Transforms/GVNSink/indirect-call.ll b/llvm/test/Transforms/GVNSink/indirect-call.ll index da98ed0819a6..57b7297c84bd 100644 --- a/llvm/test/Transforms/GVNSink/indirect-call.ll +++ b/llvm/test/Transforms/GVNSink/indirect-call.ll @@ -68,3 +68,27 @@ if.end: %tobool4 = icmp ne i8 %obeys.0, 0 ret i1 %tobool4 } + +; Make sure no indirect call is introduced from direct calls +declare i8 @ext2(i1) +define zeroext i1 @test4(i1 zeroext %flag, i32 %blksA, i32 %blksB, i32 %nblks) { +entry: + %cmp = icmp uge i32 %blksA, %nblks + br i1 %flag, label %if.then, label %if.else + +; CHECK-LABEL: test4 +; CHECK: call i8 @ext( +; CHECK: call i8 @ext2( +if.then: + %frombool1 = call i8 @ext(i1 %cmp) + br label %if.end + +if.else: + %frombool3 = call i8 @ext2(i1 %cmp) + br label %if.end + +if.end: + %obeys.0 = phi i8 [ %frombool1, %if.then ], [ %frombool3, %if.else ] + %tobool4 = icmp ne i8 %obeys.0, 0 + ret i1 %tobool4 +} diff --git a/llvm/test/Transforms/SimplifyCFG/sink-common-code.ll b/llvm/test/Transforms/SimplifyCFG/sink-common-code.ll index 8254a49e28fd..00329ae5d640 100644 --- a/llvm/test/Transforms/SimplifyCFG/sink-common-code.ll +++ b/llvm/test/Transforms/SimplifyCFG/sink-common-code.ll @@ -291,12 +291,12 @@ entry: if.then: %dummy = add i32 %w, 5 - %sv1 = call i32 @llvm.ctlz.i32(i32 %x) + %sv1 = call i32 @llvm.ctlz.i32(i32 %x, i1 false) br label %if.end if.else: %dummy1 = add i32 %w, 6 - %sv2 = call i32 @llvm.cttz.i32(i32 %x) + %sv2 = call i32 @llvm.cttz.i32(i32 %x, i1 false) br label %if.end if.end: @@ -304,8 +304,8 @@ if.end: ret i32 1 } -declare i32 @llvm.ctlz.i32(i32 %x) readnone -declare i32 @llvm.cttz.i32(i32 %x) readnone +declare i32 @llvm.ctlz.i32(i32 %x, i1 immarg) readnone +declare i32 @llvm.cttz.i32(i32 %x, i1 immarg) readnone ; CHECK-LABEL: test12 ; CHECK: call i32 @llvm.ctlz @@ -769,6 +769,120 @@ if.end: ; CHECK-NOT: exact ; CHECK: } + +; FIXME: Should turn into select +; CHECK-LABEL: @allow_intrinsic_remove_constant( +; CHECK: %sv1 = call float @llvm.fma.f32(float %dummy, float 2.000000e+00, float 1.000000e+00) +; CHECK: %sv2 = call float @llvm.fma.f32(float 2.000000e+00, float %dummy1, float 1.000000e+00) +define float @allow_intrinsic_remove_constant(i1 zeroext %flag, float %w, float %x, float %y) { +entry: + br i1 %flag, label %if.then, label %if.else + +if.then: + %dummy = fadd float %w, 4.0 + %sv1 = call float @llvm.fma.f32(float %dummy, float 2.0, float 1.0) + br label %if.end + +if.else: + %dummy1 = fadd float %w, 8.0 + %sv2 = call float @llvm.fma.f32(float 2.0, float %dummy1, float 1.0) + br label %if.end + +if.end: + %p = phi float [ %sv1, %if.then ], [ %sv2, %if.else ] + ret float %p +} + +declare float @llvm.fma.f32(float, float, float) + +; CHECK-LABEL: @no_remove_constant_immarg( +; CHECK: call i32 @llvm.ctlz.i32(i32 %x, i1 true) +; CHECK: call i32 @llvm.ctlz.i32(i32 %x, i1 false) +define i32 @no_remove_constant_immarg(i1 zeroext %flag, i32 %w, i32 %x, i32 %y) { +entry: + br i1 %flag, label %if.then, label %if.else + +if.then: + %dummy = add i32 %w, 5 + %sv1 = call i32 @llvm.ctlz.i32(i32 %x, i1 true) + br label %if.end + +if.else: + %dummy1 = add i32 %w, 6 + %sv2 = call i32 @llvm.ctlz.i32(i32 %x, i1 false) + br label %if.end + +if.end: + %p = phi i32 [ %sv1, %if.then ], [ %sv2, %if.else ] + ret i32 1 +} + +declare void @llvm.memcpy.p1i8.p1i8.i64(i8 addrspace(1)* nocapture, i8 addrspace(1)* nocapture readonly, i64, i1) + +; Make sure a memcpy size isn't replaced with a variable +; CHECK-LABEL: @no_replace_memcpy_size( +; CHECK: call void @llvm.memcpy.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 1024, i1 false) +; CHECK: call void @llvm.memcpy.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 4096, i1 false) +define void @no_replace_memcpy_size(i1 zeroext %flag, i8 addrspace(1)* %dst, i8 addrspace(1)* %src) { +entry: + br i1 %flag, label %if.then, label %if.else + +if.then: + call void @llvm.memcpy.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 1024, i1 false) + br label %if.end + +if.else: + call void @llvm.memcpy.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 4096, i1 false) + br label %if.end + +if.end: + ret void +} + +declare void @llvm.memmove.p1i8.p1i8.i64(i8 addrspace(1)* nocapture, i8 addrspace(1)* nocapture readonly, i64, i1) + +; Make sure a memmove size isn't replaced with a variable +; CHECK-LABEL: @no_replace_memmove_size( +; CHECK: call void @llvm.memmove.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 1024, i1 false) +; CHECK: call void @llvm.memmove.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 4096, i1 false) +define void @no_replace_memmove_size(i1 zeroext %flag, i8 addrspace(1)* %dst, i8 addrspace(1)* %src) { +entry: + br i1 %flag, label %if.then, label %if.else + +if.then: + call void @llvm.memmove.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 1024, i1 false) + br label %if.end + +if.else: + call void @llvm.memmove.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 4096, i1 false) + br label %if.end + +if.end: + ret void +} + +declare void @llvm.memset.p1i8.i64(i8 addrspace(1)* nocapture, i8, i64, i1) + +; Make sure a memset size isn't replaced with a variable +; CHECK-LABEL: @no_replace_memset_size( +; CHECK: call void @llvm.memset.p1i8.i64(i8 addrspace(1)* %dst, i8 0, i64 1024, i1 false) +; CHECK: call void @llvm.memset.p1i8.i64(i8 addrspace(1)* %dst, i8 0, i64 4096, i1 false) +define void @no_replace_memset_size(i1 zeroext %flag, i8 addrspace(1)* %dst) { +entry: + br i1 %flag, label %if.then, label %if.else + +if.then: + call void @llvm.memset.p1i8.i64(i8 addrspace(1)* %dst, i8 0, i64 1024, i1 false) + br label %if.end + +if.else: + call void @llvm.memset.p1i8.i64(i8 addrspace(1)* %dst, i8 0, i64 4096, i1 false) + br label %if.end + +if.end: + ret void +} + ; Check that simplifycfg doesn't sink and merge inline-asm instructions. define i32 @test_inline_asm1(i32 %c, i32 %r6) { @@ -913,7 +1027,6 @@ if.end: declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) - ; CHECK: ![[$TBAA]] = !{![[TYPE:[0-9]]], ![[TYPE]], i64 0} ; CHECK: ![[TYPE]] = !{!"float", ![[TEXT:[0-9]]]} ; CHECK: ![[TEXT]] = !{!"an example type tree"} diff --git a/llvm/unittests/Transforms/Utils/LocalTest.cpp b/llvm/unittests/Transforms/Utils/LocalTest.cpp index cd32669ca2f6..4fa6a09f2022 100644 --- a/llvm/unittests/Transforms/Utils/LocalTest.cpp +++ b/llvm/unittests/Transforms/Utils/LocalTest.cpp @@ -1001,3 +1001,63 @@ TEST(Local, SimplifyCFGWithNullAC) { // %test.bb is expected to be simplified by FoldCondBranchOnPHI. EXPECT_TRUE(simplifyCFG(TestBB, TTI, Options)); } + +TEST(Local, CanReplaceOperandWithVariable) { + LLVMContext Ctx; + Module M("test_module", Ctx); + IRBuilder<> B(Ctx); + + FunctionType *FnType = + FunctionType::get(Type::getVoidTy(Ctx), {}, false); + + FunctionType *VarArgFnType = + FunctionType::get(Type::getVoidTy(Ctx), {B.getInt32Ty()}, true); + + Function *TestBody = Function::Create(FnType, GlobalValue::ExternalLinkage, + 0, "", &M); + + BasicBlock *BB0 = BasicBlock::Create(Ctx, "", TestBody); + B.SetInsertPoint(BB0); + + Value *Intrin = M.getOrInsertFunction("llvm.foo", FnType).getCallee(); + Value *Func = M.getOrInsertFunction("foo", FnType).getCallee(); + Value *VarArgFunc + = M.getOrInsertFunction("foo.vararg", VarArgFnType).getCallee(); + Value *VarArgIntrin + = M.getOrInsertFunction("llvm.foo.vararg", VarArgFnType).getCallee(); + + auto *CallToIntrin = B.CreateCall(Intrin); + auto *CallToFunc = B.CreateCall(Func); + + // Test if it's valid to replace the callee operand. + EXPECT_FALSE(canReplaceOperandWithVariable(CallToIntrin, 0)); + EXPECT_TRUE(canReplaceOperandWithVariable(CallToFunc, 0)); + + // That it's invalid to replace an argument in the variadic argument list for + // an intrinsic, but OK for a normal function. + auto *CallToVarArgFunc = B.CreateCall( + VarArgFunc, {B.getInt32(0), B.getInt32(1), B.getInt32(2)}); + EXPECT_TRUE(canReplaceOperandWithVariable(CallToVarArgFunc, 0)); + EXPECT_TRUE(canReplaceOperandWithVariable(CallToVarArgFunc, 1)); + EXPECT_TRUE(canReplaceOperandWithVariable(CallToVarArgFunc, 2)); + EXPECT_TRUE(canReplaceOperandWithVariable(CallToVarArgFunc, 3)); + + auto *CallToVarArgIntrin = B.CreateCall( + VarArgIntrin, {B.getInt32(0), B.getInt32(1), B.getInt32(2)}); + EXPECT_TRUE(canReplaceOperandWithVariable(CallToVarArgIntrin, 0)); + EXPECT_FALSE(canReplaceOperandWithVariable(CallToVarArgIntrin, 1)); + EXPECT_FALSE(canReplaceOperandWithVariable(CallToVarArgIntrin, 2)); + EXPECT_FALSE(canReplaceOperandWithVariable(CallToVarArgIntrin, 3)); + + // Test that it's invalid to replace gcroot operands, even though it can't use + // immarg. + Type *PtrPtr = B.getInt8Ty()->getPointerTo(0); + Value *Alloca = B.CreateAlloca(PtrPtr, (unsigned)0); + CallInst *GCRoot = B.CreateIntrinsic(Intrinsic::gcroot, {}, + {Alloca, Constant::getNullValue(PtrPtr)}); + EXPECT_TRUE(canReplaceOperandWithVariable(GCRoot, 0)); // Alloca + EXPECT_FALSE(canReplaceOperandWithVariable(GCRoot, 1)); + EXPECT_FALSE(canReplaceOperandWithVariable(GCRoot, 2)); + + BB0->dropAllReferences(); +} From cfaa84e1a679b2e2eb409eb57292f7caecb642d4 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Mon, 23 Mar 2020 12:49:41 -0700 Subject: [PATCH 35/59] Fix "previously declared as a struct" warning --- clang/include/clang/AST/ASTContext.h | 2 +- clang/include/clang/Serialization/ASTRecordReader.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index d9e2945ebbea..ca0f991c24e3 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -116,7 +116,7 @@ class ObjCPropertyDecl; class ObjCPropertyImplDecl; class ObjCProtocolDecl; class ObjCTypeParamDecl; -struct OMPTraitInfo; +class OMPTraitInfo; struct ParsedTargetAttr; class Preprocessor; class Stmt; diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h index 362296024a97..5bdc9ca2ddbf 100644 --- a/clang/include/clang/Serialization/ASTRecordReader.h +++ b/clang/include/clang/Serialization/ASTRecordReader.h @@ -22,7 +22,7 @@ #include "llvm/ADT/APSInt.h" namespace clang { -struct OMPTraitInfo; +class OMPTraitInfo; /// An object for streaming information from a record. class ASTRecordReader From 5f5fb56c68e4830597a5b52d7a8edafea21566ac Mon Sep 17 00:00:00 2001 From: Ilya Leoshkevich Date: Mon, 23 Mar 2020 12:46:20 -0700 Subject: [PATCH 36/59] [compiler-rt] Intercept the uname() function Summary: Move interceptor from msan to sanitizer_common_interceptors.inc, so that other sanitizers could benefit. Adjust FixedCVE_2016_2143() to deal with the intercepted uname(). Patch by Ilya Leoshkevich. Reviewers: eugenis, vitalybuka, uweigand, jonpa Reviewed By: eugenis, vitalybuka Subscribers: dberris, krytarowski, #sanitizers, stefansf, Andreas-Krebbel Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D76578 --- compiler-rt/lib/msan/msan_interceptors.cpp | 25 ------------- .../sanitizer_common_interceptors.inc | 36 +++++++++++++++++++ .../sanitizer_common/sanitizer_linux_s390.cpp | 13 ++++--- .../sanitizer_platform_interceptors.h | 2 ++ .../sanitizer_common/TestCases/Posix/uname.c | 13 +++++++ 5 files changed, 60 insertions(+), 29 deletions(-) create mode 100644 compiler-rt/test/sanitizer_common/TestCases/Posix/uname.c diff --git a/compiler-rt/lib/msan/msan_interceptors.cpp b/compiler-rt/lib/msan/msan_interceptors.cpp index 4cdce7e29af1..9b1340b0104e 100644 --- a/compiler-rt/lib/msan/msan_interceptors.cpp +++ b/compiler-rt/lib/msan/msan_interceptors.cpp @@ -824,30 +824,6 @@ INTERCEPTOR(int, prlimit64, int pid, int resource, void *new_rlimit, #define MSAN_MAYBE_INTERCEPT_PRLIMIT64 #endif -#if SANITIZER_FREEBSD -// FreeBSD's define uname() as -// static __inline int uname(struct utsname *name) { -// return __xuname(SYS_NMLN, (void*)name); -// } -INTERCEPTOR(int, __xuname, int size, void *utsname) { - ENSURE_MSAN_INITED(); - int res = REAL(__xuname)(size, utsname); - if (!res) - __msan_unpoison(utsname, __sanitizer::struct_utsname_sz); - return res; -} -#define MSAN_INTERCEPT_UNAME INTERCEPT_FUNCTION(__xuname) -#else -INTERCEPTOR(int, uname, struct utsname *utsname) { - ENSURE_MSAN_INITED(); - int res = REAL(uname)(utsname); - if (!res) - __msan_unpoison(utsname, __sanitizer::struct_utsname_sz); - return res; -} -#define MSAN_INTERCEPT_UNAME INTERCEPT_FUNCTION(uname) -#endif - INTERCEPTOR(int, gethostname, char *name, SIZE_T len) { ENSURE_MSAN_INITED(); int res = REAL(gethostname)(name, len); @@ -1705,7 +1681,6 @@ void InitializeInterceptors() { MSAN_MAYBE_INTERCEPT_GETRLIMIT64; MSAN_MAYBE_INTERCEPT_PRLIMIT; MSAN_MAYBE_INTERCEPT_PRLIMIT64; - MSAN_INTERCEPT_UNAME; INTERCEPT_FUNCTION(gethostname); MSAN_MAYBE_INTERCEPT_EPOLL_WAIT; MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 6daed4a6736c..8267b3bb4dd0 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -9749,6 +9749,40 @@ INTERCEPTOR(int, sigaltstack, void *ss, void *oss) { #define INIT_SIGALTSTACK #endif +#if SANITIZER_INTERCEPT_UNAME +INTERCEPTOR(int, uname, struct utsname *utsname) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, uname, utsname); + int res = REAL(uname)(utsname); + if (!res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, utsname, + __sanitizer::struct_utsname_sz); + return res; +} +#define INIT_UNAME COMMON_INTERCEPT_FUNCTION(uname) +#else +#define INIT_UNAME +#endif + +#if SANITIZER_INTERCEPT___XUNAME +// FreeBSD's define uname() as +// static __inline int uname(struct utsname *name) { +// return __xuname(SYS_NMLN, (void*)name); +// } +INTERCEPTOR(int, __xuname, int size, void *utsname) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __xuname, size, utsname); + int res = REAL(__xuname)(size, utsname); + if (!res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, utsname, + __sanitizer::struct_utsname_sz); + return res; +} +#define INIT___XUNAME COMMON_INTERCEPT_FUNCTION(__xuname) +#else +#define INIT___XUNAME +#endif + #include "sanitizer_common_interceptors_netbsd_compat.inc" static void InitializeCommonInterceptors() { @@ -10055,6 +10089,8 @@ static void InitializeCommonInterceptors() { INIT_QSORT; INIT_QSORT_R; INIT_SIGALTSTACK; + INIT_UNAME; + INIT___XUNAME; INIT___PRINTF_CHK; } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux_s390.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux_s390.cpp index 9e3b4f13a436..16b4c9b633d8 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux_s390.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux_s390.cpp @@ -15,14 +15,15 @@ #if SANITIZER_LINUX && SANITIZER_S390 -#include "sanitizer_libc.h" -#include "sanitizer_linux.h" - +#include #include #include #include #include +#include "sanitizer_libc.h" +#include "sanitizer_linux.h" + namespace __sanitizer { // --------------- sanitizer_libc.h @@ -122,8 +123,12 @@ static bool FixedCVE_2016_2143() { // adjust this for their own kernels. struct utsname buf; unsigned int major, minor, patch = 0; + // Depending on the concrete sanitizer being used, uname may or may not + // be intercepted. Make sure we use the libc version in either case. + using Uname = int (*)(struct utsname *); + Uname uname = reinterpret_cast(dlsym(RTLD_NEXT, "uname")); // This should never fail, but just in case... - if (uname(&buf)) + if (uname == nullptr || uname(&buf)) return false; const char *ptr = buf.release; major = internal_simple_strtoll(ptr, &ptr, 10); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index 8d08c0de1770..9dd6d285f594 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -597,5 +597,7 @@ (SI_POSIX && !SI_IOSSIM && !SI_WATCHOS && !SI_TVOS && !SI_ANDROID) #define SANITIZER_INTERCEPT_QSORT_R (SI_LINUX && !SI_ANDROID) #define SANITIZER_INTERCEPT_SIGALTSTACK SI_POSIX +#define SANITIZER_INTERCEPT_UNAME (SI_POSIX && !SI_FREEBSD) +#define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H diff --git a/compiler-rt/test/sanitizer_common/TestCases/Posix/uname.c b/compiler-rt/test/sanitizer_common/TestCases/Posix/uname.c new file mode 100644 index 000000000000..0bf7e0fd98e3 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Posix/uname.c @@ -0,0 +1,13 @@ +// RUN: %clang %s -o %t && %run %t + +#include +#include +#include + +int main() { + struct utsname buf; + int err = uname(&buf); + assert(err == 0); + printf("%s %s %s %s %s\n", buf.sysname, buf.nodename, buf.release, + buf.version, buf.machine); +} From 67d67ebe8f2535c5de75c62820f7713f87d07307 Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Fri, 20 Mar 2020 14:59:54 -0700 Subject: [PATCH 37/59] Internal expressions shouldn't increment the result variable numbering. There an option: EvaluateExpressionOptions::SetResultIsInternal to indicate whether the result number should be returned to the pool or not. It got broken when the PersistentExpressionState was refactored. This fixes the issue and provides a test of the behavior. Differential Revision: https://reviews.llvm.org/D76532 --- .../lldb/Expression/ExpressionVariable.h | 10 ++-- lldb/include/lldb/Target/Target.h | 5 -- lldb/source/Core/ValueObject.cpp | 4 +- lldb/source/Expression/ExpressionVariable.cpp | 10 ---- lldb/source/Expression/Materializer.cpp | 8 ++-- .../Clang/ClangPersistentVariables.cpp | 11 +++++ .../Clang/ClangPersistentVariables.h | 10 ++-- .../Clang/ClangUserExpression.cpp | 4 +- lldb/source/Target/ABI.cpp | 4 +- .../expression/result_numbering/Makefile | 4 ++ .../result_numbering/TestResultNumbering.py | 48 +++++++++++++++++++ .../expression/result_numbering/main.c | 18 +++++++ 12 files changed, 99 insertions(+), 37 deletions(-) create mode 100644 lldb/test/API/commands/expression/result_numbering/Makefile create mode 100644 lldb/test/API/commands/expression/result_numbering/TestResultNumbering.py create mode 100644 lldb/test/API/commands/expression/result_numbering/main.c diff --git a/lldb/include/lldb/Expression/ExpressionVariable.h b/lldb/include/lldb/Expression/ExpressionVariable.h index c523176e003f..60062d212bad 100644 --- a/lldb/include/lldb/Expression/ExpressionVariable.h +++ b/lldb/include/lldb/Expression/ExpressionVariable.h @@ -221,11 +221,7 @@ class PersistentExpressionState : public ExpressionVariableList { uint32_t addr_byte_size) = 0; /// Return a new persistent variable name with the specified prefix. - ConstString GetNextPersistentVariableName(Target &target, - llvm::StringRef prefix); - - virtual llvm::StringRef - GetPersistentVariablePrefix(bool is_error = false) const = 0; + virtual ConstString GetNextPersistentVariableName(bool is_error = false) = 0; virtual void RemovePersistentVariable(lldb::ExpressionVariableSP variable) = 0; @@ -237,6 +233,10 @@ class PersistentExpressionState : public ExpressionVariableList { void RegisterExecutionUnit(lldb::IRExecutionUnitSP &execution_unit_sp); +protected: + virtual llvm::StringRef + GetPersistentVariablePrefix(bool is_error = false) const = 0; + private: LLVMCastKind m_kind; diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 77cda4998192..cc74fe0f3d74 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -1100,11 +1100,6 @@ class Target : public std::enable_shared_from_this, lldb::ExpressionVariableSP GetPersistentVariable(ConstString name); - /// Return the next available number for numbered persistent variables. - unsigned GetNextPersistentVariableIndex() { - return m_next_persistent_variable_index++; - } - lldb::addr_t GetPersistentSymbol(ConstString name); /// This method will return the address of the starting function for diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index e1d0ca941108..4c9c44ea15f4 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -3270,9 +3270,7 @@ ValueObjectSP ValueObject::Persist() { if (!persistent_state) return nullptr; - auto prefix = persistent_state->GetPersistentVariablePrefix(); - ConstString name = - persistent_state->GetNextPersistentVariableName(*target_sp, prefix); + ConstString name = persistent_state->GetNextPersistentVariableName(); ValueObjectSP const_result_sp = ValueObjectConstResult::Create(target_sp.get(), GetValue(), name); diff --git a/lldb/source/Expression/ExpressionVariable.cpp b/lldb/source/Expression/ExpressionVariable.cpp index 7c27c0f249ec..d95f0745cf4b 100644 --- a/lldb/source/Expression/ExpressionVariable.cpp +++ b/lldb/source/Expression/ExpressionVariable.cpp @@ -76,13 +76,3 @@ void PersistentExpressionState::RegisterExecutionUnit( } } } - -ConstString PersistentExpressionState::GetNextPersistentVariableName( - Target &target, llvm::StringRef Prefix) { - llvm::SmallString<64> name; - { - llvm::raw_svector_ostream os(name); - os << Prefix << target.GetNextPersistentVariableIndex(); - } - return ConstString(name); -} diff --git a/lldb/source/Expression/Materializer.cpp b/lldb/source/Expression/Materializer.cpp index 33c061effca4..8e96891257e4 100644 --- a/lldb/source/Expression/Materializer.cpp +++ b/lldb/source/Expression/Materializer.cpp @@ -881,11 +881,9 @@ class EntityResultVariable : public Materializer::Entity { return; } - ConstString name = - m_delegate - ? m_delegate->GetName() - : persistent_state->GetNextPersistentVariableName( - *target_sp, persistent_state->GetPersistentVariablePrefix()); + ConstString name = m_delegate + ? m_delegate->GetName() + : persistent_state->GetNextPersistentVariableName(); lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable( exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize()); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp index 3cbedf80755a..42afac9edb0d 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp @@ -108,3 +108,14 @@ ClangPersistentVariables::GetClangASTImporter() { } return m_ast_importer_sp; } + +ConstString +ClangPersistentVariables::GetNextPersistentVariableName(bool is_error) { + llvm::SmallString<64> name; + { + llvm::raw_svector_ostream os(name); + os << GetPersistentVariablePrefix(is_error) + << m_next_persistent_variable_id++; + } + return ConstString(name); +} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h index 12268b6549aa..f6298911dd6c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h @@ -51,9 +51,7 @@ class ClangPersistentVariables : public PersistentExpressionState { void RemovePersistentVariable(lldb::ExpressionVariableSP variable) override; - llvm::StringRef GetPersistentVariablePrefix(bool is_error) const override { - return "$"; - } + virtual ConstString GetNextPersistentVariableName(bool is_error = false); /// Returns the next file name that should be used for user expressions. std::string GetNextExprFileName() { @@ -80,6 +78,12 @@ class ClangPersistentVariables : public PersistentExpressionState { return m_hand_loaded_clang_modules; } +protected: + llvm::StringRef + GetPersistentVariablePrefix(bool is_error = false) const override { + return "$"; + } + private: /// The counter used by GetNextExprFileName. uint32_t m_next_user_file_id = 0; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp index 6d781934c174..b246fc374d1c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -924,9 +924,7 @@ void ClangUserExpression::ClangUserExpressionHelper::CommitPersistentDecls() { } ConstString ClangUserExpression::ResultDelegate::GetName() { - auto prefix = m_persistent_state->GetPersistentVariablePrefix(); - return m_persistent_state->GetNextPersistentVariableName(*m_target_sp, - prefix); + return m_persistent_state->GetNextPersistentVariableName(false); } void ClangUserExpression::ResultDelegate::DidDematerialize( diff --git a/lldb/source/Target/ABI.cpp b/lldb/source/Target/ABI.cpp index cb7eca280a39..4320eb93adfc 100644 --- a/lldb/source/Target/ABI.cpp +++ b/lldb/source/Target/ABI.cpp @@ -97,10 +97,8 @@ ValueObjectSP ABI::GetReturnValueObject(Thread &thread, CompilerType &ast_type, if (!persistent_expression_state) return {}; - auto prefix = persistent_expression_state->GetPersistentVariablePrefix(); ConstString persistent_variable_name = - persistent_expression_state->GetNextPersistentVariableName(target, - prefix); + persistent_expression_state->GetNextPersistentVariableName(); lldb::ValueObjectSP const_valobj_sp; diff --git a/lldb/test/API/commands/expression/result_numbering/Makefile b/lldb/test/API/commands/expression/result_numbering/Makefile new file mode 100644 index 000000000000..695335e068c0 --- /dev/null +++ b/lldb/test/API/commands/expression/result_numbering/Makefile @@ -0,0 +1,4 @@ +C_SOURCES := main.c +CFLAGS_EXTRAS := -std=c99 + +include Makefile.rules diff --git a/lldb/test/API/commands/expression/result_numbering/TestResultNumbering.py b/lldb/test/API/commands/expression/result_numbering/TestResultNumbering.py new file mode 100644 index 000000000000..cd6b9c43775c --- /dev/null +++ b/lldb/test/API/commands/expression/result_numbering/TestResultNumbering.py @@ -0,0 +1,48 @@ +""" +Make sure running internal expressions doesn't +influence the result variable numbering. +""" + + + +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.lldbtest import * + + +class TestExpressionResultNumbering(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + NO_DEBUG_INFO_TESTCASE = True + + def test_sample_rename_this(self): + self.build() + self.main_source_file = lldb.SBFileSpec("main.c") + self.do_numbering_test() + + def do_numbering_test(self): + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, + "Set a breakpoint here", self.main_source_file) + + bkpt = target.BreakpointCreateBySourceRegex("Add conditions to this breakpoint", + self.main_source_file) + self.assertEqual(bkpt.GetNumLocations(), 1, "Set the breakpoint") + + bkpt.SetCondition("call_me(value) < 6") + + # Get the number of the last expression: + result = thread.frames[0].EvaluateExpression("call_me(200)") + self.assertTrue(result.GetError().Success(), "Our expression succeeded") + name = result.GetName() + ordinal = int(name[1:]) + + process.Continue() + + # The condition evaluation had to run a 4 expressions, but we haven't + # run any user expressions. + result = thread.frames[0].EvaluateExpression("call_me(200)") + self.assertTrue(result.GetError().Success(), "Our expression succeeded the second time") + after_name = result.GetName() + after_ordinal = int(after_name[1:]) + self.assertEqual(ordinal + 1, after_ordinal) diff --git a/lldb/test/API/commands/expression/result_numbering/main.c b/lldb/test/API/commands/expression/result_numbering/main.c new file mode 100644 index 000000000000..0f5853c99fb1 --- /dev/null +++ b/lldb/test/API/commands/expression/result_numbering/main.c @@ -0,0 +1,18 @@ +#include + +int +call_me(int input) +{ + return input; +} + +int +main() +{ + int value = call_me(0); // Set a breakpoint here + while (value < 10) + { + printf("Add conditions to this breakpoint: %d.\n", value++); + } + return 0; +} From a650d555fc218891d55bfcf79ce8832c404d4dc3 Mon Sep 17 00:00:00 2001 From: Stefanos Baziotis Date: Mon, 23 Mar 2020 22:44:10 +0200 Subject: [PATCH 38/59] [Attributor][NFC] Refactorings and typos in doc Reviewed By: sstefan1, uenoku Differential Revision: https://reviews.llvm.org/D76175 --- llvm/include/llvm/Transforms/IPO/Attributor.h | 27 ++++++------- llvm/lib/Transforms/IPO/Attributor.cpp | 39 ++++++++++--------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h index 1df8ce9f17ff..a229f55e1a84 100644 --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -29,7 +29,7 @@ // automatically capture a potential dependence from Q to P. This dependence // will cause P to be reevaluated whenever Q changes in the future. // -// The Attributor will only reevaluated abstract attributes that might have +// The Attributor will only reevaluate abstract attributes that might have // changed since the last iteration. That means that the Attribute will not // revisit all instructions/blocks/functions in the module but only query // an update from a subset of the abstract attributes. @@ -152,8 +152,8 @@ struct IRPosition { /// The positions we distinguish in the IR. /// - /// The values are chosen such that the KindOrArgNo member has a value >= 1 - /// if it is an argument or call site argument while a value < 1 indicates the + /// The values are chosen such that the KindOrArgNo member has a value >= 0 + /// if it is an argument or call site argument while a value < 0 indicates the /// respective kind of that value. enum Kind : int { IRP_INVALID = -6, ///< An invalid position. @@ -273,18 +273,11 @@ struct IRPosition { /// Return the associated function, if any. Function *getAssociatedFunction() const { - if (auto *CB = dyn_cast(AnchorVal)) - return CB->getCalledFunction(); assert(KindOrArgNo != IRP_INVALID && "Invalid position does not have an anchor scope!"); - Value &V = getAnchorValue(); - if (isa(V)) - return &cast(V); - if (isa(V)) - return cast(V).getParent(); - if (isa(V)) - return cast(V).getFunction(); - return nullptr; + if (auto *CB = dyn_cast(AnchorVal)) + return CB->getCalledFunction(); + return getAnchorScope(); } /// Return the associated argument, if any. @@ -474,7 +467,10 @@ struct IRPosition { /// The value this position is anchored at. Value *AnchorVal; - /// The argument number, if non-negative, or the position "kind". + /// If AnchorVal is Argument or CallBase then this number should be + /// non-negative and it denotes the argument or call site argument index + /// respectively. Otherwise, it denotes the kind of this IRPosition according + /// to Kind above. int KindOrArgNo; }; @@ -2288,7 +2284,8 @@ struct DerefState : AbstractState { /// Add accessed bytes to the map. void addAccessedBytes(int64_t Offset, uint64_t Size) { - AccessedBytesMap[Offset] = std::max(AccessedBytesMap[Offset], Size); + uint64_t &AccessedBytes = AccessedBytesMap[Offset]; + AccessedBytes = std::max(AccessedBytes, Size); // Known bytes might increase. computeKnownDerefBytesFromAccessedMap(); diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp index 445ef3a5f4ce..dff83243e11c 100644 --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -558,7 +558,7 @@ ChangeStatus AbstractAttribute::update(Attributor &A) { ChangeStatus IRAttributeManifest::manifestAttrs(Attributor &A, const IRPosition &IRP, const ArrayRef &DeducedAttrs) { - Function *ScopeFn = IRP.getAssociatedFunction(); + Function *ScopeFn = IRP.getAnchorScope(); IRPosition::Kind PK = IRP.getPositionKind(); // In the following some generic code that will manifest attributes in @@ -627,8 +627,7 @@ SubsumingPositionIterator::SubsumingPositionIterator(const IRPosition &IRP) { return; case IRPosition::IRP_ARGUMENT: case IRPosition::IRP_RETURNED: - IRPositions.emplace_back( - IRPosition::function(*IRP.getAssociatedFunction())); + IRPositions.emplace_back(IRPosition::function(*IRP.getAnchorScope())); return; case IRPosition::IRP_CALL_SITE: assert(ICS && "Expected call site!"); @@ -2528,7 +2527,7 @@ struct AAWillReturnImpl : public AAWillReturn { void initialize(Attributor &A) override { AAWillReturn::initialize(A); - Function *F = getAssociatedFunction(); + Function *F = getAnchorScope(); if (!F || !A.isFunctionIPOAmendable(*F) || mayContainUnboundedCycle(*F, A)) indicatePessimisticFixpoint(); } @@ -3113,7 +3112,7 @@ struct AAIsDeadArgument : public AAIsDeadFloating { /// See AbstractAttribute::initialize(...). void initialize(Attributor &A) override { - if (!A.isFunctionIPOAmendable(*getAssociatedFunction())) + if (!A.isFunctionIPOAmendable(*getAnchorScope())) indicatePessimisticFixpoint(); } @@ -3273,7 +3272,7 @@ struct AAIsDeadFunction : public AAIsDead { /// See AbstractAttribute::initialize(...). void initialize(Attributor &A) override { - const Function *F = getAssociatedFunction(); + const Function *F = getAnchorScope(); if (F && !F->isDeclaration()) { ToBeExploredFrom.insert(&F->getEntryBlock().front()); assumeLive(A, F->getEntryBlock()); @@ -3283,7 +3282,7 @@ struct AAIsDeadFunction : public AAIsDead { /// See AbstractAttribute::getAsStr(). const std::string getAsStr() const override { return "Live[#BB " + std::to_string(AssumedLiveBlocks.size()) + "/" + - std::to_string(getAssociatedFunction()->size()) + "][#TBEP " + + std::to_string(getAnchorScope()->size()) + "][#TBEP " + std::to_string(ToBeExploredFrom.size()) + "][#KDE " + std::to_string(KnownDeadEnds.size()) + "]"; } @@ -3294,7 +3293,7 @@ struct AAIsDeadFunction : public AAIsDead { "Attempted to manifest an invalid state!"); ChangeStatus HasChanged = ChangeStatus::UNCHANGED; - Function &F = *getAssociatedFunction(); + Function &F = *getAnchorScope(); if (AssumedLiveBlocks.empty()) { A.deleteAfterManifest(F); @@ -3346,7 +3345,7 @@ struct AAIsDeadFunction : public AAIsDead { /// See AAIsDead::isAssumedDead(BasicBlock *). bool isAssumedDead(const BasicBlock *BB) const override { - assert(BB->getParent() == getAssociatedFunction() && + assert(BB->getParent() == getAnchorScope() && "BB must be in the same anchor scope function."); if (!getAssumed()) @@ -3361,7 +3360,7 @@ struct AAIsDeadFunction : public AAIsDead { /// See AAIsDead::isAssumed(Instruction *I). bool isAssumedDead(const Instruction *I) const override { - assert(I->getParent()->getParent() == getAssociatedFunction() && + assert(I->getParent()->getParent() == getAnchorScope() && "Instruction must be in the same anchor scope function."); if (!getAssumed()) @@ -3515,7 +3514,7 @@ ChangeStatus AAIsDeadFunction::updateImpl(Attributor &A) { ChangeStatus Change = ChangeStatus::UNCHANGED; LLVM_DEBUG(dbgs() << "[AAIsDead] Live [" << AssumedLiveBlocks.size() << "/" - << getAssociatedFunction()->size() << "] BBs and " + << getAnchorScope()->size() << "] BBs and " << ToBeExploredFrom.size() << " exploration points and " << KnownDeadEnds.size() << " known dead ends\n"); @@ -3595,7 +3594,7 @@ ChangeStatus AAIsDeadFunction::updateImpl(Attributor &A) { // discovered any non-trivial dead end and (2) not ruled unreachable code // dead. if (ToBeExploredFrom.empty() && - getAssociatedFunction()->size() == AssumedLiveBlocks.size() && + getAnchorScope()->size() == AssumedLiveBlocks.size() && llvm::all_of(KnownDeadEnds, [](const Instruction *DeadEndI) { return DeadEndI->isTerminator() && DeadEndI->getNumSuccessors() == 0; })) @@ -3935,7 +3934,7 @@ struct AAAlignImpl : AAAlign { takeKnownMaximum(Attr.getValueAsInt()); if (getIRPosition().isFnInterfaceKind() && - (!getAssociatedFunction() || + (!getAnchorScope() || !A.isFunctionIPOAmendable(*getAssociatedFunction()))) indicatePessimisticFixpoint(); } @@ -4736,7 +4735,7 @@ struct AAValueSimplifyArgument final : AAValueSimplifyImpl { void initialize(Attributor &A) override { AAValueSimplifyImpl::initialize(A); - if (!getAssociatedFunction() || getAssociatedFunction()->isDeclaration()) + if (!getAnchorScope() || getAnchorScope()->isDeclaration()) indicatePessimisticFixpoint(); if (hasAttr({Attribute::InAlloca, Attribute::StructRet, Attribute::Nest}, /* IgnoreSubsumingPositions */ true)) @@ -4980,7 +4979,7 @@ struct AAHeapToStackImpl : public AAHeapToStack { "Attempted to manifest an invalid state!"); ChangeStatus HasChanged = ChangeStatus::UNCHANGED; - Function *F = getAssociatedFunction(); + Function *F = getAnchorScope(); const auto *TLI = A.getInfoCache().getTargetLibraryInfoForFunction(*F); for (Instruction *MallocCall : MallocCalls) { @@ -5057,7 +5056,7 @@ struct AAHeapToStackImpl : public AAHeapToStack { }; ChangeStatus AAHeapToStackImpl::updateImpl(Attributor &A) { - const Function *F = getAssociatedFunction(); + const Function *F = getAnchorScope(); const auto *TLI = A.getInfoCache().getTargetLibraryInfoForFunction(*F); MustBeExecutedContextExplorer &Explorer = @@ -7655,7 +7654,7 @@ ChangeStatus Attributor::run() { unsigned IterationCounter = 1; - SmallVector ChangedAAs; + SmallVector ChangedAAs; SetVector Worklist, InvalidAAs; Worklist.insert(AllAbstractAttributes.begin(), AllAbstractAttributes.end()); @@ -8306,7 +8305,7 @@ void Attributor::initializeInformationCache(Function &F) { switch (I.getOpcode()) { default: assert((!ImmutableCallSite(&I)) && (!isa(&I)) && - "New call site/base instruction type needs to be known int the " + "New call site/base instruction type needs to be known in the " "Attributor."); break; case Instruction::Load: @@ -8635,6 +8634,10 @@ static bool runAttributorOnFunctions(InformationCache &InfoCache, // while we identify default attribute opportunities. Attributor A(Functions, InfoCache, CGUpdater, DepRecInterval); + // Note: _Don't_ combine/fuse this loop with the one below because + // when A.identifyDefaultAbstractAttributes() is called for one + // function, it assumes that the information cach has been + // initialized for _all_ functions. for (Function *F : Functions) A.initializeInformationCache(*F); From f2f96eb605bc770e4da400dbcc7a6d2526ec1fd4 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sat, 21 Mar 2020 23:39:01 -0700 Subject: [PATCH 39/59] [llvm-objcopy] Improve tool selection logic to recognize llvm-strip-$major as strip Debian and some other distributions install llvm-strip as llvm-strip-$major (e.g. `/usr/bin/llvm-strip-9`) D54193 made it work with llvm-strip-$major but did not add a test. The behavior was regressed by D69146. Fixes https://github.com/ClangBuiltLinux/linux/issues/940 Reviewed By: alexshap Differential Revision: https://reviews.llvm.org/D76562 --- llvm/test/tools/llvm-objcopy/tool-name.test | 33 +++++++++++++++++++++ llvm/tools/llvm-objcopy/llvm-objcopy.cpp | 24 +++++++++++---- 2 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 llvm/test/tools/llvm-objcopy/tool-name.test diff --git a/llvm/test/tools/llvm-objcopy/tool-name.test b/llvm/test/tools/llvm-objcopy/tool-name.test new file mode 100644 index 000000000000..a273375f109e --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/tool-name.test @@ -0,0 +1,33 @@ +## Don't make symlinks on Windows. +# UNSUPPORTED: system-windows + +# RUN: rm -rf %t +# RUN: mkdir %t + +# RUN: ln -s llvm-objcopy %t/llvm-objcopy-11.exe +# RUN: ln -s llvm-objcopy %t/powerpc64-unknown-freebsd13-objcopy + +# RUN: llvm-objcopy --help | FileCheck --check-prefix=OBJCOPY %s +# RUN: %t/llvm-objcopy-11.exe --help | FileCheck --check-prefix=OBJCOPY %s +# RUN: %t/powerpc64-unknown-freebsd13-objcopy --help | FileCheck --check-prefix=OBJCOPY %s + +# OBJCOPY: OVERVIEW: llvm-objcopy tool + +# RUN: ln -s llvm-strip %t/strip.exe +# RUN: ln -s llvm-strip %t/gnu-llvm-strip-10 + +# RUN: llvm-strip --help | FileCheck --check-prefix=STRIP %s +# RUN: %t/strip.exe --help | FileCheck --check-prefix=STRIP %s +# RUN: %t/gnu-llvm-strip-10 --help | FileCheck --check-prefix=STRIP %s + +# STRIP: OVERVIEW: llvm-strip tool + +## This driver emulates install_name_tool on macOS. +# RUN: ln -s llvm-install-name-tool %t/llvm-install-name-tool-10 +# RUN: ln -s llvm-install-name-tool %t/install_name_tool.exe + +# RUN: llvm-install-name-tool --help | FileCheck --check-prefix=INSTALL %s +# RUN: %t/llvm-install-name-tool-10 --help | FileCheck --check-prefix=INSTALL %s +# RUN: %t/install_name_tool.exe --help | FileCheck --check-prefix=INSTALL %s + +# INSTALL: OVERVIEW: llvm-install-name-tool tool diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp index 8e95ebb73331..69b23b6cf975 100644 --- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -327,11 +327,25 @@ enum class ToolType { Objcopy, Strip, InstallNameTool }; int main(int argc, char **argv) { InitLLVM X(argc, argv); ToolName = argv[0]; - ToolType Tool = StringSwitch(sys::path::stem(ToolName)) - .EndsWith("strip", ToolType::Strip) - .EndsWith("install-name-tool", ToolType::InstallNameTool) - .EndsWith("install_name_tool", ToolType::InstallNameTool) - .Default(ToolType::Objcopy); + + StringRef Stem = sys::path::stem(ToolName); + auto Is = [=](StringRef Tool) { + // We need to recognize the following filenames: + // + // llvm-objcopy -> objcopy + // strip-10.exe -> strip + // powerpc64-unknown-freebsd13-objcopy -> objcopy + // llvm-install-name-tool -> install-name-tool + auto I = Stem.rfind_lower(Tool); + return I != StringRef::npos && + (I + Tool.size() == Stem.size() || !isAlnum(Stem[I + Tool.size()])); + }; + ToolType Tool = ToolType::Objcopy; + if (Is("strip")) + Tool = ToolType::Strip; + else if (Is("install-name-tool") || Is("install_name_tool")) + Tool = ToolType::InstallNameTool; + // Expand response files. // TODO: Move these lines, which are copied from lib/Support/CommandLine.cpp, // into a separate function in the CommandLine library and call that function From 7bf871c39f739a7382ba89c97f50fd047f36f894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirst=C3=B3f=20Umann?= Date: Thu, 19 Mar 2020 14:53:09 +0100 Subject: [PATCH 40/59] [analyzer][NFC] Move the text output type to its own file, move code to PathDiagnosticConsumer creator functions TableGen and .def files (which are meant to be used with the preprocessor) come with obvious downsides. One of those issues is that generated switch-case branches have to be identical. This pushes corner cases either to an outer code block, or into the generated code. Inspect the removed code in AnalysisConsumer::DigestAnalyzerOptions. You can see how corner cases like a not existing output file, the analysis output type being set to PD_NONE, or whether to complement the output with additional diagnostics on stderr lay around the preprocessor generated code. This is a bit problematic, as to how to deal with such errors is not in the hands of the users of this interface (those implementing output types, like PlistDiagnostics etc). This patch changes this by moving these corner cases into the generated code, more specifically, into the called functions. In addition, I introduced a new output type for convenience purposes, PD_TEXT_MINIMAL, which always existed conceptually, but never in the actual Analyses.def file. This refactoring allowed me to move TextDiagnostics (renamed from ClangDiagPathDiagConsumer) to its own file, which it really deserved. Also, those that had the misfortune to gaze upon Analyses.def will probably enjoy the sight that a clang-format did on it. Differential Revision: https://reviews.llvm.org/D76509 --- .../clang/StaticAnalyzer/Core/Analyses.def | 70 ++++++-- clang/lib/StaticAnalyzer/Core/CMakeLists.txt | 2 + .../StaticAnalyzer/Core/HTMLDiagnostics.cpp | 47 +++-- .../StaticAnalyzer/Core/PlistDiagnostics.cpp | 25 ++- .../StaticAnalyzer/Core/SarifDiagnostics.cpp | 8 +- .../StaticAnalyzer/Core/TextDiagnostics.cpp | 148 ++++++++++++++++ .../Frontend/AnalysisConsumer.cpp | 166 ++---------------- .../StaticAnalyzer/Frontend/CMakeLists.txt | 2 - 8 files changed, 282 insertions(+), 186 deletions(-) create mode 100644 clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp diff --git a/clang/include/clang/StaticAnalyzer/Core/Analyses.def b/clang/include/clang/StaticAnalyzer/Core/Analyses.def index 377451576148..c4e5f5be6fd7 100644 --- a/clang/include/clang/StaticAnalyzer/Core/Analyses.def +++ b/clang/include/clang/StaticAnalyzer/Core/Analyses.def @@ -14,41 +14,80 @@ #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) #endif -ANALYSIS_STORE(RegionStore, "region", "Use region-based analyzer store", CreateRegionStoreManager) +ANALYSIS_STORE(RegionStore, "region", "Use region-based analyzer store", + CreateRegionStoreManager) #ifndef ANALYSIS_CONSTRAINTS #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) #endif -ANALYSIS_CONSTRAINTS(RangeConstraints, "range", "Use constraint tracking of concrete value ranges", CreateRangeConstraintManager) -ANALYSIS_CONSTRAINTS(Z3Constraints, "z3", "Use Z3 contraint solver", CreateZ3ConstraintManager) +ANALYSIS_CONSTRAINTS(RangeConstraints, "range", + "Use constraint tracking of concrete value ranges", + CreateRangeConstraintManager) + +ANALYSIS_CONSTRAINTS(Z3Constraints, "z3", "Use Z3 contraint solver", + CreateZ3ConstraintManager) #ifndef ANALYSIS_DIAGNOSTICS #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) #endif -ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticConsumer) -ANALYSIS_DIAGNOSTICS(HTML_SINGLE_FILE, "html-single-file", "Output analysis results using HTML (not allowing for multi-file bugs)", createHTMLSingleFileDiagnosticConsumer) -ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", createPlistDiagnosticConsumer) -ANALYSIS_DIAGNOSTICS(PLIST_MULTI_FILE, "plist-multi-file", "Output analysis results using Plists (allowing for multi-file bugs)", createPlistMultiFileDiagnosticConsumer) -ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticConsumer) -ANALYSIS_DIAGNOSTICS(SARIF, "sarif", "Output analysis results in a SARIF file", createSarifDiagnosticConsumer) -ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", + createHTMLDiagnosticConsumer) + +ANALYSIS_DIAGNOSTICS( + HTML_SINGLE_FILE, "html-single-file", + "Output analysis results using HTML (not allowing for multi-file bugs)", + createHTMLSingleFileDiagnosticConsumer) + +ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", + createPlistDiagnosticConsumer) + +ANALYSIS_DIAGNOSTICS( + PLIST_MULTI_FILE, "plist-multi-file", + "Output analysis results using Plists (allowing for multi-file bugs)", + createPlistMultiFileDiagnosticConsumer) + +ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", + "Output analysis results using HTML wrapped with Plists", + createPlistHTMLDiagnosticConsumer) + +ANALYSIS_DIAGNOSTICS(SARIF, "sarif", "Output analysis results in a SARIF file", + createSarifDiagnosticConsumer) + +ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results to stderr", + createTextPathDiagnosticConsumer) + +ANALYSIS_DIAGNOSTICS(TEXT_MINIMAL, "text-minimal", + "Emits minimal diagnostics to stderr, stating only the " + "warning message and the associated notes. Usually " + "used in addition to other analysis types", + createTextMinimalPathDiagnosticConsumer) #ifndef ANALYSIS_PURGE #define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) #endif -ANALYSIS_PURGE(PurgeStmt, "statement", "Purge symbols, bindings, and constraints before every statement") -ANALYSIS_PURGE(PurgeBlock, "block", "Purge symbols, bindings, and constraints before every basic block") -ANALYSIS_PURGE(PurgeNone, "none", "Do not purge symbols, bindings, or constraints") +ANALYSIS_PURGE( + PurgeStmt, "statement", + "Purge symbols, bindings, and constraints before every statement") + +ANALYSIS_PURGE( + PurgeBlock, "block", + "Purge symbols, bindings, and constraints before every basic block") + +ANALYSIS_PURGE(PurgeNone, "none", + "Do not purge symbols, bindings, or constraints") #ifndef ANALYSIS_INLINING_MODE #define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) #endif -ANALYSIS_INLINING_MODE(All, "all", "Analyze all functions as top level") -ANALYSIS_INLINING_MODE(NoRedundancy, "noredundancy", "Do not analyze a function which has been previously inlined") +ANALYSIS_INLINING_MODE(All, "all", "Analyze all functions as top level") + +ANALYSIS_INLINING_MODE( + NoRedundancy, "noredundancy", + "Do not analyze a function which has been previously inlined") #undef ANALYSIS_STORE #undef ANALYSIS_CONSTRAINTS @@ -56,4 +95,3 @@ ANALYSIS_INLINING_MODE(NoRedundancy, "noredundancy", "Do not analyze a function #undef ANALYSIS_PURGE #undef ANALYSIS_INLINING_MODE #undef ANALYSIS_IPA - diff --git a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt index 081d922ede80..dc2a6279b737 100644 --- a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt @@ -45,6 +45,7 @@ add_clang_library(clangStaticAnalyzerCore SValBuilder.cpp SVals.cpp SymbolManager.cpp + TextDiagnostics.cpp WorkList.cpp LINK_LIBS @@ -56,5 +57,6 @@ add_clang_library(clangStaticAnalyzerCore clangFrontend clangLex clangRewrite + clangToolingCore ) diff --git a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp index 002b6070ddcd..184fdcfb3d4b 100644 --- a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -66,11 +66,9 @@ class HTMLDiagnostics : public PathDiagnosticConsumer { const bool SupportsCrossFileDiagnostics; public: - HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, - const std::string& prefix, - const Preprocessor &pp, - bool supportsMultipleFiles) - : Directory(prefix), PP(pp), AnalyzerOpts(AnalyzerOpts), + HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, const std::string &OutputDir, + const Preprocessor &pp, bool supportsMultipleFiles) + : Directory(OutputDir), PP(pp), AnalyzerOpts(AnalyzerOpts), SupportsCrossFileDiagnostics(supportsMultipleFiles) {} ~HTMLDiagnostics() override { FlushDiagnostics(nullptr); } @@ -136,16 +134,45 @@ class HTMLDiagnostics : public PathDiagnosticConsumer { void ento::createHTMLDiagnosticConsumer( AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, - const std::string &prefix, const Preprocessor &PP, - const cross_tu::CrossTranslationUnitContext &) { - C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP, true)); + const std::string &OutputDir, const Preprocessor &PP, + const cross_tu::CrossTranslationUnitContext &CTU) { + + // FIXME: HTML is currently our default output type, but if the output + // directory isn't specified, it acts like if it was in the minimal text + // output mode. This doesn't make much sense, we should have the minimal text + // as our default. In the case of backward compatibility concerns, this could + // be preserved with -analyzer-config-compatibility-mode=true. + createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, OutputDir, PP, CTU); + + // TODO: Emit an error here. + if (OutputDir.empty()) + return; + + C.push_back(new HTMLDiagnostics(AnalyzerOpts, OutputDir, PP, true)); } void ento::createHTMLSingleFileDiagnosticConsumer( + AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, + const std::string &OutputDir, const Preprocessor &PP, + const cross_tu::CrossTranslationUnitContext &CTU) { + + // TODO: Emit an error here. + if (OutputDir.empty()) + return; + + C.push_back(new HTMLDiagnostics(AnalyzerOpts, OutputDir, PP, false)); + createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, OutputDir, PP, CTU); +} + +void ento::createPlistHTMLDiagnosticConsumer( AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, const std::string &prefix, const Preprocessor &PP, - const cross_tu::CrossTranslationUnitContext &) { - C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP, false)); + const cross_tu::CrossTranslationUnitContext &CTU) { + createHTMLDiagnosticConsumer( + AnalyzerOpts, C, std::string(llvm::sys::path::parent_path(prefix)), PP, + CTU); + createPlistMultiFileDiagnosticConsumer(AnalyzerOpts, C, prefix, PP, CTU); + createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, prefix, PP, CTU); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp index babd1401a5a7..9b6369aee7a8 100644 --- a/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -45,8 +45,8 @@ namespace { AnalyzerOptions &AnOpts; const bool SupportsCrossFileDiagnostics; public: - PlistDiagnostics(AnalyzerOptions &AnalyzerOpts, const std::string &prefix, - const Preprocessor &PP, + PlistDiagnostics(AnalyzerOptions &AnalyzerOpts, + const std::string &OutputFile, const Preprocessor &PP, const cross_tu::CrossTranslationUnitContext &CTU, bool supportsMultipleFiles); @@ -582,19 +582,32 @@ PlistDiagnostics::PlistDiagnostics( void ento::createPlistDiagnosticConsumer( AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, - const std::string &s, const Preprocessor &PP, + const std::string &OutputFile, const Preprocessor &PP, const cross_tu::CrossTranslationUnitContext &CTU) { - C.push_back(new PlistDiagnostics(AnalyzerOpts, s, PP, CTU, + + // TODO: Emit an error here. + if (OutputFile.empty()) + return; + + C.push_back(new PlistDiagnostics(AnalyzerOpts, OutputFile, PP, CTU, /*supportsMultipleFiles*/ false)); + createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, OutputFile, PP, CTU); } void ento::createPlistMultiFileDiagnosticConsumer( AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, - const std::string &s, const Preprocessor &PP, + const std::string &OutputFile, const Preprocessor &PP, const cross_tu::CrossTranslationUnitContext &CTU) { - C.push_back(new PlistDiagnostics(AnalyzerOpts, s, PP, CTU, + + // TODO: Emit an error here. + if (OutputFile.empty()) + return; + + C.push_back(new PlistDiagnostics(AnalyzerOpts, OutputFile, PP, CTU, /*supportsMultipleFiles*/ true)); + createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, OutputFile, PP, CTU); } + void PlistDiagnostics::FlushDiagnosticsImpl( std::vector &Diags, FilesMade *filesMade) { diff --git a/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp index eed45aed620f..8c2e85601576 100644 --- a/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp @@ -50,8 +50,14 @@ class SarifDiagnostics : public PathDiagnosticConsumer { void ento::createSarifDiagnosticConsumer( AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, const std::string &Output, const Preprocessor &PP, - const cross_tu::CrossTranslationUnitContext &) { + const cross_tu::CrossTranslationUnitContext &CTU) { + + // TODO: Emit an error here. + if (Output.empty()) + return; + C.push_back(new SarifDiagnostics(AnalyzerOpts, Output, PP.getLangOpts())); + createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, Output, PP, CTU); } static StringRef getFileName(const FileEntry &FE) { diff --git a/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp new file mode 100644 index 000000000000..07e5685e604c --- /dev/null +++ b/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp @@ -0,0 +1,148 @@ +//===--- TextDiagnostics.cpp - Text Diagnostics for Paths -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the TextDiagnostics object. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathDiagnostic.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Version.h" +#include "clang/CrossTU/CrossTranslationUnit.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Rewrite/Core/Rewriter.h" +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" +#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" +#include "clang/Tooling/Core/Replacement.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Casting.h" + +using namespace clang; +using namespace ento; +using namespace tooling; + +namespace { +/// Emitsd minimal diagnostics (report message + notes) for the 'none' output +/// type to the standard error, or to to compliment many others. Emits detailed +/// diagnostics in textual format for the 'text' output type. +class TextDiagnostics : public PathDiagnosticConsumer { + DiagnosticsEngine &DiagEng; + LangOptions LO; + const bool IncludePath = false; + const bool ShouldEmitAsError = false; + const bool ApplyFixIts = false; + +public: + TextDiagnostics(DiagnosticsEngine &DiagEng, LangOptions LO, + bool ShouldIncludePath, const AnalyzerOptions &AnOpts) + : DiagEng(DiagEng), LO(LO), IncludePath(ShouldIncludePath), + ShouldEmitAsError(AnOpts.AnalyzerWerror), + ApplyFixIts(AnOpts.ShouldApplyFixIts) {} + ~TextDiagnostics() override {} + + StringRef getName() const override { return "TextDiagnostics"; } + + bool supportsLogicalOpControlFlow() const override { return true; } + bool supportsCrossFileDiagnostics() const override { return true; } + + PathGenerationScheme getGenerationScheme() const override { + return IncludePath ? Minimal : None; + } + + void FlushDiagnosticsImpl(std::vector &Diags, + FilesMade *filesMade) override { + unsigned WarnID = + ShouldEmitAsError + ? DiagEng.getCustomDiagID(DiagnosticsEngine::Error, "%0") + : DiagEng.getCustomDiagID(DiagnosticsEngine::Warning, "%0"); + unsigned NoteID = DiagEng.getCustomDiagID(DiagnosticsEngine::Note, "%0"); + SourceManager &SM = DiagEng.getSourceManager(); + + Replacements Repls; + auto reportPiece = [&](unsigned ID, FullSourceLoc Loc, StringRef String, + ArrayRef Ranges, + ArrayRef Fixits) { + if (!ApplyFixIts) { + DiagEng.Report(Loc, ID) << String << Ranges << Fixits; + return; + } + + DiagEng.Report(Loc, ID) << String << Ranges; + for (const FixItHint &Hint : Fixits) { + Replacement Repl(SM, Hint.RemoveRange, Hint.CodeToInsert); + + if (llvm::Error Err = Repls.add(Repl)) { + llvm::errs() << "Error applying replacement " << Repl.toString() + << ": " << Err << "\n"; + } + } + }; + + for (std::vector::iterator I = Diags.begin(), + E = Diags.end(); + I != E; ++I) { + const PathDiagnostic *PD = *I; + reportPiece(WarnID, PD->getLocation().asLocation(), + PD->getShortDescription(), PD->path.back()->getRanges(), + PD->path.back()->getFixits()); + + // First, add extra notes, even if paths should not be included. + for (const auto &Piece : PD->path) { + if (!isa(Piece.get())) + continue; + + reportPiece(NoteID, Piece->getLocation().asLocation(), + Piece->getString(), Piece->getRanges(), Piece->getFixits()); + } + + if (!IncludePath) + continue; + + // Then, add the path notes if necessary. + PathPieces FlatPath = PD->path.flatten(/*ShouldFlattenMacros=*/true); + for (const auto &Piece : FlatPath) { + if (isa(Piece.get())) + continue; + + reportPiece(NoteID, Piece->getLocation().asLocation(), + Piece->getString(), Piece->getRanges(), Piece->getFixits()); + } + } + + if (!ApplyFixIts || Repls.empty()) + return; + + Rewriter Rewrite(SM, LO); + if (!applyAllReplacements(Repls, Rewrite)) { + llvm::errs() << "An error occured during applying fix-it.\n"; + } + + Rewrite.overwriteChangedFiles(); + } +}; +} // end anonymous namespace + +void ento::createTextPathDiagnosticConsumer( + AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, + const std::string &Prefix, const clang::Preprocessor &PP, + const cross_tu::CrossTranslationUnitContext &CTU) { + C.emplace_back(new TextDiagnostics(PP.getDiagnostics(), PP.getLangOpts(), + /*ShouldIncludePath*/ true, AnalyzerOpts)); +} + +void ento::createTextMinimalPathDiagnosticConsumer( + AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, + const std::string &Prefix, const clang::Preprocessor &PP, + const cross_tu::CrossTranslationUnitContext &CTU) { + C.emplace_back(new TextDiagnostics(PP.getDiagnostics(), PP.getLangOpts(), + /*ShouldIncludePath*/ false, + AnalyzerOpts)); +} diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index a908aede68bb..7e1e090afa60 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -64,126 +64,6 @@ STATISTIC(NumVisitedBlocksInAnalyzedFunctions, STATISTIC(PercentReachableBlocks, "The % of reachable basic blocks."); STATISTIC(MaxCFGSize, "The maximum number of basic blocks in a function."); -//===----------------------------------------------------------------------===// -// Special PathDiagnosticConsumers. -//===----------------------------------------------------------------------===// - -void ento::createPlistHTMLDiagnosticConsumer( - AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, - const std::string &prefix, const Preprocessor &PP, - const cross_tu::CrossTranslationUnitContext &CTU) { - createHTMLDiagnosticConsumer( - AnalyzerOpts, C, std::string(llvm::sys::path::parent_path(prefix)), PP, - CTU); - createPlistMultiFileDiagnosticConsumer(AnalyzerOpts, C, prefix, PP, CTU); -} - -void ento::createTextPathDiagnosticConsumer( - AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, - const std::string &Prefix, const clang::Preprocessor &PP, - const cross_tu::CrossTranslationUnitContext &CTU) { - llvm_unreachable("'text' consumer should be enabled on ClangDiags"); -} - -namespace { -class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer { - DiagnosticsEngine &Diag; - LangOptions LO; - - bool IncludePath = false; - bool ShouldEmitAsError = false; - bool ApplyFixIts = false; - -public: - ClangDiagPathDiagConsumer(DiagnosticsEngine &Diag, LangOptions LO) - : Diag(Diag), LO(LO) {} - ~ClangDiagPathDiagConsumer() override {} - StringRef getName() const override { return "ClangDiags"; } - - bool supportsLogicalOpControlFlow() const override { return true; } - bool supportsCrossFileDiagnostics() const override { return true; } - - PathGenerationScheme getGenerationScheme() const override { - return IncludePath ? Minimal : None; - } - - void enablePaths() { IncludePath = true; } - void enableWerror() { ShouldEmitAsError = true; } - void enableApplyFixIts() { ApplyFixIts = true; } - - void FlushDiagnosticsImpl(std::vector &Diags, - FilesMade *filesMade) override { - unsigned WarnID = - ShouldEmitAsError - ? Diag.getCustomDiagID(DiagnosticsEngine::Error, "%0") - : Diag.getCustomDiagID(DiagnosticsEngine::Warning, "%0"); - unsigned NoteID = Diag.getCustomDiagID(DiagnosticsEngine::Note, "%0"); - SourceManager &SM = Diag.getSourceManager(); - - Replacements Repls; - auto reportPiece = [&](unsigned ID, FullSourceLoc Loc, StringRef String, - ArrayRef Ranges, - ArrayRef Fixits) { - if (!ApplyFixIts) { - Diag.Report(Loc, ID) << String << Ranges << Fixits; - return; - } - - Diag.Report(Loc, ID) << String << Ranges; - for (const FixItHint &Hint : Fixits) { - Replacement Repl(SM, Hint.RemoveRange, Hint.CodeToInsert); - - if (llvm::Error Err = Repls.add(Repl)) { - llvm::errs() << "Error applying replacement " << Repl.toString() - << ": " << Err << "\n"; - } - } - }; - - for (std::vector::iterator I = Diags.begin(), - E = Diags.end(); - I != E; ++I) { - const PathDiagnostic *PD = *I; - reportPiece(WarnID, PD->getLocation().asLocation(), - PD->getShortDescription(), PD->path.back()->getRanges(), - PD->path.back()->getFixits()); - - // First, add extra notes, even if paths should not be included. - for (const auto &Piece : PD->path) { - if (!isa(Piece.get())) - continue; - - reportPiece(NoteID, Piece->getLocation().asLocation(), - Piece->getString(), Piece->getRanges(), Piece->getFixits()); - } - - if (!IncludePath) - continue; - - // Then, add the path notes if necessary. - PathPieces FlatPath = PD->path.flatten(/*ShouldFlattenMacros=*/true); - for (const auto &Piece : FlatPath) { - if (isa(Piece.get())) - continue; - - reportPiece(NoteID, Piece->getLocation().asLocation(), - Piece->getString(), Piece->getRanges(), Piece->getFixits()); - } - } - - if (!ApplyFixIts || Repls.empty()) - return; - - Rewriter Rewrite(SM, LO); - if (!applyAllReplacements(Repls, Rewrite)) { - llvm::errs() << "An error occured during applying fix-it.\n"; - } - - Rewrite.overwriteChangedFiles(); - } -}; -} // end anonymous namespace - //===----------------------------------------------------------------------===// // AnalysisConsumer declaration. //===----------------------------------------------------------------------===// @@ -269,31 +149,16 @@ class AnalysisConsumer : public AnalysisASTConsumer, } void DigestAnalyzerOptions() { - if (Opts->AnalysisDiagOpt != PD_NONE) { - // Create the PathDiagnosticConsumer. - ClangDiagPathDiagConsumer *clangDiags = - new ClangDiagPathDiagConsumer(PP.getDiagnostics(), PP.getLangOpts()); - PathConsumers.push_back(clangDiags); - - if (Opts->AnalyzerWerror) - clangDiags->enableWerror(); - - if (Opts->ShouldApplyFixIts) - clangDiags->enableApplyFixIts(); - - if (Opts->AnalysisDiagOpt == PD_TEXT) { - clangDiags->enablePaths(); - - } else if (!OutDir.empty()) { - switch (Opts->AnalysisDiagOpt) { - default: + switch (Opts->AnalysisDiagOpt) { + case PD_NONE: + break; #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \ case PD_##NAME: \ CREATEFN(*Opts.get(), PathConsumers, OutDir, PP, CTU); \ break; #include "clang/StaticAnalyzer/Core/Analyses.def" - } - } + default: + llvm_unreachable("Unkown analyzer output type!"); } // Create the analyzer component creators. @@ -329,20 +194,19 @@ class AnalysisConsumer : public AnalysisASTConsumer, else if (Mode == AM_Path) { llvm::errs() << " (Path, "; switch (IMode) { - case ExprEngine::Inline_Minimal: - llvm::errs() << " Inline_Minimal"; - break; - case ExprEngine::Inline_Regular: - llvm::errs() << " Inline_Regular"; - break; + case ExprEngine::Inline_Minimal: + llvm::errs() << " Inline_Minimal"; + break; + case ExprEngine::Inline_Regular: + llvm::errs() << " Inline_Regular"; + break; } llvm::errs() << ")"; - } - else + } else assert(Mode == (AM_Syntax | AM_Path) && "Unexpected mode!"); - llvm::errs() << ": " << Loc.getFilename() << ' ' - << getFunctionName(D) << '\n'; + llvm::errs() << ": " << Loc.getFilename() << ' ' << getFunctionName(D) + << '\n'; } } @@ -485,7 +349,7 @@ class AnalysisConsumer : public AnalysisASTConsumer, /// Print \p S to stderr if \c Opts->AnalyzerDisplayProgress is set. void reportAnalyzerProgress(StringRef S); -}; +}; // namespace } // end anonymous namespace diff --git a/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt b/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt index 6f1151ab0c11..5e7dd8f18cd7 100644 --- a/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt @@ -21,6 +21,4 @@ add_clang_library(clangStaticAnalyzerFrontend clangLex clangStaticAnalyzerCheckers clangStaticAnalyzerCore - clangRewrite - clangToolingCore ) From b20a1d840f0c074514a71c80bbb41702a0b86d64 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Mon, 23 Mar 2020 16:26:02 -0400 Subject: [PATCH 41/59] GVNSink: Allow handling addrspacecast --- llvm/lib/Transforms/Scalar/GVNSink.cpp | 1 + .../Transforms/GVNSink/sink-common-code.ll | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/llvm/lib/Transforms/Scalar/GVNSink.cpp b/llvm/lib/Transforms/Scalar/GVNSink.cpp index 6d0a4975e266..6b9a88d04eda 100644 --- a/llvm/lib/Transforms/Scalar/GVNSink.cpp +++ b/llvm/lib/Transforms/Scalar/GVNSink.cpp @@ -475,6 +475,7 @@ class ValueTable { case Instruction::PtrToInt: case Instruction::IntToPtr: case Instruction::BitCast: + case Instruction::AddrSpaceCast: case Instruction::Select: case Instruction::ExtractElement: case Instruction::InsertElement: diff --git a/llvm/test/Transforms/GVNSink/sink-common-code.ll b/llvm/test/Transforms/GVNSink/sink-common-code.ll index 02b1eb7fe259..160bbd370ff5 100644 --- a/llvm/test/Transforms/GVNSink/sink-common-code.ll +++ b/llvm/test/Transforms/GVNSink/sink-common-code.ll @@ -692,6 +692,73 @@ if.end: ; CHECK-NOT: exact ; CHECK: } + +; CHECK-LABEL: @common_bitcast( +; CHECK: %. = select i1 %flag, float 2.000000e+00, float 1.000000e+00 +; CHECK: %a = bitcast i32* %x to float* +; CHECK: store float %., float* %a +define i32 @common_bitcast(i1 zeroext %flag, i32* %x) { +entry: + br i1 %flag, label %if.then, label %if.else + +if.then: + %a = bitcast i32* %x to float* + store float 2.0, float* %a + br label %if.end + +if.else: + %b = bitcast i32* %x to float* + store float 1.0, float* %b + br label %if.end + +if.end: + ret i32 1 +} + +; CHECK-LABEL: @common_addrspacecast( +; CHECK: %. = select i1 %flag, i32 9, i32 10 +; CHECK: %a = addrspacecast i32* %x to i32 addrspace(1)* +; CHECK: store i32 %., i32 addrspace(1)* %a +define i32 @common_addrspacecast(i1 zeroext %flag, i32* %x) { +entry: + br i1 %flag, label %if.then, label %if.else + +if.then: + %a = addrspacecast i32* %x to i32 addrspace(1)* + store i32 9, i32 addrspace(1)* %a + br label %if.end + +if.else: + %b = addrspacecast i32* %x to i32 addrspace(1)* + store i32 10, i32 addrspace(1)* %b + br label %if.end + +if.end: + ret i32 1 +} + +; Don't merge different address spaces +; CHECK-LABEL: @no_common_addrspacecast( +; CHECK: addrspacecast i32* %x to i32 addrspace(1)* +; CHECK: addrspacecast i32* %x to i32 addrspace(3)* +define i32 @no_common_addrspacecast(i1 zeroext %flag, i32* %x) { +entry: + br i1 %flag, label %if.then, label %if.else + +if.then: + %a = addrspacecast i32* %x to i32 addrspace(1)* + store i32 9, i32 addrspace(1)* %a + br label %if.end + +if.else: + %b = addrspacecast i32* %x to i32 addrspace(3)* + store i32 10, i32 addrspace(3)* %b + br label %if.end + +if.end: + ret i32 1 +} + ; CHECK: !0 = !{!1, !1, i64 0} ; CHECK: !1 = !{!"float", !2} ; CHECK: !2 = !{!"an example type tree"} From 3f533006ba8c8ae6f3596f49f480aa794ed4e347 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Thu, 19 Mar 2020 21:40:58 -0400 Subject: [PATCH 42/59] AMDGPU: Emit llvm.fshr for __builtin_amdgcn_alignbit These are equivalent. The generic rotate builtins do not directly map to the fshr intrinsic. --- clang/lib/CodeGen/CGBuiltin.cpp | 7 +++++++ clang/test/CodeGenOpenCL/builtins-amdgcn.cl | 2 +- llvm/include/llvm/IR/IntrinsicsAMDGPU.td | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 8d86424c60a9..754d95d1ab81 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -13609,6 +13609,13 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, return emitRangedBuiltin(*this, Intrinsic::r600_read_tidig_y, 0, 1024); case AMDGPU::BI__builtin_r600_read_tidig_z: return emitRangedBuiltin(*this, Intrinsic::r600_read_tidig_z, 0, 1024); + case AMDGPU::BI__builtin_amdgcn_alignbit: { + llvm::Value *Src0 = EmitScalarExpr(E->getArg(0)); + llvm::Value *Src1 = EmitScalarExpr(E->getArg(1)); + llvm::Value *Src2 = EmitScalarExpr(E->getArg(2)); + Function *F = CGM.getIntrinsic(Intrinsic::fshr, Src0->getType()); + return Builder.CreateCall(F, { Src0, Src1, Src2 }); + } default: return nullptr; } diff --git a/clang/test/CodeGenOpenCL/builtins-amdgcn.cl b/clang/test/CodeGenOpenCL/builtins-amdgcn.cl index 85e921cbe12a..0aa3e4144c52 100644 --- a/clang/test/CodeGenOpenCL/builtins-amdgcn.cl +++ b/clang/test/CodeGenOpenCL/builtins-amdgcn.cl @@ -596,7 +596,7 @@ kernel void test_mbcnt_hi(global uint* out, uint src0, uint src1) { } // CHECK-LABEL: @test_alignbit( -// CHECK: tail call i32 @llvm.amdgcn.alignbit(i32 %src0, i32 %src1, i32 %src2) +// CHECK: tail call i32 @llvm.fshr.i32(i32 %src0, i32 %src1, i32 %src2) kernel void test_alignbit(global uint* out, uint src0, uint src1, uint src2) { *out = __builtin_amdgcn_alignbit(src0, src1, src2); } diff --git a/llvm/include/llvm/IR/IntrinsicsAMDGPU.td b/llvm/include/llvm/IR/IntrinsicsAMDGPU.td index 3f962cc667c5..c01db52b1622 100644 --- a/llvm/include/llvm/IR/IntrinsicsAMDGPU.td +++ b/llvm/include/llvm/IR/IntrinsicsAMDGPU.td @@ -1371,8 +1371,8 @@ def int_amdgcn_writelane : [IntrNoMem, IntrConvergent] >; -def int_amdgcn_alignbit : - GCCBuiltin<"__builtin_amdgcn_alignbit">, Intrinsic<[llvm_i32_ty], +// FIXME: Deprecated. This is equivalent to llvm.fshr +def int_amdgcn_alignbit : Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem, IntrSpeculatable] >; From 5896e2df45dab7680be321ee63903431a673817b Mon Sep 17 00:00:00 2001 From: Alexandre Ganea Date: Mon, 23 Mar 2020 16:54:24 -0400 Subject: [PATCH 43/59] [Clang] Fix HIP tests when running on Windows with the LLVM toolchain is in the path On Windows, when the LLVM toolchain is in the current path (%PATH%), fusing the linker yields c:\{path}\lld.exe whereas the hip tests did not expect the .exe part. This only happens if LLD is not present in the build folder, which consequently makes the code in Driver::GetProgramPath() to fall back to %PATH% and platform-specific search, which includes the .exe part (see https://github.com/llvm/llvm-project/blob/master/clang/lib/Driver/Driver.cpp#L4733). Differential Revision: https://reviews.llvm.org/D76631 --- clang/test/Driver/hip-device-compile.hip | 4 ++-- clang/test/Driver/hip-toolchain-no-rdc.hip | 8 ++++---- clang/test/Driver/hip-toolchain-rdc.hip | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/clang/test/Driver/hip-device-compile.hip b/clang/test/Driver/hip-device-compile.hip index b6f1f1cf218e..c442d23581ce 100644 --- a/clang/test/Driver/hip-device-compile.hip +++ b/clang/test/Driver/hip-device-compile.hip @@ -42,7 +42,7 @@ // CHECK-NOT: {{"*.llvm-link"}} // CHECK-NOT: {{".*opt"}} // CHECK-NOT: {{".*llc"}} -// CHECK-NOT: {{".*lld"}} +// CHECK-NOT: {{".*lld.*"}} // CHECK-NOT: {{".*clang-offload-bundler"}} // CHECK-NOT: {{".*ld.*"}} @@ -67,6 +67,6 @@ // BUNDLE: {{"*.llvm-link"}} // BUNDLE: {{".*opt"}} // BUNDLE: {{".*llc"}} -// BUNDLE: {{".*lld"}} +// BUNDLE: {{".*lld.*"}} // BUNDLE: {{".*clang-offload-bundler"}} diff --git a/clang/test/Driver/hip-toolchain-no-rdc.hip b/clang/test/Driver/hip-toolchain-no-rdc.hip index cda852e2d8c7..4371334577f7 100644 --- a/clang/test/Driver/hip-toolchain-no-rdc.hip +++ b/clang/test/Driver/hip-toolchain-no-rdc.hip @@ -38,7 +38,7 @@ // CHECK-SAME: "-filetype=obj" // CHECK-SAME: "-o" [[OBJ_DEV_A_803:".*-gfx803-.*o"]] -// CHECK: [[LLD: ".*lld"]] "-flavor" "gnu" "-shared" +// CHECK: [[LLD: ".*lld.*"]] "-flavor" "gnu" "-shared" // CHECK-SAME: "-o" "[[IMG_DEV_A_803:.*out]]" [[OBJ_DEV_A_803]] // @@ -67,7 +67,7 @@ // CHECK-SAME: "-filetype=obj" // CHECK-SAME: "-o" [[OBJ_DEV_A_900:".*-gfx900-.*o"]] -// CHECK: [[LLD: ".*lld"]] "-flavor" "gnu" "-shared" +// CHECK: [[LLD]] "-flavor" "gnu" "-shared" // CHECK-SAME: "-o" "[[IMG_DEV_A_900:.*out]]" [[OBJ_DEV_A_900]] // @@ -112,7 +112,7 @@ // CHECK-SAME: "-filetype=obj" // CHECK-SAME: "-o" [[OBJ_DEV_B_803:".*-gfx803-.*o"]] -// CHECK: [[LLD: ".*lld"]] "-flavor" "gnu" "-shared" +// CHECK: [[LLD]] "-flavor" "gnu" "-shared" // CHECK-SAME: "-o" "[[IMG_DEV_B_803:.*out]]" [[OBJ_DEV_B_803]] // @@ -141,7 +141,7 @@ // CHECK-SAME: "-filetype=obj" // CHECK-SAME: "-o" [[OBJ_DEV_B_900:".*-gfx900-.*o"]] -// CHECK: [[LLD: ".*lld"]] "-flavor" "gnu" "-shared" +// CHECK: [[LLD]] "-flavor" "gnu" "-shared" // CHECK-SAME: "-o" "[[IMG_DEV_B_900:.*out]]" [[OBJ_DEV_B_900]] // diff --git a/clang/test/Driver/hip-toolchain-rdc.hip b/clang/test/Driver/hip-toolchain-rdc.hip index 18fd1d7b09a0..203784f2ab43 100644 --- a/clang/test/Driver/hip-toolchain-rdc.hip +++ b/clang/test/Driver/hip-toolchain-rdc.hip @@ -44,7 +44,7 @@ // CHECK-SAME: "-filetype=obj" // CHECK-SAME: "-o" [[OBJ_DEV1:".*-gfx803-.*o"]] -// CHECK: [[LLD: ".*lld"]] "-flavor" "gnu" "-shared" +// CHECK: [[LLD: ".*lld.*"]] "-flavor" "gnu" "-shared" // CHECK-SAME: "-o" "[[IMG_DEV1:.*out]]" [[OBJ_DEV1]] // CHECK: [[CLANG]] "-cc1" "-triple" "amdgcn-amd-amdhsa" From 66073953a5cb7ecac32bcb897033fdc337c56b5e Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Fri, 20 Mar 2020 17:16:46 -0400 Subject: [PATCH 44/59] AMDGPU: Allow vectorization of round intrinsic There seems to be a small benefit to the legalized sequence for v2f16 round with packed instructions, so allow vectorizing it by reducing the cost. An unintended side effect is vectorization of f32 round also happens. The current FMA logic seems off to me, and isn't checking for packed instructions. --- .../AMDGPU/AMDGPUTargetTransformInfo.cpp | 25 ++++++++++-- .../Transforms/SLPVectorizer/AMDGPU/round.ll | 38 +++++++++++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 llvm/test/Transforms/SLPVectorizer/AMDGPU/round.ll diff --git a/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp b/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp index caa3a4aa31f4..318e536da6aa 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp @@ -476,11 +476,24 @@ int GCNTTIImpl::getArithmeticInstrCost(unsigned Opcode, Type *Ty, Opd1PropInfo, Opd2PropInfo); } +// Return true if there's a potential benefit from using v2f16 instructions for +// an intrinsic, even if it requires nontrivial legalization. +static bool intrinsicHasPackedVectorBenefit(Intrinsic::ID ID) { + switch (ID) { + case Intrinsic::fma: // TODO: fmuladd + // There's a small benefit to using vector ops in the legalized code. + case Intrinsic::round: + return true; + default: + return false; + } +} + template int GCNTTIImpl::getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, ArrayRef Args, FastMathFlags FMF, unsigned VF, const Instruction *I) { - if (ID != Intrinsic::fma) + if (!intrinsicHasPackedVectorBenefit(ID)) return BaseT::getIntrinsicInstrCost(ID, RetTy, Args, FMF, VF, I); EVT OrigTy = TLI->getValueType(DL, RetTy); @@ -502,8 +515,14 @@ int GCNTTIImpl::getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, if (ST->has16BitInsts() && SLT == MVT::f16) NElts = (NElts + 1) / 2; - return LT.first * NElts * (ST->hasFastFMAF32() ? getHalfRateInstrCost() - : getQuarterRateInstrCost()); + // TODO: Get more refined intrinsic costs? + unsigned InstRate = getQuarterRateInstrCost(); + if (ID == Intrinsic::fma) { + InstRate = ST->hasFastFMAF32() ? getHalfRateInstrCost() + : getQuarterRateInstrCost(); + } + + return LT.first * NElts * InstRate; } int GCNTTIImpl::getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, diff --git a/llvm/test/Transforms/SLPVectorizer/AMDGPU/round.ll b/llvm/test/Transforms/SLPVectorizer/AMDGPU/round.ll new file mode 100644 index 000000000000..84d25fe79a27 --- /dev/null +++ b/llvm/test/Transforms/SLPVectorizer/AMDGPU/round.ll @@ -0,0 +1,38 @@ +; RUN: opt -S -mtriple=amdgcn-amd-amdhsa -mcpu=hawaii -slp-vectorizer %s | FileCheck -check-prefixes=GCN,GFX7 %s +; RUN: opt -S -mtriple=amdgcn-amd-amdhsa -mcpu=fiji -slp-vectorizer %s | FileCheck -check-prefixes=GCN,GFX8 %s +; RUN: opt -S -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -slp-vectorizer %s | FileCheck -check-prefixes=GCN,GFX8 %s + +; GCN-LABEL: @round_v2f16( +; GFX7: call half @llvm.round.f16( +; GFX7: call half @llvm.round.f16( + +; GFX8: call <2 x half> @llvm.round.v2f16( +define <2 x half> @round_v2f16(<2 x half> %arg) { +bb: + %tmp = extractelement <2 x half> %arg, i64 0 + %tmp1 = tail call half @llvm.round.half(half %tmp) + %tmp2 = insertelement <2 x half> undef, half %tmp1, i64 0 + %tmp3 = extractelement <2 x half> %arg, i64 1 + %tmp4 = tail call half @llvm.round.half(half %tmp3) + %tmp5 = insertelement <2 x half> %tmp2, half %tmp4, i64 1 + ret <2 x half> %tmp5 +} + +; TODO: Should probably not really be vectorizing this +; GCN-LABEL: @round_v2f32( +; GCN: call <2 x float> @llvm.round.v2f32 +define <2 x float> @round_v2f32(<2 x float> %arg) { +bb: + %tmp = extractelement <2 x float> %arg, i64 0 + %tmp1 = tail call float @llvm.round.f32(float %tmp) + %tmp2 = insertelement <2 x float> undef, float %tmp1, i64 0 + %tmp3 = extractelement <2 x float> %arg, i64 1 + %tmp4 = tail call float @llvm.round.f32(float %tmp3) + %tmp5 = insertelement <2 x float> %tmp2, float %tmp4, i64 1 + ret <2 x float> %tmp5 +} + +declare half @llvm.round.half(half) #0 +declare float @llvm.round.f32(float) #0 + +attributes #0 = { nounwind readnone speculatable willreturn } From 1a4421a5e860ffc63c77594c9fb40787f84241aa Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Mon, 23 Mar 2020 21:02:54 +0000 Subject: [PATCH 45/59] [analyzer] ConstraintManager - use EXPENSIVE_CHECKS instead of (gcc specific) __OPTIMIZE__ guard This was noticed on D71817, which removed another use of __OPTIMIZE__ Differential Revision: https://reviews.llvm.org/D76622 --- .../StaticAnalyzer/Core/PathSensitive/ConstraintManager.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h index f85c37379158..935b2bb7b937 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h @@ -96,11 +96,7 @@ class ConstraintManager { // If StTrue is infeasible, asserting the falseness of Cond is unnecessary // because the existing constraints already establish this. if (!StTrue) { -#ifndef __OPTIMIZE__ - // This check is expensive and should be disabled even in Release+Asserts - // builds. - // FIXME: __OPTIMIZE__ is a GNU extension that Clang implements but MSVC - // does not. Is there a good equivalent there? +#ifdef EXPENSIVE_CHECKS assert(assume(State, Cond, false) && "System is over constrained."); #endif return ProgramStatePair((ProgramStateRef)nullptr, State); From defd96f1e36df9e3bbb7be7b55a14b843c3090c6 Mon Sep 17 00:00:00 2001 From: LLVM GN Syncbot Date: Mon, 23 Mar 2020 21:05:55 +0000 Subject: [PATCH 46/59] [gn build] Port 7bf871c39f7 --- llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Core/BUILD.gn | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Core/BUILD.gn b/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Core/BUILD.gn index 228d13446cab..f37cc42c481e 100644 --- a/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Core/BUILD.gn +++ b/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Core/BUILD.gn @@ -57,6 +57,7 @@ static_library("Core") { "Store.cpp", "SubEngine.cpp", "SymbolManager.cpp", + "TextDiagnostics.cpp", "WorkList.cpp", ] } From f3018068517e350f509b40f50207db25f80ff6fc Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Mon, 23 Mar 2020 12:20:05 -0700 Subject: [PATCH 47/59] [lld] Enabling loading LLVM pass plugins Add the relevant magic bits to allow "-mllvm=-load=plugin.so" etc. This is now using export_executable_symbols_for_plugins, so symbols are only exported if plugins are enabled. Differential Revision: https://reviews.llvm.org/D75879 --- lld/tools/lld/CMakeLists.txt | 4 ++++ lld/tools/lld/lld.cpp | 1 + 2 files changed, 5 insertions(+) diff --git a/lld/tools/lld/CMakeLists.txt b/lld/tools/lld/CMakeLists.txt index a15e296e31df..a37c2c702bd5 100644 --- a/lld/tools/lld/CMakeLists.txt +++ b/lld/tools/lld/CMakeLists.txt @@ -4,7 +4,11 @@ set(LLVM_LINK_COMPONENTS add_lld_tool(lld lld.cpp + + ENABLE_PLUGINS + SUPPORT_PLUGINS ) +export_executable_symbols_for_plugins(lld) target_link_libraries(lld PRIVATE diff --git a/lld/tools/lld/lld.cpp b/lld/tools/lld/lld.cpp index 72ff758164d8..646fc3d6468e 100644 --- a/lld/tools/lld/lld.cpp +++ b/lld/tools/lld/lld.cpp @@ -36,6 +36,7 @@ #include "llvm/Support/Host.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/Path.h" +#include "llvm/Support/PluginLoader.h" #include using namespace lld; From b6ae8937e031cde2e70e6a83d46c21e940fdf4ac Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Thu, 19 Mar 2020 08:43:41 -0700 Subject: [PATCH 48/59] [lldb/PlatformDarwin] Always delete destination file first in PutFile Summary: The default behavior of Platform::PutFile is to open the file and truncate it if it already exists. This works fine and is a sensible default, but it interacts badly with code-signing on iOS, as doing so invalidates the signature of the file (even if the new content has a valid code signature). We have a couple tests which on purpose reload a different binary with the same name. Those tests are currently broken because of the above interaction. This patch simply makes the Darwin platform unconditionally delete the destination file before sending the new one to work around this issue. Reviewers: jasonmolenda Subscribers: lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D76450 --- .../source/Plugins/Platform/MacOSX/PlatformDarwin.cpp | 11 +++++++++++ lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index 46dd3774e5a9..350043f8d4e9 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -58,6 +58,17 @@ PlatformDarwin::PlatformDarwin(bool is_host) /// inherited from by the plug-in instance. PlatformDarwin::~PlatformDarwin() {} +lldb_private::Status +PlatformDarwin::PutFile(const lldb_private::FileSpec &source, + const lldb_private::FileSpec &destination, uint32_t uid, + uint32_t gid) { + // Unconditionally unlink the destination. If it is an executable, + // simply opening it and truncating its contents would invalidate + // its cached code signature. + Unlink(destination); + return PlatformPOSIX::PutFile(source, destination, uid, gid); +} + FileSpecList PlatformDarwin::LocateExecutableScriptingResources( Target *target, Module &module, Stream *feedback_stream) { FileSpecList file_list; diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h index 6d51edbc9294..f6729c508f00 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h @@ -25,6 +25,11 @@ class PlatformDarwin : public PlatformPOSIX { ~PlatformDarwin() override; + lldb_private::Status PutFile(const lldb_private::FileSpec &source, + const lldb_private::FileSpec &destination, + uint32_t uid = UINT32_MAX, + uint32_t gid = UINT32_MAX) override; + // lldb_private::Platform functions lldb_private::Status ResolveSymbolFile(lldb_private::Target &target, From a20862307fff9385bbf6562de3154d05138f8bec Mon Sep 17 00:00:00 2001 From: Ladd Van Tol Date: Mon, 23 Mar 2020 14:16:55 -0700 Subject: [PATCH 49/59] Improve module.pcm lock file performance on machines with high core counts Summary: When building a large Xcode project with multiple module dependencies, and mixed Objective-C & Swift, I observed a large number of clang processes stalling at zero CPU for 30+ seconds throughout the build. This was especially prevalent on my 18-core iMac Pro. After some sampling, the major cause appears to be the lock file implementation for precompiled modules in the module cache. When the lock is heavily contended by multiple clang processes, the exponential backoff runs in lockstep, with some of the processes sleeping for 30+ seconds in order to acquire the file lock. In the attached patch, I implemented a more aggressive polling mechanism that limits the sleep interval to a max of 500ms, and randomizes the wait time. I preserved a limited form of exponential backoff. I also updated the code to use cross-platform timing, thread sleep, and random number capabilities available in C++11. On iMac Pro (2.3 GHz Intel Xeon W, 18 core): Xcode 11.1 bundled clang: 502.2 seconds (average of 5 runs) Custom clang build with LockFileManager patch applied: 276.6 seconds (average of 5 runs) This is a 1.82x speedup for this use case. On MacBook Pro (4 core 3.1GHz Intel i7): Xcode 11.1 bundled clang: 539.4 seconds (average of 2 runs) Custom clang build with LockFileManager patch applied: 509.5 seconds (average of 2 runs) As expected, machines with fewer cores benefit less from this change. ``` Call graph: 2992 Thread_393602 DispatchQueue_1: com.apple.main-thread (serial) 2992 start (in libdyld.dylib) + 1 [0x7fff6a1683d5] 2992 main (in clang) + 297 [0x1097a1059] 2992 driver_main(int, char const**) (in clang) + 2803 [0x1097a5513] 2992 cc1_main(llvm::ArrayRef, char const*, void*) (in clang) + 1608 [0x1097a7cc8] 2992 clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (in clang) + 3299 [0x1097dace3] 2992 clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (in clang) + 509 [0x1097dcc1d] 2992 clang::FrontendAction::Execute() (in clang) + 42 [0x109818b3a] 2992 clang::ParseAST(clang::Sema&, bool, bool) (in clang) + 185 [0x10981b369] 2992 clang::Parser::ParseFirstTopLevelDecl(clang::OpaquePtr&) (in clang) + 37 [0x10983e9b5] 2992 clang::Parser::ParseTopLevelDecl(clang::OpaquePtr&) (in clang) + 141 [0x10983ecfd] 2992 clang::Parser::ParseExternalDeclaration(clang::Parser::ParsedAttributesWithRange&, clang::ParsingDeclSpec*) (in clang) + 695 [0x10983f3b7] 2992 clang::Parser::ParseObjCAtDirectives(clang::Parser::ParsedAttributesWithRange&) (in clang) + 637 [0x10a9be9bd] 2992 clang::Parser::ParseModuleImport(clang::SourceLocation) (in clang) + 170 [0x10c4841ba] 2992 clang::Parser::ParseModuleName(clang::SourceLocation, llvm::SmallVectorImpl >&, bool) (in clang) + 503 [0x10c485267] 2992 clang::Preprocessor::Lex(clang::Token&) (in clang) + 316 [0x1098285cc] 2992 clang::Preprocessor::LexAfterModuleImport(clang::Token&) (in clang) + 690 [0x10cc7af62] 2992 clang::CompilerInstance::loadModule(clang::SourceLocation, llvm::ArrayRef >, clang::Module::NameVisibilityKind, bool) (in clang) + 7989 [0x10bba6535] 2992 compileAndLoadModule(clang::CompilerInstance&, clang::SourceLocation, clang::SourceLocation, clang::Module*, llvm::StringRef) (in clang) + 296 [0x10bba8318] 2992 llvm::LockFileManager::waitForUnlock() (in clang) + 91 [0x10b6953ab] 2992 nanosleep (in libsystem_c.dylib) + 199 [0x7fff6a22c914] 2992 __semwait_signal (in libsystem_kernel.dylib) + 10 [0x7fff6a2a0f32] ``` Differential Revision: https://reviews.llvm.org/D69575 --- llvm/include/llvm/Support/LockFileManager.h | 4 +- llvm/lib/Support/LockFileManager.cpp | 64 +++++++++++---------- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/llvm/include/llvm/Support/LockFileManager.h b/llvm/include/llvm/Support/LockFileManager.h index 2efeca3b6200..ab66621e6756 100644 --- a/llvm/include/llvm/Support/LockFileManager.h +++ b/llvm/include/llvm/Support/LockFileManager.h @@ -78,8 +78,8 @@ class LockFileManager { /// For a shared lock, wait until the owner releases the lock. /// Total timeout for the file to appear is ~1.5 minutes. - /// \param MaxSeconds the maximum wait time per iteration in seconds. - WaitForUnlockResult waitForUnlock(const unsigned MaxSeconds = 40); + /// \param MaxSeconds the maximum total wait time in seconds. + WaitForUnlockResult waitForUnlock(const unsigned MaxSeconds = 90); /// Remove the lock file. This may delete a different lock file than /// the one previously read if there is a race. diff --git a/llvm/lib/Support/LockFileManager.cpp b/llvm/lib/Support/LockFileManager.cpp index a4793aa7c04f..88489a658953 100644 --- a/llvm/lib/Support/LockFileManager.cpp +++ b/llvm/lib/Support/LockFileManager.cpp @@ -17,12 +17,16 @@ #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" #include +#include #include #include +#include #include #include #include +#include #include + #ifdef _WIN32 #include #endif @@ -295,23 +299,29 @@ LockFileManager::waitForUnlock(const unsigned MaxSeconds) { if (getState() != LFS_Shared) return Res_Success; -#ifdef _WIN32 - unsigned long Interval = 1; -#else - struct timespec Interval; - Interval.tv_sec = 0; - Interval.tv_nsec = 1000000; -#endif + // Since we don't yet have an event-based method to wait for the lock file, + // implement randomized exponential backoff, similar to Ethernet collision + // algorithm. This improves performance on machines with high core counts + // when the file lock is heavily contended by multiple clang processes + const unsigned long MinWaitDurationMS = 10; + const unsigned long MaxWaitMultiplier = 50; // 500ms max wait + unsigned long WaitMultiplier = 1; + unsigned long ElapsedTimeSeconds = 0; + + std::random_device Device; + std::default_random_engine Engine(Device()); + + auto StartTime = std::chrono::steady_clock::now(); + do { + // FIXME: implement event-based waiting + // Sleep for the designated interval, to allow the owning process time to // finish up and remove the lock file. - // FIXME: Should we hook in to system APIs to get a notification when the - // lock file is deleted? -#ifdef _WIN32 - Sleep(Interval); -#else - nanosleep(&Interval, nullptr); -#endif + std::uniform_int_distribution Distribution(1, + WaitMultiplier); + unsigned long WaitDurationMS = MinWaitDurationMS * Distribution(Engine); + std::this_thread::sleep_for(std::chrono::milliseconds(WaitDurationMS)); if (sys::fs::access(LockFileName.c_str(), sys::fs::AccessMode::Exist) == errc::no_such_file_or_directory) { @@ -325,24 +335,16 @@ LockFileManager::waitForUnlock(const unsigned MaxSeconds) { if (!processStillExecuting((*Owner).first, (*Owner).second)) return Res_OwnerDied; - // Exponentially increase the time we wait for the lock to be removed. -#ifdef _WIN32 - Interval *= 2; -#else - Interval.tv_sec *= 2; - Interval.tv_nsec *= 2; - if (Interval.tv_nsec >= 1000000000) { - ++Interval.tv_sec; - Interval.tv_nsec -= 1000000000; + WaitMultiplier *= 2; + if (WaitMultiplier > MaxWaitMultiplier) { + WaitMultiplier = MaxWaitMultiplier; } -#endif - } while ( -#ifdef _WIN32 - Interval < MaxSeconds * 1000 -#else - Interval.tv_sec < (time_t)MaxSeconds -#endif - ); + + ElapsedTimeSeconds = std::chrono::duration_cast( + std::chrono::steady_clock::now() - StartTime) + .count(); + + } while (ElapsedTimeSeconds < MaxSeconds); // Give up. return Res_Timeout; From 502915c619a32972ddc525be585794371bfbd27b Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 23 Mar 2020 15:05:38 -0700 Subject: [PATCH 50/59] PR45142: 'template ~X' is ill-formed; reject it rather than crashing. --- .../clang/Basic/DiagnosticParseKinds.td | 2 ++ clang/lib/Parse/ParseExprCXX.cpp | 18 +++++++++++++++++- clang/test/CXX/drs/dr4xx.cpp | 8 +++----- clang/test/SemaCXX/pseudo-destructors.cpp | 5 ++++- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index acb229225ea1..dcbb0d3f8799 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -706,6 +706,8 @@ def err_id_after_template_in_nested_name_spec : Error< "expected template name after 'template' keyword in nested name specifier">; def err_unexpected_template_in_unqualified_id : Error< "'template' keyword not permitted here">; +def err_unexpected_template_in_destructor_name : Error< + "'template' keyword not permitted in destructor name">; def err_unexpected_template_after_using : Error< "'template' keyword not permitted after 'using' keyword">; def err_two_right_angle_brackets_need_space : Error< diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index b8d91c19228f..a0b97ea7514d 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -2884,6 +2884,22 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, // Parse the '~'. SourceLocation TildeLoc = ConsumeToken(); + if (TemplateSpecified) { + // C++ [temp.names]p3: + // A name prefixed by the keyword template shall be a template-id [...] + // + // A template-id cannot begin with a '~' token. This would never work + // anyway: x.~A() would specify that the destructor is a template, + // not that 'A' is a template. + // + // FIXME: Suggest replacing the attempted destructor name with a correct + // destructor name and recover. (This is not trivial if this would become + // a pseudo-destructor name). + Diag(*TemplateKWLoc, diag::err_unexpected_template_in_destructor_name) + << Tok.getLocation(); + return true; + } + if (SS.isEmpty() && Tok.is(tok::kw_decltype)) { DeclSpec DS(AttrFactory); SourceLocation EndLoc = ParseDecltypeSpecifier(DS); @@ -2903,7 +2919,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, // If the user wrote ~T::T, correct it to T::~T. DeclaratorScopeObj DeclScopeObj(*this, SS); - if (!TemplateSpecified && NextToken().is(tok::coloncolon)) { + if (NextToken().is(tok::coloncolon)) { // Don't let ParseOptionalCXXScopeSpecifier() "correct" // `int A; struct { ~A::A(); };` to `int A; struct { ~A:A(); };`, // it will confuse this recovery logic. diff --git a/clang/test/CXX/drs/dr4xx.cpp b/clang/test/CXX/drs/dr4xx.cpp index 35fd15f0cc64..2c762237037d 100644 --- a/clang/test/CXX/drs/dr4xx.cpp +++ b/clang/test/CXX/drs/dr4xx.cpp @@ -297,13 +297,11 @@ namespace dr420 { // dr420: yes void test2(T p) { p->template Y::~Y(); p->~Y(); - // FIXME: This is ill-formed, but this diagnostic is terrible. We should - // reject this in the parser. - p->template ~Y(); // expected-error 2{{no member named '~typename Y'}} + p->template ~Y(); // expected-error {{'template' keyword not permitted in destructor name}} } template struct Y {}; - template void test2(Y*); // expected-note {{instantiation}} - template void test2(ptr >); // expected-note {{instantiation}} + template void test2(Y*); + template void test2(ptr >); void test3(int *p, ptr q) { typedef int Int; diff --git a/clang/test/SemaCXX/pseudo-destructors.cpp b/clang/test/SemaCXX/pseudo-destructors.cpp index 0cd139047432..b71b523de683 100644 --- a/clang/test/SemaCXX/pseudo-destructors.cpp +++ b/clang/test/SemaCXX/pseudo-destructors.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -emit-llvm-only -verify -std=c++11 %s struct A {}; enum Foo { F }; @@ -92,6 +92,9 @@ namespace PR11339 { template using Id = T; void AliasTemplate(int *p) { p->~Id(); + p->template ~Id(); // expected-error {{'template' keyword not permitted in destructor name}} + (0).~Id(); + (0).template ~Id(); // expected-error {{'template' keyword not permitted in destructor name}} } namespace dotPointerAccess { From f0990e104b0858fbdc4c726cd8da1ff166fe2dca Mon Sep 17 00:00:00 2001 From: Justin Hibbits Date: Mon, 23 Mar 2020 09:44:39 -0500 Subject: [PATCH 51/59] [PowerPC]: e500 target can't use lwsync, use msync instead The e500 core has a silicon bug that triggers an illegal instruction program trap on any sync other than msync. Other cores will typically ignore illegal sync types, and the documentation even implies that the 'illegal' bits are ignored. Address this hardware deficiency by only using msync, like the PPC440. Differential Revision: https://reviews.llvm.org/D76614 --- llvm/lib/Target/PowerPC/PPC.td | 2 +- llvm/test/CodeGen/PowerPC/atomics-fences.ll | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/PowerPC/PPC.td b/llvm/lib/Target/PowerPC/PPC.td index fc817631e0ac..888b228450b6 100644 --- a/llvm/lib/Target/PowerPC/PPC.td +++ b/llvm/lib/Target/PowerPC/PPC.td @@ -463,7 +463,7 @@ def : ProcessorModel<"g5", G5Model, def : ProcessorModel<"e500", PPCE500Model, [DirectiveE500, FeatureICBT, FeatureBookE, - FeatureISEL, FeatureMFTB, FeatureSPE]>; + FeatureISEL, FeatureMFTB, FeatureMSYNC, FeatureSPE]>; def : ProcessorModel<"e500mc", PPCE500mcModel, [DirectiveE500mc, FeatureSTFIWX, FeatureICBT, FeatureBookE, diff --git a/llvm/test/CodeGen/PowerPC/atomics-fences.ll b/llvm/test/CodeGen/PowerPC/atomics-fences.ll index 3fea72150000..8fe366307fd1 100644 --- a/llvm/test/CodeGen/PowerPC/atomics-fences.ll +++ b/llvm/test/CodeGen/PowerPC/atomics-fences.ll @@ -1,6 +1,7 @@ ; RUN: llc < %s -mtriple=powerpc-unknown-linux-gnu -verify-machineinstrs | FileCheck %s ; RUN: llc < %s -mtriple=powerpc64-unknown-linux-gnu -verify-machineinstrs | FileCheck %s ; RUN: llc < %s -mtriple=powerpc-unknown-linux-gnu -mcpu=440 | FileCheck %s --check-prefix=PPC440 +; RUN: llc < %s -mtriple=powerpc-unknown-linux-gnu -mcpu=e500 | FileCheck %s --check-prefix=PPC440 ; Fences define void @fence_acquire() { From 1236eb6c31ff0c1c9b69c544d735a3de4e0fc687 Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Mon, 23 Mar 2020 17:30:38 -0400 Subject: [PATCH 52/59] [OPENMP50]Add 'default' modifier in reduction clauses. Added full support for 'default' modifier in the reduction clauses. --- clang/include/clang/AST/OpenMPClause.h | 34 +++++++++++++++--- clang/include/clang/Basic/OpenMPKinds.def | 7 ++++ clang/include/clang/Basic/OpenMPKinds.h | 7 ++++ clang/include/clang/Parse/Parser.h | 2 +- clang/include/clang/Sema/Sema.h | 9 ++--- clang/lib/AST/OpenMPClause.cpp | 11 ++++-- clang/lib/Basic/OpenMPKinds.cpp | 17 +++++++-- clang/lib/Parse/ParseOpenMP.cpp | 33 ++++++++++------- clang/lib/Sema/SemaOpenMP.cpp | 36 ++++++++++++------- clang/lib/Sema/TreeTransform.h | 25 ++++++------- clang/lib/Serialization/ASTReader.cpp | 2 ++ clang/lib/Serialization/ASTWriter.cpp | 2 ++ clang/test/OpenMP/parallel_ast_print.cpp | 24 ++++++------- .../OpenMP/parallel_reduction_codegen.cpp | 26 +++++++------- .../test/OpenMP/parallel_reduction_messages.c | 13 ++++++- 15 files changed, 170 insertions(+), 78 deletions(-) diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index 8b92cb62634a..29c251ef7ee6 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -2703,6 +2703,12 @@ class OMPReductionClause final friend OMPVarListClause; friend TrailingObjects; + /// Reduction modifier. + OpenMPReductionClauseModifier Modifier = OMPC_REDUCTION_unknown; + + /// Reduction modifier location. + SourceLocation ModifierLoc; + /// Location of ':'. SourceLocation ColonLoc; @@ -2716,18 +2722,22 @@ class OMPReductionClause final /// /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. - /// \param EndLoc Ending location of the clause. + /// \param ModifierLoc Modifier location. /// \param ColonLoc Location of ':'. + /// \param EndLoc Ending location of the clause. /// \param N Number of the variables in the clause. /// \param QualifierLoc The nested-name qualifier with location information /// \param NameInfo The full name info for reduction identifier. OMPReductionClause(SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation ColonLoc, SourceLocation EndLoc, unsigned N, + SourceLocation ModifierLoc, SourceLocation ColonLoc, + SourceLocation EndLoc, + OpenMPReductionClauseModifier Modifier, unsigned N, NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo) : OMPVarListClause(OMPC_reduction, StartLoc, LParenLoc, EndLoc, N), - OMPClauseWithPostUpdate(this), ColonLoc(ColonLoc), + OMPClauseWithPostUpdate(this), Modifier(Modifier), + ModifierLoc(ModifierLoc), ColonLoc(ColonLoc), QualifierLoc(QualifierLoc), NameInfo(NameInfo) {} /// Build an empty clause. @@ -2739,6 +2749,12 @@ class OMPReductionClause final N), OMPClauseWithPostUpdate(this) {} + /// Sets reduction modifier. + void setModifier(OpenMPReductionClauseModifier M) { Modifier = M; } + + /// Sets location of the modifier. + void setModifierLoc(SourceLocation Loc) { ModifierLoc = Loc; } + /// Sets location of ':' symbol in clause. void setColonLoc(SourceLocation CL) { ColonLoc = CL; } @@ -2808,6 +2824,7 @@ class OMPReductionClause final /// /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. + /// \param ModifierLoc Modifier location. /// \param ColonLoc Location of ':'. /// \param EndLoc Ending location of the clause. /// \param VL The variables in the clause. @@ -2838,8 +2855,9 @@ class OMPReductionClause final /// OpenMP region with this clause. static OMPReductionClause * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef VL, - NestedNameSpecifierLoc QualifierLoc, + SourceLocation ModifierLoc, SourceLocation ColonLoc, + SourceLocation EndLoc, OpenMPReductionClauseModifier Modifier, + ArrayRef VL, NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo, ArrayRef Privates, ArrayRef LHSExprs, ArrayRef RHSExprs, ArrayRef ReductionOps, Stmt *PreInit, Expr *PostUpdate); @@ -2850,6 +2868,12 @@ class OMPReductionClause final /// \param N The number of variables. static OMPReductionClause *CreateEmpty(const ASTContext &C, unsigned N); + /// Returns modifier. + OpenMPReductionClauseModifier getModifier() const { return Modifier; } + + /// Returns modifier location. + SourceLocation getModifierLoc() const { return ModifierLoc; } + /// Gets location of ':' symbol in clause. SourceLocation getColonLoc() const { return ColonLoc; } diff --git a/clang/include/clang/Basic/OpenMPKinds.def b/clang/include/clang/Basic/OpenMPKinds.def index ffffed50ef86..bfb41ab105ea 100644 --- a/clang/include/clang/Basic/OpenMPKinds.def +++ b/clang/include/clang/Basic/OpenMPKinds.def @@ -218,6 +218,9 @@ #ifndef OPENMP_SCAN_CLAUSE #define OPENMP_SCAN_CLAUSE(Name) #endif +#ifndef OPENMP_REDUCTION_MODIFIER +#define OPENMP_REDUCTION_MODIFIER(Name) +#endif // OpenMP clauses. OPENMP_CLAUSE(allocator, OMPAllocatorClause) @@ -1107,6 +1110,10 @@ OPENMP_DEPOBJ_CLAUSE(depend) OPENMP_DEPOBJ_CLAUSE(destroy) OPENMP_DEPOBJ_CLAUSE(update) +// Modifiers for 'reduction' clause. +OPENMP_REDUCTION_MODIFIER(default) + +#undef OPENMP_REDUCTION_MODIFIER #undef OPENMP_SCAN_CLAUSE #undef OPENMP_DEVICE_MODIFIER #undef OPENMP_DEPOBJ_CLAUSE diff --git a/clang/include/clang/Basic/OpenMPKinds.h b/clang/include/clang/Basic/OpenMPKinds.h index 46eeffe999d9..b567f89b986e 100644 --- a/clang/include/clang/Basic/OpenMPKinds.h +++ b/clang/include/clang/Basic/OpenMPKinds.h @@ -168,6 +168,13 @@ struct OpenMPScheduleTy final { OpenMPScheduleClauseModifier M2 = OMPC_SCHEDULE_MODIFIER_unknown; }; +/// OpenMP modifiers for 'reduction' clause. +enum OpenMPReductionClauseModifier { +#define OPENMP_REDUCTION_MODIFIER(Name) OMPC_REDUCTION_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPC_REDUCTION_unknown, +}; + OpenMPClauseKind getOpenMPClauseKind(llvm::StringRef Str); const char *getOpenMPClauseName(OpenMPClauseKind Kind); diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 9a22bac75e62..69db747fbb90 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3077,7 +3077,7 @@ class Parser : public CodeCompletionHandler { SmallVector MapTypeModifiersLoc; bool IsMapTypeImplicit = false; - SourceLocation DepLinMapLastLoc; + SourceLocation ExtraModifierLoc; }; /// Parses clauses with list. diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 90ba85638f0b..9f487e37a9f1 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10500,7 +10500,7 @@ class Sema final { DeclarationNameInfo &ReductionOrMapperId, int ExtraModifier, ArrayRef MapTypeModifiers, ArrayRef MapTypeModifiersLoc, bool IsMapTypeImplicit, - SourceLocation DepLinMapLastLoc); + SourceLocation ExtraModifierLoc); /// Called on well-formed 'inclusive' clause. OMPClause *ActOnOpenMPInclusiveClause(ArrayRef VarList, SourceLocation StartLoc, @@ -10538,9 +10538,10 @@ class Sema final { SourceLocation EndLoc); /// Called on well-formed 'reduction' clause. OMPClause *ActOnOpenMPReductionClause( - ArrayRef VarList, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, - CXXScopeSpec &ReductionIdScopeSpec, + ArrayRef VarList, OpenMPReductionClauseModifier Modifier, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ModifierLoc, SourceLocation ColonLoc, + SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef UnresolvedReductions = llvm::None); /// Called on well-formed 'task_reduction' clause. diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index 87ab3e333e22..fc7912d6fdca 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -703,14 +703,16 @@ void OMPReductionClause::setReductionOps(ArrayRef ReductionOps) { OMPReductionClause *OMPReductionClause::Create( const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc, SourceLocation ColonLoc, ArrayRef VL, + SourceLocation ModifierLoc, SourceLocation EndLoc, SourceLocation ColonLoc, + OpenMPReductionClauseModifier Modifier, ArrayRef VL, NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo, ArrayRef Privates, ArrayRef LHSExprs, ArrayRef RHSExprs, ArrayRef ReductionOps, Stmt *PreInit, Expr *PostUpdate) { void *Mem = C.Allocate(totalSizeToAlloc(5 * VL.size())); - OMPReductionClause *Clause = new (Mem) OMPReductionClause( - StartLoc, LParenLoc, EndLoc, ColonLoc, VL.size(), QualifierLoc, NameInfo); + auto *Clause = new (Mem) + OMPReductionClause(StartLoc, LParenLoc, ModifierLoc, EndLoc, ColonLoc, + Modifier, VL.size(), QualifierLoc, NameInfo); Clause->setVarRefs(VL); Clause->setPrivates(Privates); Clause->setLHSExprs(LHSExprs); @@ -1595,6 +1597,9 @@ void OMPClausePrinter::VisitOMPSharedClause(OMPSharedClause *Node) { void OMPClausePrinter::VisitOMPReductionClause(OMPReductionClause *Node) { if (!Node->varlist_empty()) { OS << "reduction("; + if (Node->getModifierLoc().isValid()) + OS << getOpenMPSimpleClauseTypeName(OMPC_reduction, Node->getModifier()) + << ", "; NestedNameSpecifier *QualifierLoc = Node->getQualifierLoc().getNestedNameSpecifier(); OverloadedOperatorKind OOK = diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index 36e7f4583468..e8bf41dc07be 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -159,6 +159,11 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, #define OPENMP_DEVICE_MODIFIER(Name) .Case(#Name, OMPC_DEVICE_##Name) #include "clang/Basic/OpenMPKinds.def" .Default(OMPC_DEVICE_unknown); + case OMPC_reduction: + return llvm::StringSwitch(Str) +#define OPENMP_REDUCTION_MODIFIER(Name) .Case(#Name, OMPC_REDUCTION_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_REDUCTION_unknown); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: @@ -172,7 +177,6 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, case OMPC_private: case OMPC_firstprivate: case OMPC_shared: - case OMPC_reduction: case OMPC_task_reduction: case OMPC_in_reduction: case OMPC_aligned: @@ -396,6 +400,16 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, #include "clang/Basic/OpenMPKinds.def" } llvm_unreachable("Invalid OpenMP 'device' clause modifier"); + case OMPC_reduction: + switch (Type) { + case OMPC_REDUCTION_unknown: + return "unknown"; +#define OPENMP_REDUCTION_MODIFIER(Name) \ + case OMPC_REDUCTION_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'reduction' clause modifier"); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: @@ -409,7 +423,6 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, case OMPC_private: case OMPC_firstprivate: case OMPC_shared: - case OMPC_reduction: case OMPC_task_reduction: case OMPC_in_reduction: case OMPC_aligned: diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 33b07bad8935..7ae9885abe2b 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -13,6 +13,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/StmtOpenMP.h" #include "clang/Basic/OpenMPKinds.h" +#include "clang/Basic/TokenKinds.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" @@ -754,7 +755,7 @@ static bool parseDeclareSimdClauses( "Unexpected linear modifier."); if (P.getActions().CheckOpenMPLinearModifier( static_cast(Data.ExtraModifier), - Data.DepLinMapLastLoc)) + Data.ExtraModifierLoc)) Data.ExtraModifier = OMPC_LINEAR_val; LinModifiers.append(Linears.size() - LinModifiers.size(), Data.ExtraModifier); @@ -3016,6 +3017,17 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, // Handle reduction-identifier for reduction clause. if (Kind == OMPC_reduction || Kind == OMPC_task_reduction || Kind == OMPC_in_reduction) { + Data.ExtraModifier = OMPC_REDUCTION_unknown; + if (Kind == OMPC_reduction && getLangOpts().OpenMP >= 50 && + (Tok.is(tok::identifier) || Tok.is(tok::kw_default)) && + NextToken().is(tok::comma)) { + // Parse optional reduction modifier. + Data.ExtraModifier = getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)); + Data.ExtraModifierLoc = Tok.getLocation(); + ConsumeToken(); + assert(Tok.is(tok::comma) && "Expected comma."); + (void)ConsumeToken(); + } ColonProtectionRAIIObject ColonRAII(*this); if (getLangOpts().CPlusPlus) ParseOptionalCXXScopeSpecifier(Data.ReductionOrMapperIdScopeSpec, @@ -3040,7 +3052,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, ColonProtectionRAIIObject ColonRAII(*this); Data.ExtraModifier = getOpenMPSimpleClauseType( Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : ""); - Data.DepLinMapLastLoc = Tok.getLocation(); + Data.ExtraModifierLoc = Tok.getLocation(); if (Data.ExtraModifier == OMPC_DEPEND_unknown) { SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); @@ -3065,7 +3077,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, Data.ExtraModifier = OMPC_LINEAR_val; if (Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::l_paren)) { Data.ExtraModifier = getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)); - Data.DepLinMapLastLoc = ConsumeToken(); + Data.ExtraModifierLoc = ConsumeToken(); LinearT.consumeOpen(); NeedRParenForLinear = true; } @@ -3078,13 +3090,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, !isOpenMPTaskLoopDirective(DKind)) && Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::colon)) { Data.ExtraModifier = getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)); - Data.DepLinMapLastLoc = Tok.getLocation(); - if (Data.ExtraModifier == OMPC_LASTPRIVATE_unknown) { - SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, - StopBeforeMatch); - } else { - ConsumeToken(); - } + Data.ExtraModifierLoc = Tok.getLocation(); + ConsumeToken(); assert(Tok.is(tok::colon) && "Expected colon."); Data.ColonLoc = ConsumeToken(); } @@ -3096,7 +3103,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, // map-type-modifier. The map-type can also be delete which has the same // spelling of the C++ delete keyword. Data.ExtraModifier = OMPC_MAP_unknown; - Data.DepLinMapLastLoc = Tok.getLocation(); + Data.ExtraModifierLoc = Tok.getLocation(); // Check for presence of a colon in the map clause. TentativeParsingAction TPA(*this); @@ -3256,7 +3263,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, /// aligned-clause: /// 'aligned' '(' list [ ':' alignment ] ')' /// reduction-clause: -/// 'reduction' '(' reduction-identifier ':' list ')' +/// 'reduction' '(' [ modifier ',' ] reduction-identifier ':' list ')' /// task_reduction-clause: /// 'task_reduction' '(' reduction-identifier ':' list ')' /// in_reduction-clause: @@ -3310,6 +3317,6 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, Kind, Vars, Data.TailExpr, Locs, Data.ColonLoc, Data.ReductionOrMapperIdScopeSpec, Data.ReductionOrMapperId, Data.ExtraModifier, Data.MapTypeModifiers, Data.MapTypeModifiersLoc, - Data.IsMapTypeImplicit, Data.DepLinMapLastLoc); + Data.IsMapTypeImplicit, Data.ExtraModifierLoc); } diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index c9e2f395ec06..11cc43a16db1 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -12832,7 +12832,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause( DeclarationNameInfo &ReductionOrMapperId, int ExtraModifier, ArrayRef MapTypeModifiers, ArrayRef MapTypeModifiersLoc, bool IsMapTypeImplicit, - SourceLocation DepLinMapLastLoc) { + SourceLocation ExtraModifierLoc) { SourceLocation StartLoc = Locs.StartLoc; SourceLocation LParenLoc = Locs.LParenLoc; SourceLocation EndLoc = Locs.EndLoc; @@ -12849,15 +12849,18 @@ OMPClause *Sema::ActOnOpenMPVarListClause( "Unexpected lastprivate modifier."); Res = ActOnOpenMPLastprivateClause( VarList, static_cast(ExtraModifier), - DepLinMapLastLoc, ColonLoc, StartLoc, LParenLoc, EndLoc); + ExtraModifierLoc, ColonLoc, StartLoc, LParenLoc, EndLoc); break; case OMPC_shared: Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_reduction: - Res = ActOnOpenMPReductionClause(VarList, StartLoc, LParenLoc, ColonLoc, - EndLoc, ReductionOrMapperIdScopeSpec, - ReductionOrMapperId); + assert(0 <= ExtraModifier && ExtraModifier <= OMPC_REDUCTION_unknown && + "Unexpected lastprivate modifier."); + Res = ActOnOpenMPReductionClause( + VarList, static_cast(ExtraModifier), + StartLoc, LParenLoc, ExtraModifierLoc, ColonLoc, EndLoc, + ReductionOrMapperIdScopeSpec, ReductionOrMapperId); break; case OMPC_task_reduction: Res = ActOnOpenMPTaskReductionClause(VarList, StartLoc, LParenLoc, ColonLoc, @@ -12874,7 +12877,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause( "Unexpected linear modifier."); Res = ActOnOpenMPLinearClause( VarList, TailExpr, StartLoc, LParenLoc, - static_cast(ExtraModifier), DepLinMapLastLoc, + static_cast(ExtraModifier), ExtraModifierLoc, ColonLoc, EndLoc); break; case OMPC_aligned: @@ -12894,7 +12897,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause( assert(0 <= ExtraModifier && ExtraModifier <= OMPC_DEPEND_unknown && "Unexpected depend modifier."); Res = ActOnOpenMPDependClause( - static_cast(ExtraModifier), DepLinMapLastLoc, + static_cast(ExtraModifier), ExtraModifierLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_map: @@ -12903,7 +12906,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause( Res = ActOnOpenMPMapClause( MapTypeModifiers, MapTypeModifiersLoc, ReductionOrMapperIdScopeSpec, ReductionOrMapperId, static_cast(ExtraModifier), - IsMapTypeImplicit, DepLinMapLastLoc, ColonLoc, VarList, Locs); + IsMapTypeImplicit, ExtraModifierLoc, ColonLoc, VarList, Locs); break; case OMPC_to: Res = ActOnOpenMPToClause(VarList, ReductionOrMapperIdScopeSpec, @@ -14703,10 +14706,19 @@ static bool actOnOMPReductionKindClause( } OMPClause *Sema::ActOnOpenMPReductionClause( - ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation ColonLoc, SourceLocation EndLoc, + ArrayRef VarList, OpenMPReductionClauseModifier Modifier, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ModifierLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef UnresolvedReductions) { + if (ModifierLoc.isValid() && Modifier == OMPC_REDUCTION_unknown) { + Diag(LParenLoc, diag::err_omp_unexpected_clause_value) + << getListOfPossibleValues(OMPC_reduction, /*First=*/0, + /*Last=*/OMPC_REDUCTION_unknown) + << getOpenMPClauseName(OMPC_reduction); + return nullptr; + } + ReductionData RD(VarList.size()); if (actOnOMPReductionKindClause(*this, DSAStack, OMPC_reduction, VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, @@ -14715,8 +14727,8 @@ OMPClause *Sema::ActOnOpenMPReductionClause( return nullptr; return OMPReductionClause::Create( - Context, StartLoc, LParenLoc, ColonLoc, EndLoc, RD.Vars, - ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, + Context, StartLoc, LParenLoc, ModifierLoc, ColonLoc, EndLoc, Modifier, + RD.Vars, ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps, buildPreInits(Context, RD.ExprCaptures), buildPostUpdate(*this, RD.ExprPostUpdates)); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 3e6d67d67845..65c924a8cb73 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -28,6 +28,7 @@ #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtOpenMP.h" +#include "clang/Basic/OpenMPKinds.h" #include "clang/Sema/Designator.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Ownership.h" @@ -1717,17 +1718,16 @@ class TreeTransform { /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - OMPClause *RebuildOMPReductionClause(ArrayRef VarList, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation ColonLoc, - SourceLocation EndLoc, - CXXScopeSpec &ReductionIdScopeSpec, - const DeclarationNameInfo &ReductionId, - ArrayRef UnresolvedReductions) { + OMPClause *RebuildOMPReductionClause( + ArrayRef VarList, OpenMPReductionClauseModifier Modifier, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ModifierLoc, SourceLocation ColonLoc, + SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, + const DeclarationNameInfo &ReductionId, + ArrayRef UnresolvedReductions) { return getSema().ActOnOpenMPReductionClause( - VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec, - ReductionId, UnresolvedReductions); + VarList, Modifier, StartLoc, LParenLoc, ModifierLoc, ColonLoc, EndLoc, + ReductionIdScopeSpec, ReductionId, UnresolvedReductions); } /// Build a new OpenMP 'task_reduction' clause. @@ -9083,8 +9083,9 @@ TreeTransform::TransformOMPReductionClause(OMPReductionClause *C) { UnresolvedReductions.push_back(nullptr); } return getDerived().RebuildOMPReductionClause( - Vars, C->getBeginLoc(), C->getLParenLoc(), C->getColonLoc(), - C->getEndLoc(), ReductionIdScopeSpec, NameInfo, UnresolvedReductions); + Vars, C->getModifier(), C->getBeginLoc(), C->getLParenLoc(), + C->getModifierLoc(), C->getColonLoc(), C->getEndLoc(), + ReductionIdScopeSpec, NameInfo, UnresolvedReductions); } template diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index fbd68929b2f1..c2d28f436241 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -12093,7 +12093,9 @@ void OMPClauseReader::VisitOMPSharedClause(OMPSharedClause *C) { void OMPClauseReader::VisitOMPReductionClause(OMPReductionClause *C) { VisitOMPClauseWithPostUpdate(C); C->setLParenLoc(Record.readSourceLocation()); + C->setModifierLoc(Record.readSourceLocation()); C->setColonLoc(Record.readSourceLocation()); + C->setModifier(Record.readEnum()); NestedNameSpecifierLoc NNSL = Record.readNestedNameSpecifierLoc(); DeclarationNameInfo DNI = Record.readDeclarationNameInfo(); C->setQualifierLoc(NNSL); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index f30824622346..ec75ff5965a0 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -6242,7 +6242,9 @@ void OMPClauseWriter::VisitOMPReductionClause(OMPReductionClause *C) { Record.push_back(C->varlist_size()); VisitOMPClauseWithPostUpdate(C); Record.AddSourceLocation(C->getLParenLoc()); + Record.AddSourceLocation(C->getModifierLoc()); Record.AddSourceLocation(C->getColonLoc()); + Record.writeEnum(C->getModifier()); Record.AddNestedNameSpecifierLoc(C->getQualifierLoc()); Record.AddDeclarationNameInfo(C->getNameInfo()); for (auto *VE : C->varlists()) diff --git a/clang/test/OpenMP/parallel_ast_print.cpp b/clang/test/OpenMP/parallel_ast_print.cpp index fa96dfce67ff..7ba40d8dc1cc 100644 --- a/clang/test/OpenMP/parallel_ast_print.cpp +++ b/clang/test/OpenMP/parallel_ast_print.cpp @@ -1,10 +1,10 @@ -// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -ast-print %s | FileCheck %s -// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -emit-pch -o %t %s -// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s -// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=45 -ast-print %s | FileCheck %s -// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=45 -x c++ -std=c++11 -emit-pch -o %t %s -// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=45 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=50 -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=50 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s // expected-no-diagnostics #ifndef HEADER @@ -89,7 +89,7 @@ class S8 : public S7 { #pragma omp parallel shared(a) shared(this->a) shared(S7 < S1 > ::a) for (int k = 0; k < a.a; ++k) ++this->a.a; -#pragma omp parallel reduction(^ : S7 < S1 > ::a) reduction(+ : S7 < S1 > ::b[ : S7 < S1 > ::a.a]) +#pragma omp parallel reduction(default, ^ : S7 < S1 > ::a) reduction(+ : S7 < S1 > ::b[ : S7 < S1 > ::a.a]) for (int k = 0; k < a.a; ++k) ++this->a.a; } @@ -113,7 +113,7 @@ class S8 : public S7 { // CHECK: #pragma omp parallel private(this->a) private(this->a) private(this->S7::a) // CHECK: #pragma omp parallel firstprivate(this->a) firstprivate(this->a) firstprivate(this->S7::a) // CHECK: #pragma omp parallel shared(this->a) shared(this->a) shared(this->S7::a) -// CHECK: #pragma omp parallel reduction(^: this->S7::a) reduction(+: this->S7::b[:this->S7::a.a]) +// CHECK: #pragma omp parallel reduction(default, ^: this->S7::a) reduction(+: this->S7::b[:this->S7::a.a]) // CHECK: #pragma omp parallel private(this->a) private(this->a) // CHECK: #pragma omp parallel firstprivate(this->a) firstprivate(this->a) // CHECK: #pragma omp parallel shared(this->a) shared(this->a) @@ -152,7 +152,7 @@ T tmain(T argc, T *argv) { a=2; #pragma omp parallel default(none), private(argc,b) firstprivate(argv) shared (d) if (parallel:argc > 0) num_threads(C) copyin(S::TS, thrp) proc_bind(master) reduction(+:c, arr1[argc]) reduction(max:e, arr[:C][0:10]) foo(); -#pragma omp parallel if (C) num_threads(s) proc_bind(close) reduction(^:e, f, arr[0:C][:argc]) reduction(&& : g) +#pragma omp parallel if (C) num_threads(s) proc_bind(close) reduction(^:e, f, arr[0:C][:argc]) reduction(default, && : g) foo(); return 0; } @@ -166,7 +166,7 @@ T tmain(T argc, T *argv) { // CHECK-NEXT: a = 2; // CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(parallel: argc > 0) num_threads(C) copyin(S::TS,thrp) proc_bind(master) reduction(+: c,arr1[argc]) reduction(max: e,arr[:C][0:10]) // CHECK-NEXT: foo() -// CHECK-NEXT: #pragma omp parallel if(C) num_threads(s) proc_bind(close) reduction(^: e,f,arr[0:C][:argc]) reduction(&&: g) +// CHECK-NEXT: #pragma omp parallel if(C) num_threads(s) proc_bind(close) reduction(^: e,f,arr[0:C][:argc]) reduction(default, &&: g) // CHECK-NEXT: foo() // CHECK: template<> int tmain(int argc, int *argv) { // CHECK-NEXT: int b = argc, c, d, e, f, g; @@ -177,7 +177,7 @@ T tmain(T argc, T *argv) { // CHECK-NEXT: a = 2; // CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(parallel: argc > 0) num_threads(5) copyin(S::TS,thrp) proc_bind(master) reduction(+: c,arr1[argc]) reduction(max: e,arr[:5][0:10]) // CHECK-NEXT: foo() -// CHECK-NEXT: #pragma omp parallel if(5) num_threads(s) proc_bind(close) reduction(^: e,f,arr[0:5][:argc]) reduction(&&: g) +// CHECK-NEXT: #pragma omp parallel if(5) num_threads(s) proc_bind(close) reduction(^: e,f,arr[0:5][:argc]) reduction(default, &&: g) // CHECK-NEXT: foo() // CHECK: template<> long tmain(long argc, long *argv) { // CHECK-NEXT: long b = argc, c, d, e, f, g; @@ -188,7 +188,7 @@ T tmain(T argc, T *argv) { // CHECK-NEXT: a = 2; // CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(parallel: argc > 0) num_threads(1) copyin(S::TS,thrp) proc_bind(master) reduction(+: c,arr1[argc]) reduction(max: e,arr[:1][0:10]) // CHECK-NEXT: foo() -// CHECK-NEXT: #pragma omp parallel if(1) num_threads(s) proc_bind(close) reduction(^: e,f,arr[0:1][:argc]) reduction(&&: g) +// CHECK-NEXT: #pragma omp parallel if(1) num_threads(s) proc_bind(close) reduction(^: e,f,arr[0:1][:argc]) reduction(default, &&: g) // CHECK-NEXT: foo() enum Enum { }; diff --git a/clang/test/OpenMP/parallel_reduction_codegen.cpp b/clang/test/OpenMP/parallel_reduction_codegen.cpp index 60bf35803076..eeea0384ac04 100644 --- a/clang/test/OpenMP/parallel_reduction_codegen.cpp +++ b/clang/test/OpenMP/parallel_reduction_codegen.cpp @@ -1,14 +1,14 @@ -// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s -// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-apple-darwin10 -emit-pch -o %t %s -// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-apple-darwin10 -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s -// RUN: %clang_cc1 -verify -fopenmp -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s - -// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s -// RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -triple x86_64-apple-darwin10 -emit-pch -o %t %s -// RUN: %clang_cc1 -fopenmp-simd -x c++ -triple x86_64-apple-darwin10 -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY0 %s -// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s -// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 -x c++ -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -x c++ -std=c++11 -triple x86_64-apple-darwin10 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -x c++ -triple x86_64-apple-darwin10 -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s + +// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 -x c++ -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=50 -x c++ -std=c++11 -triple x86_64-apple-darwin10 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=50 -x c++ -triple x86_64-apple-darwin10 -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s // SIMD-ONLY0-NOT: {{__kmpc|__tgt}} // expected-no-diagnostics #ifndef HEADER @@ -31,7 +31,7 @@ struct SS { int b : 4; int &c; SS(int &d) : a(0), b(0), c(d) { -#pragma omp parallel reduction(+: a, b, c) +#pragma omp parallel reduction(default, +: a, b, c) #ifdef LAMBDA [&]() { ++this->a, --b, (this)->c /= 1; @@ -91,7 +91,7 @@ struct SST { //CHECK: call void {{.+}}@__kmpc_fork_call( //CHECK: ret void void foo_array_sect(short x[1]) { -#pragma omp parallel reduction(+ : x[:]) +#pragma omp parallel reduction(default, + : x[:]) {} } diff --git a/clang/test/OpenMP/parallel_reduction_messages.c b/clang/test/OpenMP/parallel_reduction_messages.c index f88f8e056495..61a3e9300436 100644 --- a/clang/test/OpenMP/parallel_reduction_messages.c +++ b/clang/test/OpenMP/parallel_reduction_messages.c @@ -1,8 +1,19 @@ -// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 150 -o - %s +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 -ferror-limit 150 -o - %s int incomplete[]; void test() { + int a; +#pragma omp parallel reduction( // expected-error {{expected identifier}} expected-error {{expected ')'}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-note {{to match this '('}} + ; +#pragma omp parallel reduction(unknown // expected-error {{expected expression}} expected-error {{expected ')'}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-note {{to match this '('}} + ; +#pragma omp parallel reduction(default, // expected-error {{expected identifier}} expected-error {{expected ')'}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-note {{to match this '('}} + ; +#pragma omp parallel reduction(unknown, +: a) // expected-error {{expected 'default' in OpenMP clause 'reduction'}} + ; +#pragma omp parallel reduction(default, + : a) + ; #pragma omp parallel reduction(+ : incomplete) // expected-error {{a reduction list item with incomplete type 'int []'}} ; } From 564ece93b8362e2334edbd59e1d7e4a63253c7b8 Mon Sep 17 00:00:00 2001 From: Alexander Belyaev Date: Mon, 23 Mar 2020 22:33:33 +0100 Subject: [PATCH 53/59] [MLIR] Insert loop.yield to IfOp regions only if it's void. Differential Revision: https://reviews.llvm.org/D76603 --- mlir/include/mlir/Dialect/LoopOps/LoopOps.td | 9 +++++---- mlir/lib/Dialect/LoopOps/LoopOps.cpp | 15 +++++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/mlir/include/mlir/Dialect/LoopOps/LoopOps.td b/mlir/include/mlir/Dialect/LoopOps/LoopOps.td index a20c44fa5e16..7b010729831b 100644 --- a/mlir/include/mlir/Dialect/LoopOps/LoopOps.td +++ b/mlir/include/mlir/Dialect/LoopOps/LoopOps.td @@ -223,20 +223,21 @@ def IfOp : Loop_Op<"if", OpBuilder<"Builder *builder, OperationState &result, " "Value cond, bool withElseRegion">, OpBuilder<"Builder *builder, OperationState &result, " - "TypeRange resultTypes, Value cond, " - "bool withElseRegion"> + "TypeRange resultTypes, Value cond, bool withElseRegion"> ]; let extraClassDeclaration = [{ OpBuilder getThenBodyBuilder() { assert(!thenRegion().empty() && "Unexpected empty 'then' region."); Block &body = thenRegion().front(); - return OpBuilder(&body, std::prev(body.end())); + return OpBuilder(&body, + results().empty() ? std::prev(body.end()) : body.end()); } OpBuilder getElseBodyBuilder() { assert(!elseRegion().empty() && "Unexpected empty 'else' region."); Block &body = elseRegion().front(); - return OpBuilder(&body, std::prev(body.end())); + return OpBuilder(&body, + results().empty() ? std::prev(body.end()) : body.end()); } }]; } diff --git a/mlir/lib/Dialect/LoopOps/LoopOps.cpp b/mlir/lib/Dialect/LoopOps/LoopOps.cpp index 5106cc63cb46..3d7ee3846c22 100644 --- a/mlir/lib/Dialect/LoopOps/LoopOps.cpp +++ b/mlir/lib/Dialect/LoopOps/LoopOps.cpp @@ -201,18 +201,25 @@ ForOp mlir::loop::getForInductionVarOwner(Value val) { void IfOp::build(Builder *builder, OperationState &result, Value cond, bool withElseRegion) { - build(builder, result, /*resultTypes=*/llvm::None, cond, withElseRegion); + build(builder, result, /*resultTypes=*/llvm::None, cond, withElseRegion); } void IfOp::build(Builder *builder, OperationState &result, TypeRange resultTypes, Value cond, bool withElseRegion) { result.addOperands(cond); result.addTypes(resultTypes); + Region *thenRegion = result.addRegion(); + thenRegion->push_back(new Block()); + if (resultTypes.empty()) + IfOp::ensureTerminator(*thenRegion, *builder, result.location); + Region *elseRegion = result.addRegion(); - IfOp::ensureTerminator(*thenRegion, *builder, result.location); - if (withElseRegion) - IfOp::ensureTerminator(*elseRegion, *builder, result.location); + if (withElseRegion) { + elseRegion->push_back(new Block()); + if (resultTypes.empty()) + IfOp::ensureTerminator(*elseRegion, *builder, result.location); + } } static LogicalResult verify(IfOp op) { From de0758e5bd9c880d4179b51611fb5d76bc6b305b Mon Sep 17 00:00:00 2001 From: Stephen Neuendorffer Date: Mon, 23 Mar 2020 15:20:14 -0700 Subject: [PATCH 54/59] [MLIR] Fixes for BUILD_SHARED_LIBS=on --- mlir/lib/Dialect/AVX512/CMakeLists.txt | 1 + mlir/lib/Dialect/Affine/Transforms/CMakeLists.txt | 4 ++++ mlir/test/lib/TestDialect/CMakeLists.txt | 1 + 3 files changed, 6 insertions(+) diff --git a/mlir/lib/Dialect/AVX512/CMakeLists.txt b/mlir/lib/Dialect/AVX512/CMakeLists.txt index 3f03959891ca..eb1e7dc5c4b5 100644 --- a/mlir/lib/Dialect/AVX512/CMakeLists.txt +++ b/mlir/lib/Dialect/AVX512/CMakeLists.txt @@ -11,5 +11,6 @@ target_link_libraries(MLIRAVX512 PUBLIC MLIRIR MLIRSideEffects + MLIRVectorToLLVM LLVMSupport ) diff --git a/mlir/lib/Dialect/Affine/Transforms/CMakeLists.txt b/mlir/lib/Dialect/Affine/Transforms/CMakeLists.txt index 9cdc4b92fcd5..89abbd521dec 100644 --- a/mlir/lib/Dialect/Affine/Transforms/CMakeLists.txt +++ b/mlir/lib/Dialect/Affine/Transforms/CMakeLists.txt @@ -19,7 +19,11 @@ target_link_libraries(MLIRAffineTransforms MLIRAffine MLIREDSC MLIRIR + MLIRPass MLIRSideEffects MLIRStandardOps + MLIRTransformUtils + MLIRVector + MLIRVectorToLLVM ) diff --git a/mlir/test/lib/TestDialect/CMakeLists.txt b/mlir/test/lib/TestDialect/CMakeLists.txt index d625a5819096..0d8b13c61030 100644 --- a/mlir/test/lib/TestDialect/CMakeLists.txt +++ b/mlir/test/lib/TestDialect/CMakeLists.txt @@ -27,6 +27,7 @@ target_link_libraries(MLIRTestDialect MLIRLinalgTransforms MLIRPass MLIRStandardOps + MLIRStandardToStandard MLIRTransforms MLIRTransformUtils MLIRInferTypeOpInterface From c5c4109071ce22e5d3cd8404a7e4d64debdf377a Mon Sep 17 00:00:00 2001 From: Stephen Neuendorffer Date: Mon, 23 Mar 2020 15:20:54 -0700 Subject: [PATCH 55/59] [examples] Fixes for BUILD_SHARED_LIBS=on --- .../LLJITWithGDBRegistrationListener/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm/examples/OrcV2Examples/LLJITWithGDBRegistrationListener/CMakeLists.txt b/llvm/examples/OrcV2Examples/LLJITWithGDBRegistrationListener/CMakeLists.txt index 5bf96425d60e..0b1cdffb3805 100644 --- a/llvm/examples/OrcV2Examples/LLJITWithGDBRegistrationListener/CMakeLists.txt +++ b/llvm/examples/OrcV2Examples/LLJITWithGDBRegistrationListener/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_LINK_COMPONENTS Core + ExecutionEngine IRReader JITLink OrcJIT From bfa9ce1cb27a6abac071c0b8fab76d647098eaeb Mon Sep 17 00:00:00 2001 From: Nemanja Ivanovic Date: Mon, 23 Mar 2020 17:34:05 -0500 Subject: [PATCH 56/59] [PowerPC] Improve handling of some BUILD_VECTOR nodes An analysis of real world code turned up a number of patterns with BUILD_VECTOR of nodes resulting from operations on extracted vector elements for which we produce poor code. This addresses those cases. No attempt is made for completeness as that would entail a large amount of work for something that there is no evidence of in real code. Differential revision: https://reviews.llvm.org/D72660 --- llvm/lib/Target/PowerPC/PPCInstrVSX.td | 85 ++ .../CodeGen/PowerPC/build-vector-tests.ll | 409 +++++++++ .../CodeGen/PowerPC/reduce_scalarization02.ll | 34 +- .../PowerPC/vec_conv_fp32_to_i64_elts.ll | 814 +++++++----------- llvm/test/CodeGen/PowerPC/vsx.ll | 14 +- 5 files changed, 806 insertions(+), 550 deletions(-) diff --git a/llvm/lib/Target/PowerPC/PPCInstrVSX.td b/llvm/lib/Target/PowerPC/PPCInstrVSX.td index b12096dacdd3..73529533c26b 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrVSX.td +++ b/llvm/lib/Target/PowerPC/PPCInstrVSX.td @@ -1341,6 +1341,21 @@ def DWToSPExtractConv { dag BVS = (v4f32 (build_vector El0SS1, El1SS1, El0SS2, El1SS2)); } +def WToDPExtractConv { + dag El0S = (f64 (PPCfcfid (PPCmtvsra (extractelt v4i32:$A, 0)))); + dag El1S = (f64 (PPCfcfid (PPCmtvsra (extractelt v4i32:$A, 1)))); + dag El2S = (f64 (PPCfcfid (PPCmtvsra (extractelt v4i32:$A, 2)))); + dag El3S = (f64 (PPCfcfid (PPCmtvsra (extractelt v4i32:$A, 3)))); + dag El0U = (f64 (PPCfcfidu (PPCmtvsrz (extractelt v4i32:$A, 0)))); + dag El1U = (f64 (PPCfcfidu (PPCmtvsrz (extractelt v4i32:$A, 1)))); + dag El2U = (f64 (PPCfcfidu (PPCmtvsrz (extractelt v4i32:$A, 2)))); + dag El3U = (f64 (PPCfcfidu (PPCmtvsrz (extractelt v4i32:$A, 3)))); + dag BV02S = (v2f64 (build_vector El0S, El2S)); + dag BV13S = (v2f64 (build_vector El1S, El3S)); + dag BV02U = (v2f64 (build_vector El0U, El2U)); + dag BV13U = (v2f64 (build_vector El1U, El3U)); +} + // The following VSX instructions were introduced in Power ISA 2.07 /* FIXME: if the operands are v2i64, these patterns will not match. we should define new patterns or otherwise match the same patterns @@ -4171,6 +4186,41 @@ let AddedComplexity = 400 in { def : Pat<(v4i32 (build_vector ExtDbl.A0U, ExtDbl.A1U, ExtDbl.B0U, ExtDbl.B1U)), (v4i32 (VMRGEW MrgWords.CVA0B0U, MrgWords.CVA1B1U))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 0))), + (f64 (fpextend (extractelt v4f32:$A, 1))))), + (v2f64 (XVCVSPDP (XXMRGHW $A, $A)))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 1))), + (f64 (fpextend (extractelt v4f32:$A, 0))))), + (v2f64 (XXPERMDI (XVCVSPDP (XXMRGHW $A, $A)), + (XVCVSPDP (XXMRGHW $A, $A)), 2))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 0))), + (f64 (fpextend (extractelt v4f32:$A, 2))))), + (v2f64 (XVCVSPDP $A))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 1))), + (f64 (fpextend (extractelt v4f32:$A, 3))))), + (v2f64 (XVCVSPDP (XXSLDWI $A, $A, 3)))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 2))), + (f64 (fpextend (extractelt v4f32:$A, 3))))), + (v2f64 (XVCVSPDP (XXMRGLW $A, $A)))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 3))), + (f64 (fpextend (extractelt v4f32:$A, 2))))), + (v2f64 (XXPERMDI (XVCVSPDP (XXMRGLW $A, $A)), + (XVCVSPDP (XXMRGLW $A, $A)), 2))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 0))), + (f64 (fpextend (extractelt v4f32:$B, 0))))), + (v2f64 (XVCVSPDP (XXPERMDI $A, $B, 0)))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 3))), + (f64 (fpextend (extractelt v4f32:$B, 3))))), + (v2f64 (XVCVSPDP (XXSLDWI (XXPERMDI $A, $B, 3), + (XXPERMDI $A, $B, 3), 1)))>; + def : Pat; + def : Pat; + def : Pat; + def : Pat; } let Predicates = [IsLittleEndian, HasP8Vector] in { @@ -4249,6 +4299,41 @@ let AddedComplexity = 400 in { def : Pat<(v4i32 (build_vector ExtDbl.A0U, ExtDbl.A1U, ExtDbl.B0U, ExtDbl.B1U)), (v4i32 (VMRGEW MrgWords.CVB1A1U, MrgWords.CVB0A0U))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 0))), + (f64 (fpextend (extractelt v4f32:$A, 1))))), + (v2f64 (XVCVSPDP (XXMRGLW $A, $A)))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 1))), + (f64 (fpextend (extractelt v4f32:$A, 0))))), + (v2f64 (XXPERMDI (XVCVSPDP (XXMRGLW $A, $A)), + (XVCVSPDP (XXMRGLW $A, $A)), 2))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 0))), + (f64 (fpextend (extractelt v4f32:$A, 2))))), + (v2f64 (XVCVSPDP (XXSLDWI $A, $A, 1)))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 1))), + (f64 (fpextend (extractelt v4f32:$A, 3))))), + (v2f64 (XVCVSPDP $A))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 2))), + (f64 (fpextend (extractelt v4f32:$A, 3))))), + (v2f64 (XVCVSPDP (XXMRGHW $A, $A)))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 3))), + (f64 (fpextend (extractelt v4f32:$A, 2))))), + (v2f64 (XXPERMDI (XVCVSPDP (XXMRGHW $A, $A)), + (XVCVSPDP (XXMRGHW $A, $A)), 2))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 0))), + (f64 (fpextend (extractelt v4f32:$B, 0))))), + (v2f64 (XVCVSPDP (XXSLDWI (XXPERMDI $B, $A, 3), + (XXPERMDI $B, $A, 3), 1)))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 3))), + (f64 (fpextend (extractelt v4f32:$B, 3))))), + (v2f64 (XVCVSPDP (XXPERMDI $B, $A, 0)))>; + def : Pat; + def : Pat; + def : Pat; + def : Pat; } let Predicates = [HasDirectMove] in { diff --git a/llvm/test/CodeGen/PowerPC/build-vector-tests.ll b/llvm/test/CodeGen/PowerPC/build-vector-tests.ll index 4e096b1c5c03..469cef01094b 100644 --- a/llvm/test/CodeGen/PowerPC/build-vector-tests.ll +++ b/llvm/test/CodeGen/PowerPC/build-vector-tests.ll @@ -6123,3 +6123,412 @@ entry: %splat.splat = shufflevector <2 x i64> %splat.splatinsert, <2 x i64> undef, <2 x i32> zeroinitializer ret <2 x i64> %splat.splat } + +; Some additional patterns that come up in real code. +define dso_local <2 x double> @sint_to_fp_widen02(<4 x i32> %a) { +; P9BE-LABEL: sint_to_fp_widen02: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xvcvsxwdp v2, v2 +; P9BE-NEXT: blr +; +; P9LE-LABEL: sint_to_fp_widen02: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xxsldwi vs0, v2, v2, 1 +; P9LE-NEXT: xvcvsxwdp v2, vs0 +; P9LE-NEXT: blr +; +; P8BE-LABEL: sint_to_fp_widen02: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xvcvsxwdp v2, v2 +; P8BE-NEXT: blr +; +; P8LE-LABEL: sint_to_fp_widen02: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xxsldwi vs0, v2, v2, 1 +; P8LE-NEXT: xvcvsxwdp v2, vs0 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x i32> %a, i32 0 + %conv = sitofp i32 %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x i32> %a, i32 2 + %conv2 = sitofp i32 %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @sint_to_fp_widen13(<4 x i32> %a) { +; P9BE-LABEL: sint_to_fp_widen13: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xxsldwi vs0, v2, v2, 3 +; P9BE-NEXT: xvcvsxwdp v2, vs0 +; P9BE-NEXT: blr +; +; P9LE-LABEL: sint_to_fp_widen13: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xvcvsxwdp v2, v2 +; P9LE-NEXT: blr +; +; P8BE-LABEL: sint_to_fp_widen13: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xxsldwi vs0, v2, v2, 3 +; P8BE-NEXT: xvcvsxwdp v2, vs0 +; P8BE-NEXT: blr +; +; P8LE-LABEL: sint_to_fp_widen13: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xvcvsxwdp v2, v2 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x i32> %a, i32 1 + %conv = sitofp i32 %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x i32> %a, i32 3 + %conv2 = sitofp i32 %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @uint_to_fp_widen02(<4 x i32> %a) { +; P9BE-LABEL: uint_to_fp_widen02: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xvcvuxwdp v2, v2 +; P9BE-NEXT: blr +; +; P9LE-LABEL: uint_to_fp_widen02: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xxsldwi vs0, v2, v2, 1 +; P9LE-NEXT: xvcvuxwdp v2, vs0 +; P9LE-NEXT: blr +; +; P8BE-LABEL: uint_to_fp_widen02: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xvcvuxwdp v2, v2 +; P8BE-NEXT: blr +; +; P8LE-LABEL: uint_to_fp_widen02: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xxsldwi vs0, v2, v2, 1 +; P8LE-NEXT: xvcvuxwdp v2, vs0 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x i32> %a, i32 0 + %conv = uitofp i32 %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x i32> %a, i32 2 + %conv2 = uitofp i32 %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @uint_to_fp_widen13(<4 x i32> %a) { +; P9BE-LABEL: uint_to_fp_widen13: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xxsldwi vs0, v2, v2, 3 +; P9BE-NEXT: xvcvuxwdp v2, vs0 +; P9BE-NEXT: blr +; +; P9LE-LABEL: uint_to_fp_widen13: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xvcvuxwdp v2, v2 +; P9LE-NEXT: blr +; +; P8BE-LABEL: uint_to_fp_widen13: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xxsldwi vs0, v2, v2, 3 +; P8BE-NEXT: xvcvuxwdp v2, vs0 +; P8BE-NEXT: blr +; +; P8LE-LABEL: uint_to_fp_widen13: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xvcvuxwdp v2, v2 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x i32> %a, i32 1 + %conv = uitofp i32 %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x i32> %a, i32 3 + %conv2 = uitofp i32 %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @fp_extend01(<4 x float> %a) { +; P9BE-LABEL: fp_extend01: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xxmrghw vs0, v2, v2 +; P9BE-NEXT: xvcvspdp v2, vs0 +; P9BE-NEXT: blr +; +; P9LE-LABEL: fp_extend01: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xxmrglw vs0, v2, v2 +; P9LE-NEXT: xvcvspdp v2, vs0 +; P9LE-NEXT: blr +; +; P8BE-LABEL: fp_extend01: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xxmrghw vs0, v2, v2 +; P8BE-NEXT: xvcvspdp v2, vs0 +; P8BE-NEXT: blr +; +; P8LE-LABEL: fp_extend01: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xxmrglw vs0, v2, v2 +; P8LE-NEXT: xvcvspdp v2, vs0 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x float> %a, i32 0 + %conv = fpext float %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x float> %a, i32 1 + %conv2 = fpext float %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @fp_extend10(<4 x float> %a) { +; P9BE-LABEL: fp_extend10: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xxmrghw vs0, v2, v2 +; P9BE-NEXT: xvcvspdp vs0, vs0 +; P9BE-NEXT: xxswapd v2, vs0 +; P9BE-NEXT: blr +; +; P9LE-LABEL: fp_extend10: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xxmrglw vs0, v2, v2 +; P9LE-NEXT: xvcvspdp vs0, vs0 +; P9LE-NEXT: xxswapd v2, vs0 +; P9LE-NEXT: blr +; +; P8BE-LABEL: fp_extend10: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xxmrghw vs0, v2, v2 +; P8BE-NEXT: xvcvspdp vs0, vs0 +; P8BE-NEXT: xxswapd v2, vs0 +; P8BE-NEXT: blr +; +; P8LE-LABEL: fp_extend10: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xxmrglw vs0, v2, v2 +; P8LE-NEXT: xvcvspdp vs0, vs0 +; P8LE-NEXT: xxswapd v2, vs0 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x float> %a, i32 1 + %conv = fpext float %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x float> %a, i32 0 + %conv2 = fpext float %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @fp_extend02(<4 x float> %a) { +; P9BE-LABEL: fp_extend02: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xvcvspdp v2, v2 +; P9BE-NEXT: blr +; +; P9LE-LABEL: fp_extend02: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xxsldwi vs0, v2, v2, 1 +; P9LE-NEXT: xvcvspdp v2, vs0 +; P9LE-NEXT: blr +; +; P8BE-LABEL: fp_extend02: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xvcvspdp v2, v2 +; P8BE-NEXT: blr +; +; P8LE-LABEL: fp_extend02: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xxsldwi vs0, v2, v2, 1 +; P8LE-NEXT: xvcvspdp v2, vs0 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x float> %a, i32 0 + %conv = fpext float %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x float> %a, i32 2 + %conv2 = fpext float %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @fp_extend13(<4 x float> %a) { +; P9BE-LABEL: fp_extend13: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xxsldwi vs0, v2, v2, 3 +; P9BE-NEXT: xvcvspdp v2, vs0 +; P9BE-NEXT: blr +; +; P9LE-LABEL: fp_extend13: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xvcvspdp v2, v2 +; P9LE-NEXT: blr +; +; P8BE-LABEL: fp_extend13: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xxsldwi vs0, v2, v2, 3 +; P8BE-NEXT: xvcvspdp v2, vs0 +; P8BE-NEXT: blr +; +; P8LE-LABEL: fp_extend13: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xvcvspdp v2, v2 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x float> %a, i32 1 + %conv = fpext float %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x float> %a, i32 3 + %conv2 = fpext float %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @fp_extend23(<4 x float> %a) { +; P9BE-LABEL: fp_extend23: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xxmrglw vs0, v2, v2 +; P9BE-NEXT: xvcvspdp v2, vs0 +; P9BE-NEXT: blr +; +; P9LE-LABEL: fp_extend23: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xxmrghw vs0, v2, v2 +; P9LE-NEXT: xvcvspdp v2, vs0 +; P9LE-NEXT: blr +; +; P8BE-LABEL: fp_extend23: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xxmrglw vs0, v2, v2 +; P8BE-NEXT: xvcvspdp v2, vs0 +; P8BE-NEXT: blr +; +; P8LE-LABEL: fp_extend23: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xxmrghw vs0, v2, v2 +; P8LE-NEXT: xvcvspdp v2, vs0 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x float> %a, i32 2 + %conv = fpext float %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x float> %a, i32 3 + %conv2 = fpext float %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @fp_extend32(<4 x float> %a) { +; P9BE-LABEL: fp_extend32: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xxmrglw vs0, v2, v2 +; P9BE-NEXT: xvcvspdp vs0, vs0 +; P9BE-NEXT: xxswapd v2, vs0 +; P9BE-NEXT: blr +; +; P9LE-LABEL: fp_extend32: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xxmrghw vs0, v2, v2 +; P9LE-NEXT: xvcvspdp vs0, vs0 +; P9LE-NEXT: xxswapd v2, vs0 +; P9LE-NEXT: blr +; +; P8BE-LABEL: fp_extend32: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xxmrglw vs0, v2, v2 +; P8BE-NEXT: xvcvspdp vs0, vs0 +; P8BE-NEXT: xxswapd v2, vs0 +; P8BE-NEXT: blr +; +; P8LE-LABEL: fp_extend32: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xxmrghw vs0, v2, v2 +; P8LE-NEXT: xvcvspdp vs0, vs0 +; P8LE-NEXT: xxswapd v2, vs0 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x float> %a, i32 3 + %conv = fpext float %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x float> %a, i32 2 + %conv2 = fpext float %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @fp_extend_two00(<4 x float> %a, <4 x float> %b) { +; P9BE-LABEL: fp_extend_two00: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xxmrghd vs0, v2, v3 +; P9BE-NEXT: xvcvspdp v2, vs0 +; P9BE-NEXT: blr +; +; P9LE-LABEL: fp_extend_two00: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xxmrgld vs0, v3, v2 +; P9LE-NEXT: xxsldwi vs0, vs0, vs0, 1 +; P9LE-NEXT: xvcvspdp v2, vs0 +; P9LE-NEXT: blr +; +; P8BE-LABEL: fp_extend_two00: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xxmrghd vs0, v2, v3 +; P8BE-NEXT: xvcvspdp v2, vs0 +; P8BE-NEXT: blr +; +; P8LE-LABEL: fp_extend_two00: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xxmrgld vs0, v3, v2 +; P8LE-NEXT: xxsldwi vs0, vs0, vs0, 1 +; P8LE-NEXT: xvcvspdp v2, vs0 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x float> %a, i32 0 + %conv = fpext float %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x float> %b, i32 0 + %conv2 = fpext float %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @fp_extend_two33(<4 x float> %a, <4 x float> %b) { +; P9BE-LABEL: fp_extend_two33: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xxmrgld vs0, v2, v3 +; P9BE-NEXT: xxsldwi vs0, vs0, vs0, 1 +; P9BE-NEXT: xvcvspdp v2, vs0 +; P9BE-NEXT: blr +; +; P9LE-LABEL: fp_extend_two33: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xxmrghd vs0, v3, v2 +; P9LE-NEXT: xvcvspdp v2, vs0 +; P9LE-NEXT: blr +; +; P8BE-LABEL: fp_extend_two33: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xxmrgld vs0, v2, v3 +; P8BE-NEXT: xxsldwi vs0, vs0, vs0, 1 +; P8BE-NEXT: xvcvspdp v2, vs0 +; P8BE-NEXT: blr +; +; P8LE-LABEL: fp_extend_two33: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xxmrghd vs0, v3, v2 +; P8LE-NEXT: xvcvspdp v2, vs0 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x float> %a, i32 3 + %conv = fpext float %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x float> %b, i32 3 + %conv2 = fpext float %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} diff --git a/llvm/test/CodeGen/PowerPC/reduce_scalarization02.ll b/llvm/test/CodeGen/PowerPC/reduce_scalarization02.ll index f7727d6f4ea1..1dc40edf7146 100644 --- a/llvm/test/CodeGen/PowerPC/reduce_scalarization02.ll +++ b/llvm/test/CodeGen/PowerPC/reduce_scalarization02.ll @@ -47,33 +47,23 @@ define dso_local void @test2(<16 x float>* nocapture readonly %a, <2 x double>* ; CHECK-LABEL: test2: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: lxv vs0, 0(r3) -; CHECK-NEXT: xxsldwi vs1, vs0, vs0, 1 -; CHECK-NEXT: xscvspdpn f2, vs0 -; CHECK-NEXT: xxsldwi vs3, vs0, vs0, 3 -; CHECK-NEXT: xxswapd vs0, vs0 -; CHECK-NEXT: xscvspdpn f1, vs1 -; CHECK-NEXT: xscvspdpn f3, vs3 -; CHECK-NEXT: xscvspdpn f0, vs0 -; CHECK-NEXT: xxmrghd vs0, vs0, vs3 -; CHECK-NEXT: xxmrghd vs1, vs2, vs1 -; CHECK-NEXT: stxv vs0, 0(r4) -; CHECK-NEXT: stxv vs1, 0(r5) +; CHECK-NEXT: xxmrglw vs1, vs0, vs0 +; CHECK-NEXT: xxmrghw vs0, vs0, vs0 +; CHECK-NEXT: xvcvspdp vs1, vs1 +; CHECK-NEXT: xvcvspdp vs0, vs0 +; CHECK-NEXT: stxv vs1, 0(r4) +; CHECK-NEXT: stxv vs0, 0(r5) ; CHECK-NEXT: blr ; ; CHECK-BE-LABEL: test2: ; CHECK-BE: # %bb.0: # %entry ; CHECK-BE-NEXT: lxv vs0, 0(r3) -; CHECK-BE-NEXT: xxswapd vs1, vs0 -; CHECK-BE-NEXT: xxsldwi vs2, vs0, vs0, 3 -; CHECK-BE-NEXT: xscvspdpn f3, vs0 -; CHECK-BE-NEXT: xxsldwi vs0, vs0, vs0, 1 -; CHECK-BE-NEXT: xscvspdpn f1, vs1 -; CHECK-BE-NEXT: xscvspdpn f2, vs2 -; CHECK-BE-NEXT: xscvspdpn f0, vs0 -; CHECK-BE-NEXT: xxmrghd vs0, vs3, vs0 -; CHECK-BE-NEXT: xxmrghd vs1, vs1, vs2 -; CHECK-BE-NEXT: stxv vs0, 0(r4) -; CHECK-BE-NEXT: stxv vs1, 0(r5) +; CHECK-BE-NEXT: xxmrghw vs1, vs0, vs0 +; CHECK-BE-NEXT: xxmrglw vs0, vs0, vs0 +; CHECK-BE-NEXT: xvcvspdp vs1, vs1 +; CHECK-BE-NEXT: xvcvspdp vs0, vs0 +; CHECK-BE-NEXT: stxv vs1, 0(r4) +; CHECK-BE-NEXT: stxv vs0, 0(r5) ; CHECK-BE-NEXT: blr entry: %0 = load <16 x float>, <16 x float>* %a, align 16 diff --git a/llvm/test/CodeGen/PowerPC/vec_conv_fp32_to_i64_elts.ll b/llvm/test/CodeGen/PowerPC/vec_conv_fp32_to_i64_elts.ll index cf4a6d636207..d355dcd08b0f 100644 --- a/llvm/test/CodeGen/PowerPC/vec_conv_fp32_to_i64_elts.ll +++ b/llvm/test/CodeGen/PowerPC/vec_conv_fp32_to_i64_elts.ll @@ -14,10 +14,8 @@ define <2 x i64> @test2elt(i64 %a.coerce) local_unnamed_addr #0 { ; CHECK-P8: # %bb.0: # %entry ; CHECK-P8-NEXT: mtvsrd f0, r3 ; CHECK-P8-NEXT: xxswapd v2, vs0 -; CHECK-P8-NEXT: xscvspdpn f0, vs0 -; CHECK-P8-NEXT: xxsldwi vs1, v2, v2, 3 -; CHECK-P8-NEXT: xscvspdpn f1, vs1 -; CHECK-P8-NEXT: xxmrghd vs0, vs0, vs1 +; CHECK-P8-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P8-NEXT: xvcvspdp vs0, vs0 ; CHECK-P8-NEXT: xvcvdpuxds v2, vs0 ; CHECK-P8-NEXT: blr ; @@ -25,20 +23,16 @@ define <2 x i64> @test2elt(i64 %a.coerce) local_unnamed_addr #0 { ; CHECK-P9: # %bb.0: # %entry ; CHECK-P9-NEXT: mtvsrd f0, r3 ; CHECK-P9-NEXT: xxswapd v2, vs0 -; CHECK-P9-NEXT: xscvspdpn f0, vs0 -; CHECK-P9-NEXT: xxsldwi vs1, v2, v2, 3 -; CHECK-P9-NEXT: xscvspdpn f1, vs1 -; CHECK-P9-NEXT: xxmrghd vs0, vs0, vs1 +; CHECK-P9-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P9-NEXT: xvcvspdp vs0, vs0 ; CHECK-P9-NEXT: xvcvdpuxds v2, vs0 ; CHECK-P9-NEXT: blr ; ; CHECK-BE-LABEL: test2elt: ; CHECK-BE: # %bb.0: # %entry ; CHECK-BE-NEXT: mtvsrd f0, r3 -; CHECK-BE-NEXT: xscvspdpn f1, vs0 -; CHECK-BE-NEXT: xxsldwi vs0, vs0, vs0, 1 -; CHECK-BE-NEXT: xscvspdpn f0, vs0 -; CHECK-BE-NEXT: xxmrghd vs0, vs1, vs0 +; CHECK-BE-NEXT: xxmrghw vs0, vs0, vs0 +; CHECK-BE-NEXT: xvcvspdp vs0, vs0 ; CHECK-BE-NEXT: xvcvdpuxds v2, vs0 ; CHECK-BE-NEXT: blr entry: @@ -50,16 +44,11 @@ entry: define void @test4elt(<4 x i64>* noalias nocapture sret %agg.result, <4 x float> %a) local_unnamed_addr #1 { ; CHECK-P8-LABEL: test4elt: ; CHECK-P8: # %bb.0: # %entry -; CHECK-P8-NEXT: xxsldwi vs0, v2, v2, 3 -; CHECK-P8-NEXT: xxswapd vs1, v2 +; CHECK-P8-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P8-NEXT: xxmrghw vs1, v2, v2 ; CHECK-P8-NEXT: li r4, 16 -; CHECK-P8-NEXT: xxsldwi vs3, v2, v2, 1 -; CHECK-P8-NEXT: xscvspdpn f2, v2 -; CHECK-P8-NEXT: xscvspdpn f0, vs0 -; CHECK-P8-NEXT: xscvspdpn f1, vs1 -; CHECK-P8-NEXT: xscvspdpn f3, vs3 -; CHECK-P8-NEXT: xxmrghd vs0, vs1, vs0 -; CHECK-P8-NEXT: xxmrghd vs1, vs2, vs3 +; CHECK-P8-NEXT: xvcvspdp vs0, vs0 +; CHECK-P8-NEXT: xvcvspdp vs1, vs1 ; CHECK-P8-NEXT: xvcvdpuxds v2, vs0 ; CHECK-P8-NEXT: xvcvdpuxds v3, vs1 ; CHECK-P8-NEXT: xxswapd vs1, v2 @@ -70,36 +59,26 @@ define void @test4elt(<4 x i64>* noalias nocapture sret %agg.result, <4 x float> ; ; CHECK-P9-LABEL: test4elt: ; CHECK-P9: # %bb.0: # %entry -; CHECK-P9-NEXT: xxsldwi vs0, v2, v2, 3 -; CHECK-P9-NEXT: xxswapd vs1, v2 -; CHECK-P9-NEXT: xscvspdpn f0, vs0 -; CHECK-P9-NEXT: xscvspdpn f1, vs1 -; CHECK-P9-NEXT: xxsldwi vs2, v2, v2, 1 -; CHECK-P9-NEXT: xscvspdpn f2, vs2 -; CHECK-P9-NEXT: xxmrghd vs0, vs1, vs0 -; CHECK-P9-NEXT: xscvspdpn f1, v2 -; CHECK-P9-NEXT: xxmrghd vs1, vs1, vs2 +; CHECK-P9-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P9-NEXT: xxmrghw vs1, v2, v2 +; CHECK-P9-NEXT: xvcvspdp vs0, vs0 +; CHECK-P9-NEXT: xvcvspdp vs1, vs1 ; CHECK-P9-NEXT: xvcvdpuxds vs0, vs0 ; CHECK-P9-NEXT: xvcvdpuxds vs1, vs1 -; CHECK-P9-NEXT: stxv vs0, 0(r3) ; CHECK-P9-NEXT: stxv vs1, 16(r3) +; CHECK-P9-NEXT: stxv vs0, 0(r3) ; CHECK-P9-NEXT: blr ; ; CHECK-BE-LABEL: test4elt: ; CHECK-BE: # %bb.0: # %entry -; CHECK-BE-NEXT: xxsldwi vs1, v2, v2, 1 -; CHECK-BE-NEXT: xscvspdpn f0, v2 -; CHECK-BE-NEXT: xxswapd vs2, v2 -; CHECK-BE-NEXT: xscvspdpn f1, vs1 -; CHECK-BE-NEXT: xxmrghd vs0, vs0, vs1 -; CHECK-BE-NEXT: xxsldwi vs1, v2, v2, 3 -; CHECK-BE-NEXT: xscvspdpn f1, vs1 -; CHECK-BE-NEXT: xscvspdpn f2, vs2 +; CHECK-BE-NEXT: xxmrghw vs0, v2, v2 +; CHECK-BE-NEXT: xxmrglw vs1, v2, v2 +; CHECK-BE-NEXT: xvcvspdp vs0, vs0 +; CHECK-BE-NEXT: xvcvspdp vs1, vs1 ; CHECK-BE-NEXT: xvcvdpuxds vs0, vs0 -; CHECK-BE-NEXT: xxmrghd vs1, vs2, vs1 ; CHECK-BE-NEXT: xvcvdpuxds vs1, vs1 -; CHECK-BE-NEXT: stxv vs0, 0(r3) ; CHECK-BE-NEXT: stxv vs1, 16(r3) +; CHECK-BE-NEXT: stxv vs0, 0(r3) ; CHECK-BE-NEXT: blr entry: %0 = fptoui <4 x float> %a to <4 x i64> @@ -115,31 +94,21 @@ define void @test8elt(<8 x i64>* noalias nocapture sret %agg.result, <8 x float> ; CHECK-P8-NEXT: li r6, 32 ; CHECK-P8-NEXT: lvx v2, r4, r5 ; CHECK-P8-NEXT: li r4, 48 -; CHECK-P8-NEXT: xxsldwi vs5, v3, v3, 3 -; CHECK-P8-NEXT: xxswapd vs6, v3 -; CHECK-P8-NEXT: xxsldwi vs0, v2, v2, 3 -; CHECK-P8-NEXT: xxswapd vs1, v2 -; CHECK-P8-NEXT: xxsldwi vs3, v2, v2, 1 -; CHECK-P8-NEXT: xxsldwi vs7, v3, v3, 1 -; CHECK-P8-NEXT: xscvspdpn f2, v2 -; CHECK-P8-NEXT: xscvspdpn f4, v3 -; CHECK-P8-NEXT: xscvspdpn f0, vs0 -; CHECK-P8-NEXT: xscvspdpn f1, vs1 -; CHECK-P8-NEXT: xscvspdpn f3, vs3 -; CHECK-P8-NEXT: xscvspdpn f5, vs5 -; CHECK-P8-NEXT: xscvspdpn f6, vs6 -; CHECK-P8-NEXT: xscvspdpn f7, vs7 -; CHECK-P8-NEXT: xxmrghd vs0, vs1, vs0 -; CHECK-P8-NEXT: xxmrghd vs1, vs2, vs3 -; CHECK-P8-NEXT: xxmrghd vs2, vs6, vs5 +; CHECK-P8-NEXT: xxmrglw vs2, v3, v3 +; CHECK-P8-NEXT: xxmrghw vs3, v3, v3 +; CHECK-P8-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P8-NEXT: xxmrghw vs1, v2, v2 +; CHECK-P8-NEXT: xvcvspdp vs2, vs2 +; CHECK-P8-NEXT: xvcvspdp vs0, vs0 +; CHECK-P8-NEXT: xvcvspdp vs1, vs1 +; CHECK-P8-NEXT: xvcvspdp vs3, vs3 +; CHECK-P8-NEXT: xvcvdpuxds v4, vs2 ; CHECK-P8-NEXT: xvcvdpuxds v2, vs0 -; CHECK-P8-NEXT: xxmrghd vs3, vs4, vs7 ; CHECK-P8-NEXT: xvcvdpuxds v3, vs1 -; CHECK-P8-NEXT: xvcvdpuxds v4, vs2 ; CHECK-P8-NEXT: xvcvdpuxds v5, vs3 +; CHECK-P8-NEXT: xxswapd vs3, v4 ; CHECK-P8-NEXT: xxswapd vs1, v2 ; CHECK-P8-NEXT: xxswapd vs0, v3 -; CHECK-P8-NEXT: xxswapd vs3, v4 ; CHECK-P8-NEXT: xxswapd vs2, v5 ; CHECK-P8-NEXT: stxvd2x vs0, r3, r4 ; CHECK-P8-NEXT: stxvd2x vs1, r3, r6 @@ -149,65 +118,45 @@ define void @test8elt(<8 x i64>* noalias nocapture sret %agg.result, <8 x float> ; ; CHECK-P9-LABEL: test8elt: ; CHECK-P9: # %bb.0: # %entry -; CHECK-P9-NEXT: lxv vs0, 0(r4) -; CHECK-P9-NEXT: xxsldwi vs1, vs0, vs0, 3 -; CHECK-P9-NEXT: xxswapd vs2, vs0 -; CHECK-P9-NEXT: xscvspdpn f1, vs1 -; CHECK-P9-NEXT: xscvspdpn f2, vs2 -; CHECK-P9-NEXT: xscvspdpn f3, vs0 -; CHECK-P9-NEXT: xxsldwi vs0, vs0, vs0, 1 -; CHECK-P9-NEXT: xscvspdpn f0, vs0 -; CHECK-P9-NEXT: xxmrghd vs1, vs2, vs1 -; CHECK-P9-NEXT: lxv vs2, 16(r4) -; CHECK-P9-NEXT: xxmrghd vs0, vs3, vs0 +; CHECK-P9-NEXT: lxv vs0, 16(r4) +; CHECK-P9-NEXT: lxv vs1, 0(r4) +; CHECK-P9-NEXT: xxmrglw vs2, vs1, vs1 +; CHECK-P9-NEXT: xxmrghw vs1, vs1, vs1 +; CHECK-P9-NEXT: xxmrglw vs3, vs0, vs0 +; CHECK-P9-NEXT: xxmrghw vs0, vs0, vs0 +; CHECK-P9-NEXT: xvcvspdp vs2, vs2 +; CHECK-P9-NEXT: xvcvspdp vs1, vs1 +; CHECK-P9-NEXT: xvcvspdp vs3, vs3 +; CHECK-P9-NEXT: xvcvspdp vs0, vs0 +; CHECK-P9-NEXT: xvcvdpuxds vs2, vs2 ; CHECK-P9-NEXT: xvcvdpuxds vs1, vs1 -; CHECK-P9-NEXT: xvcvdpuxds vs0, vs0 -; CHECK-P9-NEXT: xxsldwi vs3, vs2, vs2, 3 -; CHECK-P9-NEXT: xxswapd vs4, vs2 -; CHECK-P9-NEXT: xscvspdpn f3, vs3 -; CHECK-P9-NEXT: xscvspdpn f4, vs4 -; CHECK-P9-NEXT: stxv vs0, 16(r3) -; CHECK-P9-NEXT: xxmrghd vs3, vs4, vs3 -; CHECK-P9-NEXT: xscvspdpn f4, vs2 -; CHECK-P9-NEXT: xxsldwi vs2, vs2, vs2, 1 -; CHECK-P9-NEXT: xscvspdpn f2, vs2 ; CHECK-P9-NEXT: xvcvdpuxds vs3, vs3 -; CHECK-P9-NEXT: xxmrghd vs2, vs4, vs2 -; CHECK-P9-NEXT: xvcvdpuxds vs2, vs2 +; CHECK-P9-NEXT: xvcvdpuxds vs0, vs0 +; CHECK-P9-NEXT: stxv vs0, 48(r3) ; CHECK-P9-NEXT: stxv vs3, 32(r3) -; CHECK-P9-NEXT: stxv vs2, 48(r3) -; CHECK-P9-NEXT: stxv vs1, 0(r3) +; CHECK-P9-NEXT: stxv vs1, 16(r3) +; CHECK-P9-NEXT: stxv vs2, 0(r3) ; CHECK-P9-NEXT: blr ; ; CHECK-BE-LABEL: test8elt: ; CHECK-BE: # %bb.0: # %entry -; CHECK-BE-NEXT: lxv vs1, 0(r4) -; CHECK-BE-NEXT: xxsldwi vs3, vs1, vs1, 1 -; CHECK-BE-NEXT: xscvspdpn f2, vs1 -; CHECK-BE-NEXT: xscvspdpn f3, vs3 ; CHECK-BE-NEXT: lxv vs0, 16(r4) -; CHECK-BE-NEXT: xxsldwi vs4, vs0, vs0, 1 -; CHECK-BE-NEXT: xscvspdpn f4, vs4 -; CHECK-BE-NEXT: xxmrghd vs2, vs2, vs3 -; CHECK-BE-NEXT: xxsldwi vs3, vs1, vs1, 3 -; CHECK-BE-NEXT: xxswapd vs1, vs1 -; CHECK-BE-NEXT: xscvspdpn f3, vs3 -; CHECK-BE-NEXT: xscvspdpn f1, vs1 -; CHECK-BE-NEXT: xxmrghd vs1, vs1, vs3 -; CHECK-BE-NEXT: xscvspdpn f3, vs0 -; CHECK-BE-NEXT: xxmrghd vs3, vs3, vs4 -; CHECK-BE-NEXT: xxsldwi vs4, vs0, vs0, 3 -; CHECK-BE-NEXT: xxswapd vs0, vs0 -; CHECK-BE-NEXT: xscvspdpn f0, vs0 -; CHECK-BE-NEXT: xscvspdpn f4, vs4 -; CHECK-BE-NEXT: xxmrghd vs0, vs0, vs4 +; CHECK-BE-NEXT: lxv vs1, 0(r4) +; CHECK-BE-NEXT: xxmrghw vs2, vs1, vs1 +; CHECK-BE-NEXT: xxmrglw vs1, vs1, vs1 +; CHECK-BE-NEXT: xxmrghw vs3, vs0, vs0 +; CHECK-BE-NEXT: xxmrglw vs0, vs0, vs0 +; CHECK-BE-NEXT: xvcvspdp vs2, vs2 +; CHECK-BE-NEXT: xvcvspdp vs1, vs1 +; CHECK-BE-NEXT: xvcvspdp vs3, vs3 +; CHECK-BE-NEXT: xvcvspdp vs0, vs0 ; CHECK-BE-NEXT: xvcvdpuxds vs2, vs2 ; CHECK-BE-NEXT: xvcvdpuxds vs1, vs1 ; CHECK-BE-NEXT: xvcvdpuxds vs3, vs3 -; CHECK-BE-NEXT: stxv vs1, 16(r3) ; CHECK-BE-NEXT: xvcvdpuxds vs0, vs0 -; CHECK-BE-NEXT: stxv vs3, 32(r3) ; CHECK-BE-NEXT: stxv vs0, 48(r3) +; CHECK-BE-NEXT: stxv vs3, 32(r3) +; CHECK-BE-NEXT: stxv vs1, 16(r3) ; CHECK-BE-NEXT: stxv vs2, 0(r3) ; CHECK-BE-NEXT: blr entry: @@ -220,70 +169,50 @@ entry: define void @test16elt(<16 x i64>* noalias nocapture sret %agg.result, <16 x float>* nocapture readonly) local_unnamed_addr #2 { ; CHECK-P8-LABEL: test16elt: ; CHECK-P8: # %bb.0: # %entry -; CHECK-P8-NEXT: li r5, 16 ; CHECK-P8-NEXT: li r7, 48 +; CHECK-P8-NEXT: li r5, 16 ; CHECK-P8-NEXT: li r6, 32 -; CHECK-P8-NEXT: lvx v4, 0, r4 ; CHECK-P8-NEXT: li r8, 64 -; CHECK-P8-NEXT: lvx v5, r4, r5 -; CHECK-P8-NEXT: lvx v3, r4, r7 -; CHECK-P8-NEXT: lvx v2, r4, r6 +; CHECK-P8-NEXT: lvx v4, r4, r7 +; CHECK-P8-NEXT: lvx v2, r4, r5 +; CHECK-P8-NEXT: lvx v3, r4, r6 +; CHECK-P8-NEXT: xxmrghw vs3, v4, v4 +; CHECK-P8-NEXT: xxmrglw vs5, v4, v4 +; CHECK-P8-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P8-NEXT: xxmrghw vs1, v2, v2 +; CHECK-P8-NEXT: lvx v2, 0, r4 ; CHECK-P8-NEXT: li r4, 112 -; CHECK-P8-NEXT: xxsldwi vs13, v4, v4, 3 -; CHECK-P8-NEXT: xscvspdpn f6, v4 -; CHECK-P8-NEXT: xxsldwi vs1, v5, v5, 3 -; CHECK-P8-NEXT: xxswapd vs3, v5 -; CHECK-P8-NEXT: xxsldwi vs9, v3, v3, 1 -; CHECK-P8-NEXT: xscvspdpn f4, v3 -; CHECK-P8-NEXT: xxsldwi vs5, v5, v5, 1 -; CHECK-P8-NEXT: xxsldwi vs10, v3, v3, 3 -; CHECK-P8-NEXT: xscvspdpn f1, vs1 -; CHECK-P8-NEXT: xxswapd vs11, v3 -; CHECK-P8-NEXT: xscvspdpn f3, vs3 -; CHECK-P8-NEXT: xxsldwi vs7, v2, v2, 3 -; CHECK-P8-NEXT: xscvspdpn f9, vs9 -; CHECK-P8-NEXT: xxswapd vs8, v2 -; CHECK-P8-NEXT: xscvspdpn f0, v5 -; CHECK-P8-NEXT: xxsldwi vs12, v2, v2, 1 -; CHECK-P8-NEXT: xscvspdpn f2, v2 -; CHECK-P8-NEXT: xxswapd v2, v4 -; CHECK-P8-NEXT: xscvspdpn f5, vs5 -; CHECK-P8-NEXT: xxsldwi v3, v4, v4, 1 -; CHECK-P8-NEXT: xscvspdpn f10, vs10 -; CHECK-P8-NEXT: xscvspdpn f11, vs11 -; CHECK-P8-NEXT: xxmrghd vs1, vs3, vs1 -; CHECK-P8-NEXT: xscvspdpn f7, vs7 -; CHECK-P8-NEXT: xxmrghd vs4, vs4, vs9 -; CHECK-P8-NEXT: xscvspdpn f8, vs8 -; CHECK-P8-NEXT: xscvspdpn f12, vs12 -; CHECK-P8-NEXT: xscvspdpn f13, vs13 -; CHECK-P8-NEXT: xxmrghd vs0, vs0, vs5 -; CHECK-P8-NEXT: xscvspdpn f3, v2 -; CHECK-P8-NEXT: xscvspdpn f9, v3 -; CHECK-P8-NEXT: xxmrghd vs5, vs11, vs10 -; CHECK-P8-NEXT: xvcvdpuxds v3, vs4 -; CHECK-P8-NEXT: xvcvdpuxds v2, vs1 -; CHECK-P8-NEXT: xxmrghd vs1, vs2, vs12 -; CHECK-P8-NEXT: xxmrghd vs2, vs8, vs7 -; CHECK-P8-NEXT: xvcvdpuxds v4, vs0 -; CHECK-P8-NEXT: xxmrghd vs0, vs3, vs13 +; CHECK-P8-NEXT: xxmrglw vs2, v3, v3 +; CHECK-P8-NEXT: xxmrghw vs4, v3, v3 +; CHECK-P8-NEXT: xvcvspdp vs3, vs3 +; CHECK-P8-NEXT: xxmrglw vs6, v2, v2 +; CHECK-P8-NEXT: xxmrghw vs7, v2, v2 +; CHECK-P8-NEXT: xvcvspdp vs5, vs5 +; CHECK-P8-NEXT: xvcvspdp vs0, vs0 +; CHECK-P8-NEXT: xvcvspdp vs1, vs1 +; CHECK-P8-NEXT: xvcvspdp vs2, vs2 +; CHECK-P8-NEXT: xvcvspdp vs4, vs4 +; CHECK-P8-NEXT: xvcvspdp vs6, vs6 +; CHECK-P8-NEXT: xvcvspdp vs7, vs7 +; CHECK-P8-NEXT: xvcvdpuxds v3, vs3 ; CHECK-P8-NEXT: xvcvdpuxds v5, vs5 -; CHECK-P8-NEXT: xxmrghd vs3, vs6, vs9 -; CHECK-P8-NEXT: xvcvdpuxds v0, vs1 +; CHECK-P8-NEXT: xvcvdpuxds v2, vs0 +; CHECK-P8-NEXT: xvcvdpuxds v4, vs1 +; CHECK-P8-NEXT: xvcvdpuxds v0, vs4 ; CHECK-P8-NEXT: xvcvdpuxds v1, vs2 -; CHECK-P8-NEXT: xvcvdpuxds v6, vs0 +; CHECK-P8-NEXT: xvcvdpuxds v6, vs6 ; CHECK-P8-NEXT: xxswapd vs0, v3 -; CHECK-P8-NEXT: xvcvdpuxds v7, vs3 -; CHECK-P8-NEXT: xxswapd vs4, v2 -; CHECK-P8-NEXT: xxswapd vs3, v4 +; CHECK-P8-NEXT: xvcvdpuxds v7, vs7 ; CHECK-P8-NEXT: xxswapd vs1, v5 +; CHECK-P8-NEXT: xxswapd vs4, v2 ; CHECK-P8-NEXT: stxvd2x vs0, r3, r4 ; CHECK-P8-NEXT: li r4, 96 +; CHECK-P8-NEXT: xxswapd vs3, v4 ; CHECK-P8-NEXT: xxswapd vs2, v0 -; CHECK-P8-NEXT: xxswapd vs0, v1 ; CHECK-P8-NEXT: stxvd2x vs1, r3, r4 -; CHECK-P8-NEXT: xxswapd vs5, v6 ; CHECK-P8-NEXT: li r4, 80 +; CHECK-P8-NEXT: xxswapd vs0, v1 +; CHECK-P8-NEXT: xxswapd vs5, v6 ; CHECK-P8-NEXT: xxswapd vs1, v7 ; CHECK-P8-NEXT: stxvd2x vs2, r3, r4 ; CHECK-P8-NEXT: stxvd2x vs0, r3, r8 @@ -295,122 +224,82 @@ define void @test16elt(<16 x i64>* noalias nocapture sret %agg.result, <16 x flo ; ; CHECK-P9-LABEL: test16elt: ; CHECK-P9: # %bb.0: # %entry -; CHECK-P9-NEXT: lxv vs4, 16(r4) -; CHECK-P9-NEXT: xxsldwi vs5, vs4, vs4, 3 -; CHECK-P9-NEXT: xxswapd vs6, vs4 -; CHECK-P9-NEXT: lxv vs0, 0(r4) -; CHECK-P9-NEXT: xxsldwi vs1, vs0, vs0, 3 -; CHECK-P9-NEXT: xxswapd vs2, vs0 -; CHECK-P9-NEXT: xscvspdpn f5, vs5 -; CHECK-P9-NEXT: xscvspdpn f6, vs6 -; CHECK-P9-NEXT: xxmrghd vs5, vs6, vs5 -; CHECK-P9-NEXT: xscvspdpn f6, vs4 -; CHECK-P9-NEXT: xxsldwi vs4, vs4, vs4, 1 -; CHECK-P9-NEXT: lxv vs3, 32(r4) -; CHECK-P9-NEXT: xscvspdpn f2, vs2 -; CHECK-P9-NEXT: xxswapd vs7, vs3 -; CHECK-P9-NEXT: xscvspdpn f7, vs7 -; CHECK-P9-NEXT: xscvspdpn f4, vs4 -; CHECK-P9-NEXT: xscvspdpn f1, vs1 -; CHECK-P9-NEXT: xxmrghd vs1, vs2, vs1 -; CHECK-P9-NEXT: xscvspdpn f2, vs0 -; CHECK-P9-NEXT: xxsldwi vs0, vs0, vs0, 1 -; CHECK-P9-NEXT: xscvspdpn f0, vs0 -; CHECK-P9-NEXT: xxmrghd vs0, vs2, vs0 -; CHECK-P9-NEXT: xxmrghd vs4, vs6, vs4 -; CHECK-P9-NEXT: xxsldwi vs6, vs3, vs3, 3 +; CHECK-P9-NEXT: lxv vs0, 48(r4) +; CHECK-P9-NEXT: lxv vs1, 0(r4) +; CHECK-P9-NEXT: lxv vs3, 16(r4) +; CHECK-P9-NEXT: lxv vs5, 32(r4) +; CHECK-P9-NEXT: xxmrglw vs2, vs1, vs1 +; CHECK-P9-NEXT: xxmrghw vs1, vs1, vs1 +; CHECK-P9-NEXT: xxmrglw vs4, vs3, vs3 +; CHECK-P9-NEXT: xxmrghw vs3, vs3, vs3 +; CHECK-P9-NEXT: xxmrglw vs6, vs5, vs5 +; CHECK-P9-NEXT: xxmrghw vs5, vs5, vs5 +; CHECK-P9-NEXT: xxmrglw vs7, vs0, vs0 +; CHECK-P9-NEXT: xxmrghw vs0, vs0, vs0 +; CHECK-P9-NEXT: xvcvspdp vs2, vs2 +; CHECK-P9-NEXT: xvcvspdp vs1, vs1 +; CHECK-P9-NEXT: xvcvspdp vs4, vs4 +; CHECK-P9-NEXT: xvcvspdp vs3, vs3 +; CHECK-P9-NEXT: xvcvspdp vs6, vs6 +; CHECK-P9-NEXT: xvcvspdp vs5, vs5 +; CHECK-P9-NEXT: xvcvspdp vs7, vs7 +; CHECK-P9-NEXT: xvcvspdp vs0, vs0 +; CHECK-P9-NEXT: xvcvdpuxds vs2, vs2 ; CHECK-P9-NEXT: xvcvdpuxds vs1, vs1 -; CHECK-P9-NEXT: xvcvdpuxds vs5, vs5 -; CHECK-P9-NEXT: xscvspdpn f6, vs6 -; CHECK-P9-NEXT: xxmrghd vs6, vs7, vs6 -; CHECK-P9-NEXT: xscvspdpn f7, vs3 -; CHECK-P9-NEXT: xxsldwi vs3, vs3, vs3, 1 -; CHECK-P9-NEXT: lxv vs2, 48(r4) -; CHECK-P9-NEXT: xxswapd vs8, vs2 -; CHECK-P9-NEXT: xscvspdpn f8, vs8 ; CHECK-P9-NEXT: xvcvdpuxds vs4, vs4 -; CHECK-P9-NEXT: xscvspdpn f3, vs3 -; CHECK-P9-NEXT: xxmrghd vs3, vs7, vs3 -; CHECK-P9-NEXT: xxsldwi vs7, vs2, vs2, 3 -; CHECK-P9-NEXT: xvcvdpuxds vs0, vs0 -; CHECK-P9-NEXT: xvcvdpuxds vs6, vs6 -; CHECK-P9-NEXT: stxv vs6, 64(r3) -; CHECK-P9-NEXT: xscvspdpn f7, vs7 -; CHECK-P9-NEXT: xxmrghd vs7, vs8, vs7 -; CHECK-P9-NEXT: xscvspdpn f8, vs2 -; CHECK-P9-NEXT: xxsldwi vs2, vs2, vs2, 1 -; CHECK-P9-NEXT: xscvspdpn f2, vs2 -; CHECK-P9-NEXT: xxmrghd vs2, vs8, vs2 ; CHECK-P9-NEXT: xvcvdpuxds vs3, vs3 +; CHECK-P9-NEXT: xvcvdpuxds vs6, vs6 +; CHECK-P9-NEXT: xvcvdpuxds vs5, vs5 ; CHECK-P9-NEXT: xvcvdpuxds vs7, vs7 -; CHECK-P9-NEXT: stxv vs3, 80(r3) -; CHECK-P9-NEXT: xvcvdpuxds vs2, vs2 +; CHECK-P9-NEXT: xvcvdpuxds vs0, vs0 +; CHECK-P9-NEXT: stxv vs0, 112(r3) ; CHECK-P9-NEXT: stxv vs7, 96(r3) -; CHECK-P9-NEXT: stxv vs2, 112(r3) -; CHECK-P9-NEXT: stxv vs4, 48(r3) -; CHECK-P9-NEXT: stxv vs5, 32(r3) -; CHECK-P9-NEXT: stxv vs0, 16(r3) -; CHECK-P9-NEXT: stxv vs1, 0(r3) +; CHECK-P9-NEXT: stxv vs5, 80(r3) +; CHECK-P9-NEXT: stxv vs6, 64(r3) +; CHECK-P9-NEXT: stxv vs3, 48(r3) +; CHECK-P9-NEXT: stxv vs4, 32(r3) +; CHECK-P9-NEXT: stxv vs1, 16(r3) +; CHECK-P9-NEXT: stxv vs2, 0(r3) ; CHECK-P9-NEXT: blr ; ; CHECK-BE-LABEL: test16elt: ; CHECK-BE: # %bb.0: # %entry -; CHECK-BE-NEXT: lxv vs0, 0(r4) -; CHECK-BE-NEXT: lxv vs4, 16(r4) -; CHECK-BE-NEXT: xxsldwi vs2, vs0, vs0, 1 -; CHECK-BE-NEXT: xscvspdpn f1, vs0 -; CHECK-BE-NEXT: xxsldwi vs5, vs0, vs0, 3 -; CHECK-BE-NEXT: xxswapd vs0, vs0 -; CHECK-BE-NEXT: xscvspdpn f5, vs5 -; CHECK-BE-NEXT: xscvspdpn f0, vs0 -; CHECK-BE-NEXT: xxsldwi vs6, vs4, vs4, 1 -; CHECK-BE-NEXT: xscvspdpn f6, vs6 -; CHECK-BE-NEXT: xxmrghd vs0, vs0, vs5 -; CHECK-BE-NEXT: xscvspdpn f5, vs4 -; CHECK-BE-NEXT: lxv vs3, 32(r4) -; CHECK-BE-NEXT: xxsldwi vs7, vs3, vs3, 1 -; CHECK-BE-NEXT: xscvspdpn f7, vs7 -; CHECK-BE-NEXT: xxmrghd vs5, vs5, vs6 -; CHECK-BE-NEXT: xxsldwi vs6, vs4, vs4, 3 -; CHECK-BE-NEXT: xxswapd vs4, vs4 -; CHECK-BE-NEXT: xscvspdpn f6, vs6 -; CHECK-BE-NEXT: xscvspdpn f4, vs4 -; CHECK-BE-NEXT: xscvspdpn f2, vs2 -; CHECK-BE-NEXT: xxmrghd vs1, vs1, vs2 -; CHECK-BE-NEXT: lxv vs2, 48(r4) -; CHECK-BE-NEXT: xxsldwi vs8, vs2, vs2, 1 +; CHECK-BE-NEXT: lxv vs0, 48(r4) +; CHECK-BE-NEXT: lxv vs1, 0(r4) +; CHECK-BE-NEXT: lxv vs3, 16(r4) +; CHECK-BE-NEXT: lxv vs5, 32(r4) +; CHECK-BE-NEXT: xxmrghw vs2, vs1, vs1 +; CHECK-BE-NEXT: xxmrglw vs1, vs1, vs1 +; CHECK-BE-NEXT: xxmrghw vs4, vs3, vs3 +; CHECK-BE-NEXT: xxmrglw vs3, vs3, vs3 +; CHECK-BE-NEXT: xxmrghw vs6, vs5, vs5 +; CHECK-BE-NEXT: xxmrglw vs5, vs5, vs5 +; CHECK-BE-NEXT: xxmrghw vs7, vs0, vs0 +; CHECK-BE-NEXT: xxmrglw vs0, vs0, vs0 +; CHECK-BE-NEXT: xvcvspdp vs2, vs2 +; CHECK-BE-NEXT: xvcvspdp vs1, vs1 +; CHECK-BE-NEXT: xvcvspdp vs4, vs4 +; CHECK-BE-NEXT: xvcvspdp vs3, vs3 +; CHECK-BE-NEXT: xvcvspdp vs6, vs6 +; CHECK-BE-NEXT: xvcvspdp vs5, vs5 +; CHECK-BE-NEXT: xvcvspdp vs7, vs7 +; CHECK-BE-NEXT: xvcvspdp vs0, vs0 +; CHECK-BE-NEXT: xvcvdpuxds vs2, vs2 ; CHECK-BE-NEXT: xvcvdpuxds vs1, vs1 -; CHECK-BE-NEXT: xvcvdpuxds vs0, vs0 -; CHECK-BE-NEXT: xvcvdpuxds vs5, vs5 -; CHECK-BE-NEXT: xscvspdpn f8, vs8 -; CHECK-BE-NEXT: xxmrghd vs4, vs4, vs6 -; CHECK-BE-NEXT: xscvspdpn f6, vs3 -; CHECK-BE-NEXT: stxv vs0, 16(r3) -; CHECK-BE-NEXT: xxmrghd vs6, vs6, vs7 -; CHECK-BE-NEXT: xxsldwi vs7, vs3, vs3, 3 -; CHECK-BE-NEXT: xxswapd vs3, vs3 -; CHECK-BE-NEXT: xscvspdpn f7, vs7 -; CHECK-BE-NEXT: xscvspdpn f3, vs3 -; CHECK-BE-NEXT: xxmrghd vs3, vs3, vs7 -; CHECK-BE-NEXT: xscvspdpn f7, vs2 -; CHECK-BE-NEXT: xxmrghd vs7, vs7, vs8 -; CHECK-BE-NEXT: xxsldwi vs8, vs2, vs2, 3 -; CHECK-BE-NEXT: xxswapd vs2, vs2 -; CHECK-BE-NEXT: xscvspdpn f8, vs8 -; CHECK-BE-NEXT: xscvspdpn f2, vs2 -; CHECK-BE-NEXT: xxmrghd vs2, vs2, vs8 -; CHECK-BE-NEXT: stxv vs5, 32(r3) ; CHECK-BE-NEXT: xvcvdpuxds vs4, vs4 -; CHECK-BE-NEXT: xvcvdpuxds vs6, vs6 ; CHECK-BE-NEXT: xvcvdpuxds vs3, vs3 +; CHECK-BE-NEXT: xvcvdpuxds vs6, vs6 +; CHECK-BE-NEXT: xvcvdpuxds vs5, vs5 ; CHECK-BE-NEXT: xvcvdpuxds vs7, vs7 -; CHECK-BE-NEXT: stxv vs3, 80(r3) +; CHECK-BE-NEXT: xvcvdpuxds vs0, vs0 +; CHECK-BE-NEXT: stxv vs0, 112(r3) ; CHECK-BE-NEXT: stxv vs7, 96(r3) -; CHECK-BE-NEXT: xvcvdpuxds vs2, vs2 -; CHECK-BE-NEXT: stxv vs2, 112(r3) +; CHECK-BE-NEXT: stxv vs5, 80(r3) ; CHECK-BE-NEXT: stxv vs6, 64(r3) -; CHECK-BE-NEXT: stxv vs4, 48(r3) -; CHECK-BE-NEXT: stxv vs1, 0(r3) +; CHECK-BE-NEXT: stxv vs3, 48(r3) +; CHECK-BE-NEXT: stxv vs4, 32(r3) +; CHECK-BE-NEXT: stxv vs1, 16(r3) +; CHECK-BE-NEXT: stxv vs2, 0(r3) ; CHECK-BE-NEXT: blr entry: %a = load <16 x float>, <16 x float>* %0, align 64 @@ -424,10 +313,8 @@ define <2 x i64> @test2elt_signed(i64 %a.coerce) local_unnamed_addr #0 { ; CHECK-P8: # %bb.0: # %entry ; CHECK-P8-NEXT: mtvsrd f0, r3 ; CHECK-P8-NEXT: xxswapd v2, vs0 -; CHECK-P8-NEXT: xscvspdpn f0, vs0 -; CHECK-P8-NEXT: xxsldwi vs1, v2, v2, 3 -; CHECK-P8-NEXT: xscvspdpn f1, vs1 -; CHECK-P8-NEXT: xxmrghd vs0, vs0, vs1 +; CHECK-P8-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P8-NEXT: xvcvspdp vs0, vs0 ; CHECK-P8-NEXT: xvcvdpuxds v2, vs0 ; CHECK-P8-NEXT: blr ; @@ -435,20 +322,16 @@ define <2 x i64> @test2elt_signed(i64 %a.coerce) local_unnamed_addr #0 { ; CHECK-P9: # %bb.0: # %entry ; CHECK-P9-NEXT: mtvsrd f0, r3 ; CHECK-P9-NEXT: xxswapd v2, vs0 -; CHECK-P9-NEXT: xscvspdpn f0, vs0 -; CHECK-P9-NEXT: xxsldwi vs1, v2, v2, 3 -; CHECK-P9-NEXT: xscvspdpn f1, vs1 -; CHECK-P9-NEXT: xxmrghd vs0, vs0, vs1 +; CHECK-P9-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P9-NEXT: xvcvspdp vs0, vs0 ; CHECK-P9-NEXT: xvcvdpuxds v2, vs0 ; CHECK-P9-NEXT: blr ; ; CHECK-BE-LABEL: test2elt_signed: ; CHECK-BE: # %bb.0: # %entry ; CHECK-BE-NEXT: mtvsrd f0, r3 -; CHECK-BE-NEXT: xscvspdpn f1, vs0 -; CHECK-BE-NEXT: xxsldwi vs0, vs0, vs0, 1 -; CHECK-BE-NEXT: xscvspdpn f0, vs0 -; CHECK-BE-NEXT: xxmrghd vs0, vs1, vs0 +; CHECK-BE-NEXT: xxmrghw vs0, vs0, vs0 +; CHECK-BE-NEXT: xvcvspdp vs0, vs0 ; CHECK-BE-NEXT: xvcvdpuxds v2, vs0 ; CHECK-BE-NEXT: blr entry: @@ -460,16 +343,11 @@ entry: define void @test4elt_signed(<4 x i64>* noalias nocapture sret %agg.result, <4 x float> %a) local_unnamed_addr #1 { ; CHECK-P8-LABEL: test4elt_signed: ; CHECK-P8: # %bb.0: # %entry -; CHECK-P8-NEXT: xxsldwi vs0, v2, v2, 3 -; CHECK-P8-NEXT: xxswapd vs1, v2 +; CHECK-P8-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P8-NEXT: xxmrghw vs1, v2, v2 ; CHECK-P8-NEXT: li r4, 16 -; CHECK-P8-NEXT: xxsldwi vs3, v2, v2, 1 -; CHECK-P8-NEXT: xscvspdpn f2, v2 -; CHECK-P8-NEXT: xscvspdpn f0, vs0 -; CHECK-P8-NEXT: xscvspdpn f1, vs1 -; CHECK-P8-NEXT: xscvspdpn f3, vs3 -; CHECK-P8-NEXT: xxmrghd vs0, vs1, vs0 -; CHECK-P8-NEXT: xxmrghd vs1, vs2, vs3 +; CHECK-P8-NEXT: xvcvspdp vs0, vs0 +; CHECK-P8-NEXT: xvcvspdp vs1, vs1 ; CHECK-P8-NEXT: xvcvdpuxds v2, vs0 ; CHECK-P8-NEXT: xvcvdpuxds v3, vs1 ; CHECK-P8-NEXT: xxswapd vs1, v2 @@ -480,36 +358,26 @@ define void @test4elt_signed(<4 x i64>* noalias nocapture sret %agg.result, <4 x ; ; CHECK-P9-LABEL: test4elt_signed: ; CHECK-P9: # %bb.0: # %entry -; CHECK-P9-NEXT: xxsldwi vs0, v2, v2, 3 -; CHECK-P9-NEXT: xxswapd vs1, v2 -; CHECK-P9-NEXT: xscvspdpn f0, vs0 -; CHECK-P9-NEXT: xscvspdpn f1, vs1 -; CHECK-P9-NEXT: xxsldwi vs2, v2, v2, 1 -; CHECK-P9-NEXT: xscvspdpn f2, vs2 -; CHECK-P9-NEXT: xxmrghd vs0, vs1, vs0 -; CHECK-P9-NEXT: xscvspdpn f1, v2 -; CHECK-P9-NEXT: xxmrghd vs1, vs1, vs2 +; CHECK-P9-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P9-NEXT: xxmrghw vs1, v2, v2 +; CHECK-P9-NEXT: xvcvspdp vs0, vs0 +; CHECK-P9-NEXT: xvcvspdp vs1, vs1 ; CHECK-P9-NEXT: xvcvdpuxds vs0, vs0 ; CHECK-P9-NEXT: xvcvdpuxds vs1, vs1 -; CHECK-P9-NEXT: stxv vs0, 0(r3) ; CHECK-P9-NEXT: stxv vs1, 16(r3) +; CHECK-P9-NEXT: stxv vs0, 0(r3) ; CHECK-P9-NEXT: blr ; ; CHECK-BE-LABEL: test4elt_signed: ; CHECK-BE: # %bb.0: # %entry -; CHECK-BE-NEXT: xxsldwi vs1, v2, v2, 1 -; CHECK-BE-NEXT: xscvspdpn f0, v2 -; CHECK-BE-NEXT: xxswapd vs2, v2 -; CHECK-BE-NEXT: xscvspdpn f1, vs1 -; CHECK-BE-NEXT: xxmrghd vs0, vs0, vs1 -; CHECK-BE-NEXT: xxsldwi vs1, v2, v2, 3 -; CHECK-BE-NEXT: xscvspdpn f1, vs1 -; CHECK-BE-NEXT: xscvspdpn f2, vs2 +; CHECK-BE-NEXT: xxmrghw vs0, v2, v2 +; CHECK-BE-NEXT: xxmrglw vs1, v2, v2 +; CHECK-BE-NEXT: xvcvspdp vs0, vs0 +; CHECK-BE-NEXT: xvcvspdp vs1, vs1 ; CHECK-BE-NEXT: xvcvdpuxds vs0, vs0 -; CHECK-BE-NEXT: xxmrghd vs1, vs2, vs1 ; CHECK-BE-NEXT: xvcvdpuxds vs1, vs1 -; CHECK-BE-NEXT: stxv vs0, 0(r3) ; CHECK-BE-NEXT: stxv vs1, 16(r3) +; CHECK-BE-NEXT: stxv vs0, 0(r3) ; CHECK-BE-NEXT: blr entry: %0 = fptoui <4 x float> %a to <4 x i64> @@ -525,31 +393,21 @@ define void @test8elt_signed(<8 x i64>* noalias nocapture sret %agg.result, <8 x ; CHECK-P8-NEXT: li r6, 32 ; CHECK-P8-NEXT: lvx v2, r4, r5 ; CHECK-P8-NEXT: li r4, 48 -; CHECK-P8-NEXT: xxsldwi vs5, v3, v3, 3 -; CHECK-P8-NEXT: xxswapd vs6, v3 -; CHECK-P8-NEXT: xxsldwi vs0, v2, v2, 3 -; CHECK-P8-NEXT: xxswapd vs1, v2 -; CHECK-P8-NEXT: xxsldwi vs3, v2, v2, 1 -; CHECK-P8-NEXT: xxsldwi vs7, v3, v3, 1 -; CHECK-P8-NEXT: xscvspdpn f2, v2 -; CHECK-P8-NEXT: xscvspdpn f4, v3 -; CHECK-P8-NEXT: xscvspdpn f0, vs0 -; CHECK-P8-NEXT: xscvspdpn f1, vs1 -; CHECK-P8-NEXT: xscvspdpn f3, vs3 -; CHECK-P8-NEXT: xscvspdpn f5, vs5 -; CHECK-P8-NEXT: xscvspdpn f6, vs6 -; CHECK-P8-NEXT: xscvspdpn f7, vs7 -; CHECK-P8-NEXT: xxmrghd vs0, vs1, vs0 -; CHECK-P8-NEXT: xxmrghd vs1, vs2, vs3 -; CHECK-P8-NEXT: xxmrghd vs2, vs6, vs5 +; CHECK-P8-NEXT: xxmrglw vs2, v3, v3 +; CHECK-P8-NEXT: xxmrghw vs3, v3, v3 +; CHECK-P8-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P8-NEXT: xxmrghw vs1, v2, v2 +; CHECK-P8-NEXT: xvcvspdp vs2, vs2 +; CHECK-P8-NEXT: xvcvspdp vs0, vs0 +; CHECK-P8-NEXT: xvcvspdp vs1, vs1 +; CHECK-P8-NEXT: xvcvspdp vs3, vs3 +; CHECK-P8-NEXT: xvcvdpuxds v4, vs2 ; CHECK-P8-NEXT: xvcvdpuxds v2, vs0 -; CHECK-P8-NEXT: xxmrghd vs3, vs4, vs7 ; CHECK-P8-NEXT: xvcvdpuxds v3, vs1 -; CHECK-P8-NEXT: xvcvdpuxds v4, vs2 ; CHECK-P8-NEXT: xvcvdpuxds v5, vs3 +; CHECK-P8-NEXT: xxswapd vs3, v4 ; CHECK-P8-NEXT: xxswapd vs1, v2 ; CHECK-P8-NEXT: xxswapd vs0, v3 -; CHECK-P8-NEXT: xxswapd vs3, v4 ; CHECK-P8-NEXT: xxswapd vs2, v5 ; CHECK-P8-NEXT: stxvd2x vs0, r3, r4 ; CHECK-P8-NEXT: stxvd2x vs1, r3, r6 @@ -559,65 +417,45 @@ define void @test8elt_signed(<8 x i64>* noalias nocapture sret %agg.result, <8 x ; ; CHECK-P9-LABEL: test8elt_signed: ; CHECK-P9: # %bb.0: # %entry -; CHECK-P9-NEXT: lxv vs0, 0(r4) -; CHECK-P9-NEXT: xxsldwi vs1, vs0, vs0, 3 -; CHECK-P9-NEXT: xxswapd vs2, vs0 -; CHECK-P9-NEXT: xscvspdpn f1, vs1 -; CHECK-P9-NEXT: xscvspdpn f2, vs2 -; CHECK-P9-NEXT: xscvspdpn f3, vs0 -; CHECK-P9-NEXT: xxsldwi vs0, vs0, vs0, 1 -; CHECK-P9-NEXT: xscvspdpn f0, vs0 -; CHECK-P9-NEXT: xxmrghd vs1, vs2, vs1 -; CHECK-P9-NEXT: lxv vs2, 16(r4) -; CHECK-P9-NEXT: xxmrghd vs0, vs3, vs0 +; CHECK-P9-NEXT: lxv vs0, 16(r4) +; CHECK-P9-NEXT: lxv vs1, 0(r4) +; CHECK-P9-NEXT: xxmrglw vs2, vs1, vs1 +; CHECK-P9-NEXT: xxmrghw vs1, vs1, vs1 +; CHECK-P9-NEXT: xxmrglw vs3, vs0, vs0 +; CHECK-P9-NEXT: xxmrghw vs0, vs0, vs0 +; CHECK-P9-NEXT: xvcvspdp vs2, vs2 +; CHECK-P9-NEXT: xvcvspdp vs1, vs1 +; CHECK-P9-NEXT: xvcvspdp vs3, vs3 +; CHECK-P9-NEXT: xvcvspdp vs0, vs0 +; CHECK-P9-NEXT: xvcvdpuxds vs2, vs2 ; CHECK-P9-NEXT: xvcvdpuxds vs1, vs1 -; CHECK-P9-NEXT: xvcvdpuxds vs0, vs0 -; CHECK-P9-NEXT: xxsldwi vs3, vs2, vs2, 3 -; CHECK-P9-NEXT: xxswapd vs4, vs2 -; CHECK-P9-NEXT: xscvspdpn f3, vs3 -; CHECK-P9-NEXT: xscvspdpn f4, vs4 -; CHECK-P9-NEXT: stxv vs0, 16(r3) -; CHECK-P9-NEXT: xxmrghd vs3, vs4, vs3 -; CHECK-P9-NEXT: xscvspdpn f4, vs2 -; CHECK-P9-NEXT: xxsldwi vs2, vs2, vs2, 1 -; CHECK-P9-NEXT: xscvspdpn f2, vs2 ; CHECK-P9-NEXT: xvcvdpuxds vs3, vs3 -; CHECK-P9-NEXT: xxmrghd vs2, vs4, vs2 -; CHECK-P9-NEXT: xvcvdpuxds vs2, vs2 +; CHECK-P9-NEXT: xvcvdpuxds vs0, vs0 +; CHECK-P9-NEXT: stxv vs0, 48(r3) ; CHECK-P9-NEXT: stxv vs3, 32(r3) -; CHECK-P9-NEXT: stxv vs2, 48(r3) -; CHECK-P9-NEXT: stxv vs1, 0(r3) +; CHECK-P9-NEXT: stxv vs1, 16(r3) +; CHECK-P9-NEXT: stxv vs2, 0(r3) ; CHECK-P9-NEXT: blr ; ; CHECK-BE-LABEL: test8elt_signed: ; CHECK-BE: # %bb.0: # %entry -; CHECK-BE-NEXT: lxv vs1, 0(r4) -; CHECK-BE-NEXT: xxsldwi vs3, vs1, vs1, 1 -; CHECK-BE-NEXT: xscvspdpn f2, vs1 -; CHECK-BE-NEXT: xscvspdpn f3, vs3 ; CHECK-BE-NEXT: lxv vs0, 16(r4) -; CHECK-BE-NEXT: xxsldwi vs4, vs0, vs0, 1 -; CHECK-BE-NEXT: xscvspdpn f4, vs4 -; CHECK-BE-NEXT: xxmrghd vs2, vs2, vs3 -; CHECK-BE-NEXT: xxsldwi vs3, vs1, vs1, 3 -; CHECK-BE-NEXT: xxswapd vs1, vs1 -; CHECK-BE-NEXT: xscvspdpn f3, vs3 -; CHECK-BE-NEXT: xscvspdpn f1, vs1 -; CHECK-BE-NEXT: xxmrghd vs1, vs1, vs3 -; CHECK-BE-NEXT: xscvspdpn f3, vs0 -; CHECK-BE-NEXT: xxmrghd vs3, vs3, vs4 -; CHECK-BE-NEXT: xxsldwi vs4, vs0, vs0, 3 -; CHECK-BE-NEXT: xxswapd vs0, vs0 -; CHECK-BE-NEXT: xscvspdpn f0, vs0 -; CHECK-BE-NEXT: xscvspdpn f4, vs4 -; CHECK-BE-NEXT: xxmrghd vs0, vs0, vs4 +; CHECK-BE-NEXT: lxv vs1, 0(r4) +; CHECK-BE-NEXT: xxmrghw vs2, vs1, vs1 +; CHECK-BE-NEXT: xxmrglw vs1, vs1, vs1 +; CHECK-BE-NEXT: xxmrghw vs3, vs0, vs0 +; CHECK-BE-NEXT: xxmrglw vs0, vs0, vs0 +; CHECK-BE-NEXT: xvcvspdp vs2, vs2 +; CHECK-BE-NEXT: xvcvspdp vs1, vs1 +; CHECK-BE-NEXT: xvcvspdp vs3, vs3 +; CHECK-BE-NEXT: xvcvspdp vs0, vs0 ; CHECK-BE-NEXT: xvcvdpuxds vs2, vs2 ; CHECK-BE-NEXT: xvcvdpuxds vs1, vs1 ; CHECK-BE-NEXT: xvcvdpuxds vs3, vs3 -; CHECK-BE-NEXT: stxv vs1, 16(r3) ; CHECK-BE-NEXT: xvcvdpuxds vs0, vs0 -; CHECK-BE-NEXT: stxv vs3, 32(r3) ; CHECK-BE-NEXT: stxv vs0, 48(r3) +; CHECK-BE-NEXT: stxv vs3, 32(r3) +; CHECK-BE-NEXT: stxv vs1, 16(r3) ; CHECK-BE-NEXT: stxv vs2, 0(r3) ; CHECK-BE-NEXT: blr entry: @@ -630,70 +468,50 @@ entry: define void @test16elt_signed(<16 x i64>* noalias nocapture sret %agg.result, <16 x float>* nocapture readonly) local_unnamed_addr #2 { ; CHECK-P8-LABEL: test16elt_signed: ; CHECK-P8: # %bb.0: # %entry -; CHECK-P8-NEXT: li r5, 16 ; CHECK-P8-NEXT: li r7, 48 +; CHECK-P8-NEXT: li r5, 16 ; CHECK-P8-NEXT: li r6, 32 -; CHECK-P8-NEXT: lvx v4, 0, r4 ; CHECK-P8-NEXT: li r8, 64 -; CHECK-P8-NEXT: lvx v5, r4, r5 -; CHECK-P8-NEXT: lvx v3, r4, r7 -; CHECK-P8-NEXT: lvx v2, r4, r6 +; CHECK-P8-NEXT: lvx v4, r4, r7 +; CHECK-P8-NEXT: lvx v2, r4, r5 +; CHECK-P8-NEXT: lvx v3, r4, r6 +; CHECK-P8-NEXT: xxmrghw vs3, v4, v4 +; CHECK-P8-NEXT: xxmrglw vs5, v4, v4 +; CHECK-P8-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P8-NEXT: xxmrghw vs1, v2, v2 +; CHECK-P8-NEXT: lvx v2, 0, r4 ; CHECK-P8-NEXT: li r4, 112 -; CHECK-P8-NEXT: xxsldwi vs13, v4, v4, 3 -; CHECK-P8-NEXT: xscvspdpn f6, v4 -; CHECK-P8-NEXT: xxsldwi vs1, v5, v5, 3 -; CHECK-P8-NEXT: xxswapd vs3, v5 -; CHECK-P8-NEXT: xxsldwi vs9, v3, v3, 1 -; CHECK-P8-NEXT: xscvspdpn f4, v3 -; CHECK-P8-NEXT: xxsldwi vs5, v5, v5, 1 -; CHECK-P8-NEXT: xxsldwi vs10, v3, v3, 3 -; CHECK-P8-NEXT: xscvspdpn f1, vs1 -; CHECK-P8-NEXT: xxswapd vs11, v3 -; CHECK-P8-NEXT: xscvspdpn f3, vs3 -; CHECK-P8-NEXT: xxsldwi vs7, v2, v2, 3 -; CHECK-P8-NEXT: xscvspdpn f9, vs9 -; CHECK-P8-NEXT: xxswapd vs8, v2 -; CHECK-P8-NEXT: xscvspdpn f0, v5 -; CHECK-P8-NEXT: xxsldwi vs12, v2, v2, 1 -; CHECK-P8-NEXT: xscvspdpn f2, v2 -; CHECK-P8-NEXT: xxswapd v2, v4 -; CHECK-P8-NEXT: xscvspdpn f5, vs5 -; CHECK-P8-NEXT: xxsldwi v3, v4, v4, 1 -; CHECK-P8-NEXT: xscvspdpn f10, vs10 -; CHECK-P8-NEXT: xscvspdpn f11, vs11 -; CHECK-P8-NEXT: xxmrghd vs1, vs3, vs1 -; CHECK-P8-NEXT: xscvspdpn f7, vs7 -; CHECK-P8-NEXT: xxmrghd vs4, vs4, vs9 -; CHECK-P8-NEXT: xscvspdpn f8, vs8 -; CHECK-P8-NEXT: xscvspdpn f12, vs12 -; CHECK-P8-NEXT: xscvspdpn f13, vs13 -; CHECK-P8-NEXT: xxmrghd vs0, vs0, vs5 -; CHECK-P8-NEXT: xscvspdpn f3, v2 -; CHECK-P8-NEXT: xscvspdpn f9, v3 -; CHECK-P8-NEXT: xxmrghd vs5, vs11, vs10 -; CHECK-P8-NEXT: xvcvdpuxds v3, vs4 -; CHECK-P8-NEXT: xvcvdpuxds v2, vs1 -; CHECK-P8-NEXT: xxmrghd vs1, vs2, vs12 -; CHECK-P8-NEXT: xxmrghd vs2, vs8, vs7 -; CHECK-P8-NEXT: xvcvdpuxds v4, vs0 -; CHECK-P8-NEXT: xxmrghd vs0, vs3, vs13 +; CHECK-P8-NEXT: xxmrglw vs2, v3, v3 +; CHECK-P8-NEXT: xxmrghw vs4, v3, v3 +; CHECK-P8-NEXT: xvcvspdp vs3, vs3 +; CHECK-P8-NEXT: xxmrglw vs6, v2, v2 +; CHECK-P8-NEXT: xxmrghw vs7, v2, v2 +; CHECK-P8-NEXT: xvcvspdp vs5, vs5 +; CHECK-P8-NEXT: xvcvspdp vs0, vs0 +; CHECK-P8-NEXT: xvcvspdp vs1, vs1 +; CHECK-P8-NEXT: xvcvspdp vs2, vs2 +; CHECK-P8-NEXT: xvcvspdp vs4, vs4 +; CHECK-P8-NEXT: xvcvspdp vs6, vs6 +; CHECK-P8-NEXT: xvcvspdp vs7, vs7 +; CHECK-P8-NEXT: xvcvdpuxds v3, vs3 ; CHECK-P8-NEXT: xvcvdpuxds v5, vs5 -; CHECK-P8-NEXT: xxmrghd vs3, vs6, vs9 -; CHECK-P8-NEXT: xvcvdpuxds v0, vs1 +; CHECK-P8-NEXT: xvcvdpuxds v2, vs0 +; CHECK-P8-NEXT: xvcvdpuxds v4, vs1 +; CHECK-P8-NEXT: xvcvdpuxds v0, vs4 ; CHECK-P8-NEXT: xvcvdpuxds v1, vs2 -; CHECK-P8-NEXT: xvcvdpuxds v6, vs0 +; CHECK-P8-NEXT: xvcvdpuxds v6, vs6 ; CHECK-P8-NEXT: xxswapd vs0, v3 -; CHECK-P8-NEXT: xvcvdpuxds v7, vs3 -; CHECK-P8-NEXT: xxswapd vs4, v2 -; CHECK-P8-NEXT: xxswapd vs3, v4 +; CHECK-P8-NEXT: xvcvdpuxds v7, vs7 ; CHECK-P8-NEXT: xxswapd vs1, v5 +; CHECK-P8-NEXT: xxswapd vs4, v2 ; CHECK-P8-NEXT: stxvd2x vs0, r3, r4 ; CHECK-P8-NEXT: li r4, 96 +; CHECK-P8-NEXT: xxswapd vs3, v4 ; CHECK-P8-NEXT: xxswapd vs2, v0 -; CHECK-P8-NEXT: xxswapd vs0, v1 ; CHECK-P8-NEXT: stxvd2x vs1, r3, r4 -; CHECK-P8-NEXT: xxswapd vs5, v6 ; CHECK-P8-NEXT: li r4, 80 +; CHECK-P8-NEXT: xxswapd vs0, v1 +; CHECK-P8-NEXT: xxswapd vs5, v6 ; CHECK-P8-NEXT: xxswapd vs1, v7 ; CHECK-P8-NEXT: stxvd2x vs2, r3, r4 ; CHECK-P8-NEXT: stxvd2x vs0, r3, r8 @@ -705,122 +523,82 @@ define void @test16elt_signed(<16 x i64>* noalias nocapture sret %agg.result, <1 ; ; CHECK-P9-LABEL: test16elt_signed: ; CHECK-P9: # %bb.0: # %entry -; CHECK-P9-NEXT: lxv vs4, 16(r4) -; CHECK-P9-NEXT: xxsldwi vs5, vs4, vs4, 3 -; CHECK-P9-NEXT: xxswapd vs6, vs4 -; CHECK-P9-NEXT: lxv vs0, 0(r4) -; CHECK-P9-NEXT: xxsldwi vs1, vs0, vs0, 3 -; CHECK-P9-NEXT: xxswapd vs2, vs0 -; CHECK-P9-NEXT: xscvspdpn f5, vs5 -; CHECK-P9-NEXT: xscvspdpn f6, vs6 -; CHECK-P9-NEXT: xxmrghd vs5, vs6, vs5 -; CHECK-P9-NEXT: xscvspdpn f6, vs4 -; CHECK-P9-NEXT: xxsldwi vs4, vs4, vs4, 1 -; CHECK-P9-NEXT: lxv vs3, 32(r4) -; CHECK-P9-NEXT: xscvspdpn f2, vs2 -; CHECK-P9-NEXT: xxswapd vs7, vs3 -; CHECK-P9-NEXT: xscvspdpn f7, vs7 -; CHECK-P9-NEXT: xscvspdpn f4, vs4 -; CHECK-P9-NEXT: xscvspdpn f1, vs1 -; CHECK-P9-NEXT: xxmrghd vs1, vs2, vs1 -; CHECK-P9-NEXT: xscvspdpn f2, vs0 -; CHECK-P9-NEXT: xxsldwi vs0, vs0, vs0, 1 -; CHECK-P9-NEXT: xscvspdpn f0, vs0 -; CHECK-P9-NEXT: xxmrghd vs0, vs2, vs0 -; CHECK-P9-NEXT: xxmrghd vs4, vs6, vs4 -; CHECK-P9-NEXT: xxsldwi vs6, vs3, vs3, 3 +; CHECK-P9-NEXT: lxv vs0, 48(r4) +; CHECK-P9-NEXT: lxv vs1, 0(r4) +; CHECK-P9-NEXT: lxv vs3, 16(r4) +; CHECK-P9-NEXT: lxv vs5, 32(r4) +; CHECK-P9-NEXT: xxmrglw vs2, vs1, vs1 +; CHECK-P9-NEXT: xxmrghw vs1, vs1, vs1 +; CHECK-P9-NEXT: xxmrglw vs4, vs3, vs3 +; CHECK-P9-NEXT: xxmrghw vs3, vs3, vs3 +; CHECK-P9-NEXT: xxmrglw vs6, vs5, vs5 +; CHECK-P9-NEXT: xxmrghw vs5, vs5, vs5 +; CHECK-P9-NEXT: xxmrglw vs7, vs0, vs0 +; CHECK-P9-NEXT: xxmrghw vs0, vs0, vs0 +; CHECK-P9-NEXT: xvcvspdp vs2, vs2 +; CHECK-P9-NEXT: xvcvspdp vs1, vs1 +; CHECK-P9-NEXT: xvcvspdp vs4, vs4 +; CHECK-P9-NEXT: xvcvspdp vs3, vs3 +; CHECK-P9-NEXT: xvcvspdp vs6, vs6 +; CHECK-P9-NEXT: xvcvspdp vs5, vs5 +; CHECK-P9-NEXT: xvcvspdp vs7, vs7 +; CHECK-P9-NEXT: xvcvspdp vs0, vs0 +; CHECK-P9-NEXT: xvcvdpuxds vs2, vs2 ; CHECK-P9-NEXT: xvcvdpuxds vs1, vs1 -; CHECK-P9-NEXT: xvcvdpuxds vs5, vs5 -; CHECK-P9-NEXT: xscvspdpn f6, vs6 -; CHECK-P9-NEXT: xxmrghd vs6, vs7, vs6 -; CHECK-P9-NEXT: xscvspdpn f7, vs3 -; CHECK-P9-NEXT: xxsldwi vs3, vs3, vs3, 1 -; CHECK-P9-NEXT: lxv vs2, 48(r4) -; CHECK-P9-NEXT: xxswapd vs8, vs2 -; CHECK-P9-NEXT: xscvspdpn f8, vs8 ; CHECK-P9-NEXT: xvcvdpuxds vs4, vs4 -; CHECK-P9-NEXT: xscvspdpn f3, vs3 -; CHECK-P9-NEXT: xxmrghd vs3, vs7, vs3 -; CHECK-P9-NEXT: xxsldwi vs7, vs2, vs2, 3 -; CHECK-P9-NEXT: xvcvdpuxds vs0, vs0 -; CHECK-P9-NEXT: xvcvdpuxds vs6, vs6 -; CHECK-P9-NEXT: stxv vs6, 64(r3) -; CHECK-P9-NEXT: xscvspdpn f7, vs7 -; CHECK-P9-NEXT: xxmrghd vs7, vs8, vs7 -; CHECK-P9-NEXT: xscvspdpn f8, vs2 -; CHECK-P9-NEXT: xxsldwi vs2, vs2, vs2, 1 -; CHECK-P9-NEXT: xscvspdpn f2, vs2 -; CHECK-P9-NEXT: xxmrghd vs2, vs8, vs2 ; CHECK-P9-NEXT: xvcvdpuxds vs3, vs3 +; CHECK-P9-NEXT: xvcvdpuxds vs6, vs6 +; CHECK-P9-NEXT: xvcvdpuxds vs5, vs5 ; CHECK-P9-NEXT: xvcvdpuxds vs7, vs7 -; CHECK-P9-NEXT: stxv vs3, 80(r3) -; CHECK-P9-NEXT: xvcvdpuxds vs2, vs2 +; CHECK-P9-NEXT: xvcvdpuxds vs0, vs0 +; CHECK-P9-NEXT: stxv vs0, 112(r3) ; CHECK-P9-NEXT: stxv vs7, 96(r3) -; CHECK-P9-NEXT: stxv vs2, 112(r3) -; CHECK-P9-NEXT: stxv vs4, 48(r3) -; CHECK-P9-NEXT: stxv vs5, 32(r3) -; CHECK-P9-NEXT: stxv vs0, 16(r3) -; CHECK-P9-NEXT: stxv vs1, 0(r3) +; CHECK-P9-NEXT: stxv vs5, 80(r3) +; CHECK-P9-NEXT: stxv vs6, 64(r3) +; CHECK-P9-NEXT: stxv vs3, 48(r3) +; CHECK-P9-NEXT: stxv vs4, 32(r3) +; CHECK-P9-NEXT: stxv vs1, 16(r3) +; CHECK-P9-NEXT: stxv vs2, 0(r3) ; CHECK-P9-NEXT: blr ; ; CHECK-BE-LABEL: test16elt_signed: ; CHECK-BE: # %bb.0: # %entry -; CHECK-BE-NEXT: lxv vs0, 0(r4) -; CHECK-BE-NEXT: lxv vs4, 16(r4) -; CHECK-BE-NEXT: xxsldwi vs2, vs0, vs0, 1 -; CHECK-BE-NEXT: xscvspdpn f1, vs0 -; CHECK-BE-NEXT: xxsldwi vs5, vs0, vs0, 3 -; CHECK-BE-NEXT: xxswapd vs0, vs0 -; CHECK-BE-NEXT: xscvspdpn f5, vs5 -; CHECK-BE-NEXT: xscvspdpn f0, vs0 -; CHECK-BE-NEXT: xxsldwi vs6, vs4, vs4, 1 -; CHECK-BE-NEXT: xscvspdpn f6, vs6 -; CHECK-BE-NEXT: xxmrghd vs0, vs0, vs5 -; CHECK-BE-NEXT: xscvspdpn f5, vs4 -; CHECK-BE-NEXT: lxv vs3, 32(r4) -; CHECK-BE-NEXT: xxsldwi vs7, vs3, vs3, 1 -; CHECK-BE-NEXT: xscvspdpn f7, vs7 -; CHECK-BE-NEXT: xxmrghd vs5, vs5, vs6 -; CHECK-BE-NEXT: xxsldwi vs6, vs4, vs4, 3 -; CHECK-BE-NEXT: xxswapd vs4, vs4 -; CHECK-BE-NEXT: xscvspdpn f6, vs6 -; CHECK-BE-NEXT: xscvspdpn f4, vs4 -; CHECK-BE-NEXT: xscvspdpn f2, vs2 -; CHECK-BE-NEXT: xxmrghd vs1, vs1, vs2 -; CHECK-BE-NEXT: lxv vs2, 48(r4) -; CHECK-BE-NEXT: xxsldwi vs8, vs2, vs2, 1 +; CHECK-BE-NEXT: lxv vs0, 48(r4) +; CHECK-BE-NEXT: lxv vs1, 0(r4) +; CHECK-BE-NEXT: lxv vs3, 16(r4) +; CHECK-BE-NEXT: lxv vs5, 32(r4) +; CHECK-BE-NEXT: xxmrghw vs2, vs1, vs1 +; CHECK-BE-NEXT: xxmrglw vs1, vs1, vs1 +; CHECK-BE-NEXT: xxmrghw vs4, vs3, vs3 +; CHECK-BE-NEXT: xxmrglw vs3, vs3, vs3 +; CHECK-BE-NEXT: xxmrghw vs6, vs5, vs5 +; CHECK-BE-NEXT: xxmrglw vs5, vs5, vs5 +; CHECK-BE-NEXT: xxmrghw vs7, vs0, vs0 +; CHECK-BE-NEXT: xxmrglw vs0, vs0, vs0 +; CHECK-BE-NEXT: xvcvspdp vs2, vs2 +; CHECK-BE-NEXT: xvcvspdp vs1, vs1 +; CHECK-BE-NEXT: xvcvspdp vs4, vs4 +; CHECK-BE-NEXT: xvcvspdp vs3, vs3 +; CHECK-BE-NEXT: xvcvspdp vs6, vs6 +; CHECK-BE-NEXT: xvcvspdp vs5, vs5 +; CHECK-BE-NEXT: xvcvspdp vs7, vs7 +; CHECK-BE-NEXT: xvcvspdp vs0, vs0 +; CHECK-BE-NEXT: xvcvdpuxds vs2, vs2 ; CHECK-BE-NEXT: xvcvdpuxds vs1, vs1 -; CHECK-BE-NEXT: xvcvdpuxds vs0, vs0 -; CHECK-BE-NEXT: xvcvdpuxds vs5, vs5 -; CHECK-BE-NEXT: xscvspdpn f8, vs8 -; CHECK-BE-NEXT: xxmrghd vs4, vs4, vs6 -; CHECK-BE-NEXT: xscvspdpn f6, vs3 -; CHECK-BE-NEXT: stxv vs0, 16(r3) -; CHECK-BE-NEXT: xxmrghd vs6, vs6, vs7 -; CHECK-BE-NEXT: xxsldwi vs7, vs3, vs3, 3 -; CHECK-BE-NEXT: xxswapd vs3, vs3 -; CHECK-BE-NEXT: xscvspdpn f7, vs7 -; CHECK-BE-NEXT: xscvspdpn f3, vs3 -; CHECK-BE-NEXT: xxmrghd vs3, vs3, vs7 -; CHECK-BE-NEXT: xscvspdpn f7, vs2 -; CHECK-BE-NEXT: xxmrghd vs7, vs7, vs8 -; CHECK-BE-NEXT: xxsldwi vs8, vs2, vs2, 3 -; CHECK-BE-NEXT: xxswapd vs2, vs2 -; CHECK-BE-NEXT: xscvspdpn f8, vs8 -; CHECK-BE-NEXT: xscvspdpn f2, vs2 -; CHECK-BE-NEXT: xxmrghd vs2, vs2, vs8 -; CHECK-BE-NEXT: stxv vs5, 32(r3) ; CHECK-BE-NEXT: xvcvdpuxds vs4, vs4 -; CHECK-BE-NEXT: xvcvdpuxds vs6, vs6 ; CHECK-BE-NEXT: xvcvdpuxds vs3, vs3 +; CHECK-BE-NEXT: xvcvdpuxds vs6, vs6 +; CHECK-BE-NEXT: xvcvdpuxds vs5, vs5 ; CHECK-BE-NEXT: xvcvdpuxds vs7, vs7 -; CHECK-BE-NEXT: stxv vs3, 80(r3) +; CHECK-BE-NEXT: xvcvdpuxds vs0, vs0 +; CHECK-BE-NEXT: stxv vs0, 112(r3) ; CHECK-BE-NEXT: stxv vs7, 96(r3) -; CHECK-BE-NEXT: xvcvdpuxds vs2, vs2 -; CHECK-BE-NEXT: stxv vs2, 112(r3) +; CHECK-BE-NEXT: stxv vs5, 80(r3) ; CHECK-BE-NEXT: stxv vs6, 64(r3) -; CHECK-BE-NEXT: stxv vs4, 48(r3) -; CHECK-BE-NEXT: stxv vs1, 0(r3) +; CHECK-BE-NEXT: stxv vs3, 48(r3) +; CHECK-BE-NEXT: stxv vs4, 32(r3) +; CHECK-BE-NEXT: stxv vs1, 16(r3) +; CHECK-BE-NEXT: stxv vs2, 0(r3) ; CHECK-BE-NEXT: blr entry: %a = load <16 x float>, <16 x float>* %0, align 64 diff --git a/llvm/test/CodeGen/PowerPC/vsx.ll b/llvm/test/CodeGen/PowerPC/vsx.ll index 9923cb02cc8d..7cf43a92a5dc 100644 --- a/llvm/test/CodeGen/PowerPC/vsx.ll +++ b/llvm/test/CodeGen/PowerPC/vsx.ll @@ -1554,11 +1554,8 @@ define <2 x i64> @test46(<2 x float> %a) { ; ; CHECK-LE-LABEL: test46: ; CHECK-LE: # %bb.0: -; CHECK-LE-NEXT: xxsldwi vs0, v2, v2, 3 -; CHECK-LE-NEXT: xxswapd vs1, v2 -; CHECK-LE-NEXT: xscvspdpn f0, vs0 -; CHECK-LE-NEXT: xscvspdpn f1, vs1 -; CHECK-LE-NEXT: xxmrghd vs0, vs1, vs0 +; CHECK-LE-NEXT: xxmrglw vs0, v2, v2 +; CHECK-LE-NEXT: xvcvspdp vs0, vs0 ; CHECK-LE-NEXT: xvcvdpuxds v2, vs0 ; CHECK-LE-NEXT: blr %v = fptoui <2 x float> %a to <2 x i64> @@ -1625,11 +1622,8 @@ define <2 x i64> @test47(<2 x float> %a) { ; ; CHECK-LE-LABEL: test47: ; CHECK-LE: # %bb.0: -; CHECK-LE-NEXT: xxsldwi vs0, v2, v2, 3 -; CHECK-LE-NEXT: xxswapd vs1, v2 -; CHECK-LE-NEXT: xscvspdpn f0, vs0 -; CHECK-LE-NEXT: xscvspdpn f1, vs1 -; CHECK-LE-NEXT: xxmrghd vs0, vs1, vs0 +; CHECK-LE-NEXT: xxmrglw vs0, v2, v2 +; CHECK-LE-NEXT: xvcvspdp vs0, vs0 ; CHECK-LE-NEXT: xvcvdpsxds v2, vs0 ; CHECK-LE-NEXT: blr %v = fptosi <2 x float> %a to <2 x i64> From 2b4027f2b8d8224266cc2a423d9ccd74f6800711 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Mon, 23 Mar 2020 16:09:59 -0700 Subject: [PATCH 57/59] [analyzer] Delete unneeded headers and using after D76509 for layering check Otherwise it is incorrect to remove clangStaticAnalyzerFrontend's dependency on clangRewrite and clangToolingCore. --- clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 7e1e090afa60..2e3aa0669061 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -34,8 +34,6 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h" -#include "clang/Tooling/Core/Replacement.h" -#include "clang/Tooling/Tooling.h" #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/FileSystem.h" @@ -49,7 +47,6 @@ using namespace clang; using namespace ento; -using namespace tooling; #define DEBUG_TYPE "AnalysisConsumer" From 987f153929e813db1ea7e3354fd7a0b6b4adf4c0 Mon Sep 17 00:00:00 2001 From: Evgenii Stepanov Date: Mon, 23 Mar 2020 16:15:58 -0700 Subject: [PATCH 58/59] [msan] Fix sigaltstack false positive. struct stack_t on Linux x86_64 has internal padding which may be left uninitialized. The check should be replaced with multiple checks for individual fields of the struct. For now, remove the check altogether. --- .../lib/sanitizer_common/sanitizer_common_interceptors.inc | 3 --- compiler-rt/test/msan/sigaltstack.cpp | 7 +------ 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 8267b3bb4dd0..1671273174de 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -9735,9 +9735,6 @@ INTERCEPTOR(void, qsort_r, void *base, SIZE_T nmemb, SIZE_T size, INTERCEPTOR(int, sigaltstack, void *ss, void *oss) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, sigaltstack, ss, oss); - if (ss != nullptr) { - COMMON_INTERCEPTOR_READ_RANGE(ctx, ss, struct_stack_t_sz); - } int r = REAL(sigaltstack)(ss, oss); if (r == 0 && oss != nullptr) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oss, struct_stack_t_sz); diff --git a/compiler-rt/test/msan/sigaltstack.cpp b/compiler-rt/test/msan/sigaltstack.cpp index 4b97bb461d47..c1b8b7eefee1 100644 --- a/compiler-rt/test/msan/sigaltstack.cpp +++ b/compiler-rt/test/msan/sigaltstack.cpp @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -O0 -g %s -o %t && not %run %t +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t // #include #include @@ -11,10 +11,5 @@ int main(void) { assert(sigaltstack(nullptr, &old_ss) == 0); __msan_check_mem_is_initialized(&old_ss, sizeof(stack_t)); - stack_t ss; - sigaltstack(&ss, nullptr); -// CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value -// CHECK: in main {{.*}}sigaltstack.cpp:15 - return 0; } From 5bd06118c2a798f1f87b9251953bae8a27f21e5f Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Mon, 23 Mar 2020 16:30:46 -0700 Subject: [PATCH 59/59] Update documentation for __builtin_operator_new and __builtin_operator_delete to match r328134. --- clang/docs/LanguageExtensions.rst | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index aee0b82880ba..f9511dc1a02f 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -2129,21 +2129,32 @@ object that overloads ``operator&``. ``__builtin_operator_new`` and ``__builtin_operator_delete`` ------------------------------------------------------------ -``__builtin_operator_new`` allocates memory just like a non-placement non-class -*new-expression*. This is exactly like directly calling the normal -non-placement ``::operator new``, except that it allows certain optimizations +A call to ``__builtin_operator_new(args)`` is exactly the same as a call to +``::operator new(args)``, except that it allows certain optimizations that the C++ standard does not permit for a direct function call to ``::operator new`` (in particular, removing ``new`` / ``delete`` pairs and -merging allocations). +merging allocations), and that the call is required to resolve to a +`replaceable global allocation function +`_. -Likewise, ``__builtin_operator_delete`` deallocates memory just like a -non-class *delete-expression*, and is exactly like directly calling the normal -``::operator delete``, except that it permits optimizations. Only the unsized -form of ``__builtin_operator_delete`` is currently available. +Likewise, ``__builtin_operator_delete`` is exactly the same as a call to +``::operator delete(args)``, except that it permits optimizations +and that the call is required to resolve to a +`replaceable global deallocation function +`_. These builtins are intended for use in the implementation of ``std::allocator`` and other similar allocation libraries, and are only available in C++. +Query for this feature with ``__has_builtin(__builtin_operator_new)`` or +``__has_builtin(__builtin_operator_delete)``: + + * If the value is at least ``201802L``, the builtins behave as described above. + + * If the value is non-zero, the builtins may not support calling arbitrary + replaceable global (de)allocation functions, but do support calling at least + ``::operator new(size_t)`` and ``::operator delete(void*)``. + ``__builtin_preserve_access_index`` -----------------------------------