https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/231407
>From 1556c94736f8744755ab28636ba30919673a545c Mon Sep 17 00:00:00 2001 From: Fangrui Song <[email protected]> Date: Mon, 12 Oct 2026 21:43:33 -0700 Subject: [PATCH 1/4] [Option] Let an LLVMContext override library options `OptionsStruct<..., perContext = true>` lets each LLVMContext hold its own values of a library's options, so that two contexts in one process can compile with different values. The static member `Global` becomes private, and readers call `Ctx.getLibraryOptions().get<T>()`, which returns the context's copy, (temporary fallback) or `Global` if it has none. InstCombine is the first such library. The new cl::parseCommandLineOptions sets per-context libraries' options in the given cl::LibraryOptionsContext instead of Global. opt parses into its LLVMContext; clang -cc1 parses -mllvm into its CompilerInstance and replays the arguments into each code generation LLVMContext. An embedder calls set({"-x=v"}), which dispatches through the cl:: registry. https://discourse.llvm.org/t/rfc-declare-library-command-line-options-in-tablegen-one-struct-per-library/91877 LLM-aided --- .../include/clang/Frontend/CompilerInstance.h | 9 ++ clang/lib/CIR/FrontendAction/CIRGenAction.cpp | 2 + clang/lib/CodeGen/CodeGenAction.cpp | 2 + clang/lib/Frontend/CompilerInstance.cpp | 5 +- .../test/CIR/CodeGen/mllvm-library-options.c | 17 +++ clang/test/CodeGen/mllvm-library-options.ll | 21 ++++ llvm/include/llvm/IR/LLVMContext.h | 7 ++ llvm/include/llvm/Option/LibraryOptions.h | 36 +++--- llvm/include/llvm/Option/LibraryOptions.td | 4 +- llvm/include/llvm/Support/CommandLine.h | 35 +++++- .../llvm/Support/LibraryOptionsContext.h | 64 +++++++++++ llvm/lib/IR/LLVMContext.cpp | 4 + llvm/lib/IR/LLVMContextImpl.h | 3 + llvm/lib/Option/LibraryOptions.cpp | 4 +- llvm/lib/Support/CommandLine.cpp | 103 ++++++++++++++---- .../InstCombine/InstCombineCLOptions.td | 2 +- .../InstCombine/InstructionCombining.cpp | 4 +- llvm/tools/opt/optdriver.cpp | 8 +- llvm/unittests/IR/CMakeLists.txt | 2 + .../IR/LibraryOptionsContextTest.cpp | 69 ++++++++++++ llvm/unittests/Option/LibraryOptionsTest.cpp | 56 ++++++++-- llvm/unittests/Support/CommandLineTest.cpp | 4 +- .../TableGen/Basic/OptionParserEmitter.cpp | 15 ++- .../gn/secondary/llvm/unittests/IR/BUILD.gn | 2 + .../llvm/unittests/BUILD.bazel | 1 + 25 files changed, 417 insertions(+), 62 deletions(-) create mode 100644 clang/test/CIR/CodeGen/mllvm-library-options.c create mode 100644 clang/test/CodeGen/mllvm-library-options.ll create mode 100644 llvm/include/llvm/Support/LibraryOptionsContext.h create mode 100644 llvm/unittests/IR/LibraryOptionsContextTest.cpp diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h index b87dd037480d6c..bceb85f6e923bf 100644 --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -26,6 +26,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/BuryPointer.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/LibraryOptionsContext.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/VirtualOutputBackend.h" #include <cassert> @@ -147,6 +148,10 @@ class CompilerInstance : public ModuleLoader { /// The frontend timer. std::unique_ptr<llvm::Timer> FrontendTimer; + /// The -mllvm options of per-context libraries, which every LLVMContext that + /// compiles for this instance receives. + llvm::cl::LibraryOptionsContext LibraryOptions; + /// The ASTReader, if one exists. IntrusiveRefCntPtr<ASTReader> TheASTReader; @@ -269,6 +274,10 @@ class CompilerInstance : public ModuleLoader { /// This should be called after plugins are loaded and before ExecuteAction. void parseLLVMArgs(); + const llvm::cl::LibraryOptionsContext &getLibraryOptions() const { + return LibraryOptions; + } + /// @} /// @name Compiler Invocation and Options /// @{ diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp index 71a7a17146af3d..a04aa51e163af3 100644 --- a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp +++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp @@ -35,6 +35,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Linker/Linker.h" +#include "llvm/Support/LibraryOptionsContext.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" @@ -367,6 +368,7 @@ CIRGenAction::CIRGenAction(OutputType Act, mlir::MLIRContext *MLIRCtx) CIRGenAction::~CIRGenAction() { MLIRMod.release(); } bool CIRGenAction::BeginSourceFileAction(CompilerInstance &CI) { + cantFail(Ctx->getLibraryOptions().set(CI.getLibraryOptions().args())); if (clang::loadLinkModules(CI, *Ctx, LinkModules)) return false; return ASTFrontendAction::BeginSourceFileAction(CI); diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index 1abd8b0455a19b..22925cc55f495f 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -42,6 +42,7 @@ #include "llvm/LTO/LTOBackend.h" #include "llvm/Linker/Linker.h" #include "llvm/Pass.h" +#include "llvm/Support/LibraryOptionsContext.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Mutex.h" @@ -366,6 +367,7 @@ CodeGenerator *CodeGenAction::getCodeGenerator() const { } bool CodeGenAction::BeginSourceFileAction(CompilerInstance &CI) { + cantFail(VMContext->getLibraryOptions().set(CI.getLibraryOptions().args())); if (CI.getFrontendOpts().GenReducedBMI) CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleInterface); return ASTFrontendAction::BeginSourceFileAction(CI); diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index b09c9a9f5a5bed..f122208d6b4c8b 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1143,8 +1143,9 @@ void CompilerInstance::parseLLVMArgs() { for (unsigned i = 0; i != NumArgs; ++i) Args[i + 1] = getFrontendOpts().LLVMArgs[i].c_str(); Args[NumArgs + 1] = nullptr; - llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get(), /*Overview=*/"", - /*Errs=*/nullptr, + llvm::cl::parseCommandLineOptions(LibraryOptions, + ArrayRef(Args.get(), NumArgs + 1), + /*Overview=*/"", /*Errs=*/nullptr, /*VFS=*/&getVirtualFileSystem()); } } diff --git a/clang/test/CIR/CodeGen/mllvm-library-options.c b/clang/test/CIR/CodeGen/mllvm-library-options.c new file mode 100644 index 00000000000000..4f584b4058a81c --- /dev/null +++ b/clang/test/CIR/CodeGen/mllvm-library-options.c @@ -0,0 +1,17 @@ +// -mllvm options of per-context libraries reach the LLVMContext that CIR is +// lowered into. +// RUN: %clang_cc1 -triple x86_64 -O1 -fclangir -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,SINK +// RUN: %clang_cc1 -triple x86_64 -O1 -fclangir -emit-llvm -mllvm -instcombine-code-sinking=0 %s -o - | FileCheck %s --check-prefixes=CHECK,NOSINK + +void use(int); + +// CHECK-LABEL: define {{.*}} @f( +// SINK-NOT: sdiv +// NOSINK: sdiv +// CHECK: br i1 +// SINK: sdiv +void f(int c, int a, int b) { + int d = a / b; + if (c) + use(d); +} diff --git a/clang/test/CodeGen/mllvm-library-options.ll b/clang/test/CodeGen/mllvm-library-options.ll new file mode 100644 index 00000000000000..a4938f811537cf --- /dev/null +++ b/clang/test/CodeGen/mllvm-library-options.ll @@ -0,0 +1,21 @@ +;; -mllvm options of per-context libraries reach the LLVMContext that compiles. +; RUN: %clang_cc1 -O1 -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,SINK +; RUN: %clang_cc1 -O1 -emit-llvm -mllvm -instcombine-code-sinking=0 %s -o - | FileCheck %s --check-prefixes=CHECK,NOSINK + +; CHECK-LABEL: define {{.*}} @f( +; NOSINK-NEXT: entry: +; NOSINK-NEXT: = sdiv +; CHECK: {{^}}t: +; SINK-NEXT: = sdiv +define void @f(i1 %c, i32 %a, i32 %b) { +entry: + %d = sdiv i32 %a, %b + br i1 %c, label %t, label %e +t: + call void @use(i32 %d) + ret void +e: + ret void +} + +declare void @use(i32) diff --git a/llvm/include/llvm/IR/LLVMContext.h b/llvm/include/llvm/IR/LLVMContext.h index ced9b9227538e4..be0d27bacf3e4a 100644 --- a/llvm/include/llvm/IR/LLVMContext.h +++ b/llvm/include/llvm/IR/LLVMContext.h @@ -32,6 +32,9 @@ class Instruction; class LLVMContextImpl; class Module; class OptPassGate; +namespace cl { +class LibraryOptionsContext; +} // namespace cl template <typename T> class SmallVectorImpl; template <typename T> class StringMapEntry; class StringRef; @@ -329,6 +332,10 @@ class LLVMContext { /// LLVMContext is used by compilation. LLVM_ABI void setOptPassGate(OptPassGate &); + /// The library options this context reads in place of their process-wide + /// values. + LLVM_ABI cl::LibraryOptionsContext &getLibraryOptions() const; + /// Get or set the current "default" target CPU (target-cpu function /// attribute). The intent is that compiler frontends will set this to a value /// that reflects the attribute that a function would get "by default" without diff --git a/llvm/include/llvm/Option/LibraryOptions.h b/llvm/include/llvm/Option/LibraryOptions.h index 8b5c34525fa7c6..19df88f77e586a 100644 --- a/llvm/include/llvm/Option/LibraryOptions.h +++ b/llvm/include/llvm/Option/LibraryOptions.h @@ -27,6 +27,7 @@ #include "llvm/Support/Compiler.h" #include <optional> #include <type_traits> +#include <utility> namespace llvm { namespace opt { @@ -118,23 +119,36 @@ class LLVM_ABI LibraryOptTable : public OptTable { ~LibraryOptTable() override; }; -/// Connects an options struct to cl::ParseCommandLineOptions. +/// Connects options struct T to cl::ParseCommandLineOptions and +/// cl::LibraryOptionsContext. class LLVM_ABI LibraryOptionsParser final : public cl::LibraryOptions { public: - using ApplyFn = bool (*)(const Arg &, BumpPtrAllocator &); - using TableFn = const OptTable &(*)(); - LibraryOptionsParser(TableFn Table, ApplyFn Apply, void (*Reset)()) - : Table(Table), Apply(Apply), Reset(Reset) {} + template <typename T> + explicit LibraryOptionsParser(std::in_place_type_t<T>) + : LibraryOptions(T::PerContext), Table(T::optTable), Global(&T::Global), + Apply([](void *Opts, const Arg &A, BumpPtrAllocator &Alloc) { + return static_cast<T *>(Opts)->apply(A, Alloc); + }), + Copy([](BumpPtrAllocator &Alloc) -> void * { + return new (Alloc) T(T::Global); + }), + Reset([] { T::Global = T(); }) {} void forEachOption( function_ref<void(StringRef, StringRef, StringRef)> Fn) const override; - Error parse(ArrayRef<const char *> Args, unsigned &Consumed, + Error parse(void *Opts, ArrayRef<const char *> Args, unsigned &Consumed, BumpPtrAllocator &Alloc) override; + void *global() override { return Global; } + void *copyGlobal(BumpPtrAllocator &Alloc) const override { + return Copy(Alloc); + } void reset() override { Reset(); } private: - TableFn Table; - ApplyFn Apply; + const OptTable &(*Table)(); + void *Global; + bool (*Apply)(void *Opts, const Arg &A, BumpPtrAllocator &Alloc); + void *(*Copy)(BumpPtrAllocator &Alloc); void (*Reset)(); }; @@ -144,11 +158,7 @@ class LLVM_ABI LibraryOptionsParser final : public cl::LibraryOptions { template <typename T> class RegisterLibraryOptions { static_assert(std::is_trivially_destructible_v<T>, "an options struct must not need an exit-time destructor"); - LibraryOptionsParser Parser{T::optTable, - [](const Arg &A, BumpPtrAllocator &Alloc) { - return T::Global.apply(A, Alloc); - }, - [] { T::Global = T(); }}; + LibraryOptionsParser Parser{std::in_place_type<T>}; public: RegisterLibraryOptions() { cl::addLibraryOptions(Parser); } diff --git a/llvm/include/llvm/Option/LibraryOptions.td b/llvm/include/llvm/Option/LibraryOptions.td index d901f8027f7028..ab027c056831ea 100644 --- a/llvm/include/llvm/Option/LibraryOptions.td +++ b/llvm/include/llvm/Option/LibraryOptions.td @@ -17,9 +17,11 @@ include "llvm/Option/OptParser.td" // A row whose spelling starts with prefix names its member without it. -class OptionsStruct<string namespace = "llvm", string prefix = ""> { +// perContext makes Global private; read through cl::LibraryOptionsContext::get. +class OptionsStruct<string namespace = "llvm", string prefix = "", bit perContext = false> { string Namespace = namespace; string MemberPrefix = prefix; + bit PerContext = perContext; } // The builds an option exists in, as a preprocessor expression. diff --git a/llvm/include/llvm/Support/CommandLine.h b/llvm/include/llvm/Support/CommandLine.h index bc7059244461e3..1b3e3745ce7246 100644 --- a/llvm/include/llvm/Support/CommandLine.h +++ b/llvm/include/llvm/Support/CommandLine.h @@ -50,6 +50,8 @@ class Error; /// It is intentionally a short name to make qualified usage concise. namespace cl { +class LibraryOptionsContext; + //===----------------------------------------------------------------------===// // Command line option processing entry point. // @@ -70,6 +72,15 @@ LLVM_ABI bool ParseCommandLineOptions(int argc, const char *const *argv, vfs::FileSystem *VFS = nullptr, const char *EnvVar = nullptr); +// Like ParseCommandLineOptions, but sets the library registered options +// as per-context in LibraryOptions rather than in their global(). +LLVM_ABI bool parseCommandLineOptions(LibraryOptionsContext &LibraryOptions, + ArrayRef<const char *> Args, + StringRef Overview = "", + raw_ostream *Errs = nullptr, + vfs::FileSystem *VFS = nullptr, + const char *EnvVar = nullptr); + // Function pointer type for printing version information. using VersionPrinterTy = std::function<void(raw_ostream &)>; @@ -2176,18 +2187,32 @@ class LLVM_ABI LibraryOptions { Fn) const = 0; /// Parses the option spelled by Args[0], which may take Args[1] as its - /// value, and sets \p Consumed to the number of arguments it spans. The - /// strings in \p Args and the memory from \p Alloc remain valid until - /// reset(). - virtual Error parse(ArrayRef<const char *> Args, unsigned &Consumed, - BumpPtrAllocator &Alloc) = 0; + /// value, into \p Opts, which is global() or a copy of it, and sets + /// \p Consumed to the number of arguments it spans. The strings in \p Args + /// and the memory from \p Alloc remain valid as long as \p Opts is used. + virtual Error parse(void *Opts, ArrayRef<const char *> Args, + unsigned &Consumed, BumpPtrAllocator &Alloc) = 0; + + /// Returns the values that ParseCommandLineOptions sets. + virtual void *global() = 0; + + /// Returns a copy of global() allocated from \p Alloc. + virtual void *copyGlobal(BumpPtrAllocator &Alloc) const = 0; /// Restores the default values. virtual void reset() = 0; + /// Whether every reader of the options goes through a context's + /// LibraryOptionsContext, so that they need not be set in global(). + bool isPerContext() const { return PerContext; } + protected: + explicit LibraryOptions(bool PerContext = false) : PerContext(PerContext) {} // Registrations are static and never destroyed through this class. ~LibraryOptions() = default; + +private: + bool PerContext; }; /// Makes ParseCommandLineOptions recognize \p L's options. A name that is also diff --git a/llvm/include/llvm/Support/LibraryOptionsContext.h b/llvm/include/llvm/Support/LibraryOptionsContext.h new file mode 100644 index 00000000000000..150a8c1d5a7719 --- /dev/null +++ b/llvm/include/llvm/Support/LibraryOptionsContext.h @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// +// 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_SUPPORT_LIBRARYOPTIONSCONTEXT_H +#define LLVM_SUPPORT_LIBRARYOPTIONSCONTEXT_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Compiler.h" + +namespace llvm { + +class Error; + +namespace cl { + +class LibraryOptions; + +// Values of library options that override their global() in one compilation +// context, such as an LLVMContext. +class LLVM_ABI LibraryOptionsContext { +public: + // Sets the library options that Args spell, e.g. {"-x=v"}. A library's values + // start as a copy of its global(), and later calls add to them. Fails at the + // first argument that is not a library option or has an invalid value. + // + // Strings copied from global() die with ResetAllOptionOccurrences. The first + // call (or ParseCommandLineOptions) indexes the registry, which is not + // thread-safe. + Error set(ArrayRef<const char *> Args); + + // Parses the option of L that Args[0] spells, as set() does. + Error parse(LibraryOptions &L, ArrayRef<const char *> Args, + unsigned &Consumed); + + // The arguments set so far, for replaying into another context. + ArrayRef<const char *> args() const { return Args; } + + // T's values, or T::Global if there are none. + template <typename T> const T &get() const { + if (const void *Opts = Values.lookup(&T::Global)) + return *static_cast<const T *>(Opts); + // TODO: Return the defaults once cl::ParseCommandLineOptions callers have + // migrated to parseCommandLineOptions and no longer set T::Global. + return T::Global; + } + +private: + DenseMap<const void *, void *> Values; + SmallVector<const char *, 0> Args; + BumpPtrAllocator Alloc; +}; + +} // namespace cl +} // namespace llvm + +#endif // LLVM_SUPPORT_LIBRARYOPTIONSCONTEXT_H diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp index 1fcdd3bc4c142a..fb3b4bd8b206f3 100644 --- a/llvm/lib/IR/LLVMContext.cpp +++ b/llvm/lib/IR/LLVMContext.cpp @@ -357,6 +357,10 @@ void LLVMContext::setOptPassGate(OptPassGate& OPG) { pImpl->setOptPassGate(OPG); } +cl::LibraryOptionsContext &LLVMContext::getLibraryOptions() const { + return pImpl->LibraryOptions; +} + const DiagnosticHandler *LLVMContext::getDiagHandlerPtr() const { return pImpl->DiagHandler.get(); } diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h index 74a73664473b03..d02d57e4c0197f 100644 --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -40,6 +40,7 @@ #include "llvm/IR/Value.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/LibraryOptionsContext.h" #include "llvm/Support/StringSaver.h" #include <algorithm> #include <cassert> @@ -1951,6 +1952,8 @@ class LLVMContextImpl { std::string DefaultTargetCPU; std::string DefaultTargetFeatures; + cl::LibraryOptionsContext LibraryOptions; + /// The next available source atom group number. The front end is responsible /// for assigning source atom numbers, but certain optimisations need to /// assign new group numbers to a set of instructions. Most often code diff --git a/llvm/lib/Option/LibraryOptions.cpp b/llvm/lib/Option/LibraryOptions.cpp index cfcb82273eb6d8..e5848a0498f23c 100644 --- a/llvm/lib/Option/LibraryOptions.cpp +++ b/llvm/lib/Option/LibraryOptions.cpp @@ -34,7 +34,7 @@ void LibraryOptionsParser::forEachOption( } } -Error LibraryOptionsParser::parse(ArrayRef<const char *> Args, +Error LibraryOptionsParser::parse(void *Opts, ArrayRef<const char *> Args, unsigned &Consumed, BumpPtrAllocator &Alloc) { InputArgList List(Args.begin(), Args.end()); Consumed = 0; @@ -45,7 +45,7 @@ Error LibraryOptionsParser::parse(ArrayRef<const char *> Args, "' requires an argument"); if (A->getOption().getKind() == Option::UnknownClass) return createStringError("unknown argument '" + Twine(Args[0]) + "'"); - if (!Apply(*A, Alloc)) + if (!Apply(Opts, *A, Alloc)) return createStringError("invalid value '" + Twine(A->getValue()) + "' in '" + A->getAsString(List) + "'"); return Error::success(); diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp index 1cb5fccb07a1be..31f07e114cace1 100644 --- a/llvm/lib/Support/CommandLine.cpp +++ b/llvm/lib/Support/CommandLine.cpp @@ -35,6 +35,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/LibraryOptionsContext.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" @@ -189,7 +190,8 @@ class CommandLineParser { bool ParseCommandLineOptions(int argc, const char *const *argv, StringRef Overview, raw_ostream *Errs = nullptr, - vfs::FileSystem *VFS = nullptr); + vfs::FileSystem *VFS = nullptr, + LibraryOptionsContext *Context = nullptr); void forEachSubCommand(Option &Opt, function_ref<void(SubCommand &)> Action) { if (Opt.Subs.empty()) { @@ -440,6 +442,26 @@ static CommandLineParser &globalParser() { return *GlobalParser; } +// Parses the library option spelled by Args[0], which takes at most one +// separate value, into Opts. Opts may refer to the arguments, so they are +// copied into Alloc, and appended to Record if given. +static Error +parseLibraryOption(LibraryOptions &L, void *Opts, ArrayRef<const char *> Args, + unsigned &Consumed, BumpPtrAllocator &Alloc, + SmallVectorImpl<const char *> *Record = nullptr) { + StringSaver Saver(Alloc); + const char *Saved[2]; + unsigned NumArgs = std::min<size_t>(Args.size(), 2); + for (unsigned J = 0; J != NumArgs; ++J) + Saved[J] = Saver.save(Args[J]).data(); + Consumed = 1; + if (Error E = L.parse(Opts, ArrayRef(Saved, NumArgs), Consumed, Alloc)) + return E; + if (Record) + Record->append(Saved, Saved + Consumed); + return Error::success(); +} + template <typename T, T TrueVal, T FalseVal> static bool parseBool(Option &O, StringRef ArgName, StringRef Arg, T &Value) { // ProvideOption passes a null Arg for a bare -flag (treated as true) and an @@ -1424,14 +1446,15 @@ Error ExpansionContext::readConfigFile(StringRef CfgFile, } static void initCommonOptions(); -bool cl::ParseCommandLineOptions(int argc, const char *const *argv, - StringRef Overview, raw_ostream *Errs, - vfs::FileSystem *VFS, const char *EnvVar) { +static bool parseCommandLineOptionsImpl(LibraryOptionsContext *Context, ArrayRef<const char *> Args, + StringRef Overview, raw_ostream *Errs, + vfs::FileSystem *VFS, + const char *EnvVar) { initCommonOptions(); SmallVector<const char *, 20> NewArgv; BumpPtrAllocator A; StringSaver Saver(A); - NewArgv.push_back(argv[0]); + NewArgv.push_back(Args[0]); // Parse options from environment variable. if (EnvVar) { @@ -1441,13 +1464,27 @@ bool cl::ParseCommandLineOptions(int argc, const char *const *argv, } // Append options from command line. - for (int I = 1; I < argc; ++I) - NewArgv.push_back(argv[I]); + append_range(NewArgv, Args.drop_front()); int NewArgc = static_cast<int>(NewArgv.size()); // Parse all options. return globalParser().ParseCommandLineOptions(NewArgc, &NewArgv[0], Overview, - Errs, VFS); + Errs, VFS, Context); +} + +bool cl::ParseCommandLineOptions(int argc, const char *const *argv, + StringRef Overview, raw_ostream *Errs, + vfs::FileSystem *VFS, const char *EnvVar) { + return parseCommandLineOptionsImpl(nullptr, ArrayRef(argv, argc), Overview, + Errs, VFS, EnvVar); +} + +bool cl::parseCommandLineOptions(LibraryOptionsContext &LibraryOptions, + ArrayRef<const char *> Args, + StringRef Overview, raw_ostream *Errs, + vfs::FileSystem *VFS, const char *EnvVar) { + return parseCommandLineOptionsImpl(&LibraryOptions, Args, Overview, Errs, VFS, + EnvVar); } /// Reset all options at least once, so that we can parse different options. @@ -1474,11 +1511,9 @@ void CommandLineParser::ResetAllOptionOccurrences() { LibraryArgAlloc.Reset(); } -bool CommandLineParser::ParseCommandLineOptions(int argc, - const char *const *argv, - StringRef Overview, - raw_ostream *Errs, - vfs::FileSystem *VFS) { +bool CommandLineParser::ParseCommandLineOptions( + int argc, const char *const *argv, StringRef Overview, raw_ostream *Errs, + vfs::FileSystem *VFS, LibraryOptionsContext *Context) { assert(hasOptions() && "No options specified!"); ProgramOverview = Overview; @@ -1654,14 +1689,12 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, if (!Handler) { if (LibraryOptions *L = lookupLibraryOption(ArgName.split('=').first)) { - // An option takes at most one separate value. - StringSaver Saver(LibraryArgAlloc); - const char *Args[2]; - unsigned NumArgs = std::min(argc - i, 2); - for (unsigned J = 0; J != NumArgs; ++J) - Args[J] = Saver.save(argv[i + J]).data(); - unsigned N = 1; - if (Error E = L->parse(ArrayRef(Args, NumArgs), N, LibraryArgAlloc)) { + ArrayRef<const char *> Rest(argv + i, argc - i); + unsigned N; + if (Error E = Context && L->isPerContext() + ? Context->parse(*L, Rest, N) + : parseLibraryOption(*L, L->global(), Rest, N, + LibraryArgAlloc)) { *Errs << ProgramName << ": " << toString(std::move(E)) << '\n'; ErrorParsing = true; } @@ -2909,6 +2942,34 @@ void cl::addLibraryOptions(LibraryOptions &L) { globalParser().Libraries.push_back(&L); } +Error LibraryOptionsContext::set(ArrayRef<const char *> Args) { + for (size_t I = 0, E = Args.size(); I != E;) { + StringRef Name = Args[I]; + LibraryOptions *L = nullptr; + if (Name.consume_front("-")) { + Name.consume_front("-"); + L = globalParser().lookupLibraryOption(Name.split('=').first); + } + if (!L) + return createStringError("'" + Twine(Args[I]) + + "' is not a library option"); + unsigned N; + if (Error Err = parse(*L, Args.drop_front(I), N)) + return Err; + I += N; + } + return Error::success(); +} + +Error LibraryOptionsContext::parse(LibraryOptions &L, + ArrayRef<const char *> Args, + unsigned &Consumed) { + auto [It, Inserted] = Values.try_emplace(L.global()); + if (Inserted) + It->second = L.copyGlobal(Alloc); + return parseLibraryOption(L, It->second, Args, Consumed, Alloc, &this->Args); +} + void cl::ResetAllOptionOccurrences() { globalParser().ResetAllOptionOccurrences(); } diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCLOptions.td b/llvm/lib/Transforms/InstCombine/InstCombineCLOptions.td index 9fc098796f9e45..d2f850f5972eff 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCLOptions.td +++ b/llvm/lib/Transforms/InstCombine/InstCombineCLOptions.td @@ -8,7 +8,7 @@ include "llvm/Option/LibraryOptions.td" -def InstCombineCLOptions : OptionsStruct<prefix = "instcombine-">; +def InstCombineCLOptions : OptionsStruct<prefix = "instcombine-", perContext = true>; defm : BoolField<"instcombine-code-sinking", "true", "Enable code sinking">; diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index 6986fb324bfeef..7158dec4277b4e 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -96,6 +96,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/KnownBits.h" #include "llvm/Support/KnownFPClass.h" +#include "llvm/Support/LibraryOptionsContext.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/InstCombine/InstCombine.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" @@ -6269,7 +6270,8 @@ static bool combineInstructionsOverFunction( // Lower dbg.declare intrinsics otherwise their value may be clobbered // by instcombiner. - const InstCombineCLOptions &CLOpts = InstCombineCLOptions::Global; + const auto &CLOpts = + F.getContext().getLibraryOptions().get<InstCombineCLOptions>(); bool MadeIRChange = false; if (CLOpts.lower_dbg_declare) MadeIRChange = LowerDbgDeclare(F); diff --git a/llvm/tools/opt/optdriver.cpp b/llvm/tools/opt/optdriver.cpp index 068e227328c168..da87ef049c7d4e 100644 --- a/llvm/tools/opt/optdriver.cpp +++ b/llvm/tools/opt/optdriver.cpp @@ -456,8 +456,10 @@ optMain(int argc, char **argv, // Register the Target and CPU printer for --version. cl::AddExtraVersionPrinter(sys::printDefaultTargetAndDetectedCPU); - cl::ParseCommandLineOptions( - argc, argv, "llvm .bc -> .bc modular optimizer and analysis printer\n"); + LLVMContext Context; + cl::parseCommandLineOptions( + Context.getLibraryOptions(), ArrayRef(argv, argc), + "llvm .bc -> .bc modular optimizer and analysis printer\n"); SmallVector<PassPluginLibraryInfo, 0> Extensions; for (const std::string &Path : PassPlugins) { @@ -471,8 +473,6 @@ optMain(int argc, char **argv, if (Error E = passPluginArguments(Extensions, PluginArgs)) reportFatalUsageError(std::move(E)); - LLVMContext Context; - // TODO: remove shouldForceLegacyPM(). const bool UseNPM = !shouldForceLegacyPM() || PassPipeline.getNumOccurrences() > 0; diff --git a/llvm/unittests/IR/CMakeLists.txt b/llvm/unittests/IR/CMakeLists.txt index df83992fadd1e4..ad94dcc32a880b 100644 --- a/llvm/unittests/IR/CMakeLists.txt +++ b/llvm/unittests/IR/CMakeLists.txt @@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS Analysis AsmParser Core + InstCombine Support Passes TargetParser @@ -35,6 +36,7 @@ add_llvm_unittest(IRTests InstructionsTest.cpp IntrinsicsTest.cpp LegacyPassManagerTest.cpp + LibraryOptionsContextTest.cpp MDBuilderTest.cpp MemoryModelRelaxationAnnotationsTest.cpp ManglerTest.cpp diff --git a/llvm/unittests/IR/LibraryOptionsContextTest.cpp b/llvm/unittests/IR/LibraryOptionsContextTest.cpp new file mode 100644 index 00000000000000..2588bdcda41cb7 --- /dev/null +++ b/llvm/unittests/IR/LibraryOptionsContextTest.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/AsmParser/Parser.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/ValueSymbolTable.h" +#include "llvm/Passes/PassBuilder.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Transforms/InstCombine/InstCombine.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +// InstCombine sinks %a into its only user's block unless +// -instcombine-code-sinking=0. +const char *IR = R"( +define i32 @f(i1 %c, i32 %x) { +entry: + %a = add i32 %x, 1 + br i1 %c, label %t, label %e +t: + ret i32 %a +e: + ret i32 0 +} +)"; + +// Runs InstCombine on IR in Ctx and returns the block that holds %a. +std::string runInstCombine(LLVMContext &Ctx) { + SMDiagnostic Err; + std::unique_ptr<Module> M = parseAssemblyString(IR, Err, Ctx); + if (!M) + return Err.getMessage().str(); + LoopAnalysisManager LAM; + FunctionAnalysisManager FAM; + CGSCCAnalysisManager CGAM; + ModuleAnalysisManager MAM; + PassBuilder PB; + PB.registerModuleAnalyses(MAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); + PB.registerLoopAnalyses(LAM); + PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); + Function &F = *M->getFunction("f"); + InstCombinePass().run(F, FAM); + auto *A = cast<Instruction>(F.getValueSymbolTable()->lookup("a")); + return A->getParent()->getName().str(); +} + +// parseCommandLineOptions sets InstCombine's options in the given context +// only, so two contexts in one process run InstCombine with different options. +TEST(LibraryOptionsContextTest, InstCombine) { + LLVMContext C1, C2; + const char *Args[] = {"prog", "-instcombine-code-sinking=0"}; + ASSERT_TRUE( + cl::parseCommandLineOptions(C2.getLibraryOptions(), Args, "", &nulls())); + EXPECT_EQ(runInstCombine(C1), "t"); + EXPECT_EQ(runInstCombine(C2), "entry"); +} + +} // namespace diff --git a/llvm/unittests/Option/LibraryOptionsTest.cpp b/llvm/unittests/Option/LibraryOptionsTest.cpp index dff1d179845b7e..0120f105353323 100644 --- a/llvm/unittests/Option/LibraryOptionsTest.cpp +++ b/llvm/unittests/Option/LibraryOptionsTest.cpp @@ -17,6 +17,7 @@ enum class Mode { A, B }; #include "llvm/Option/ArgList.h" #include "llvm/Option/LibraryOptions.h" +#include "llvm/Support/LibraryOptionsContext.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -115,12 +116,7 @@ TEST(LibraryOptionsTest, BoolOrDefault) { // What cl:: sees of the struct, without cl::. TEST(LibraryOptionsTest, Parser) { - opt::LibraryOptionsParser P( - TestLibraryOptions::optTable, - [](const opt::Arg &A, BumpPtrAllocator &Alloc) { - return TestLibraryOptions::Global.apply(A, Alloc); - }, - [] { TestLibraryOptions::Global = TestLibraryOptions(); }); + opt::LibraryOptionsParser P(std::in_place_type<TestLibraryOptions>); std::vector<std::string> Rows; P.forEachOption([&](StringRef Spelling, StringRef MetaVar, StringRef Help) { @@ -140,7 +136,7 @@ TEST(LibraryOptionsTest, Parser) { BumpPtrAllocator Alloc; auto Parse = [&](std::initializer_list<const char *> Argv) { unsigned Consumed = 0; - std::string Err = toString(P.parse(Argv, Consumed, Alloc)); + std::string Err = toString(P.parse(P.global(), Argv, Consumed, Alloc)); return std::to_string(Consumed) + " " + Err; }; EXPECT_EQ(Parse({"-lib-count", "5"}), "2 "); @@ -193,4 +189,50 @@ TEST(LibraryOptionsTest, Register) { cl::ResetCommandLineParser(); } +// parseCommandLineOptions sets the options of a library that is not +// per-context in its Global, which a context without values reads. +TEST(LibraryOptionsTest, ParseIntoGlobal) { + cl::ResetCommandLineParser(); + opt::RegisterLibraryOptions<TestLibraryOptions> Registration; + cl::LibraryOptionsContext V; + const char *Args[] = {"prog", "-lib-count=5"}; + EXPECT_TRUE(cl::parseCommandLineOptions(V, Args, "", &nulls())); + EXPECT_EQ(TestLibraryOptions::Global.count, 5u); + EXPECT_EQ(&V.get<TestLibraryOptions>(), &TestLibraryOptions::Global); + cl::ResetCommandLineParser(); +} + +// Values that override Global, as an LLVMContext holds them. +TEST(LibraryOptionsTest, Values) { + cl::ResetCommandLineParser(); + opt::RegisterLibraryOptions<TestLibraryOptions> Registration; + cl::opt<bool> NotLibrary("lib-cl-opt"); + cl::LibraryOptionsContext V; + auto Set = [&](std::initializer_list<const char *> Args) { + return toString(V.set(Args)); + }; + std::string Path = "-lib-path=q"; + EXPECT_EQ(Set({"-lib-count", "7", Path.c_str(), "--lib-list=1,2"}), ""); + Path.assign(Path.size(), ' '); + EXPECT_EQ(TestLibraryOptions::Global.count, 3u); + + // A later call keeps the earlier values. + EXPECT_EQ(Set({"-lib-list=3"}), ""); + EXPECT_THAT(V.get<TestLibraryOptions>().list, + testing::ElementsAre(1u, 2u, 3u)); + + // Another context replays the arguments, which outlive the caller's. + cl::LibraryOptionsContext Copy; + EXPECT_EQ(toString(Copy.set(V.args())), ""); + const TestLibraryOptions &C = Copy.get<TestLibraryOptions>(); + EXPECT_EQ(C.count, 7u); + EXPECT_EQ(C.Path, "q"); + EXPECT_THAT(C.list, testing::ElementsAre(1u, 2u, 3u)); + + EXPECT_EQ(Set({"-lib-count=x"}), "invalid value 'x' in '-lib-count=x'"); + EXPECT_EQ(Set({"-lib-cl-opt"}), "'-lib-cl-opt' is not a library option"); + EXPECT_EQ(Set({"lib-count=1"}), "'lib-count=1' is not a library option"); + cl::ResetCommandLineParser(); +} + } // namespace diff --git a/llvm/unittests/Support/CommandLineTest.cpp b/llvm/unittests/Support/CommandLineTest.cpp index ccf45962ba04fc..ae9e0969d15407 100644 --- a/llvm/unittests/Support/CommandLineTest.cpp +++ b/llvm/unittests/Support/CommandLineTest.cpp @@ -2346,7 +2346,7 @@ struct TestLibrary final : cl::LibraryOptions { Fn("library-flag", "", "A flag"); Fn("library-int", " <int>", ""); } - Error parse(ArrayRef<const char *> Argv, unsigned &Consumed, + Error parse(void *, ArrayRef<const char *> Argv, unsigned &Consumed, BumpPtrAllocator &) override { Consumed = 1; Args.push_back(Argv[0]); @@ -2360,6 +2360,8 @@ struct TestLibrary final : cl::LibraryOptions { return createStringError("bad value"); return Error::success(); } + void *global() override { return this; } + void *copyGlobal(BumpPtrAllocator &) const override { return nullptr; } void reset() override { Args.clear(); } }; diff --git a/llvm/utils/TableGen/Basic/OptionParserEmitter.cpp b/llvm/utils/TableGen/Basic/OptionParserEmitter.cpp index c4b23c046e7186..8df952eb8664e0 100644 --- a/llvm/utils/TableGen/Basic/OptionParserEmitter.cpp +++ b/llvm/utils/TableGen/Basic/OptionParserEmitter.cpp @@ -353,8 +353,10 @@ static void emitOptionsStruct(const Record &Struct, OS << "#include \"llvm/ADT/StringRef.h\"\n"; OS << "#include \"llvm/Support/Allocator.h\"\n\n"; StringRef Namespace = Struct.getValueAsString("Namespace"); - OS << "namespace llvm {\nnamespace opt {\nclass Arg;\n" - "class OptTable;\n} // namespace opt\n} // namespace llvm\n\n"; + OS << "namespace llvm {\nnamespace cl {\nclass LibraryOptionsContext;\n" + "} // namespace cl\nnamespace opt {\nclass Arg;\n" + "class LibraryOptionsParser;\nclass OptTable;\n} // namespace opt\n" + "} // namespace llvm\n\n"; OS << "namespace " << Namespace << " {\n"; OS << "struct " << Name << " {\n"; if (Namespace != "llvm") @@ -363,13 +365,18 @@ static void emitOptionsStruct(const Record &Struct, ConditionScope CS(OS, *R); OS << " " << M.Type << " " << M.Name << "{" << M.Default << "};\n"; } - OS << "\n /// The instance cl::ParseCommandLineOptions sets.\n"; - OS << " static " << Name << " Global;\n\n"; + bool PerContext = Struct.getValueAsBit("PerContext"); + OS << "\n static constexpr bool PerContext = " + << (PerContext ? "true" : "false") << ";\n"; OS << " static const llvm::opt::OptTable &optTable();\n"; OS << " /// Sets the member that \\p A names, allocating a list from \\p " "Alloc.\n /// Returns false if the value is invalid.\n"; OS << " bool apply(const llvm::opt::Arg &A, llvm::BumpPtrAllocator " "&Alloc);\n"; + if (PerContext) + OS << "\nprivate:\n friend class llvm::cl::LibraryOptionsContext;\n" + " friend class llvm::opt::LibraryOptionsParser;\n"; + OS << "\n static " << Name << " Global;\n"; OS << "};\n} // namespace " << Namespace << "\n"; OS << "#endif // OPTIONS_STRUCT_DECL\n"; diff --git a/llvm/utils/gn/secondary/llvm/unittests/IR/BUILD.gn b/llvm/utils/gn/secondary/llvm/unittests/IR/BUILD.gn index 547d82187b87f1..21d7a82a713b4c 100644 --- a/llvm/utils/gn/secondary/llvm/unittests/IR/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/unittests/IR/BUILD.gn @@ -8,6 +8,7 @@ unittest("IRTests") { "//llvm/lib/Passes", "//llvm/lib/Support", "//llvm/lib/Testing/Support", + "//llvm/lib/Transforms/InstCombine", "//llvm/lib/Transforms/Utils", ] sources = [ @@ -36,6 +37,7 @@ unittest("IRTests") { "InstructionsTest.cpp", "IntrinsicsTest.cpp", "LegacyPassManagerTest.cpp", + "LibraryOptionsContextTest.cpp", "MDBuilderTest.cpp", "ManglerTest.cpp", "MemoryModelRelaxationAnnotationsTest.cpp", diff --git a/utils/bazel/llvm-project-overlay/llvm/unittests/BUILD.bazel b/utils/bazel/llvm-project-overlay/llvm/unittests/BUILD.bazel index 89c25df2d1d92e..05e3760c588cf5 100644 --- a/utils/bazel/llvm-project-overlay/llvm/unittests/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/llvm/unittests/BUILD.bazel @@ -474,6 +474,7 @@ cc_test( "//llvm:BinaryFormat", "//llvm:CodeGen", "//llvm:Core", + "//llvm:InstCombine", "//llvm:Passes", "//llvm:Plugins", "//llvm:Scalar", >From 7719060711312ca95463b6c197a929723d412840 Mon Sep 17 00:00:00 2001 From: Fangrui Song <[email protected]> Date: Tue, 13 Oct 2026 22:50:17 -0700 Subject: [PATCH 2/4] port Vectorize; replace set() with assign() --- clang/lib/CIR/FrontendAction/CIRGenAction.cpp | 2 +- clang/lib/CodeGen/CodeGenAction.cpp | 3 ++- .../unittests/Frontend/CodeGenActionTest.cpp | 24 +++++++++++++++++++ llvm/include/llvm/Option/LibraryOptions.h | 2 +- llvm/include/llvm/SandboxIR/Context.h | 3 +++ .../llvm/Support/LibraryOptionsContext.h | 20 ++++++++-------- .../SandboxVectorizer/Passes/BundleVec.h | 5 ++++ .../SandboxVectorizer/SeedCollector.h | 3 ++- llvm/lib/Support/CommandLine.cpp | 7 ++++-- .../InstCombine/InstructionCombining.cpp | 1 - .../Vectorize/LoopIdiomVectorize.cpp | 3 ++- .../Transforms/Vectorize/LoopVectorize.cpp | 7 ++++-- .../Transforms/Vectorize/SLPVectorizer.cpp | 2 +- .../SandboxVectorizer/Passes/BundleVec.cpp | 13 +++++----- .../SandboxVectorizer/Passes/LoadStoreVec.cpp | 4 +++- .../Passes/SeedCollection.cpp | 3 ++- .../Passes/TransactionAcceptOrRevert.cpp | 3 ++- .../SandboxVectorizer/SandboxVectorizer.cpp | 2 +- .../SandboxVectorizer/SeedCollector.cpp | 14 +++++++---- .../Vectorize/SandboxVectorizer/VecUtils.cpp | 5 ++-- .../Transforms/Vectorize/VPlanTransforms.cpp | 12 ++++++---- .../Transforms/Vectorize/VPlanTransforms.h | 4 ++-- .../Transforms/Vectorize/VectorCombine.cpp | 5 ++-- .../Transforms/Vectorize/VectorizeOptions.td | 2 +- llvm/unittests/Option/LibraryOptionsTest.cpp | 24 +++++++++---------- .../Vectorize/VPlanVerifierTest.cpp | 4 +--- .../TableGen/Basic/OptionParserEmitter.cpp | 15 +++++++----- 27 files changed, 123 insertions(+), 69 deletions(-) diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp index a04aa51e163af3..54a6b5336662bb 100644 --- a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp +++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp @@ -368,7 +368,7 @@ CIRGenAction::CIRGenAction(OutputType Act, mlir::MLIRContext *MLIRCtx) CIRGenAction::~CIRGenAction() { MLIRMod.release(); } bool CIRGenAction::BeginSourceFileAction(CompilerInstance &CI) { - cantFail(Ctx->getLibraryOptions().set(CI.getLibraryOptions().args())); + cantFail(Ctx->getLibraryOptions().assign(CI.getLibraryOptions().args())); if (clang::loadLinkModules(CI, *Ctx, LinkModules)) return false; return ASTFrontendAction::BeginSourceFileAction(CI); diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index 22925cc55f495f..cd5047659eef7a 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -367,7 +367,8 @@ CodeGenerator *CodeGenAction::getCodeGenerator() const { } bool CodeGenAction::BeginSourceFileAction(CompilerInstance &CI) { - cantFail(VMContext->getLibraryOptions().set(CI.getLibraryOptions().args())); + cantFail( + VMContext->getLibraryOptions().assign(CI.getLibraryOptions().args())); if (CI.getFrontendOpts().GenReducedBMI) CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleInterface); return ASTFrontendAction::BeginSourceFileAction(CI); diff --git a/clang/unittests/Frontend/CodeGenActionTest.cpp b/clang/unittests/Frontend/CodeGenActionTest.cpp index d2befe1af4a591..f119c51128796c 100644 --- a/clang/unittests/Frontend/CodeGenActionTest.cpp +++ b/clang/unittests/Frontend/CodeGenActionTest.cpp @@ -15,7 +15,9 @@ #include "clang/CodeGen/BackendUtil.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Lex/PreprocessorOptions.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/LibraryOptionsContext.h" #include "llvm/Support/VirtualFileSystem.h" #include "gtest/gtest.h" @@ -76,4 +78,26 @@ TEST(CodeGenTest, CodeGenFromIRMemBuffer) { bool Success = Compiler.ExecuteAction(Action); EXPECT_TRUE(Success); } + +// Each input assigns -mllvm library options to the LLVMContext anew. +TEST(CodeGenTest, LibraryOptionsPerInput) { + auto Invocation = std::make_shared<CompilerInvocation>(); + std::unique_ptr<MemoryBuffer> MemBuffer = + MemoryBuffer::getMemBuffer("", "test.ll"); + for (int I = 0; I != 2; ++I) + Invocation->getFrontendOpts().Inputs.push_back( + FrontendInputFile(*MemBuffer, Language::LLVM_IR)); + Invocation->getFrontendOpts().LLVMArgs = {"-instcombine-code-sinking=0"}; + Invocation->getFrontendOpts().ProgramAction = frontend::EmitLLVMOnly; + Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu"; + CompilerInstance Compiler(std::move(Invocation)); + Compiler.setVirtualFileSystem(llvm::vfs::getRealFileSystem()); + Compiler.createDiagnostics(); + Compiler.parseLLVMArgs(); + + LLVMContext Ctx; + EmitLLVMOnlyAction Action(&Ctx); + EXPECT_TRUE(Compiler.ExecuteAction(Action)); + EXPECT_EQ(Ctx.getLibraryOptions().args().size(), 1u); +} } diff --git a/llvm/include/llvm/Option/LibraryOptions.h b/llvm/include/llvm/Option/LibraryOptions.h index 19df88f77e586a..830cc52fd14fbc 100644 --- a/llvm/include/llvm/Option/LibraryOptions.h +++ b/llvm/include/llvm/Option/LibraryOptions.h @@ -119,7 +119,7 @@ class LLVM_ABI LibraryOptTable : public OptTable { ~LibraryOptTable() override; }; -/// Connects options struct T to cl::ParseCommandLineOptions and +/// Connects options struct T to cl::parseCommandLineOptions and /// cl::LibraryOptionsContext. class LLVM_ABI LibraryOptionsParser final : public cl::LibraryOptions { public: diff --git a/llvm/include/llvm/SandboxIR/Context.h b/llvm/include/llvm/SandboxIR/Context.h index 2467c5d7fb3d51..4d1cd45612f41e 100644 --- a/llvm/include/llvm/SandboxIR/Context.h +++ b/llvm/include/llvm/SandboxIR/Context.h @@ -237,6 +237,9 @@ class LLVM_ABI Context { /// Clears function-level state. void clear(); + cl::LibraryOptionsContext &getLibraryOptions() const { + return LLVMCtx.getLibraryOptions(); + } Tracker &getTracker() { return IRTracker; } /// Convenience function for `getTracker().save()` void save() { IRTracker.save(); } diff --git a/llvm/include/llvm/Support/LibraryOptionsContext.h b/llvm/include/llvm/Support/LibraryOptionsContext.h index 150a8c1d5a7719..f9b74ea181ef07 100644 --- a/llvm/include/llvm/Support/LibraryOptionsContext.h +++ b/llvm/include/llvm/Support/LibraryOptionsContext.h @@ -23,20 +23,20 @@ namespace cl { class LibraryOptions; -// Values of library options that override their global() in one compilation -// context, such as an LLVMContext. +// The library options of one compilation context, such as an LLVMContext. +// Libraries declared with perContext read their options here. class LLVM_ABI LibraryOptionsContext { public: - // Sets the library options that Args spell, e.g. {"-x=v"}. A library's values - // start as a copy of its global(), and later calls add to them. Fails at the - // first argument that is not a library option or has an invalid value. + // Replaces the library options with those that Args spell, e.g. {"-x=v"}. + // Fails at the first argument that is not a library option or has an invalid + // value. // - // Strings copied from global() die with ResetAllOptionOccurrences. The first - // call (or ParseCommandLineOptions) indexes the registry, which is not - // thread-safe. - Error set(ArrayRef<const char *> Args); + // A library's values start as a copy of its global(), which may refer to + // strings that ResetAllOptionOccurrences frees. + // Indexing libraries registered since the last parse is not thread-safe. + Error assign(ArrayRef<const char *> Args); - // Parses the option of L that Args[0] spells, as set() does. + // Parses the option of L that Args[0] spells, keeping the other values. Error parse(LibraryOptions &L, ArrayRef<const char *> Args, unsigned &Consumed); diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Passes/BundleVec.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Passes/BundleVec.h index 08d7c8981f092a..04d03ada87b247 100644 --- a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Passes/BundleVec.h +++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Passes/BundleVec.h @@ -23,6 +23,10 @@ #include "llvm/Transforms/Vectorize/SandboxVectorizer/Legality.h" #include "llvm/Transforms/Vectorize/SandboxVectorizer/Scheduler.h" +namespace llvm { +struct VectorizeOptions; +} // namespace llvm + namespace llvm::sandboxir { /// This is a simple bottom-up (top-down) vectorizer Region pass. @@ -38,6 +42,7 @@ namespace llvm::sandboxir { /// accepts or rejects the IR transaction, depending on the cost. class LLVM_ABI BundleVec final : public RegionPass { private: + const VectorizeOptions *Opts = nullptr; /// Set to true whenever the pass modifies the IR. bool Change = false; AuxPassArgsRegistry ArgsRegistry; diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/SeedCollector.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/SeedCollector.h index 3f8b49af7b1bdd..d63c0276a6e9c6 100644 --- a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/SeedCollector.h +++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/SeedCollector.h @@ -197,12 +197,13 @@ class SeedContainer { DenseMap<Instruction *, SeedBundle *> SeedLookupMap; ScalarEvolution &SE; + unsigned BundleSizeLimit; template <typename LoadOrStoreT> KeyT getKey(LoadOrStoreT *LSI, bool AllowDiffTypes) const; public: - SeedContainer(ScalarEvolution &SE) : SE(SE) {} + LLVM_ABI SeedContainer(ScalarEvolution &SE); class iterator { BundleMapT *Map = nullptr; diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp index 31f07e114cace1..6e304b28da6c49 100644 --- a/llvm/lib/Support/CommandLine.cpp +++ b/llvm/lib/Support/CommandLine.cpp @@ -1446,7 +1446,8 @@ Error ExpansionContext::readConfigFile(StringRef CfgFile, } static void initCommonOptions(); -static bool parseCommandLineOptionsImpl(LibraryOptionsContext *Context, ArrayRef<const char *> Args, +static bool parseCommandLineOptionsImpl(LibraryOptionsContext *Context, + ArrayRef<const char *> Args, StringRef Overview, raw_ostream *Errs, vfs::FileSystem *VFS, const char *EnvVar) { @@ -2942,7 +2943,9 @@ void cl::addLibraryOptions(LibraryOptions &L) { globalParser().Libraries.push_back(&L); } -Error LibraryOptionsContext::set(ArrayRef<const char *> Args) { +Error LibraryOptionsContext::assign(ArrayRef<const char *> Args) { + Values.clear(); + this->Args.clear(); for (size_t I = 0, E = Args.size(); I != E;) { StringRef Name = Args[I]; LibraryOptions *L = nullptr; diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index 7158dec4277b4e..36293a73ebdb9e 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -96,7 +96,6 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/KnownBits.h" #include "llvm/Support/KnownFPClass.h" -#include "llvm/Support/LibraryOptionsContext.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/InstCombine/InstCombine.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" diff --git a/llvm/lib/Transforms/Vectorize/LoopIdiomVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopIdiomVectorize.cpp index 67fc06e8c5ad7e..3801e4f9eb02cb 100644 --- a/llvm/lib/Transforms/Vectorize/LoopIdiomVectorize.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopIdiomVectorize.cpp @@ -160,7 +160,8 @@ class LoopIdiomVectorize { PreservedAnalyses LoopIdiomVectorizePass::run(Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR, LPMUpdater &) { - const VectorizeOptions &Opts = VectorizeOptions::Global; + const VectorizeOptions &Opts = + L.getHeader()->getContext().getLibraryOptions().get<VectorizeOptions>(); if (Opts.disable_loop_idiom_vectorize_all) return PreservedAnalyses::all(); diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp index 24f50d2120b0c5..0619a0e36c678d 100644 --- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -7400,7 +7400,8 @@ static void connectEpilogueVectorLoop(VPlan &EpiPlan, DominatorTree *DT, } bool LoopVectorizePass::processLoop(Loop *L) { - const VectorizeOptions &Opts = VectorizeOptions::Global; + const VectorizeOptions &Opts = + L->getHeader()->getContext().getLibraryOptions().get<VectorizeOptions>(); assert((Opts.enable_vplan_native_path || L->isInnermost()) && "VPlan-native path is not enabled. Only process inner loops."); @@ -7963,8 +7964,10 @@ LoopVectorizeResult LoopVectorizePass::runImpl(Function &F) { // and can invalidate iterators across the loops. SmallVector<Loop *, 8> Worklist; + const VectorizeOptions &Opts = + F.getContext().getLibraryOptions().get<VectorizeOptions>(); for (Loop *L : *LI) - collectSupportedLoops(VectorizeOptions::Global, *L, LI, ORE, Worklist); + collectSupportedLoops(Opts, *L, LI, ORE, Worklist); LoopsAnalyzed += Worklist.size(); diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp index 1ced55cea8d724..9f37ebea74f475 100644 --- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp +++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp @@ -29450,7 +29450,7 @@ bool SLPVectorizerPass::runImpl(Function &F, ScalarEvolution *SE_, LoopInfo *LI_, DominatorTree *DT_, AssumptionCache *AC_, DemandedBits *DB_, OptimizationRemarkEmitter *ORE_) { - Opts = &VectorizeOptions::Global; + Opts = &F.getContext().getLibraryOptions().get<VectorizeOptions>(); if (!Opts->vectorize_slp) return false; SE = SE_; diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/BundleVec.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/BundleVec.cpp index 28e2877cc77aa8..f6bb1abc0454b3 100644 --- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/BundleVec.cpp +++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/BundleVec.cpp @@ -205,9 +205,8 @@ Value *BundleVec::createPack(BndlRef<Value *> ToPack, BasicBlock *UserBB) { Action *BundleVec::vectorizeRec(BndlRef<Value *> Bndl, BndlRef<Value *> UserBndl, unsigned Depth, LegalityAnalysis &Legality) { - const VectorizeOptions &Opts = VectorizeOptions::Global; - bool StopForDebug = DebugBndlCnt++ >= Opts.sbvec_stop_bndl && - Opts.sbvec_stop_bndl != SBVecStopDisabled; + bool StopForDebug = DebugBndlCnt++ >= Opts->sbvec_stop_bndl && + Opts->sbvec_stop_bndl != SBVecStopDisabled; LLVM_DEBUG(dbgs() << DEBUG_PREFIX << "canVectorize() Bundle:\n"; VecUtils::dump(Bndl)); const auto &LegalityRes = StopForDebug ? Legality.getForcedPackForDebugging() @@ -479,7 +478,7 @@ Value *BundleVec::emitVectors() { ActionPtr->Vec = NewVec; } #ifndef NDEBUG - if (VectorizeOptions::Global.sbvec_always_verify) { + if (Opts->sbvec_always_verify) { // This helps find broken IR by constantly verifying the function. Note // that this is very expensive and should only be used for debugging. Instruction *I0 = isa<Instruction>(Bndl[0]) @@ -495,10 +494,9 @@ Value *BundleVec::emitVectors() { bool BundleVec::tryVectorize(BndlRef<Value *> Bndl, LegalityAnalysis &Legality) { - const VectorizeOptions &Opts = VectorizeOptions::Global; Change = false; - if (LLVM_UNLIKELY(InvocationCnt++ >= Opts.sbvec_stop_at && - Opts.sbvec_stop_at != SBVecStopDisabled)) + if (LLVM_UNLIKELY(InvocationCnt++ >= Opts->sbvec_stop_at && + Opts->sbvec_stop_at != SBVecStopDisabled)) return false; Legality.clear(); Actions.clear(); @@ -513,6 +511,7 @@ bool BundleVec::tryVectorize(BndlRef<Value *> Bndl, } bool BundleVec::runOnRegion(Region &Rgn, const Analyses &A) { + Opts = &Rgn.getContext().getLibraryOptions().get<VectorizeOptions>(); const auto &SeedSlice = Rgn.getAux(); if (SeedSlice.size() < 2) return false; diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/LoadStoreVec.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/LoadStoreVec.cpp index d4898ff577471a..f5f4c12c7ad0d5 100644 --- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/LoadStoreVec.cpp +++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/LoadStoreVec.cpp @@ -55,7 +55,9 @@ bool LoadStoreVec::acceptOrRevert() { LLVM_DEBUG(dbgs() << DEBUG_PREFIX_LOCAL << "CostGain=" << CostGain << " (After=" << CostAfter << " Before=" << CostBefore << ")\n"); - if (CostGain > VectorizeOptions::Global.sbvec_cost_threshold) { + const VectorizeOptions &Opts = + Ctx->getLibraryOptions().get<VectorizeOptions>(); + if (CostGain > Opts.sbvec_cost_threshold) { LLVM_DEBUG(dbgs() << DEBUG_PREFIX_LOCAL << "Not profitable, reverting.\n"); Ctx->revert(); return false; diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/SeedCollection.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/SeedCollection.cpp index 27fd775ee20777..97822a64e4b1c5 100644 --- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/SeedCollection.cpp +++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/SeedCollection.cpp @@ -30,7 +30,8 @@ SeedCollection::SeedCollection(StringRef Pipeline, StringRef AuxArg) } bool SeedCollection::runOnFunction(Function &F, const Analyses &A) { - const VectorizeOptions &Opts = VectorizeOptions::Global; + const VectorizeOptions &Opts = + F.getContext().getLibraryOptions().get<VectorizeOptions>(); bool Change = false; const auto &DL = F.getParent()->getDataLayout(); diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/TransactionAcceptOrRevert.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/TransactionAcceptOrRevert.cpp index b4157cbcf232b7..394b511605eb15 100644 --- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/TransactionAcceptOrRevert.cpp +++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/TransactionAcceptOrRevert.cpp @@ -17,7 +17,8 @@ namespace llvm { namespace sandboxir { bool TransactionAcceptOrRevert::runOnRegion(Region &Rgn, const Analyses &A) { - const VectorizeOptions &Opts = VectorizeOptions::Global; + const VectorizeOptions &Opts = + Rgn.getContext().getLibraryOptions().get<VectorizeOptions>(); const auto &SB = cast<RegionWithScore>(Rgn).getScoreboard(); [[maybe_unused]] auto CostBefore = SB.getBeforeCost(); [[maybe_unused]] auto CostAfter = SB.getAfterCost(); diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizer.cpp index 5d3369cae02565..7310a39421b07b 100644 --- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizer.cpp +++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizer.cpp @@ -83,7 +83,7 @@ bool SandboxVectorizerPass::allowFile(const std::string &SrcFilePath) { } bool SandboxVectorizerPass::runImpl(Function &LLVMF) { - Opts = &VectorizeOptions::Global; + Opts = &LLVMF.getContext().getLibraryOptions().get<VectorizeOptions>(); if (Ctx == nullptr) { Ctx = std::make_unique<sandboxir::Context>(LLVMF.getContext()); buildPipeline(); diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/SeedCollector.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/SeedCollector.cpp index 48e7a7fa99002d..ccab5e105bf0f2 100644 --- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/SeedCollector.cpp +++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/SeedCollector.cpp @@ -98,6 +98,12 @@ bool SeedContainer::erase(Instruction *I) { return true; } +SeedContainer::SeedContainer(ScalarEvolution &SE) : SE(SE) { + const VectorizeOptions &Opts = + SE.getContext().getLibraryOptions().get<VectorizeOptions>(); + BundleSizeLimit = Opts.sbvec_seed_bundle_size_limit; +} + template <typename LoadOrStoreT> void SeedContainer::insert(LoadOrStoreT *LSI, bool AllowDiffTypes) { // Find the bundle containing seeds for this symbol and type-of-access. @@ -105,9 +111,7 @@ void SeedContainer::insert(LoadOrStoreT *LSI, bool AllowDiffTypes) { // Fill this vector of bundles front to back so that only the last bundle in // the vector may have available space. This avoids iteration to find one with // space. - if (BundleVec.empty() || - BundleVec.back()->size() == - VectorizeOptions::Global.sbvec_seed_bundle_size_limit) + if (BundleVec.empty() || BundleVec.back()->size() == BundleSizeLimit) BundleVec.emplace_back(std::make_unique<MemSeedBundle<LoadOrStoreT>>(LSI)); else BundleVec.back()->tryInsert(LSI, SE); @@ -175,6 +179,8 @@ SeedCollector::SeedCollector(BasicBlock *BB, ScalarEvolution &SE, }); // Actually collect the seeds. + const VectorizeOptions &Opts = + Ctx.getLibraryOptions().get<VectorizeOptions>(); for (auto &I : *BB) { if (StoreInst *SI = dyn_cast<StoreInst>(&I)) if (CollectStores && isValidMemSeed(SI)) @@ -183,7 +189,7 @@ SeedCollector::SeedCollector(BasicBlock *BB, ScalarEvolution &SE, if (CollectLoads && isValidMemSeed(LI)) LoadSeeds.insert(LI, AllowDiffTypes); // Cap compilation time. - if (totalNumSeedGroups() > VectorizeOptions::Global.sbvec_seed_groups_limit) + if (totalNumSeedGroups() > Opts.sbvec_seed_groups_limit) break; } } diff --git a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/VecUtils.cpp b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/VecUtils.cpp index 4299bbac1bf11a..7592749d1fc09d 100644 --- a/llvm/lib/Transforms/Vectorize/SandboxVectorizer/VecUtils.cpp +++ b/llvm/lib/Transforms/Vectorize/SandboxVectorizer/VecUtils.cpp @@ -69,13 +69,14 @@ VecUtils::getNextUserBundles(ArrayRef<Value *> Bndl, const InstrMaps &IMaps, Value *V0 = Bndl[0]; DenseSet<User *> SeenUsers; + const VectorizeOptions &Opts = + V0->getContext().getLibraryOptions().get<VectorizeOptions>(); // For each user U0 of lane 0, try to form a bundle of matching users across // all lanes. Cap the number of users considered to bound compilation time, // since each one may trigger an O(Bndl.size()) search across the other // lanes' users. for (User *U0 : V0->users()) { - if (SeenUsers.size() >= - VectorizeOptions::Global.sbvec_max_users_to_consider) + if (SeenUsers.size() >= Opts.sbvec_max_users_to_consider) break; if (!SeenUsers.insert(U0).second) continue; diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp index e042eb1063761c..3f34669819e342 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp @@ -49,20 +49,24 @@ using namespace VPlanPatternMatch; using namespace SCEVPatternMatch; void VPlanTransforms::verifyIfRequested(VPlan &Plan) { - if (VectorizeOptions::Global.vplan_verify_each && !verifyVPlanIsValid(Plan)) + const VectorizeOptions &Opts = + Plan.getContext().getLibraryOptions().get<VectorizeOptions>(); + if (Opts.vplan_verify_each && !verifyVPlanIsValid(Plan)) report_fatal_error("Broken VPlan found, compilation aborted!"); } #ifndef NDEBUG -bool VPlanTransforms::isPrintingRequested() { - const VectorizeOptions &Opts = VectorizeOptions::Global; +bool VPlanTransforms::isPrintingRequested(const VPlan &Plan) { + const VectorizeOptions &Opts = + Plan.getContext().getLibraryOptions().get<VectorizeOptions>(); return Opts.vplan_print_before_all || Opts.vplan_print_after_all || !Opts.vplan_print_before.empty() || !Opts.vplan_print_after.empty(); } void VPlanTransforms::printIfRequested(VPlan &Plan, Function *Fn, StringRef NumberedPassName, bool After) { - const VectorizeOptions &Opts = VectorizeOptions::Global; + const VectorizeOptions &Opts = + Plan.getContext().getLibraryOptions().get<VectorizeOptions>(); bool All = After ? Opts.vplan_print_after_all : Opts.vplan_print_before_all; ArrayRef<StringRef> Passes = After ? Opts.vplan_print_after : Opts.vplan_print_before; diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h index 927ffb76486ea1..9144b2e1a8fda9 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h +++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h @@ -41,7 +41,7 @@ struct VPlanTransforms { LLVM_ABI_FOR_TEST static void verifyIfRequested(VPlan &Plan); #ifndef NDEBUG - LLVM_ABI_FOR_TEST static bool isPrintingRequested(); + LLVM_ABI_FOR_TEST static bool isPrintingRequested(const VPlan &Plan); /// Print \p Plan of \p Fn before or after the pass \p NumberedPassName if /// requested. @@ -65,7 +65,7 @@ struct VPlanTransforms { unsigned Instance; std::string NumberedPassName; - if (isPrintingRequested()) { + if (isPrintingRequested(Plan)) { Instance = ++PassCounter[{Fn, PassName}]; NumberedPassName = Instance == 1 diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp index 6a75a0f3d66ee8..e7927ea6b5198e 100644 --- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp +++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp @@ -7252,8 +7252,9 @@ PreservedAnalyses VectorCombinePass::run(Function &F, const DataLayout *DL = &F.getDataLayout(); TTI::TargetCostKind CostKind = F.hasOptSize() ? TTI::TCK_CodeSize : TTI::TCK_RecipThroughput; - VectorCombine Combiner(VectorizeOptions::Global, F, TTI, DT, AA, AC, DL, - CostKind, TryEarlyFoldsOnly); + VectorCombine Combiner( + F.getContext().getLibraryOptions().get<VectorizeOptions>(), F, TTI, DT, + AA, AC, DL, CostKind, TryEarlyFoldsOnly); if (!Combiner.run()) return PreservedAnalyses::all(); PreservedAnalyses PA; diff --git a/llvm/lib/Transforms/Vectorize/VectorizeOptions.td b/llvm/lib/Transforms/Vectorize/VectorizeOptions.td index e3bb555306f387..9a43436ee057a3 100644 --- a/llvm/lib/Transforms/Vectorize/VectorizeOptions.td +++ b/llvm/lib/Transforms/Vectorize/VectorizeOptions.td @@ -8,7 +8,7 @@ include "llvm/Option/LibraryOptions.td" -def VectorizeOptions : OptionsStruct; +def VectorizeOptions : OptionsStruct<perContext = true>; // LoopIdiomVectorize.cpp defm : BoolField<"disable-loop-idiom-vectorize-all", "false", diff --git a/llvm/unittests/Option/LibraryOptionsTest.cpp b/llvm/unittests/Option/LibraryOptionsTest.cpp index 0120f105353323..c360f73270379f 100644 --- a/llvm/unittests/Option/LibraryOptionsTest.cpp +++ b/llvm/unittests/Option/LibraryOptionsTest.cpp @@ -208,30 +208,28 @@ TEST(LibraryOptionsTest, Values) { opt::RegisterLibraryOptions<TestLibraryOptions> Registration; cl::opt<bool> NotLibrary("lib-cl-opt"); cl::LibraryOptionsContext V; - auto Set = [&](std::initializer_list<const char *> Args) { - return toString(V.set(Args)); + auto Assign = [&](std::initializer_list<const char *> Args) { + return toString(V.assign(Args)); }; + EXPECT_EQ(Assign({"-lib-list=9"}), ""); std::string Path = "-lib-path=q"; - EXPECT_EQ(Set({"-lib-count", "7", Path.c_str(), "--lib-list=1,2"}), ""); + EXPECT_EQ(Assign({"-lib-count", "7", Path.c_str(), "--lib-list=1,2"}), ""); Path.assign(Path.size(), ' '); EXPECT_EQ(TestLibraryOptions::Global.count, 3u); - - // A later call keeps the earlier values. - EXPECT_EQ(Set({"-lib-list=3"}), ""); - EXPECT_THAT(V.get<TestLibraryOptions>().list, - testing::ElementsAre(1u, 2u, 3u)); + // The earlier call's values are discarded. + EXPECT_THAT(V.get<TestLibraryOptions>().list, testing::ElementsAre(1u, 2u)); // Another context replays the arguments, which outlive the caller's. cl::LibraryOptionsContext Copy; - EXPECT_EQ(toString(Copy.set(V.args())), ""); + EXPECT_EQ(toString(Copy.assign(V.args())), ""); const TestLibraryOptions &C = Copy.get<TestLibraryOptions>(); EXPECT_EQ(C.count, 7u); EXPECT_EQ(C.Path, "q"); - EXPECT_THAT(C.list, testing::ElementsAre(1u, 2u, 3u)); + EXPECT_THAT(C.list, testing::ElementsAre(1u, 2u)); - EXPECT_EQ(Set({"-lib-count=x"}), "invalid value 'x' in '-lib-count=x'"); - EXPECT_EQ(Set({"-lib-cl-opt"}), "'-lib-cl-opt' is not a library option"); - EXPECT_EQ(Set({"lib-count=1"}), "'lib-count=1' is not a library option"); + EXPECT_EQ(Assign({"-lib-count=x"}), "invalid value 'x' in '-lib-count=x'"); + EXPECT_EQ(Assign({"-lib-cl-opt"}), "'-lib-cl-opt' is not a library option"); + EXPECT_EQ(Assign({"lib-count=1"}), "'lib-count=1' is not a library option"); cl::ResetCommandLineParser(); } diff --git a/llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp b/llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp index d1d971285eb781..2100f558b24c35 100644 --- a/llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp +++ b/llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp @@ -13,7 +13,6 @@ #include "VPlanTestBase.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" -#include "llvm/Support/SaveAndRestore.h" #include "gtest/gtest.h" using namespace llvm; @@ -485,8 +484,7 @@ TEST_F(VPVerifierTest, testRUN_VPLAN_PASS) { VPBB1->appendRecipe(UseI); VPBB1->appendRecipe(DefI); - llvm::SaveAndRestore<bool> RestoreVerifyEachVPlan( - VectorizeOptions::Global.vplan_verify_each, true); + cantFail(C.getLibraryOptions().assign({"-vplan-verify-each"})); auto NopPass = [](VPlan &Plan) {}; EXPECT_DEATH( { VPlanTransforms::runPass("simplifyRecipes", NopPass, Plan); }, diff --git a/llvm/utils/TableGen/Basic/OptionParserEmitter.cpp b/llvm/utils/TableGen/Basic/OptionParserEmitter.cpp index 8df952eb8664e0..08b94a68c4e985 100644 --- a/llvm/utils/TableGen/Basic/OptionParserEmitter.cpp +++ b/llvm/utils/TableGen/Basic/OptionParserEmitter.cpp @@ -351,12 +351,16 @@ static void emitOptionsStruct(const Record &Struct, OS << "#include \"llvm/ADT/ArrayRef.h\"\n"; OS << "#include \"llvm/ADT/BoolOrDefault.h\"\n"; OS << "#include \"llvm/ADT/StringRef.h\"\n"; - OS << "#include \"llvm/Support/Allocator.h\"\n\n"; + OS << "#include \"llvm/Support/Allocator.h\"\n"; + bool PerContext = Struct.getValueAsBit("PerContext"); + if (PerContext) + OS << "#include \"llvm/Support/LibraryOptionsContext.h\"\n"; + OS << "\n"; StringRef Namespace = Struct.getValueAsString("Namespace"); - OS << "namespace llvm {\nnamespace cl {\nclass LibraryOptionsContext;\n" - "} // namespace cl\nnamespace opt {\nclass Arg;\n" - "class LibraryOptionsParser;\nclass OptTable;\n} // namespace opt\n" - "} // namespace llvm\n\n"; + OS << "namespace llvm {\nnamespace opt {\nclass Arg;\n"; + if (PerContext) + OS << "class LibraryOptionsParser;\n"; + OS << "class OptTable;\n} // namespace opt\n} // namespace llvm\n\n"; OS << "namespace " << Namespace << " {\n"; OS << "struct " << Name << " {\n"; if (Namespace != "llvm") @@ -365,7 +369,6 @@ static void emitOptionsStruct(const Record &Struct, ConditionScope CS(OS, *R); OS << " " << M.Type << " " << M.Name << "{" << M.Default << "};\n"; } - bool PerContext = Struct.getValueAsBit("PerContext"); OS << "\n static constexpr bool PerContext = " << (PerContext ? "true" : "false") << ";\n"; OS << " static const llvm::opt::OptTable &optTable();\n"; >From c383f9b28650ba338f20f47bab85fff04145b209 Mon Sep 17 00:00:00 2001 From: Fangrui Song <[email protected]> Date: Tue, 13 Oct 2026 23:29:07 -0700 Subject: [PATCH 3/4] simplify assign() --- clang/lib/CIR/FrontendAction/CIRGenAction.cpp | 2 +- clang/lib/CodeGen/CodeGenAction.cpp | 3 +- llvm/include/llvm/Support/CommandLine.h | 6 ++-- .../llvm/Support/LibraryOptionsContext.h | 12 ++++---- llvm/lib/Support/CommandLine.cpp | 28 ++++++++----------- .../IR/LibraryOptionsContextTest.cpp | 8 ++---- llvm/unittests/Option/LibraryOptionsTest.cpp | 28 +++++++++---------- .../Vectorize/VPlanVerifierTest.cpp | 6 ++-- 8 files changed, 42 insertions(+), 51 deletions(-) diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp index 54a6b5336662bb..442562a4fffff0 100644 --- a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp +++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp @@ -368,7 +368,7 @@ CIRGenAction::CIRGenAction(OutputType Act, mlir::MLIRContext *MLIRCtx) CIRGenAction::~CIRGenAction() { MLIRMod.release(); } bool CIRGenAction::BeginSourceFileAction(CompilerInstance &CI) { - cantFail(Ctx->getLibraryOptions().assign(CI.getLibraryOptions().args())); + Ctx->getLibraryOptions().assign(CI.getLibraryOptions()); if (clang::loadLinkModules(CI, *Ctx, LinkModules)) return false; return ASTFrontendAction::BeginSourceFileAction(CI); diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index cd5047659eef7a..772bb8872517b0 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -367,8 +367,7 @@ CodeGenerator *CodeGenAction::getCodeGenerator() const { } bool CodeGenAction::BeginSourceFileAction(CompilerInstance &CI) { - cantFail( - VMContext->getLibraryOptions().assign(CI.getLibraryOptions().args())); + VMContext->getLibraryOptions().assign(CI.getLibraryOptions()); if (CI.getFrontendOpts().GenReducedBMI) CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleInterface); return ASTFrontendAction::BeginSourceFileAction(CI); diff --git a/llvm/include/llvm/Support/CommandLine.h b/llvm/include/llvm/Support/CommandLine.h index 1b3e3745ce7246..f51cd4879eafdb 100644 --- a/llvm/include/llvm/Support/CommandLine.h +++ b/llvm/include/llvm/Support/CommandLine.h @@ -72,9 +72,9 @@ LLVM_ABI bool ParseCommandLineOptions(int argc, const char *const *argv, vfs::FileSystem *VFS = nullptr, const char *EnvVar = nullptr); -// Like ParseCommandLineOptions, but sets the library registered options -// as per-context in LibraryOptions rather than in their global(). -LLVM_ABI bool parseCommandLineOptions(LibraryOptionsContext &LibraryOptions, +// Like ParseCommandLineOptions, but sets per-context libraries' options in +// Context instead of their global(). +LLVM_ABI bool parseCommandLineOptions(LibraryOptionsContext &Context, ArrayRef<const char *> Args, StringRef Overview = "", raw_ostream *Errs = nullptr, diff --git a/llvm/include/llvm/Support/LibraryOptionsContext.h b/llvm/include/llvm/Support/LibraryOptionsContext.h index f9b74ea181ef07..16312dc4ba32b1 100644 --- a/llvm/include/llvm/Support/LibraryOptionsContext.h +++ b/llvm/include/llvm/Support/LibraryOptionsContext.h @@ -27,21 +27,19 @@ class LibraryOptions; // Libraries declared with perContext read their options here. class LLVM_ABI LibraryOptionsContext { public: - // Replaces the library options with those that Args spell, e.g. {"-x=v"}. - // Fails at the first argument that is not a library option or has an invalid - // value. + // Replaces the library options with Other's by replaying its arguments. // // A library's values start as a copy of its global(), which may refer to // strings that ResetAllOptionOccurrences frees. // Indexing libraries registered since the last parse is not thread-safe. - Error assign(ArrayRef<const char *> Args); + void assign(const LibraryOptionsContext &Other); // Parses the option of L that Args[0] spells, keeping the other values. Error parse(LibraryOptions &L, ArrayRef<const char *> Args, unsigned &Consumed); - // The arguments set so far, for replaying into another context. - ArrayRef<const char *> args() const { return Args; } + // The arguments assigned so far. + ArrayRef<const char *> args() const { return SavedArgs; } // T's values, or T::Global if there are none. template <typename T> const T &get() const { @@ -54,7 +52,7 @@ class LLVM_ABI LibraryOptionsContext { private: DenseMap<const void *, void *> Values; - SmallVector<const char *, 0> Args; + SmallVector<const char *, 0> SavedArgs; BumpPtrAllocator Alloc; }; diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp index 6e304b28da6c49..12cef93255e485 100644 --- a/llvm/lib/Support/CommandLine.cpp +++ b/llvm/lib/Support/CommandLine.cpp @@ -1480,11 +1480,11 @@ bool cl::ParseCommandLineOptions(int argc, const char *const *argv, Errs, VFS, EnvVar); } -bool cl::parseCommandLineOptions(LibraryOptionsContext &LibraryOptions, +bool cl::parseCommandLineOptions(LibraryOptionsContext &Context, ArrayRef<const char *> Args, StringRef Overview, raw_ostream *Errs, vfs::FileSystem *VFS, const char *EnvVar) { - return parseCommandLineOptionsImpl(&LibraryOptions, Args, Overview, Errs, VFS, + return parseCommandLineOptionsImpl(&Context, Args, Overview, Errs, VFS, EnvVar); } @@ -2943,25 +2943,21 @@ void cl::addLibraryOptions(LibraryOptions &L) { globalParser().Libraries.push_back(&L); } -Error LibraryOptionsContext::assign(ArrayRef<const char *> Args) { +void LibraryOptionsContext::assign(const LibraryOptionsContext &Other) { + assert(this != &Other); Values.clear(); - this->Args.clear(); + SavedArgs.clear(); + ArrayRef<const char *> Args = Other.SavedArgs; for (size_t I = 0, E = Args.size(); I != E;) { StringRef Name = Args[I]; - LibraryOptions *L = nullptr; - if (Name.consume_front("-")) { - Name.consume_front("-"); - L = globalParser().lookupLibraryOption(Name.split('=').first); - } - if (!L) - return createStringError("'" + Twine(Args[I]) + - "' is not a library option"); + Name.consume_front("-"); + Name.consume_front("-"); + LibraryOptions *L = + globalParser().lookupLibraryOption(Name.split('=').first); unsigned N; - if (Error Err = parse(*L, Args.drop_front(I), N)) - return Err; + cantFail(parse(*L, Args.drop_front(I), N)); I += N; } - return Error::success(); } Error LibraryOptionsContext::parse(LibraryOptions &L, @@ -2970,7 +2966,7 @@ Error LibraryOptionsContext::parse(LibraryOptions &L, auto [It, Inserted] = Values.try_emplace(L.global()); if (Inserted) It->second = L.copyGlobal(Alloc); - return parseLibraryOption(L, It->second, Args, Consumed, Alloc, &this->Args); + return parseLibraryOption(L, It->second, Args, Consumed, Alloc, &SavedArgs); } void cl::ResetAllOptionOccurrences() { diff --git a/llvm/unittests/IR/LibraryOptionsContextTest.cpp b/llvm/unittests/IR/LibraryOptionsContextTest.cpp index 2588bdcda41cb7..87fd1a2378b3b0 100644 --- a/llvm/unittests/IR/LibraryOptionsContextTest.cpp +++ b/llvm/unittests/IR/LibraryOptionsContextTest.cpp @@ -17,11 +17,9 @@ using namespace llvm; -namespace { - // InstCombine sinks %a into its only user's block unless // -instcombine-code-sinking=0. -const char *IR = R"( +const char IR[] = R"( define i32 @f(i1 %c, i32 %x) { entry: %a = add i32 %x, 1 @@ -34,7 +32,7 @@ define i32 @f(i1 %c, i32 %x) { )"; // Runs InstCombine on IR in Ctx and returns the block that holds %a. -std::string runInstCombine(LLVMContext &Ctx) { +static std::string runInstCombine(LLVMContext &Ctx) { SMDiagnostic Err; std::unique_ptr<Module> M = parseAssemblyString(IR, Err, Ctx); if (!M) @@ -65,5 +63,3 @@ TEST(LibraryOptionsContextTest, InstCombine) { EXPECT_EQ(runInstCombine(C1), "t"); EXPECT_EQ(runInstCombine(C2), "entry"); } - -} // namespace diff --git a/llvm/unittests/Option/LibraryOptionsTest.cpp b/llvm/unittests/Option/LibraryOptionsTest.cpp index c360f73270379f..558a78c2c390bb 100644 --- a/llvm/unittests/Option/LibraryOptionsTest.cpp +++ b/llvm/unittests/Option/LibraryOptionsTest.cpp @@ -206,30 +206,30 @@ TEST(LibraryOptionsTest, ParseIntoGlobal) { TEST(LibraryOptionsTest, Values) { cl::ResetCommandLineParser(); opt::RegisterLibraryOptions<TestLibraryOptions> Registration; - cl::opt<bool> NotLibrary("lib-cl-opt"); - cl::LibraryOptionsContext V; - auto Assign = [&](std::initializer_list<const char *> Args) { - return toString(V.assign(Args)); + opt::LibraryOptionsParser L{std::in_place_type<TestLibraryOptions>}; + auto Parse = [&](cl::LibraryOptionsContext &V, ArrayRef<const char *> Args) { + unsigned N; + return toString(V.parse(L, Args, N)); }; - EXPECT_EQ(Assign({"-lib-list=9"}), ""); + cl::LibraryOptionsContext V; std::string Path = "-lib-path=q"; - EXPECT_EQ(Assign({"-lib-count", "7", Path.c_str(), "--lib-list=1,2"}), ""); + EXPECT_EQ(Parse(V, {"-lib-count", "7"}), ""); + EXPECT_EQ(Parse(V, Path.c_str()), ""); + EXPECT_EQ(Parse(V, "--lib-list=1,2"), ""); Path.assign(Path.size(), ' '); EXPECT_EQ(TestLibraryOptions::Global.count, 3u); - // The earlier call's values are discarded. - EXPECT_THAT(V.get<TestLibraryOptions>().list, testing::ElementsAre(1u, 2u)); + EXPECT_EQ(Parse(V, "-lib-count=x"), "invalid value 'x' in '-lib-count=x'"); - // Another context replays the arguments, which outlive the caller's. + // assign() replays the arguments, which outlive the caller's, and discards + // the earlier values. cl::LibraryOptionsContext Copy; - EXPECT_EQ(toString(Copy.assign(V.args())), ""); + EXPECT_EQ(Parse(Copy, "-lib-list=9"), ""); + Copy.assign(V); const TestLibraryOptions &C = Copy.get<TestLibraryOptions>(); EXPECT_EQ(C.count, 7u); EXPECT_EQ(C.Path, "q"); EXPECT_THAT(C.list, testing::ElementsAre(1u, 2u)); - - EXPECT_EQ(Assign({"-lib-count=x"}), "invalid value 'x' in '-lib-count=x'"); - EXPECT_EQ(Assign({"-lib-cl-opt"}), "'-lib-cl-opt' is not a library option"); - EXPECT_EQ(Assign({"lib-count=1"}), "'lib-count=1' is not a library option"); + EXPECT_EQ(Copy.args().size(), V.args().size()); cl::ResetCommandLineParser(); } diff --git a/llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp b/llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp index 2100f558b24c35..6eed6c30538198 100644 --- a/llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp +++ b/llvm/unittests/Transforms/Vectorize/VPlanVerifierTest.cpp @@ -9,10 +9,10 @@ #include "../lib/Transforms/Vectorize/VPlanVerifier.h" #include "../lib/Transforms/Vectorize/LoopVectorizationPlanner.h" #include "../lib/Transforms/Vectorize/VPlan.h" -#include "../lib/Transforms/Vectorize/VectorizeOptions.h" #include "VPlanTestBase.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" +#include "llvm/Support/CommandLine.h" #include "gtest/gtest.h" using namespace llvm; @@ -484,7 +484,9 @@ TEST_F(VPVerifierTest, testRUN_VPLAN_PASS) { VPBB1->appendRecipe(UseI); VPBB1->appendRecipe(DefI); - cantFail(C.getLibraryOptions().assign({"-vplan-verify-each"})); + const char *Args[] = {"prog", "-vplan-verify-each"}; + ASSERT_TRUE( + cl::parseCommandLineOptions(C.getLibraryOptions(), Args, "", &nulls())); auto NopPass = [](VPlan &Plan) {}; EXPECT_DEATH( { VPlanTransforms::runPass("simplifyRecipes", NopPass, Plan); }, >From 9eada30679fd2647e618f4e167c351d04d5e4d74 Mon Sep 17 00:00:00 2001 From: Fangrui Song <[email protected]> Date: Wed, 14 Oct 2026 10:53:27 -0700 Subject: [PATCH 4/4] fix bazel build --- clang/unittests/Frontend/CMakeLists.txt | 1 + llvm/utils/gn/secondary/clang/unittests/Frontend/BUILD.gn | 1 + utils/bazel/llvm-project-overlay/clang/unittests/BUILD.bazel | 1 + 3 files changed, 3 insertions(+) diff --git a/clang/unittests/Frontend/CMakeLists.txt b/clang/unittests/Frontend/CMakeLists.txt index 0d9fc714212d50..7fca6348ae9da3 100644 --- a/clang/unittests/Frontend/CMakeLists.txt +++ b/clang/unittests/Frontend/CMakeLists.txt @@ -24,6 +24,7 @@ add_clang_unittest(FrontendTests clangSerialization clangTooling LLVM_COMPONENTS + Core Support TargetParser ) diff --git a/llvm/utils/gn/secondary/clang/unittests/Frontend/BUILD.gn b/llvm/utils/gn/secondary/clang/unittests/Frontend/BUILD.gn index 6f1e5c8c593ca3..c7244ea9f15158 100644 --- a/llvm/utils/gn/secondary/clang/unittests/Frontend/BUILD.gn +++ b/llvm/utils/gn/secondary/clang/unittests/Frontend/BUILD.gn @@ -11,6 +11,7 @@ unittest("FrontendTests") { "//clang/lib/Lex", "//clang/lib/Sema", "//clang/lib/Tooling", + "//llvm/lib/IR", "//llvm/lib/Support", "//llvm/lib/Target:AllTargetsDescs", "//llvm/lib/TargetParser", diff --git a/utils/bazel/llvm-project-overlay/clang/unittests/BUILD.bazel b/utils/bazel/llvm-project-overlay/clang/unittests/BUILD.bazel index 1996fa21d7e4eb..e5a749e160f02d 100644 --- a/utils/bazel/llvm-project-overlay/clang/unittests/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/clang/unittests/BUILD.bazel @@ -310,6 +310,7 @@ cc_test( "//clang:serialization", "//clang:static_analyzer_core_options", "//clang:tooling", + "//llvm:Core", "//llvm:Option", "//llvm:Support", "//llvm:TargetParser", _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
