https://github.com/MaskRay created 
https://github.com/llvm/llvm-project/pull/231407

`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

>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] [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 b87dd037480d6..bceb85f6e923b 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 71a7a17146af3..a04aa51e163af 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 1abd8b0455a19..22925cc55f495 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 b09c9a9f5a5be..f122208d6b4c8 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 0000000000000..4f584b4058a81
--- /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 0000000000000..a4938f811537c
--- /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 ced9b9227538e..be0d27bacf3e4 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 8b5c34525fa7c..19df88f77e586 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 d901f8027f702..ab027c056831e 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 bc7059244461e..1b3e3745ce724 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 0000000000000..150a8c1d5a771
--- /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 1fcdd3bc4c142..fb3b4bd8b206f 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 74a73664473b0..d02d57e4c0197 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 cfcb82273eb6d..e5848a0498f23 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 1cb5fccb07a1b..31f07e114cace 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 9fc098796f9e4..d2f850f5972ef 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 6986fb324bfee..7158dec4277b4 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 068e227328c16..da87ef049c7d4 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 df83992fadd1e..ad94dcc32a880 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 0000000000000..2588bdcda41cb
--- /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 dff1d179845b7..0120f10535332 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 ccf45962ba04f..ae9e0969d1540 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 c4b23c046e718..8df952eb8664e 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 547d82187b87f..21d7a82a713b4 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 89c25df2d1d92..05e3760c588cf 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",

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to