[flang-commits] [clang] [flang] [lld] [llvm] [polly] [Option] Make Passes, Scalar, Instrumentation, and CGData options per-context (PR #232599)

Fangrui Song via flang-commits flang-commits at lists.llvm.org
Fri Oct 16 10:51:32 PDT 2026


https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/232599

>From 4568fe7f4d0d330a00014c42e304f9ea2a3af4d6 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Thu, 15 Oct 2026 08:40:57 -0700
Subject: [PATCH] [Option] Make Passes, Scalar, Instrumentation, and CGData
 options per-context

Follow-up to #232365: drop `perContext = false` from PassesOptions,
ScalarOptions, InstrumentationOptions, and CGDataOptions.

* IR passes read their LLVMContext's options in run(). Legacy passes
  that chose analyses from an option now always require them
  (ConstantHoisting, StructurizeCFG, GVN).
* Pass parameters that an option overrides are combined in run(), so
  -print-pipeline-passes no longer folds such options (e.g.
  -bonus-inst-threshold) into the printed parameters.
* PipelineTuningOptions carries the library options to PassBuilder,
  which falls back to the TargetMachine's. opt, clang, flang, and Polly
  pass their module's.
* The CodeGenData singleton is configured by its first caller. lld and
  llvm-cgdata pass an empty context.
* GCOVOptions::getDefault is removed.

LLM-aided
---
 clang/lib/CodeGen/BackendUtil.cpp             |  48 ++++----
 flang/lib/Frontend/FrontendActions.cpp        |   6 +-
 lld/MachO/Driver.cpp                          |   3 +-
 llvm/include/llvm/CGData/CodeGenData.h        |  49 +++++---
 llvm/include/llvm/CGData/CodeGenDataReader.h  |  13 ++-
 llvm/include/llvm/CGData/StableFunctionMap.h  |   7 +-
 .../llvm/CGData/StableFunctionMapRecord.h     |   5 +-
 .../llvm/Frontend/Driver/CodeGenOptions.h     |   6 +-
 llvm/include/llvm/Passes/PassBuilder.h        |  25 +++-
 .../llvm/Passes/StandardInstrumentations.h    |  31 +++--
 .../Instrumentation/AddressSanitizerCommon.h  |   3 +-
 .../Instrumentation/ControlHeightReduction.h  |   8 +-
 .../Transforms/Instrumentation/GCOVProfiler.h |   5 +-
 .../Instrumentation/InstrProfiling.h          |   6 +-
 .../Instrumentation/LowerAllowCheckPass.h     |   7 +-
 .../Instrumentation/MemorySanitizer.h         |   6 +
 .../Instrumentation/PGOCtxProfLowering.h      |   6 +-
 .../Instrumentation/PGOInstrumentation.h      |   6 +-
 .../llvm/Transforms/Scalar/ConstantHoisting.h |   2 +
 llvm/include/llvm/Transforms/Scalar/LICM.h    |  28 +++--
 .../llvm/Transforms/Scalar/LoopUnrollPass.h   |  10 +-
 .../llvm/Transforms/Scalar/Reassociate.h      |   1 +
 .../Transforms/Scalar/SpeculativeExecution.h  |   3 +
 .../llvm/Transforms/Utils/Instrumentation.h   |   2 -
 llvm/lib/CGData/CGDataOptions.td              |   2 +-
 llvm/lib/CGData/CodeGenData.cpp               |  29 +++--
 llvm/lib/CGData/CodeGenDataReader.cpp         |  18 +--
 llvm/lib/CGData/StableFunctionMap.cpp         |  10 +-
 llvm/lib/CodeGen/GlobalMergeFunctions.cpp     |  12 +-
 llvm/lib/CodeGen/MachineOutliner.cpp          |  12 +-
 llvm/lib/Frontend/Driver/CodeGenOptions.cpp   |   7 +-
 llvm/lib/LTO/LTO.cpp                          |   5 +-
 llvm/lib/Passes/PassBuilder.cpp               |  17 ++-
 llvm/lib/Passes/PassBuilderPipelines.cpp      |  24 ++--
 llvm/lib/Passes/PassesOptions.td              |   2 +-
 llvm/lib/Passes/RunCodeGen.cpp                |   7 +-
 llvm/lib/Passes/StandardInstrumentations.cpp  |  82 +++++++-------
 llvm/lib/Target/AMDGPU/AMDGPUSwLowerLDS.cpp   |   4 +-
 llvm/lib/Target/X86/X86MCInstLower.cpp        |   3 +-
 .../Instrumentation/AddressSanitizer.cpp      |  11 +-
 .../Transforms/Instrumentation/AllocToken.cpp |   4 +-
 .../Instrumentation/BoundsChecking.cpp        |  15 +--
 .../ControlHeightReduction.cpp                |  42 ++++---
 .../Instrumentation/DataFlowSanitizer.cpp     |   5 +-
 .../Instrumentation/GCOVProfiling.cpp         |   9 +-
 .../Instrumentation/HWAddressSanitizer.cpp    |   3 +-
 .../Instrumentation/IndirectCallPromotion.cpp |   3 +-
 .../Instrumentation/InstrProfiling.cpp        |  16 ++-
 .../Instrumentation/InstrumentationOptions.td |   2 +-
 .../Instrumentation/LowerAllowCheckPass.cpp   |   9 +-
 .../MemProfInstrumentation.cpp                |   7 +-
 .../Transforms/Instrumentation/MemProfUse.cpp |   9 +-
 .../Instrumentation/MemorySanitizer.cpp       |  51 ++++++---
 .../NumericalStabilitySanitizer.cpp           |   4 +-
 .../Instrumentation/PGOCtxProfLowering.cpp    |  10 +-
 .../Instrumentation/PGOInstrumentation.cpp    |  44 ++++---
 .../Instrumentation/PGOMemOPSizeOpt.cpp       |   5 +-
 .../SanitizerBinaryMetadata.cpp               |   5 +-
 .../Instrumentation/SanitizerCoverage.cpp     |   3 +-
 .../Instrumentation/ThreadSanitizer.cpp       |   3 +-
 .../Instrumentation/TypeSanitizer.cpp         |   3 +-
 .../Instrumentation/ValueProfilePlugins.inc   |   6 +-
 llvm/lib/Transforms/Scalar/ADCE.cpp           |  12 +-
 .../Transforms/Scalar/CallSiteSplitting.cpp   |  15 ++-
 .../Transforms/Scalar/ConstantHoisting.cpp    |  17 +--
 .../Scalar/ConstraintElimination.cpp          |   3 +-
 .../Transforms/Scalar/DFAJumpThreading.cpp    |  12 +-
 .../Scalar/DeadStoreElimination.cpp           |   3 +-
 llvm/lib/Transforms/Scalar/EarlyCSE.cpp       |  29 +++--
 llvm/lib/Transforms/Scalar/ExpandMemCmp.cpp   |  13 ++-
 llvm/lib/Transforms/Scalar/Float2Int.cpp      |   3 +-
 llvm/lib/Transforms/Scalar/GVN.cpp            |  82 +++++++-------
 llvm/lib/Transforms/Scalar/GVNHoist.cpp       |  10 +-
 llvm/lib/Transforms/Scalar/GuardWidening.cpp  |  28 +++--
 llvm/lib/Transforms/Scalar/IndVarSimplify.cpp |   3 +-
 .../Scalar/InductiveRangeCheckElimination.cpp |   3 +-
 .../Transforms/Scalar/JumpTableToSwitch.cpp   |   8 +-
 llvm/lib/Transforms/Scalar/JumpThreading.cpp  |   2 +-
 llvm/lib/Transforms/Scalar/LICM.cpp           |  78 ++++++-------
 .../Transforms/Scalar/LoopDataPrefetch.cpp    |  16 ++-
 llvm/lib/Transforms/Scalar/LoopDeletion.cpp   |   6 +-
 llvm/lib/Transforms/Scalar/LoopDistribute.cpp |   3 +-
 llvm/lib/Transforms/Scalar/LoopFlatten.cpp    |   8 +-
 llvm/lib/Transforms/Scalar/LoopFuse.cpp       |   4 +-
 .../Transforms/Scalar/LoopIdiomRecognize.cpp  |  14 ++-
 .../lib/Transforms/Scalar/LoopInterchange.cpp |  12 +-
 .../Transforms/Scalar/LoopLoadElimination.cpp |   3 +-
 .../lib/Transforms/Scalar/LoopPredication.cpp |  12 +-
 llvm/lib/Transforms/Scalar/LoopRotation.cpp   |   3 +-
 .../lib/Transforms/Scalar/LoopSimplifyCFG.cpp |   9 +-
 llvm/lib/Transforms/Scalar/LoopSink.cpp       |   3 +-
 .../Transforms/Scalar/LoopStrengthReduce.cpp  |   3 +-
 .../Scalar/LoopUnrollAndJamPass.cpp           |   3 +-
 llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp |  22 +++-
 .../Transforms/Scalar/LoopVersioningLICM.cpp  |   5 +-
 .../Scalar/LowerExpectIntrinsic.cpp           |  30 ++---
 .../Scalar/LowerMatrixIntrinsics.cpp          | 107 +++++++++---------
 llvm/lib/Transforms/Scalar/NewGVN.cpp         |  14 +--
 .../lib/Transforms/Scalar/PlaceSafepoints.cpp |  13 ++-
 llvm/lib/Transforms/Scalar/Reassociate.cpp    |   6 +-
 .../Scalar/RewriteStatepointsForGC.cpp        |   3 +-
 llvm/lib/Transforms/Scalar/SROA.cpp           |   2 +-
 llvm/lib/Transforms/Scalar/ScalarOptions.td   |   2 +-
 .../Scalar/SeparateConstOffsetFromGEP.cpp     |   3 +-
 .../Transforms/Scalar/SimpleLoopUnswitch.cpp  |   3 +-
 .../lib/Transforms/Scalar/SimplifyCFGPass.cpp |  23 ++--
 .../Scalar/SpeculativeExecution.cpp           |  18 ++-
 .../Scalar/StraightLineStrengthReduce.cpp     |  18 ++-
 llvm/lib/Transforms/Scalar/StructurizeCFG.cpp |  39 +++----
 .../Scalar/TailRecursionElimination.cpp       |   3 +-
 llvm/tools/llvm-cgdata/llvm-cgdata.cpp        |   9 +-
 llvm/tools/opt/NewPMDriver.cpp                |   2 +-
 .../CGData/StableFunctionMapTest.cpp          |   7 +-
 polly/lib/Support/RegisterPasses.cpp          |  43 ++++---
 polly/lib/Transform/ScopInliner.cpp           |   2 +-
 115 files changed, 955 insertions(+), 628 deletions(-)

diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 77c53c612df8f1..1ffcf7d7f6b0a7 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -144,10 +144,13 @@ extern llvm::cl::opt<bool> ClSanitizeGuardChecks;
 }
 
 // Path and name of file used for profile generation
-static std::string getProfileGenName(const CodeGenOptions &CodeGenOpts) {
-  std::string FileName = CodeGenOpts.InstrProfileOutput.empty()
-                             ? llvm::driver::getDefaultProfileGenName()
-                             : CodeGenOpts.InstrProfileOutput;
+static std::string
+getProfileGenName(const cl::LibraryOptionsContext &LibraryOptions,
+                  const CodeGenOptions &CodeGenOpts) {
+  std::string FileName =
+      CodeGenOpts.InstrProfileOutput.empty()
+          ? llvm::driver::getDefaultProfileGenName(LibraryOptions)
+          : CodeGenOpts.InstrProfileOutput;
   if (CodeGenOpts.ContinuousProfileSync)
     FileName = "%c" + FileName;
   return FileName;
@@ -529,8 +532,8 @@ getGCOVOptions(const CodeGenOptions &CodeGenOpts, const LangOptions &LangOpts) {
   if (CodeGenOpts.CoverageNotesFile.empty() &&
       CodeGenOpts.CoverageDataFile.empty())
     return std::nullopt;
-  // Not using 'GCOVOptions::getDefault' allows us to avoid exiting if
-  // LLVM's -default-gcov-version flag is set to something invalid.
+  // Not using GCOVProfilerPass's default options allows us to avoid exiting
+  // if LLVM's -default-gcov-version flag is set to something invalid.
   GCOVOptions Options;
   Options.EmitNotes = !CodeGenOpts.CoverageNotesFile.empty();
   Options.EmitData = !CodeGenOpts.CoverageDataFile.empty();
@@ -773,7 +776,8 @@ static void addSanitizers(const Triple &TargetTriple,
   }
 }
 
-void addLowerAllowCheckPass(const CodeGenOptions &CodeGenOpts,
+void addLowerAllowCheckPass(const cl::LibraryOptionsContext &LibraryOptions,
+                            const CodeGenOptions &CodeGenOpts,
                             const LangOptions &LangOpts, PassBuilder &PB) {
   // SanitizeSkipHotCutoffs: doubles with range [0, 1]
   // Opts.cutoffs: unsigned ints with range [0, 1000000]
@@ -788,8 +792,9 @@ void addLowerAllowCheckPass(const CodeGenOptions &CodeGenOpts,
       SanitizerKind::KernelMemory | SanitizerKind::HWAddress |
       SanitizerKind::KernelHWAddress);
 
-  // TODO: remove IsRequested()
-  if (LowerAllowCheckPass::IsRequested() || ScaledCutoffs.has_value() ||
+  // TODO: remove isRequested()
+  if (LowerAllowCheckPass::isRequested(LibraryOptions) ||
+      ScaledCutoffs.has_value() ||
       CodeGenOpts.AllowRuntimeCheckSkipHotCutoff.has_value() ||
       LowerAllowSanitize) {
     // We want to call it after inline, which is about OptimizerEarlyEPCallback.
@@ -798,7 +803,7 @@ void addLowerAllowCheckPass(const CodeGenOptions &CodeGenOpts,
             ModulePassManager &MPM, OptimizationLevel Level,
             ThinOrFullLTOPhase Phase) {
           LowerAllowCheckPass::Options Opts;
-          // TODO: after removing IsRequested(), make this unconditional
+          // TODO: after removing isRequested(), make this unconditional
           if (ScaledCutoffs.has_value())
             Opts.cutoffs = ScaledCutoffs.value();
           Opts.runtime_check = AllowRuntimeCheckSkipHotCutoff;
@@ -843,11 +848,13 @@ static void addAMDGCNSPIRVSizeOptimizationPasses(ModulePassManager &MPM) {
 void EmitAssemblyHelper::RunOptimizationPipeline(
     BackendAction Action, std::unique_ptr<raw_pwrite_stream> &OS,
     std::unique_ptr<llvm::ToolOutputFile> &ThinLinkOS, BackendConsumer *BC) {
+  const cl::LibraryOptionsContext &LibraryOptions =
+      TheModule->getContext().getLibraryOptions();
   std::optional<PGOOptions> PGOOpt;
 
   if (CodeGenOpts.hasProfileIRInstr())
     // -fprofile-generate.
-    PGOOpt = PGOOptions(getProfileGenName(CodeGenOpts), "", "",
+    PGOOpt = PGOOptions(getProfileGenName(LibraryOptions, CodeGenOpts), "", "",
                         CodeGenOpts.MemoryProfileUsePath, PGOOptions::IRInstr,
                         PGOOptions::NoCSAction, ClPGOColdFuncAttr,
                         CodeGenOpts.DebugInfoForProfiling,
@@ -894,18 +901,18 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
              PGOOpt->Action != PGOOptions::SampleUse &&
              "Cannot run CSProfileGen pass with ProfileGen or SampleUse "
              " pass");
-      PGOOpt->CSProfileGenFile = getProfileGenName(CodeGenOpts);
+      PGOOpt->CSProfileGenFile = getProfileGenName(LibraryOptions, CodeGenOpts);
       PGOOpt->CSAction = PGOOptions::CSIRInstr;
     } else
-      PGOOpt = PGOOptions("", getProfileGenName(CodeGenOpts), "",
-                          /*MemoryProfile=*/"", PGOOptions::NoAction,
-                          PGOOptions::CSIRInstr, ClPGOColdFuncAttr,
-                          CodeGenOpts.DebugInfoForProfiling);
+      PGOOpt = PGOOptions(
+          "", getProfileGenName(LibraryOptions, CodeGenOpts), "",
+          /*MemoryProfile=*/"", PGOOptions::NoAction, PGOOptions::CSIRInstr,
+          ClPGOColdFuncAttr, CodeGenOpts.DebugInfoForProfiling);
   }
   if (TM)
     TM->setPGOOption(PGOOpt);
 
-  PipelineTuningOptions PTO;
+  PipelineTuningOptions PTO(&LibraryOptions);
   PTO.LoopUnrolling = CodeGenOpts.UnrollLoops;
   PTO.LoopInterchange = CodeGenOpts.InterchangeLoops;
   PTO.LoopFusion = CodeGenOpts.FuseLoops;
@@ -1086,7 +1093,7 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
       // Most sanitizers only run during PreLink stage.
       addSanitizers(TargetTriple, CodeGenOpts, LangOpts, PB);
       addKCFIPass(TargetTriple, LangOpts, PB);
-      addLowerAllowCheckPass(CodeGenOpts, LangOpts, PB);
+      addLowerAllowCheckPass(LibraryOptions, CodeGenOpts, LangOpts, PB);
 
       PB.registerPipelineStartEPCallback(
           [&](ModulePassManager &MPM, OptimizationLevel Level) {
@@ -1378,6 +1385,9 @@ runThinLTOBackend(CompilerInstance &CI, ModuleSummaryIndex *CombinedIndex,
   Conf.OptLevel = CGOpts.OptimizationLevel;
   initTargetOptions(CI, Diags, Conf.Options);
   Conf.SampleProfile = std::move(SampleProfile);
+  const cl::LibraryOptionsContext &LibraryOptions =
+      M->getContext().getLibraryOptions();
+  Conf.PTO = PipelineTuningOptions(&LibraryOptions);
   Conf.PTO.LoopUnrolling = CGOpts.UnrollLoops;
   Conf.PTO.LoopInterchange = CGOpts.InterchangeLoops;
   Conf.PTO.LoopFusion = CGOpts.FuseLoops;
@@ -1393,7 +1403,7 @@ runThinLTOBackend(CompilerInstance &CI, ModuleSummaryIndex *CombinedIndex,
   // Context sensitive profile.
   if (CGOpts.hasProfileCSIRInstr()) {
     Conf.RunCSIRInstr = true;
-    Conf.CSIRProfile = getProfileGenName(CGOpts);
+    Conf.CSIRProfile = getProfileGenName(LibraryOptions, CGOpts);
   } else if (CGOpts.hasProfileCSIRUse()) {
     Conf.RunCSIRInstr = false;
     Conf.CSIRProfile = std::move(CGOpts.ProfileInstrumentUsePath);
diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index b8b8b426dfe86d..21170893e6e898 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -974,14 +974,16 @@ void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) {
 
   // Create the pass manager builder.
   llvm::PassInstrumentationCallbacks pic;
-  llvm::PipelineTuningOptions pto;
+  const llvm::cl::LibraryOptionsContext &libraryOptions =
+      llvmModule->getContext().getLibraryOptions();
+  llvm::PipelineTuningOptions pto(&libraryOptions);
   std::optional<llvm::PGOOptions> pgoOpt;
 
   if (opts.hasProfileIRInstr()) {
     // -fprofile-generate.
     pgoOpt = llvm::PGOOptions(
         opts.InstrProfileOutput.empty()
-            ? llvm::driver::getDefaultProfileGenName()
+            ? llvm::driver::getDefaultProfileGenName(libraryOptions)
             : opts.InstrProfileOutput,
         "", "", opts.MemoryProfileUsePath, llvm::PGOOptions::IRInstr,
         llvm::PGOOptions::NoCSAction, llvm::PGOOptions::ColdFuncOpt::Default,
diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 0dfced91c511dd..5f2c541bdd2fd9 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -45,6 +45,7 @@
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/FileSystem.h"
+#include "llvm/Support/LibraryOptionsContext.h"
 #include "llvm/Support/Parallel.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Process.h"
@@ -1562,7 +1563,7 @@ static void codegenDataGenerate() {
     }
   }
 
-  globalMergeRecord.finalize();
+  globalMergeRecord.finalize(cl::LibraryOptionsContext());
 
   CodeGenDataWriter Writer;
   if (!globalOutlineRecord.empty())
diff --git a/llvm/include/llvm/CGData/CodeGenData.h b/llvm/include/llvm/CGData/CodeGenData.h
index cd1d849fdc1551..c1919428fa1d07 100644
--- a/llvm/include/llvm/CGData/CodeGenData.h
+++ b/llvm/include/llvm/CGData/CodeGenData.h
@@ -30,6 +30,10 @@
 
 namespace llvm {
 
+namespace cl {
+class LibraryOptionsContext;
+} // namespace cl
+
 enum CGDataSectKind {
 #define CG_DATA_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) Kind,
 #include "llvm/CGData/CodeGenData.inc"
@@ -131,7 +135,9 @@ class CodeGenData {
 public:
   ~CodeGenData() = default;
 
-  LLVM_ABI static CodeGenData &getInstance();
+  /// The first call's \p LibraryOptions configure the singleton.
+  LLVM_ABI static CodeGenData &
+  getInstance(const cl::LibraryOptionsContext &LibraryOptions);
 
   /// Returns true if we have a valid outlined hash tree.
   bool hasOutlinedHashTree() {
@@ -169,32 +175,42 @@ class CodeGenData {
 
 namespace cgdata {
 
-inline bool hasOutlinedHashTree() {
-  return CodeGenData::getInstance().hasOutlinedHashTree();
+inline bool
+hasOutlinedHashTree(const cl::LibraryOptionsContext &LibraryOptions) {
+  return CodeGenData::getInstance(LibraryOptions).hasOutlinedHashTree();
 }
 
-inline bool hasStableFunctionMap() {
-  return CodeGenData::getInstance().hasStableFunctionMap();
+inline bool
+hasStableFunctionMap(const cl::LibraryOptionsContext &LibraryOptions) {
+  return CodeGenData::getInstance(LibraryOptions).hasStableFunctionMap();
 }
 
-inline const OutlinedHashTree *getOutlinedHashTree() {
-  return CodeGenData::getInstance().getOutlinedHashTree();
+inline const OutlinedHashTree *
+getOutlinedHashTree(const cl::LibraryOptionsContext &LibraryOptions) {
+  return CodeGenData::getInstance(LibraryOptions).getOutlinedHashTree();
 }
 
-inline const StableFunctionMap *getStableFunctionMap() {
-  return CodeGenData::getInstance().getStableFunctionMap();
+inline const StableFunctionMap *
+getStableFunctionMap(const cl::LibraryOptionsContext &LibraryOptions) {
+  return CodeGenData::getInstance(LibraryOptions).getStableFunctionMap();
 }
 
-inline bool emitCGData() { return CodeGenData::getInstance().emitCGData(); }
+inline bool emitCGData(const cl::LibraryOptionsContext &LibraryOptions) {
+  return CodeGenData::getInstance(LibraryOptions).emitCGData();
+}
 
 inline void
-publishOutlinedHashTree(std::unique_ptr<OutlinedHashTree> HashTree) {
-  CodeGenData::getInstance().publishOutlinedHashTree(std::move(HashTree));
+publishOutlinedHashTree(const cl::LibraryOptionsContext &LibraryOptions,
+                        std::unique_ptr<OutlinedHashTree> HashTree) {
+  CodeGenData::getInstance(LibraryOptions)
+      .publishOutlinedHashTree(std::move(HashTree));
 }
 
 inline void
-publishStableFunctionMap(std::unique_ptr<StableFunctionMap> FunctionMap) {
-  CodeGenData::getInstance().publishStableFunctionMap(std::move(FunctionMap));
+publishStableFunctionMap(const cl::LibraryOptionsContext &LibraryOptions,
+                         std::unique_ptr<StableFunctionMap> FunctionMap) {
+  CodeGenData::getInstance(LibraryOptions)
+      .publishStableFunctionMap(std::move(FunctionMap));
 }
 
 struct StreamCacheData {
@@ -244,7 +260,7 @@ struct StreamCacheData {
 
 /// Returns whether ThinLTO runs two rounds of code generation
 /// (-codegen-data-thinlto-two-rounds).
-LLVM_ABI bool thinLTOTwoRounds();
+LLVM_ABI bool thinLTOTwoRounds(const cl::LibraryOptionsContext &LibraryOptions);
 
 /// Save \p TheModule before the first codegen round.
 /// \p Task represents the partition number in the parallel code generation
@@ -267,7 +283,8 @@ loadModuleForTwoRounds(BitcodeModule &OrigModule, unsigned Task,
 /// first codegen round.
 /// \return the combined hash of the merged codegen data.
 LLVM_ABI Expected<stable_hash>
-mergeCodeGenData(ArrayRef<StringRef> ObjectFiles);
+mergeCodeGenData(const cl::LibraryOptionsContext &LibraryOptions,
+                 ArrayRef<StringRef> ObjectFiles);
 
 LLVM_ABI void warn(Error E, StringRef Whence = "");
 LLVM_ABI void warn(Twine Message, StringRef Whence = "", StringRef Hint = "");
diff --git a/llvm/include/llvm/CGData/CodeGenDataReader.h b/llvm/include/llvm/CGData/CodeGenDataReader.h
index 94f7af2de17012..0b827cd97c08b5 100644
--- a/llvm/include/llvm/CGData/CodeGenDataReader.h
+++ b/llvm/include/llvm/CGData/CodeGenDataReader.h
@@ -52,12 +52,14 @@ class CodeGenDataReader {
   /// codegen data file path and file system. \p LazyLoading defers
   /// deserializing the stable function map of indexed codegen data.
   LLVM_ABI static Expected<std::unique_ptr<CodeGenDataReader>>
-  create(const Twine &Path, vfs::FileSystem &FS, bool LazyLoading = false);
+  create(const cl::LibraryOptionsContext &LibraryOptions, const Twine &Path,
+         vfs::FileSystem &FS, bool LazyLoading = false);
 
   /// Factory method to create an appropriately typed reader for the given
   /// memory buffer.
   LLVM_ABI static Expected<std::unique_ptr<CodeGenDataReader>>
-  create(std::unique_ptr<MemoryBuffer> Buffer, bool LazyLoading = false);
+  create(const cl::LibraryOptionsContext &LibraryOptions,
+         std::unique_ptr<MemoryBuffer> Buffer, bool LazyLoading = false);
 
   /// Extract the cgdata embedded in sections from the given object file and
   /// merge them into the GlobalOutlineRecord. This is a static helper that
@@ -101,6 +103,7 @@ class CodeGenDataReader {
 };
 
 class LLVM_ABI IndexedCodeGenDataReader : public CodeGenDataReader {
+  bool ReadStableFunctionMapNames;
   /// The codegen data file contents.
   std::unique_ptr<MemoryBuffer> DataBuffer;
   /// The header
@@ -108,9 +111,11 @@ class LLVM_ABI IndexedCodeGenDataReader : public CodeGenDataReader {
   bool LazyLoading;
 
 public:
-  IndexedCodeGenDataReader(std::unique_ptr<MemoryBuffer> DataBuffer,
+  IndexedCodeGenDataReader(bool ReadStableFunctionMapNames,
+                           std::unique_ptr<MemoryBuffer> DataBuffer,
                            bool LazyLoading = false)
-      : DataBuffer(std::move(DataBuffer)), LazyLoading(LazyLoading) {}
+      : ReadStableFunctionMapNames(ReadStableFunctionMapNames),
+        DataBuffer(std::move(DataBuffer)), LazyLoading(LazyLoading) {}
   IndexedCodeGenDataReader(const IndexedCodeGenDataReader &) = delete;
   IndexedCodeGenDataReader &
   operator=(const IndexedCodeGenDataReader &) = delete;
diff --git a/llvm/include/llvm/CGData/StableFunctionMap.h b/llvm/include/llvm/CGData/StableFunctionMap.h
index 909d0e1debe7e6..b9be47177c9a31 100644
--- a/llvm/include/llvm/CGData/StableFunctionMap.h
+++ b/llvm/include/llvm/CGData/StableFunctionMap.h
@@ -26,6 +26,10 @@
 
 namespace llvm {
 
+namespace cl {
+class LibraryOptionsContext;
+} // namespace cl
+
 using IndexPairHash = std::pair<IndexPair, stable_hash>;
 using IndexOperandHashVecType = SmallVector<IndexPairHash>;
 
@@ -153,7 +157,8 @@ struct StableFunctionMap {
   LLVM_ABI size_t size(SizeType Type = UniqueHashCount) const;
 
   /// Finalize the stable function map by trimming content.
-  LLVM_ABI void finalize(bool SkipTrim = false);
+  LLVM_ABI void finalize(const cl::LibraryOptionsContext &LibraryOptions,
+                         bool SkipTrim = false);
 
 private:
   /// Insert a `StableFunctionEntry` into the function map directly. This
diff --git a/llvm/include/llvm/CGData/StableFunctionMapRecord.h b/llvm/include/llvm/CGData/StableFunctionMapRecord.h
index 2d8b573a3cb467..24e7ef1af2ea81 100644
--- a/llvm/include/llvm/CGData/StableFunctionMapRecord.h
+++ b/llvm/include/llvm/CGData/StableFunctionMapRecord.h
@@ -87,7 +87,10 @@ struct StableFunctionMapRecord {
   LLVM_ABI void deserializeYAML(yaml::Input &YIS);
 
   /// Finalize the stable function map by trimming content.
-  void finalize(bool SkipTrim = false) { FunctionMap->finalize(SkipTrim); }
+  void finalize(const cl::LibraryOptionsContext &LibraryOptions,
+                bool SkipTrim = false) {
+    FunctionMap->finalize(LibraryOptions, SkipTrim);
+  }
 
   /// Merge the stable function map into this one.
   void merge(const StableFunctionMapRecord &Other) {
diff --git a/llvm/include/llvm/Frontend/Driver/CodeGenOptions.h b/llvm/include/llvm/Frontend/Driver/CodeGenOptions.h
index 77ab477986d31c..3d292139cb7d06 100644
--- a/llvm/include/llvm/Frontend/Driver/CodeGenOptions.h
+++ b/llvm/include/llvm/Frontend/Driver/CodeGenOptions.h
@@ -20,6 +20,9 @@ namespace llvm {
 class Triple;
 class TargetLibraryInfoImpl;
 enum class VectorLibrary;
+namespace cl {
+class LibraryOptionsContext;
+} // namespace cl
 } // namespace llvm
 
 namespace llvm::driver {
@@ -67,7 +70,8 @@ enum ProfileInstrKind {
 };
 
 // Default filename used for profile generation.
-LLVM_ABI std::string getDefaultProfileGenName();
+LLVM_ABI std::string
+getDefaultProfileGenName(const cl::LibraryOptionsContext &LibraryOptions);
 } // end namespace llvm::driver
 
 #endif
diff --git a/llvm/include/llvm/Passes/PassBuilder.h b/llvm/include/llvm/Passes/PassBuilder.h
index 502dfd93842bea..2dd74624b424e3 100644
--- a/llvm/include/llvm/Passes/PassBuilder.h
+++ b/llvm/include/llvm/Passes/PassBuilder.h
@@ -37,13 +37,24 @@ class AAManager;
 class TargetMachine;
 class ModuleSummaryIndex;
 struct PassesOptions;
+namespace cl {
+class LibraryOptionsContext;
+} // namespace cl
 
 /// Tunable parameters for passes in the default pipelines.
 class PipelineTuningOptions {
 public:
-  /// Constructor sets pipeline tuning defaults based on cl::opts. Each option
-  /// can be set in the PassBuilder when using a LLVM as a library.
-  LLVM_ABI PipelineTuningOptions();
+  /// Constructor sets pipeline tuning defaults based on the global values of
+  /// the library options. Each option can be set in the PassBuilder when using
+  /// a LLVM as a library.
+  PipelineTuningOptions() : PipelineTuningOptions(nullptr) {}
+
+  /// Reads the defaults from \p LibraryOptions, or their global values if
+  /// null.
+  LLVM_ABI explicit PipelineTuningOptions(
+      const cl::LibraryOptionsContext *LibraryOptions);
+
+  const cl::LibraryOptionsContext *LibraryOptions;
 
   /// Tuning option to set loop interleaving on/off, set based on opt level.
   bool LoopInterleaving;
@@ -118,6 +129,7 @@ enum class PrintPipelinePassesFormat {
 /// of the built-in passes, and those may reference these members during
 /// construction.
 class PassBuilder {
+  const cl::LibraryOptionsContext *LibraryOptions;
   const PassesOptions &Opts;
   TargetMachine *TM;
   PipelineTuningOptions PTO;
@@ -674,6 +686,13 @@ class PassBuilder {
     return PIC;
   }
 
+  /// Returns the library options the pipelines read: the
+  /// PipelineTuningOptions', else the TargetMachine's, else null for the global
+  /// values.
+  const cl::LibraryOptionsContext *getLibraryOptions() const {
+    return LibraryOptions;
+  }
+
   /// Returns the virtual file system.
   IntrusiveRefCntPtr<vfs::FileSystem> getVirtualFileSystemPtr() const {
     return FS;
diff --git a/llvm/include/llvm/Passes/StandardInstrumentations.h b/llvm/include/llvm/Passes/StandardInstrumentations.h
index d485ea78f462a1..1c378941cc1259 100644
--- a/llvm/include/llvm/Passes/StandardInstrumentations.h
+++ b/llvm/include/llvm/Passes/StandardInstrumentations.h
@@ -43,6 +43,7 @@ class Function;
 class MachineFunction;
 class PassInstrumentationCallbacks;
 struct ExtendedIRContext;
+struct PassesOptions;
 
 /// Instrumentation to print IR before/after passes.
 ///
@@ -50,6 +51,7 @@ struct ExtendedIRContext;
 /// (typically Loop or SCC).
 class PrintIRInstrumentation {
 public:
+  explicit PrintIRInstrumentation(const PassesOptions &Opts) : Opts(Opts) {}
   LLVM_ABI ~PrintIRInstrumentation();
 
   LLVM_ABI void registerCallbacks(PassInstrumentationCallbacks &PIC,
@@ -98,6 +100,7 @@ class PrintIRInstrumentation {
                                 unsigned PassNumber,
                                 IRDumpFileSuffixType SuffixType);
 
+  const PassesOptions &Opts;
   PassInstrumentationCallbacks *PIC;
   /// Stack of Pass Run descriptions, enough to print the IR unit after a given
   /// pass.
@@ -121,10 +124,12 @@ class OptNoneInstrumentation {
 };
 
 class OptPassGateInstrumentation {
+  const PassesOptions &Opts;
   LLVMContext &Context;
   bool HasWrittenIR = false;
 public:
-  OptPassGateInstrumentation(LLVMContext &Context) : Context(Context) {}
+  OptPassGateInstrumentation(const PassesOptions &Opts, LLVMContext &Context)
+      : Opts(Opts), Context(Context) {}
   LLVM_ABI bool shouldRun(StringRef PassName, IRUnitRef IR);
   LLVM_ABI void registerCallbacks(PassInstrumentationCallbacks &PIC,
                                   ExtendedIRContext *IRContext = nullptr);
@@ -161,6 +166,9 @@ class PrintPassInstrumentation {
 
 class PreservedCFGCheckerInstrumentation {
 public:
+  explicit PreservedCFGCheckerInstrumentation(const PassesOptions &Opts)
+      : Opts(Opts) {}
+
   // Keeps sticky poisoned flag for the given basic block once it has been
   // deleted or RAUWed.
   struct BBGuard final : public CallbackVH {
@@ -206,6 +214,9 @@ class PreservedCFGCheckerInstrumentation {
 
   LLVM_ABI void registerCallbacks(PassInstrumentationCallbacks &PIC,
                                   ModuleAnalysisManager &MAM);
+
+private:
+  const PassesOptions &Opts;
 };
 
 class ExtendedIRTraits {
@@ -336,12 +347,14 @@ class LLVM_ABI TextChangeReporter : public ChangeReporter<IRUnitT> {
 // included in this representation but it is massaged before reporting.
 class LLVM_ABI IRChangedPrinter : public TextChangeReporter<std::string> {
 public:
-  IRChangedPrinter(bool VerboseMode)
-      : TextChangeReporter<std::string>(VerboseMode) {}
+  IRChangedPrinter(const PassesOptions &Opts, bool VerboseMode)
+      : TextChangeReporter<std::string>(VerboseMode), Opts(Opts) {}
   ~IRChangedPrinter() override;
   void registerCallbacks(PassInstrumentationCallbacks &PIC);
 
 protected:
+  const PassesOptions &Opts;
+
   // Called before and after a pass to get the representation of the IR.
   void generateIRRepresentation(IRUnitRef IR, StringRef PassID,
                                 std::string &Output) override;
@@ -353,7 +366,8 @@ class LLVM_ABI IRChangedPrinter : public TextChangeReporter<std::string> {
 
 class LLVM_ABI IRChangedTester : public IRChangedPrinter {
 public:
-  IRChangedTester() : IRChangedPrinter(true) {}
+  explicit IRChangedTester(const PassesOptions &Opts)
+      : IRChangedPrinter(Opts, true) {}
   ~IRChangedTester() override;
   void registerCallbacks(PassInstrumentationCallbacks &PIC);
 
@@ -590,7 +604,7 @@ class DCData {
 // dot control flow graphs with changed instructions shown in colour.
 class LLVM_ABI DotCfgChangeReporter : public ChangeReporter<IRDataT<DCData>> {
 public:
-  DotCfgChangeReporter(bool Verbose);
+  DotCfgChangeReporter(const PassesOptions &Opts, bool Verbose);
   ~DotCfgChangeReporter() override;
   void registerCallbacks(PassInstrumentationCallbacks &PIC);
 
@@ -626,6 +640,7 @@ class LLVM_ABI DotCfgChangeReporter : public ChangeReporter<IRDataT<DCData>> {
                              const FuncDataT<DCData> &Before,
                              const FuncDataT<DCData> &After);
 
+  const PassesOptions &Opts;
   unsigned N = 0;
   // -dot-cfg-dir with ~ expanded, made absolute.
   std::string OutputDir;
@@ -635,13 +650,14 @@ class LLVM_ABI DotCfgChangeReporter : public ChangeReporter<IRDataT<DCData>> {
 // Print IR on crash.
 class PrintCrashIRInstrumentation {
 public:
-  PrintCrashIRInstrumentation()
-      : SavedIR("*** Dump of IR Before Last Pass Unknown ***") {}
+  explicit PrintCrashIRInstrumentation(const PassesOptions &Opts)
+      : Opts(Opts), SavedIR("*** Dump of IR Before Last Pass Unknown ***") {}
   LLVM_ABI ~PrintCrashIRInstrumentation();
   LLVM_ABI void registerCallbacks(PassInstrumentationCallbacks &PIC);
   LLVM_ABI void reportCrashIR();
 
 protected:
+  const PassesOptions &Opts;
   std::string SavedIR;
 
 private:
@@ -654,6 +670,7 @@ class PrintCrashIRInstrumentation {
 /// This class provides an interface to register all the standard pass
 /// instrumentations and manages their state (if any).
 class StandardInstrumentations {
+  const PassesOptions &Opts;
   PrintIRInstrumentation PrintIR;
   PrintPassInstrumentation PrintPass;
   TimePassesHandler TimePasses;
diff --git a/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerCommon.h b/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerCommon.h
index f8635154e486b1..839ef752aec3b0 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerCommon.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerCommon.h
@@ -24,7 +24,8 @@
 
 namespace llvm {
 // Get AddressSanitizer parameters.
-LLVM_ABI void getAddressSanitizerParams(const Triple &TargetTriple,
+LLVM_ABI void getAddressSanitizerParams(const LLVMContext &Ctx,
+                                        const Triple &TargetTriple,
                                         int LongSize, bool IsKasan,
                                         uint64_t *ShadowBase, int *MappingScale,
                                         bool *OrShadowOffset);
diff --git a/llvm/include/llvm/Transforms/Instrumentation/ControlHeightReduction.h b/llvm/include/llvm/Transforms/Instrumentation/ControlHeightReduction.h
index b3bda90550037a..716a50afbe598b 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/ControlHeightReduction.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/ControlHeightReduction.h
@@ -14,15 +14,21 @@
 #ifndef LLVM_TRANSFORMS_INSTRUMENTATION_CONTROLHEIGHTREDUCTION_H
 #define LLVM_TRANSFORMS_INSTRUMENTATION_CONTROLHEIGHTREDUCTION_H
 
+#include "llvm/ADT/StringSet.h"
 #include "llvm/IR/PassManager.h"
 
 namespace llvm {
 
+struct InstrumentationOptions;
+
 class ControlHeightReductionPass
     : public OptionalPassInfoMixin<ControlHeightReductionPass> {
 public:
-  LLVM_ABI ControlHeightReductionPass();
   LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
+
+private:
+  const InstrumentationOptions *ParsedOpts = nullptr;
+  StringSet<> CHRModules, CHRFunctions;
 };
 } // end namespace llvm
 
diff --git a/llvm/include/llvm/Transforms/Instrumentation/GCOVProfiler.h b/llvm/include/llvm/Transforms/Instrumentation/GCOVProfiler.h
index 4d1688cc1676f1..2a76433f438e8b 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/GCOVProfiler.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/GCOVProfiler.h
@@ -16,19 +16,20 @@
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/VirtualFileSystem.h"
 #include "llvm/Transforms/Utils/Instrumentation.h"
+#include <optional>
 
 namespace llvm {
 /// The gcov-style instrumentation pass
 class GCOVProfilerPass : public OptionalPassInfoMixin<GCOVProfilerPass> {
 public:
   GCOVProfilerPass(
-      const GCOVOptions &Options = GCOVOptions::getDefault(),
+      std::optional<GCOVOptions> Options = std::nullopt,
       IntrusiveRefCntPtr<vfs::FileSystem> VFS = vfs::getRealFileSystem())
       : GCOVOpts(Options), VFS(std::move(VFS)) {}
   LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
 
 private:
-  GCOVOptions GCOVOpts;
+  std::optional<GCOVOptions> GCOVOpts;
   IntrusiveRefCntPtr<vfs::FileSystem> VFS;
 };
 
diff --git a/llvm/include/llvm/Transforms/Instrumentation/InstrProfiling.h b/llvm/include/llvm/Transforms/Instrumentation/InstrProfiling.h
index 9d4c40b25cd19a..c3d9f406d1776c 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/InstrProfiling.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/InstrProfiling.h
@@ -20,6 +20,9 @@
 namespace llvm {
 
 class TargetLibraryInfo;
+namespace cl {
+class LibraryOptionsContext;
+} // namespace cl
 /// Instrumentation based profiling lowering pass. This pass lowers
 /// the profile instrumented code generated by FE or the IR based
 /// instrumentation pass.
@@ -38,7 +41,8 @@ class InstrProfilingLoweringPass
 };
 
 /// Return true if -profile-correlate is set.
-LLVM_ABI bool isProfileCorrelationEnabled();
+LLVM_ABI bool
+isProfileCorrelationEnabled(const cl::LibraryOptionsContext &LibraryOptions);
 } // end namespace llvm
 
 #endif // LLVM_TRANSFORMS_INSTRUMENTATION_INSTRPROFILING_H
diff --git a/llvm/include/llvm/Transforms/Instrumentation/LowerAllowCheckPass.h b/llvm/include/llvm/Transforms/Instrumentation/LowerAllowCheckPass.h
index cf5fe6d2ab5067..62a58fc6490833 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/LowerAllowCheckPass.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/LowerAllowCheckPass.h
@@ -21,6 +21,10 @@
 
 namespace llvm {
 
+namespace cl {
+class LibraryOptionsContext;
+} // namespace cl
+
 // This pass is responsible for removing optional traps, like llvm.ubsantrap
 // from the hot code.
 class LowerAllowCheckPass : public RequiredPassInfoMixin<LowerAllowCheckPass> {
@@ -34,7 +38,8 @@ class LowerAllowCheckPass : public RequiredPassInfoMixin<LowerAllowCheckPass> {
       : Opts(std::move(Opts)) {};
   LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
 
-  LLVM_ABI static bool IsRequested();
+  LLVM_ABI static bool
+  isRequested(const cl::LibraryOptionsContext &LibraryOptions);
   LLVM_ABI void
   printPipeline(raw_ostream &OS,
                 function_ref<StringRef(StringRef)> MapClassName2PassName);
diff --git a/llvm/include/llvm/Transforms/Instrumentation/MemorySanitizer.h b/llvm/include/llvm/Transforms/Instrumentation/MemorySanitizer.h
index b42f2e21aa52f4..33713f7aec2d05 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/MemorySanitizer.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/MemorySanitizer.h
@@ -16,6 +16,7 @@
 #include "llvm/ADT/STLFunctionalExtras.h"
 #include "llvm/IR/PassManager.h"
 #include "llvm/Support/Compiler.h"
+#include <optional>
 
 namespace llvm {
 class Module;
@@ -32,6 +33,11 @@ struct MemorySanitizerOptions {
   int TrackOrigins;
   bool Recover;
   bool EagerChecks;
+  // msan<...> parameters, which override the -msan-* options.
+  std::optional<bool> KernelParam;
+  std::optional<int> TrackOriginsParam;
+  std::optional<bool> RecoverParam;
+  std::optional<bool> EagerChecksParam;
 };
 
 /// A module pass for msan instrumentation.
diff --git a/llvm/include/llvm/Transforms/Instrumentation/PGOCtxProfLowering.h b/llvm/include/llvm/Transforms/Instrumentation/PGOCtxProfLowering.h
index 930c8bf9d96463..1d4c21d91a9b1f 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/PGOCtxProfLowering.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/PGOCtxProfLowering.h
@@ -15,13 +15,17 @@
 #include "llvm/IR/PassManager.h"
 namespace llvm {
 class Type;
+namespace cl {
+class LibraryOptionsContext;
+} // namespace cl
 
 class PGOCtxProfLoweringPass
     : public OptionalPassInfoMixin<PGOCtxProfLoweringPass> {
 public:
   explicit PGOCtxProfLoweringPass() = default;
   // True if contextual instrumentation is enabled.
-  LLVM_ABI static bool isCtxIRPGOInstrEnabled();
+  LLVM_ABI static bool
+  isCtxIRPGOInstrEnabled(const cl::LibraryOptionsContext *LibraryOptions);
 
   LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
 };
diff --git a/llvm/include/llvm/Transforms/Instrumentation/PGOInstrumentation.h b/llvm/include/llvm/Transforms/Instrumentation/PGOInstrumentation.h
index 8f5c9d57d02d9d..af2e5373f1d6de 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/PGOInstrumentation.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/PGOInstrumentation.h
@@ -111,8 +111,10 @@ LLVM_ABI void setProfMetadata(Instruction *TI, ArrayRef<uint64_t> EdgeCounts,
 LLVM_ABI void setIrrLoopHeaderMetadata(Module *M, Instruction *TI,
                                        uint64_t Count);
 
-/// Return the value of -pgo-instrument-cold-function-only.
-LLVM_ABI bool isPGOInstrumentColdFunctionOnly();
+/// Return the value of -pgo-instrument-cold-function-only in LibraryOptions, or
+/// its global value if null.
+LLVM_ABI bool isPGOInstrumentColdFunctionOnly(
+    const cl::LibraryOptionsContext *LibraryOptions);
 
 } // end namespace llvm
 
diff --git a/llvm/include/llvm/Transforms/Scalar/ConstantHoisting.h b/llvm/include/llvm/Transforms/Scalar/ConstantHoisting.h
index 7a872ef1021b2c..f1ed7c6b042924 100644
--- a/llvm/include/llvm/Transforms/Scalar/ConstantHoisting.h
+++ b/llvm/include/llvm/Transforms/Scalar/ConstantHoisting.h
@@ -59,6 +59,7 @@ class Function;
 class GlobalVariable;
 class Instruction;
 class ProfileSummaryInfo;
+struct ScalarOptions;
 class TargetTransformInfo;
 class TargetTransformInfo;
 
@@ -145,6 +146,7 @@ class ConstantHoistingPass
   using ConstPtrUnionType = PointerUnion<ConstantInt *, ConstantExpr *>;
   using ConstCandMapType = DenseMap<ConstPtrUnionType, unsigned>;
 
+  const ScalarOptions *Opts = nullptr;
   const TargetTransformInfo *TTI;
   DominatorTree *DT;
   BlockFrequencyInfo *BFI;
diff --git a/llvm/include/llvm/Transforms/Scalar/LICM.h b/llvm/include/llvm/Transforms/Scalar/LICM.h
index 4cabf02cb3b154..7eb460e7b33599 100644
--- a/llvm/include/llvm/Transforms/Scalar/LICM.h
+++ b/llvm/include/llvm/Transforms/Scalar/LICM.h
@@ -34,27 +34,33 @@
 
 #include "llvm/Analysis/LoopAnalysisManager.h"
 #include "llvm/IR/PassManager.h"
+#include <optional>
 
 namespace llvm {
 
 class LPMUpdater;
 class Loop;
 class LoopNest;
-
-/// Returns -licm-mssa-optimization-cap.
-LLVM_ABI unsigned getLicmMssaOptCap();
-/// Returns -licm-mssa-max-acc-promotion.
-LLVM_ABI unsigned getLicmMssaNoAccForPromotionCap();
+namespace cl {
+class LibraryOptionsContext;
+} // namespace cl
+
+/// Returns -licm-mssa-optimization-cap of LibraryOptions, or its global value
+/// if null.
+LLVM_ABI unsigned
+getLicmMssaOptCap(const cl::LibraryOptionsContext *LibraryOptions);
+/// Returns -licm-mssa-max-acc-promotion of LibraryOptions, or its global value
+/// if null.
+LLVM_ABI unsigned getLicmMssaNoAccForPromotionCap(
+    const cl::LibraryOptionsContext *LibraryOptions);
 
 struct LICMOptions {
-  unsigned MssaOptCap;
-  unsigned MssaNoAccForPromotionCap;
+  // Unset means the -licm-mssa-* value of the loop's LLVMContext.
+  std::optional<unsigned> MssaOptCap;
+  std::optional<unsigned> MssaNoAccForPromotionCap;
   bool AllowSpeculation;
 
-  LICMOptions()
-      : MssaOptCap(getLicmMssaOptCap()),
-        MssaNoAccForPromotionCap(getLicmMssaNoAccForPromotionCap()),
-        AllowSpeculation(true) {}
+  LICMOptions() : AllowSpeculation(true) {}
 
   LICMOptions(unsigned MssaOptCap, unsigned MssaNoAccForPromotionCap,
               bool AllowSpeculation)
diff --git a/llvm/include/llvm/Transforms/Scalar/LoopUnrollPass.h b/llvm/include/llvm/Transforms/Scalar/LoopUnrollPass.h
index 9d2b221b9ad73f..7955d8f79dc5c0 100644
--- a/llvm/include/llvm/Transforms/Scalar/LoopUnrollPass.h
+++ b/llvm/include/llvm/Transforms/Scalar/LoopUnrollPass.h
@@ -15,8 +15,14 @@
 
 namespace llvm {
 
-/// Returns -forget-scev-loop-unroll.
-LLVM_ABI bool getForgetSCEVInLoopUnroll();
+namespace cl {
+class LibraryOptionsContext;
+} // namespace cl
+
+/// Returns -forget-scev-loop-unroll of LibraryOptions, or its global value if
+/// null.
+LLVM_ABI bool
+getForgetSCEVInLoopUnroll(const cl::LibraryOptionsContext *LibraryOptions);
 
 class Function;
 class Loop;
diff --git a/llvm/include/llvm/Transforms/Scalar/Reassociate.h b/llvm/include/llvm/Transforms/Scalar/Reassociate.h
index a261d0b9baf026..db6c34fc6571bb 100644
--- a/llvm/include/llvm/Transforms/Scalar/Reassociate.h
+++ b/llvm/include/llvm/Transforms/Scalar/Reassociate.h
@@ -97,6 +97,7 @@ class ReassociatePass : public OptionalPassInfoMixin<ReassociatePass> {
 
   bool MadeChange;
   UniformityInfo *UA = nullptr;
+  bool UseCSELocal = false;
 
 public:
   LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
diff --git a/llvm/include/llvm/Transforms/Scalar/SpeculativeExecution.h b/llvm/include/llvm/Transforms/Scalar/SpeculativeExecution.h
index b0e2bff1e6c646..753e5c7a423d7d 100644
--- a/llvm/include/llvm/Transforms/Scalar/SpeculativeExecution.h
+++ b/llvm/include/llvm/Transforms/Scalar/SpeculativeExecution.h
@@ -66,6 +66,7 @@
 
 namespace llvm {
 class BasicBlock;
+struct ScalarOptions;
 class TargetTransformInfo;
 
 class SpeculativeExecutionPass
@@ -86,6 +87,8 @@ class SpeculativeExecutionPass
   bool runOnBasicBlock(BasicBlock &B);
   bool considerHoistingFromTo(BasicBlock &FromBlock, BasicBlock &ToBlock);
 
+  const ScalarOptions *Opts = nullptr;
+
   // If true, this pass is a nop unless the target architecture has branch
   // divergence.
   const bool OnlyIfDivergentTarget = false;
diff --git a/llvm/include/llvm/Transforms/Utils/Instrumentation.h b/llvm/include/llvm/Transforms/Utils/Instrumentation.h
index 8405245b2bc0ac..9945ef5665e9be 100644
--- a/llvm/include/llvm/Transforms/Utils/Instrumentation.h
+++ b/llvm/include/llvm/Transforms/Utils/Instrumentation.h
@@ -62,8 +62,6 @@ LLVM_ABI void setGlobalVariableLargeSection(const Triple &TargetTriple,
 
 // Insert GCOV profiling instrumentation
 struct GCOVOptions {
-  LLVM_ABI static GCOVOptions getDefault();
-
   // Specify whether to emit .gcno files.
   bool EmitNotes;
 
diff --git a/llvm/lib/CGData/CGDataOptions.td b/llvm/lib/CGData/CGDataOptions.td
index 0e4cbdcc005bac..025e91f5bca236 100644
--- a/llvm/lib/CGData/CGDataOptions.td
+++ b/llvm/lib/CGData/CGDataOptions.td
@@ -8,7 +8,7 @@
 
 include "llvm/Option/LibraryOptions.td"
 
-def CGDataOptions : OptionsStruct<perContext = false>;
+def CGDataOptions : OptionsStruct;
 
 defm : BoolField<"codegen-data-generate", "false",
   "Emit CodeGen Data into custom sections">;
diff --git a/llvm/lib/CGData/CodeGenData.cpp b/llvm/lib/CGData/CodeGenData.cpp
index d27ac5a589fea5..aab15ae700c104 100644
--- a/llvm/lib/CGData/CodeGenData.cpp
+++ b/llvm/lib/CGData/CodeGenData.cpp
@@ -108,8 +108,9 @@ const char *CodeGenDataSectNamePrefix[] = {
 
 } // namespace
 
-bool llvm::cgdata::thinLTOTwoRounds() {
-  return CGDataOptions::Global.codegen_data_thinlto_two_rounds;
+bool llvm::cgdata::thinLTOTwoRounds(
+    const cl::LibraryOptionsContext &LibraryOptions) {
+  return LibraryOptions.get<CGDataOptions>().codegen_data_thinlto_two_rounds;
 }
 
 namespace llvm {
@@ -133,11 +134,12 @@ std::string getCodeGenDataSectionName(CGDataSectKind CGSK,
 std::unique_ptr<CodeGenData> CodeGenData::Instance = nullptr;
 std::once_flag CodeGenData::OnceFlag;
 
-CodeGenData &CodeGenData::getInstance() {
-  std::call_once(CodeGenData::OnceFlag, []() {
+CodeGenData &
+CodeGenData::getInstance(const cl::LibraryOptionsContext &LibraryOptions) {
+  std::call_once(CodeGenData::OnceFlag, [&LibraryOptions]() {
     Instance = std::unique_ptr<CodeGenData>(new CodeGenData());
 
-    const CGDataOptions &Opts = CGDataOptions::Global;
+    const CGDataOptions &Opts = LibraryOptions.get<CGDataOptions>();
     if (Opts.codegen_data_generate || Opts.codegen_data_thinlto_two_rounds)
       Instance->EmitCGData = true;
     else if (!Opts.codegen_data_use_path.empty()) {
@@ -146,9 +148,9 @@ CodeGenData &CodeGenData::getInstance() {
       // Instead, just emit an warning message and fall back as if no CGData
       // were available.
       auto FS = vfs::getRealFileSystem();
-      auto ReaderOrErr =
-          CodeGenDataReader::create(Opts.codegen_data_use_path, *FS,
-                                    Opts.indexed_codegen_data_lazy_loading);
+      auto ReaderOrErr = CodeGenDataReader::create(
+          LibraryOptions, Opts.codegen_data_use_path, *FS,
+          Opts.indexed_codegen_data_lazy_loading);
       if (Error E = ReaderOrErr.takeError()) {
         warn(std::move(E), Opts.codegen_data_use_path);
         return;
@@ -250,7 +252,9 @@ std::unique_ptr<Module> loadModuleForTwoRounds(BitcodeModule &OrigModule,
   return std::move(*RestoredModule);
 }
 
-Expected<stable_hash> mergeCodeGenData(ArrayRef<StringRef> ObjFiles) {
+Expected<stable_hash>
+mergeCodeGenData(const cl::LibraryOptionsContext &LibraryOptions,
+                 ArrayRef<StringRef> ObjFiles) {
   OutlinedHashTreeRecord GlobalOutlineRecord;
   StableFunctionMapRecord GlobalStableFunctionMapRecord;
   stable_hash CombinedHash = 0;
@@ -271,13 +275,14 @@ Expected<stable_hash> mergeCodeGenData(ArrayRef<StringRef> ObjFiles) {
       return E;
   }
 
-  GlobalStableFunctionMapRecord.finalize();
+  GlobalStableFunctionMapRecord.finalize(LibraryOptions);
 
   if (!GlobalOutlineRecord.empty())
-    cgdata::publishOutlinedHashTree(std::move(GlobalOutlineRecord.HashTree));
+    cgdata::publishOutlinedHashTree(LibraryOptions,
+                                    std::move(GlobalOutlineRecord.HashTree));
   if (!GlobalStableFunctionMapRecord.empty())
     cgdata::publishStableFunctionMap(
-        std::move(GlobalStableFunctionMapRecord.FunctionMap));
+        LibraryOptions, std::move(GlobalStableFunctionMapRecord.FunctionMap));
 
   return CombinedHash;
 }
diff --git a/llvm/lib/CGData/CodeGenDataReader.cpp b/llvm/lib/CGData/CodeGenDataReader.cpp
index 5e6fb34dce21b4..46f4e863264433 100644
--- a/llvm/lib/CGData/CodeGenDataReader.cpp
+++ b/llvm/lib/CGData/CodeGenDataReader.cpp
@@ -110,8 +110,7 @@ Error IndexedCodeGenDataReader::read() {
     const unsigned char *Ptr = Start + Header.StableFunctionMapOffset;
     if (Ptr >= End)
       return error(cgdata_error::eof);
-    FunctionMapRecord.setReadStableFunctionMapNames(
-        CGDataOptions::Global.indexed_codegen_data_read_function_map_names);
+    FunctionMapRecord.setReadStableFunctionMapNames(ReadStableFunctionMapNames);
     if (LazyLoading)
       FunctionMapRecord.lazyDeserialize(std::move(SharedDataBuffer),
                                         Header.StableFunctionMapOffset);
@@ -123,17 +122,20 @@ Error IndexedCodeGenDataReader::read() {
 }
 
 Expected<std::unique_ptr<CodeGenDataReader>>
-CodeGenDataReader::create(const Twine &Path, vfs::FileSystem &FS,
+CodeGenDataReader::create(const cl::LibraryOptionsContext &LibraryOptions,
+                          const Twine &Path, vfs::FileSystem &FS,
                           bool LazyLoading) {
   // Set up the buffer to read.
   auto BufferOrError = setupMemoryBuffer(Path, FS);
   if (Error E = BufferOrError.takeError())
     return std::move(E);
-  return CodeGenDataReader::create(std::move(BufferOrError.get()), LazyLoading);
+  return CodeGenDataReader::create(LibraryOptions,
+                                   std::move(BufferOrError.get()), LazyLoading);
 }
 
 Expected<std::unique_ptr<CodeGenDataReader>>
-CodeGenDataReader::create(std::unique_ptr<MemoryBuffer> Buffer,
+CodeGenDataReader::create(const cl::LibraryOptionsContext &LibraryOptions,
+                          std::unique_ptr<MemoryBuffer> Buffer,
                           bool LazyLoading) {
   if (Buffer->getBufferSize() == 0)
     return make_error<CGDataError>(cgdata_error::empty_cgdata);
@@ -141,8 +143,10 @@ CodeGenDataReader::create(std::unique_ptr<MemoryBuffer> Buffer,
   std::unique_ptr<CodeGenDataReader> Reader;
   // Create the reader.
   if (IndexedCodeGenDataReader::hasFormat(*Buffer))
-    Reader = std::make_unique<IndexedCodeGenDataReader>(std::move(Buffer),
-                                                        LazyLoading);
+    Reader = std::make_unique<IndexedCodeGenDataReader>(
+        LibraryOptions.get<CGDataOptions>()
+            .indexed_codegen_data_read_function_map_names,
+        std::move(Buffer), LazyLoading);
   else if (TextCodeGenDataReader::hasFormat(*Buffer))
     Reader = std::make_unique<TextCodeGenDataReader>(std::move(Buffer));
   else
diff --git a/llvm/lib/CGData/StableFunctionMap.cpp b/llvm/lib/CGData/StableFunctionMap.cpp
index b8b8cfd1286ae1..4b3a82c87f164e 100644
--- a/llvm/lib/CGData/StableFunctionMap.cpp
+++ b/llvm/lib/CGData/StableFunctionMap.cpp
@@ -161,8 +161,8 @@ removeIdenticalIndexPair(StableFunctionMap::StableFunctionEntries &SFS) {
       SF->IndexOperandHashMap->erase(Pair);
 }
 
-static bool isProfitable(const StableFunctionMap::StableFunctionEntries &SFS) {
-  const CGDataOptions &Opts = CGDataOptions::Global;
+static bool isProfitable(const CGDataOptions &Opts,
+                         const StableFunctionMap::StableFunctionEntries &SFS) {
   unsigned StableFunctionCount = SFS.size();
   if (StableFunctionCount < Opts.global_merging_min_merges)
     return false;
@@ -203,7 +203,9 @@ static bool isProfitable(const StableFunctionMap::StableFunctionEntries &SFS) {
   return Result;
 }
 
-void StableFunctionMap::finalize(bool SkipTrim) {
+void StableFunctionMap::finalize(
+    const cl::LibraryOptionsContext &LibraryOptions, bool SkipTrim) {
+  const CGDataOptions &Opts = LibraryOptions.get<CGDataOptions>();
   deserializeLazyLoadingEntries();
   SmallVector<HashFuncsMapType::iterator> ToDelete;
   for (auto It = HashToFuncs.begin(); It != HashToFuncs.end(); ++It) {
@@ -252,7 +254,7 @@ void StableFunctionMap::finalize(bool SkipTrim) {
     // stable functions.
     removeIdenticalIndexPair(SFS);
 
-    if (!isProfitable(SFS))
+    if (!isProfitable(Opts, SFS))
       ToDelete.push_back(It);
   }
   for (auto It : ToDelete)
diff --git a/llvm/lib/CodeGen/GlobalMergeFunctions.cpp b/llvm/lib/CodeGen/GlobalMergeFunctions.cpp
index e13d7b47600fde..1b9cf2d528a0ec 100644
--- a/llvm/lib/CodeGen/GlobalMergeFunctions.cpp
+++ b/llvm/lib/CodeGen/GlobalMergeFunctions.cpp
@@ -535,9 +535,11 @@ void GlobalMergeFunc::initializeMergerMode(const Module &M) {
   if (Index && !Index->hasExportedFunctions(M))
     return;
 
-  if (cgdata::emitCGData())
+  const cl::LibraryOptionsContext &LibraryOptions =
+      M.getContext().getLibraryOptions();
+  if (cgdata::emitCGData(LibraryOptions))
     MergerMode = HashFunctionMode::BuildingHashFuncion;
-  else if (cgdata::hasStableFunctionMap())
+  else if (cgdata::hasStableFunctionMap(LibraryOptions))
     MergerMode = HashFunctionMode::UsingHashFunction;
 }
 
@@ -566,18 +568,20 @@ void GlobalMergeFunc::emitFunctionMap(Module &M) {
 
 bool GlobalMergeFunc::run(Module &M) {
   initializeMergerMode(M);
+  const cl::LibraryOptionsContext &LibraryOptions =
+      M.getContext().getLibraryOptions();
 
   const StableFunctionMap *FuncMap;
   if (MergerMode == HashFunctionMode::UsingHashFunction) {
     // Use the prior CG data to optimistically create global merge candidates.
-    FuncMap = cgdata::getStableFunctionMap();
+    FuncMap = cgdata::getStableFunctionMap(LibraryOptions);
   } else {
     analyze(M);
     // Emit the local function map to the custom section, __llvm_merge before
     // finalizing it.
     if (MergerMode == HashFunctionMode::BuildingHashFuncion)
       emitFunctionMap(M);
-    LocalFunctionMap->finalize();
+    LocalFunctionMap->finalize(LibraryOptions);
     FuncMap = LocalFunctionMap.get();
   }
 
diff --git a/llvm/lib/CodeGen/MachineOutliner.cpp b/llvm/lib/CodeGen/MachineOutliner.cpp
index 540c9c8b018da1..5251ee13683b23 100644
--- a/llvm/lib/CodeGen/MachineOutliner.cpp
+++ b/llvm/lib/CodeGen/MachineOutliner.cpp
@@ -683,8 +683,10 @@ static SmallVector<MatchedEntry> getMatchedEntries(InstructionMapper &Mapper) {
   auto Size = UnsignedVec.size();
 
   // Get the global outlined hash tree built from the previous run.
-  assert(cgdata::hasOutlinedHashTree());
-  const auto *RootNode = cgdata::getOutlinedHashTree()->getRoot();
+  const cl::LibraryOptionsContext &LibraryOptions =
+      Mapper.MMI.getModule()->getContext().getLibraryOptions();
+  assert(cgdata::hasOutlinedHashTree(LibraryOptions));
+  const auto *RootNode = cgdata::getOutlinedHashTree(LibraryOptions)->getRoot();
 
   auto getValidInstr = [&](unsigned Index) -> const MachineInstr * {
     if (UnsignedVec[Index] >= Mapper.LegalInstrNumber)
@@ -1537,12 +1539,14 @@ void MachineOutliner::initializeOutlinerMode(const Module &M) {
   // hash tree to the custom section, `__llvm_outline`.
   // When the outlined hash tree is available from the previous codegen data,
   // we want to read it to optimistically create global outlining candidates.
-  if (cgdata::emitCGData()) {
+  const cl::LibraryOptionsContext &LibraryOptions =
+      M.getContext().getLibraryOptions();
+  if (cgdata::emitCGData(LibraryOptions)) {
     OutlinerMode = CGDataMode::Write;
     // Create a local outlined hash tree to be published.
     LocalHashTree = std::make_unique<OutlinedHashTree>();
     // We don't need to read the outlined hash tree from the previous codegen
-  } else if (cgdata::hasOutlinedHashTree())
+  } else if (cgdata::hasOutlinedHashTree(LibraryOptions))
     OutlinerMode = CGDataMode::Read;
 }
 
diff --git a/llvm/lib/Frontend/Driver/CodeGenOptions.cpp b/llvm/lib/Frontend/Driver/CodeGenOptions.cpp
index e4d5317d68fc85..e893c15d76147f 100644
--- a/llvm/lib/Frontend/Driver/CodeGenOptions.cpp
+++ b/llvm/lib/Frontend/Driver/CodeGenOptions.cpp
@@ -45,8 +45,9 @@ TargetLibraryInfoImpl *createTLII(const llvm::Triple &TargetTriple,
       TargetTriple, convertDriverVectorLibraryToVectorLibrary(Veclib));
 }
 
-std::string getDefaultProfileGenName() {
-  return isProfileCorrelationEnabled() ? "default_%m.proflite"
-                                       : "default_%m.profraw";
+std::string
+getDefaultProfileGenName(const cl::LibraryOptionsContext &LibraryOptions) {
+  return isProfileCorrelationEnabled(LibraryOptions) ? "default_%m.proflite"
+                                                     : "default_%m.profraw";
 }
 } // namespace llvm::driver
diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp
index 50232bf87d257d..e92c33a15e88aa 100644
--- a/llvm/lib/LTO/LTO.cpp
+++ b/llvm/lib/LTO/LTO.cpp
@@ -2296,7 +2296,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
     return BackendProcess->wait();
   };
 
-  if (!cgdata::thinLTOTwoRounds()) {
+  if (!cgdata::thinLTOTwoRounds(RegularLTO.Ctx.getLibraryOptions())) {
     std::unique_ptr<ThinBackendProc> BackendProc =
         ThinLTO.Backend(Conf, ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
                         AddStream, Cache, BitcodeLibFuncs);
@@ -2327,7 +2327,8 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
     return E;
 
   LLVM_DEBUG(dbgs() << "[TwoRounds] Merging codegen data\n");
-  auto CombinedHashOrErr = cgdata::mergeCodeGenData(*CG.getResult());
+  auto CombinedHashOrErr = cgdata::mergeCodeGenData(
+      RegularLTO.Ctx.getLibraryOptions(), *CG.getResult());
   if (Error E = CombinedHashOrErr.takeError())
     return E;
   auto CombinedHash = *CombinedHashOrErr;
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 96d18057a594d4..6eb5281513d125 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -570,8 +570,11 @@ PassBuilder::PassBuilder(TargetMachine *TM, PipelineTuningOptions PTO,
                          std::optional<PGOOptions> PGOOpt,
                          PassInstrumentationCallbacks *PIC,
                          IntrusiveRefCntPtr<vfs::FileSystem> FS)
-    : Opts(PassesOptions::Global), TM(TM), PTO(PTO), PGOOpt(PGOOpt), PIC(PIC),
-      FS(std::move(FS)) {
+    : LibraryOptions(PTO.LibraryOptions ? PTO.LibraryOptions
+                     : TM               ? TM->Options.MCOptions.LibraryOptions
+                                        : nullptr),
+      Opts(cl::LibraryOptionsContext::get<PassesOptions>(LibraryOptions)),
+      TM(TM), PTO(PTO), PGOOpt(PGOOpt), PIC(PIC), FS(std::move(FS)) {
   if (TM)
     TM->registerPassBuilderCallbacks(*this);
   if (PIC) {
@@ -1162,19 +1165,21 @@ Expected<MemorySanitizerOptions> parseMSanPassOptions(StringRef Params) {
     std::tie(ParamName, Params) = Params.split(';');
 
     if (ParamName == "recover") {
-      Result.Recover = true;
+      Result.RecoverParam = true;
     } else if (ParamName == "kernel") {
-      Result.Kernel = true;
+      Result.KernelParam = true;
     } else if (ParamName.consume_front("track-origins=")) {
-      if (ParamName.getAsInteger(0, Result.TrackOrigins))
+      int TrackOrigins;
+      if (ParamName.getAsInteger(0, TrackOrigins))
         return make_error<StringError>(
             formatv("invalid argument to MemorySanitizer pass track-origins "
                     "parameter: '{}'",
                     ParamName)
                 .str(),
             inconvertibleErrorCode());
+      Result.TrackOriginsParam = TrackOrigins;
     } else if (ParamName == "eager-checks") {
-      Result.EagerChecks = true;
+      Result.EagerChecksParam = true;
     } else {
       return make_error<StringError>(
           formatv("invalid MemorySanitizer pass parameter '{}'", ParamName)
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index 348f52fbe933f8..125c8e442f27b6 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -167,17 +167,21 @@ extern cl::opt<std::string> UseCtxProfile;
 extern cl::opt<bool> EnableMemProfContextDisambiguation;
 } // namespace llvm
 
-PipelineTuningOptions::PipelineTuningOptions() {
-  const PassesOptions &Opts = PassesOptions::Global;
+PipelineTuningOptions::PipelineTuningOptions(
+    const cl::LibraryOptionsContext *LibraryOptions)
+    : LibraryOptions(LibraryOptions) {
+  const PassesOptions &Opts =
+      cl::LibraryOptionsContext::get<PassesOptions>(LibraryOptions);
   LoopInterleaving = true;
   LoopVectorization = true;
   SLPVectorization = false;
   LoopUnrolling = true;
   LoopInterchange = Opts.enable_loopinterchange;
   LoopFusion = false;
-  ForgetAllSCEVInLoopUnroll = getForgetSCEVInLoopUnroll();
-  LicmMssaOptCap = getLicmMssaOptCap();
-  LicmMssaNoAccForPromotionCap = getLicmMssaNoAccForPromotionCap();
+  ForgetAllSCEVInLoopUnroll = getForgetSCEVInLoopUnroll(LibraryOptions);
+  LicmMssaOptCap = getLicmMssaOptCap(LibraryOptions);
+  LicmMssaNoAccForPromotionCap =
+      getLicmMssaNoAccForPromotionCap(LibraryOptions);
   CallGraphProfile = true;
   UnifiedLTO = false;
   MergeFunctions = Opts.enable_merge_functions;
@@ -1127,7 +1131,8 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
   const bool IsPreLink = !isThinLTOPostLink(Phase);
   // Enable contextual profiling instrumentation.
   const bool IsCtxProfGen =
-      IsPreLink && PGOCtxProfLoweringPass::isCtxIRPGOInstrEnabled();
+      IsPreLink &&
+      PGOCtxProfLoweringPass::isCtxIRPGOInstrEnabled(LibraryOptions);
   const bool IsPGOPreLink = !IsCtxProfGen && PGOOpt && IsPreLink;
   const bool IsPGOInstrGen =
       IsPGOPreLink && PGOOpt->Action == PGOOptions::IRInstr;
@@ -1136,17 +1141,18 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
   const bool IsMemprofUse = IsPGOPreLink && !PGOOpt->MemoryProfile.empty();
   // We don't want to mix pgo ctx gen and pgo gen; we also don't currently
   // enable ctx profiling from the frontend.
-  assert(!(IsPGOInstrGen && PGOCtxProfLoweringPass::isCtxIRPGOInstrEnabled()) &&
+  assert(!(IsPGOInstrGen &&
+           PGOCtxProfLoweringPass::isCtxIRPGOInstrEnabled(LibraryOptions)) &&
          "Enabling both instrumented PGO and contextual instrumentation is not "
          "supported.");
   const bool IsCtxProfUse = !UseCtxProfile.empty() && isThinLTOPreLink(Phase);
 
   assert((Opts.instrument_cold_function_only_path.empty() ||
-          isPGOInstrumentColdFunctionOnly()) &&
+          isPGOInstrumentColdFunctionOnly(LibraryOptions)) &&
          "--instrument-cold-function-only-path is provided but "
          "--pgo-instrument-cold-function-only is not enabled");
   const bool IsColdFuncOnlyInstrGen =
-      isPGOInstrumentColdFunctionOnly() && IsPGOPreLink &&
+      isPGOInstrumentColdFunctionOnly(LibraryOptions) && IsPGOPreLink &&
       !Opts.instrument_cold_function_only_path.empty();
 
   if (IsPGOInstrGen || IsPGOInstrUse || IsMemprofUse || IsCtxProfGen ||
diff --git a/llvm/lib/Passes/PassesOptions.td b/llvm/lib/Passes/PassesOptions.td
index 8789b2a243dd8c..4398d5c06bff2b 100644
--- a/llvm/lib/Passes/PassesOptions.td
+++ b/llvm/lib/Passes/PassesOptions.td
@@ -8,7 +8,7 @@
 
 include "llvm/Option/LibraryOptions.td"
 
-def PassesOptions : OptionsStruct<perContext = false>;
+def PassesOptions : OptionsStruct;
 
 // PassBuilder.cpp
 defm : FlagOrEnumField<"print-pipeline-passes",
diff --git a/llvm/lib/Passes/RunCodeGen.cpp b/llvm/lib/Passes/RunCodeGen.cpp
index 611b5963af3f37..7514d6cbb9aca0 100644
--- a/llvm/lib/Passes/RunCodeGen.cpp
+++ b/llvm/lib/Passes/RunCodeGen.cpp
@@ -67,7 +67,7 @@ static Error runCodeGenPipelineNewPM(TargetMachine &TM, Module &M,
   Opt.DisableVerify = DisableVerify;
   MachineModuleInfo MMI(&TM);
   PassInstrumentationCallbacks PIC;
-  PipelineTuningOptions PTOptions;
+  PipelineTuningOptions PTOptions(&M.getContext().getLibraryOptions());
   TargetMachine *TMPointer = &TM;
   PassBuilder PB(TMPointer, PTOptions, std::nullopt, &PIC, VFS);
   PB.registerModuleAnalyses(MAM);
@@ -95,8 +95,9 @@ Error llvm::runCodeGenPipeline(TargetMachine &TM, Module &M,
                                CodeGenFileType CGFT, bool DisableVerify,
                                bool DisableSimplifyLibCalls,
                                IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
-  if (valueOr(PassesOptions::Global.force_new_pm_codegen,
-              TM.shouldDefaultToNewPM())) {
+  const PassesOptions &Opts =
+      M.getContext().getLibraryOptions().get<PassesOptions>();
+  if (valueOr(Opts.force_new_pm_codegen, TM.shouldDefaultToNewPM())) {
     return runCodeGenPipelineNewPM(TM, M, OS, DwoOS, CGFT, DisableVerify, VFS);
   }
 
diff --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp
index 974412960083d3..c86a7cc02fb68a 100644
--- a/llvm/lib/Passes/StandardInstrumentations.cpp
+++ b/llvm/lib/Passes/StandardInstrumentations.cpp
@@ -454,7 +454,7 @@ void IRChangedPrinter::handleAfter(StringRef PassID, std::string &Name,
                                    const std::string &Before,
                                    const std::string &After, IRUnitRef) {
   // Report the IR before the changes when requested.
-  if (PassesOptions::Global.print_before_changed)
+  if (Opts.print_before_changed)
     Out << "*** IR Dump Before " << PassID << " on " << Name << " ***\n"
         << Before;
 
@@ -471,12 +471,11 @@ void IRChangedPrinter::handleAfter(StringRef PassID, std::string &Name,
 IRChangedTester::~IRChangedTester() = default;
 
 void IRChangedTester::registerCallbacks(PassInstrumentationCallbacks &PIC) {
-  if (PassesOptions::Global.exec_on_ir_change != "")
+  if (Opts.exec_on_ir_change != "")
     TextChangeReporter<std::string>::registerRequiredCallbacks(PIC);
 }
 
 void IRChangedTester::handleIR(const std::string &S, StringRef PassID) {
-  const PassesOptions &Opts = PassesOptions::Global;
   // Store the body into a temporary file
   static SmallVector<int> FD{-1};
   SmallVector<StringRef> SR{S};
@@ -748,7 +747,6 @@ StringRef PrintIRInstrumentation::getFileSuffix(IRDumpFileSuffixType Type) {
 std::string PrintIRInstrumentation::fetchDumpFilename(
     StringRef PassName, StringRef IRFileDisplayName, unsigned PassNumber,
     IRDumpFileSuffixType SuffixType) {
-  const PassesOptions &Opts = PassesOptions::Global;
   assert(!Opts.ir_dump_directory.empty() &&
          "The flag -ir-dump-directory must be passed to dump IR to files");
 
@@ -833,7 +831,7 @@ void PrintIRInstrumentation::printBeforePass(StringRef PassID, IRUnitRef IR) {
     unwrapAndPrint(Stream, IR);
   };
 
-  if (!PassesOptions::Global.ir_dump_directory.empty()) {
+  if (!Opts.ir_dump_directory.empty()) {
     std::string DumpIRFilename =
         fetchDumpFilename(PassID, getIRFileDisplayName(IR), CurrentPassNumber,
                           IRDumpFileSuffixType::Before);
@@ -868,7 +866,7 @@ void PrintIRInstrumentation::printAfterPass(StringRef PassID, IRUnitRef IR) {
     unwrapAndPrint(Stream, IR);
   };
 
-  if (!PassesOptions::Global.ir_dump_directory.empty()) {
+  if (!Opts.ir_dump_directory.empty()) {
     std::string DumpIRFilename =
         fetchDumpFilename(PassID, getIRFileDisplayName(IR), CurrentPassNumber,
                           IRDumpFileSuffixType::After);
@@ -906,7 +904,7 @@ void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) {
     printIR(Stream, M);
   };
 
-  if (!PassesOptions::Global.ir_dump_directory.empty()) {
+  if (!Opts.ir_dump_directory.empty()) {
     std::string DumpIRFilename =
         fetchDumpFilename(PassID, IRFileDisplayName, PassNumber,
                           IRDumpFileSuffixType::Invalidated);
@@ -946,7 +944,7 @@ bool PrintIRInstrumentation::shouldPrintAfterCurrentPassNumber() {
 }
 
 bool PrintIRInstrumentation::shouldPrintPassNumbers() {
-  return PassesOptions::Global.print_pass_numbers;
+  return Opts.print_pass_numbers;
 }
 
 bool PrintIRInstrumentation::shouldPrintBeforeSomePassNumber() {
@@ -1007,7 +1005,6 @@ bool OptNoneInstrumentation::shouldRun(StringRef PassID, IRUnitRef IR) {
 }
 
 bool OptPassGateInstrumentation::shouldRun(StringRef PassName, IRUnitRef IR) {
-  const PassesOptions &Opts = PassesOptions::Global;
   if (isIgnored(PassName))
     return true;
 
@@ -1320,8 +1317,7 @@ void PreservedCFGCheckerInstrumentation::registerCallbacks(
 #else
   constexpr bool VerifyByDefault = false;
 #endif
-  if (!valueOr(PassesOptions::Global.verify_analysis_invalidation,
-               VerifyByDefault))
+  if (!valueOr(Opts.verify_analysis_invalidation, VerifyByDefault))
     return;
 
   bool Registered = false;
@@ -1760,11 +1756,11 @@ class DotCfgDiffNode {
 
   // Create a node in Dot difference graph \p G representing the basic block
   // represented by \p BD with colour \p Colour (where it exists).
-  DotCfgDiffNode(DotCfgDiff &G, unsigned N, const BlockDataT<DCData> &BD,
-                 StringRef Colour)
-      : Graph(G), N(N), Data{&BD, nullptr}, Colour(Colour) {}
+  DotCfgDiffNode(const PassesOptions &Opts, DotCfgDiff &G, unsigned N,
+                 const BlockDataT<DCData> &BD, StringRef Colour)
+      : Opts(Opts), Graph(G), N(N), Data{&BD, nullptr}, Colour(Colour) {}
   DotCfgDiffNode(const DotCfgDiffNode &DN)
-      : Graph(DN.Graph), N(DN.N), Data{DN.Data[0], DN.Data[1]},
+      : Opts(DN.Opts), Graph(DN.Graph), N(DN.N), Data{DN.Data[0], DN.Data[1]},
         Colour(DN.Colour), EdgesMap(DN.EdgesMap), Children(DN.Children),
         Edges(DN.Edges) {}
 
@@ -1782,13 +1778,12 @@ class DotCfgDiffNode {
   void setCommon(const BlockDataT<DCData> &Other) {
     assert(!Data[1] && "Expected only one block datum");
     Data[1] = &Other;
-    Colour = PassesOptions::Global.dot_cfg_common_color;
+    Colour = Opts.dot_cfg_common_color;
   }
   // Add an edge to \p E of colour {\p Value, \p Colour}.
   void addEdge(unsigned E, StringRef Value, StringRef Colour) {
     // This is a new edge or it is an edge being made common.
-    assert((EdgesMap.count(E) == 0 ||
-            Colour == PassesOptions::Global.dot_cfg_common_color) &&
+    assert((EdgesMap.count(E) == 0 || Colour == Opts.dot_cfg_common_color) &&
            "Unexpected edge count and color.");
     EdgesMap[E] = {Value.str(), Colour};
   }
@@ -1808,6 +1803,7 @@ class DotCfgDiffNode {
                           std::map<const unsigned, unsigned> &NodeMap) const;
 
 protected:
+  const PassesOptions &Opts;
   DotCfgDiff &Graph;
   const unsigned N;
   const BlockDataT<DCData> *Data[2];
@@ -1824,8 +1820,8 @@ class DotCfgDiff {
   // entry node for the function.  \p Before and \p After are the before
   // after versions of the function, respectively.  \p Dir is the directory
   // in which to store the results.
-  DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,
-             const FuncDataT<DCData> &After);
+  DotCfgDiff(const PassesOptions &Opts, StringRef Title,
+             const FuncDataT<DCData> &Before, const FuncDataT<DCData> &After);
 
   DotCfgDiff(const DotCfgDiff &) = delete;
   DotCfgDiff &operator=(const DotCfgDiff &) = delete;
@@ -1859,10 +1855,11 @@ class DotCfgDiff {
 
   void createNode(StringRef Label, const BlockDataT<DCData> &BD, StringRef C) {
     unsigned Pos = Nodes.size();
-    Nodes.emplace_back(*this, Pos, BD, C);
+    Nodes.emplace_back(Opts, *this, Pos, BD, C);
     NodePosition.insert({Label, Pos});
   }
 
+  const PassesOptions &Opts;
   // TODO Nodes should probably be a StringMap<DotCfgDiffNode> after the
   // display graph is separated out, which would remove the need for
   // NodePosition.
@@ -1874,7 +1871,6 @@ class DotCfgDiff {
 };
 
 std::string DotCfgDiffNode::getBodyContent() const {
-  const PassesOptions &Opts = PassesOptions::Global;
   if (Colour == Opts.dot_cfg_common_color) {
     assert(Data[1] && "Expected Data[1] to be set.");
 
@@ -1949,10 +1945,10 @@ std::string DotCfgDiff::colourize(std::string S, StringRef Colour) const {
   return "<FONT COLOR=\"" + Colour.str() + "\">" + S + "</FONT>";
 }
 
-DotCfgDiff::DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,
+DotCfgDiff::DotCfgDiff(const PassesOptions &Opts, StringRef Title,
+                       const FuncDataT<DCData> &Before,
                        const FuncDataT<DCData> &After)
-    : GraphName(Title.str()) {
-  const PassesOptions &Opts = PassesOptions::Global;
+    : Opts(Opts), GraphName(Title.str()) {
   StringMap<StringRef> EdgesMap;
 
   // Handle each basic block in the before IR.
@@ -2189,8 +2185,9 @@ DCData::DCData(const MachineBasicBlock &B) {
     addSuccessorLabel(Succ->getName().str(), "");
 }
 
-DotCfgChangeReporter::DotCfgChangeReporter(bool Verbose)
-    : ChangeReporter<IRDataT<DCData>>(Verbose) {}
+DotCfgChangeReporter::DotCfgChangeReporter(const PassesOptions &Opts,
+                                           bool Verbose)
+    : ChangeReporter<IRDataT<DCData>>(Verbose), Opts(Opts) {}
 
 void DotCfgChangeReporter::handleFunctionCompare(
     StringRef Name, StringRef Prefix, StringRef PassID, StringRef Divider,
@@ -2218,7 +2215,7 @@ void DotCfgChangeReporter::handleFunctionCompare(
   Text = formatv("{0}.{1}{2}{3}{4}", Number, Prefix, makeHTMLReady(PassID),
                  Divider, Name);
 
-  DotCfgDiff Diff(Text, Before, After);
+  DotCfgDiff Diff(Opts, Text, Before, After);
   std::string EntryBlockName = After.getEntryBlockName();
   // Use the before entry block if the after entry block was removed.
   if (EntryBlockName == "")
@@ -2236,7 +2233,6 @@ void DotCfgChangeReporter::handleFunctionCompare(
 
 std::string DotCfgChangeReporter::genHTML(StringRef Text, StringRef DotFile,
                                           StringRef PDFFileName) const {
-  const PassesOptions &Opts = PassesOptions::Global;
   SmallString<20> PDFFile = formatv("{0}/{1}", OutputDir, PDFFileName);
   // Create the PDF file.
   static ErrorOr<std::string> DotExe =
@@ -2403,7 +2399,7 @@ void DotCfgChangeReporter::registerCallbacks(
   if (PrintChanged == ChangePrinter::DotCfgVerbose ||
        PrintChanged == ChangePrinter::DotCfgQuiet) {
     SmallString<128> Dir;
-    sys::fs::expand_tilde(PassesOptions::Global.dot_cfg_dir, Dir);
+    sys::fs::expand_tilde(Opts.dot_cfg_dir, Dir);
     sys::fs::make_absolute(Dir);
     assert(!Dir.empty() && "expected output dir to be non-empty");
     OutputDir = Dir.str();
@@ -2418,23 +2414,22 @@ void DotCfgChangeReporter::registerCallbacks(
 StandardInstrumentations::StandardInstrumentations(
     LLVMContext &Context, bool DebugLogging, bool VerifyEach,
     PrintPassOptions PrintPassOpts)
-    : PrintPass(DebugLogging, PrintPassOpts), OptNone(DebugLogging),
-      OptPassGate(Context),
-      PrintChangedIR(PrintChanged == ChangePrinter::Verbose),
+    : Opts(Context.getLibraryOptions().get<PassesOptions>()), PrintIR(Opts),
+      PrintPass(DebugLogging, PrintPassOpts), OptNone(DebugLogging),
+      OptPassGate(Opts, Context), PreservedCFGChecker(Opts),
+      PrintChangedIR(Opts, PrintChanged == ChangePrinter::Verbose),
       PrintChangedDiff(PrintChanged == ChangePrinter::DiffVerbose ||
                            PrintChanged == ChangePrinter::ColourDiffVerbose,
                        PrintChanged == ChangePrinter::ColourDiffVerbose ||
                            PrintChanged == ChangePrinter::ColourDiffQuiet),
-      WebsiteChangeReporter(PrintChanged == ChangePrinter::DotCfgVerbose),
-      Verify(DebugLogging),
-      DroppedStatsIR(PassesOptions::Global.dropped_variable_stats),
-      VerifyEach(VerifyEach) {}
+      WebsiteChangeReporter(Opts, PrintChanged == ChangePrinter::DotCfgVerbose),
+      PrintCrashIR(Opts), ChangeTester(Opts), Verify(DebugLogging),
+      DroppedStatsIR(Opts.dropped_variable_stats), VerifyEach(VerifyEach) {}
 
 PrintCrashIRInstrumentation *PrintCrashIRInstrumentation::CrashReporter =
     nullptr;
 
 void PrintCrashIRInstrumentation::reportCrashIR() {
-  const PassesOptions &Opts = PassesOptions::Global;
   if (!Opts.print_on_crash_path.empty()) {
     std::error_code EC;
     raw_fd_ostream Out(Opts.print_on_crash_path, EC);
@@ -2452,8 +2447,8 @@ void PrintCrashIRInstrumentation::SignalHandler(void *) {
   if (!CrashReporter)
     return;
 
-  assert((PassesOptions::Global.print_on_crash ||
-          !PassesOptions::Global.print_on_crash_path.empty()) &&
+  assert((CrashReporter->Opts.print_on_crash ||
+          !CrashReporter->Opts.print_on_crash_path.empty()) &&
          "Did not expect to get here without option set.");
   CrashReporter->reportCrashIR();
 }
@@ -2462,15 +2457,14 @@ PrintCrashIRInstrumentation::~PrintCrashIRInstrumentation() {
   if (!CrashReporter)
     return;
 
-  assert((PassesOptions::Global.print_on_crash ||
-          !PassesOptions::Global.print_on_crash_path.empty()) &&
+  assert((CrashReporter->Opts.print_on_crash ||
+          !CrashReporter->Opts.print_on_crash_path.empty()) &&
          "Did not expect to get here without option set.");
   CrashReporter = nullptr;
 }
 
 void PrintCrashIRInstrumentation::registerCallbacks(
     PassInstrumentationCallbacks &PIC) {
-  const PassesOptions &Opts = PassesOptions::Global;
   if ((!Opts.print_on_crash && Opts.print_on_crash_path.empty()) ||
       CrashReporter)
     return;
@@ -2496,7 +2490,7 @@ void PrintCrashIRInstrumentation::registerCallbacks(
 void StandardInstrumentations::registerCallbacks(
     PassInstrumentationCallbacks &PIC, ModuleAnalysisManager *MAM,
     ExtendedIRContext *IRContext) {
-  if (PassesOptions::Global.instnamer_after_each_pass)
+  if (Opts.instnamer_after_each_pass)
     InstructionNamerPass::registerCallbacks(PIC, InstNamerNextID);
   PrintIR.registerCallbacks(PIC, IRContext);
   PrintPass.registerCallbacks(PIC, IRContext);
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUSwLowerLDS.cpp b/llvm/lib/Target/AMDGPU/AMDGPUSwLowerLDS.cpp
index 65e808fba74681..e639ffa23954b4 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUSwLowerLDS.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUSwLowerLDS.cpp
@@ -1206,8 +1206,8 @@ void AMDGPUSwLowerLDS::initAsanInfo() {
   uint64_t Offset;
   int Scale;
   bool OrShadowOffset;
-  llvm::getAddressSanitizerParams(M.getTargetTriple(), LongSize, false, &Offset,
-                                  &Scale, &OrShadowOffset);
+  llvm::getAddressSanitizerParams(M.getContext(), M.getTargetTriple(), LongSize,
+                                  false, &Offset, &Scale, &OrShadowOffset);
   AsanInfo.Scale = Scale;
   AsanInfo.Offset = Offset;
 }
diff --git a/llvm/lib/Target/X86/X86MCInstLower.cpp b/llvm/lib/Target/X86/X86MCInstLower.cpp
index b18329082cfdb1..7a71b2746e7980 100644
--- a/llvm/lib/Target/X86/X86MCInstLower.cpp
+++ b/llvm/lib/Target/X86/X86MCInstLower.cpp
@@ -951,7 +951,8 @@ void X86AsmPrinter::LowerASAN_CHECK_MEMACCESS(const MachineInstr &MI) {
   uint64_t ShadowBase;
   int MappingScale;
   bool OrShadowOffset;
-  getAddressSanitizerParams(TM.getTargetTriple(), 64, AccessInfo.CompileKernel,
+  getAddressSanitizerParams(MF->getFunction().getContext(),
+                            TM.getTargetTriple(), 64, AccessInfo.CompileKernel,
                             &ShadowBase, &MappingScale, &OrShadowOffset);
 
   StringRef Name = AccessInfo.IsWrite ? "store" : "load";
diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
index 8de58841938a87..70841c8324aa3f 100644
--- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
@@ -350,11 +350,13 @@ static ShadowMapping getShadowMapping(const InstrumentationOptions &Opts,
   return Mapping;
 }
 
-void llvm::getAddressSanitizerParams(const Triple &TargetTriple, int LongSize,
+void llvm::getAddressSanitizerParams(const LLVMContext &Ctx,
+                                     const Triple &TargetTriple, int LongSize,
                                      bool IsKasan, uint64_t *ShadowBase,
                                      int *MappingScale, bool *OrShadowOffset) {
-  auto Mapping = getShadowMapping(InstrumentationOptions::Global, TargetTriple,
-                                  LongSize, IsKasan);
+  auto Mapping =
+      getShadowMapping(Ctx.getLibraryOptions().get<InstrumentationOptions>(),
+                       TargetTriple, LongSize, IsKasan);
   *ShadowBase = Mapping.Offset;
   *MappingScale = Mapping.Scale;
   *OrShadowOffset = Mapping.OrShadowOffset;
@@ -1057,7 +1059,8 @@ PreservedAnalyses AddressSanitizerPass::run(Module &M,
   if (checkIfAlreadyInstrumented(M, "nosanitize_address"))
     return PreservedAnalyses::all();
 
-  const InstrumentationOptions &Opts = InstrumentationOptions::Global;
+  const InstrumentationOptions &Opts =
+      M.getContext().getLibraryOptions().get<InstrumentationOptions>();
   ModuleAddressSanitizer ModuleSanitizer(Opts, M, Options.InsertVersionCheck,
                                          Options.CompileKernel, Options.Recover,
                                          UseGlobalGC, UseOdrIndicator,
diff --git a/llvm/lib/Transforms/Instrumentation/AllocToken.cpp b/llvm/lib/Transforms/Instrumentation/AllocToken.cpp
index 753f665e148f85..70a5fea9652a11 100644
--- a/llvm/lib/Transforms/Instrumentation/AllocToken.cpp
+++ b/llvm/lib/Transforms/Instrumentation/AllocToken.cpp
@@ -578,7 +578,9 @@ AllocTokenPass::AllocTokenPass(AllocTokenOptions Opts)
     : Options(std::move(Opts)) {}
 
 PreservedAnalyses AllocTokenPass::run(Module &M, ModuleAnalysisManager &MAM) {
-  AllocToken Pass(InstrumentationOptions::Global, Options, M, MAM);
+  const InstrumentationOptions &CLOpts =
+      M.getContext().getLibraryOptions().get<InstrumentationOptions>();
+  AllocToken Pass(CLOpts, Options, M, MAM);
   bool Modified = false;
 
   for (Function &F : M) {
diff --git a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp
index 814500214c9cf2..b1c3d642ce9ba8 100644
--- a/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp
+++ b/llvm/lib/Transforms/Instrumentation/BoundsChecking.cpp
@@ -195,7 +195,8 @@ getRuntimeCallName(const BoundsCheckingPass::Options::Runtime &Opts) {
 
 static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI,
                               ScalarEvolution &SE,
-                              const BoundsCheckingPass::Options &Opts) {
+                              const BoundsCheckingPass::Options &Opts,
+                              bool SingleTrap) {
   if (F.hasFnAttribute(Attribute::NoSanitizeBounds))
     return false;
 
@@ -248,8 +249,8 @@ static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI,
   // flags, this will either create a single block for the entire function or
   // will create a fresh block every time it is called.
   BasicBlock *ReuseTrapBB = nullptr;
-  auto GetTrapBB = [&ReuseTrapBB, &Opts, &Name](BuilderTy &IRB,
-                                                BasicBlock *Cont) {
+  auto GetTrapBB = [&ReuseTrapBB, &Opts, &Name, SingleTrap](BuilderTy &IRB,
+                                                            BasicBlock *Cont) {
     Function *Fn = IRB.GetInsertBlock()->getParent();
     auto DebugLoc = IRB.getCurrentDebugLocation();
     IRBuilder<>::InsertPointGuard Guard(IRB);
@@ -283,9 +284,7 @@ static bool addBoundsChecking(Function &F, TargetLibraryInfo &TLI,
     // local-bounds. Make sure to change that too.
     if (Opts.Rt && Opts.Rt->HandlerPreserveAllRegs && MayReturn)
       TrapCall->setCallingConv(CallingConv::PreserveAll);
-    if (!MayReturn &&
-        InstrumentationOptions::Global.bounds_checking_single_trap &&
-        !DebugTrapBB)
+    if (!MayReturn && SingleTrap && !DebugTrapBB)
       ReuseTrapBB = TrapBB;
 
     return TrapBB;
@@ -304,7 +303,9 @@ PreservedAnalyses BoundsCheckingPass::run(Function &F, FunctionAnalysisManager &
   auto &TLI = AM.getResult<TargetLibraryAnalysis>(F);
   auto &SE = AM.getResult<ScalarEvolutionAnalysis>(F);
 
-  if (!addBoundsChecking(F, TLI, SE, Opts))
+  const InstrumentationOptions &CLOpts =
+      F.getContext().getLibraryOptions().get<InstrumentationOptions>();
+  if (!addBoundsChecking(F, TLI, SE, Opts, CLOpts.bounds_checking_single_trap))
     return PreservedAnalyses::all();
 
   return PreservedAnalyses::none();
diff --git a/llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp b/llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp
index d4e6a6936bbcc8..145f4c77632f20 100644
--- a/llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp
+++ b/llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp
@@ -48,11 +48,9 @@ using namespace llvm;
 
 #define CHR_DEBUG(X) LLVM_DEBUG(X)
 
-static StringSet<> CHRModules;
-static StringSet<> CHRFunctions;
-
-static void parseCHRFilterFiles() {
-  const InstrumentationOptions &Opts = InstrumentationOptions::Global;
+static void parseCHRFilterFiles(const InstrumentationOptions &Opts,
+                                StringSet<> &CHRModules,
+                                StringSet<> &CHRFunctions) {
   if (!Opts.chr_module_list.empty()) {
     auto FileOrErr = MemoryBuffer::getFile(Opts.chr_module_list);
     if (!FileOrErr) {
@@ -262,11 +260,12 @@ class CHRScope {
 
 class CHR {
 public:
-  CHR(const InstrumentationOptions &Opts, Function &Fin,
-      BlockFrequencyInfo &BFIin, DominatorTree &DTin, ProfileSummaryInfo &PSIin,
-      RegionInfo &RIin, OptimizationRemarkEmitter &OREin)
-      : Opts(Opts), F(Fin), BFI(BFIin), DT(DTin), PSI(PSIin), RI(RIin),
-        ORE(OREin) {}
+  CHR(const InstrumentationOptions &Opts, const StringSet<> &CHRModules,
+      const StringSet<> &CHRFunctions, Function &Fin, BlockFrequencyInfo &BFIin,
+      DominatorTree &DTin, ProfileSummaryInfo &PSIin, RegionInfo &RIin,
+      OptimizationRemarkEmitter &OREin)
+      : Opts(Opts), CHRModules(CHRModules), CHRFunctions(CHRFunctions), F(Fin),
+        BFI(BFIin), DT(DTin), PSI(PSIin), RI(RIin), ORE(OREin) {}
 
   ~CHR() {
     for (CHRScope *Scope : Scopes) {
@@ -347,6 +346,8 @@ class CHR {
   }
 
   const InstrumentationOptions &Opts;
+  const StringSet<> &CHRModules;
+  const StringSet<> &CHRFunctions;
   Function &F;
   BlockFrequencyInfo &BFI;
   DominatorTree &DT;
@@ -387,7 +388,9 @@ raw_ostream &operator<<(raw_ostream &OS, const CHRScope &Scope) {
   return OS;
 }
 
-static bool shouldApply(const InstrumentationOptions &Opts, Function &F,
+static bool shouldApply(const InstrumentationOptions &Opts,
+                        const StringSet<> &CHRModules,
+                        const StringSet<> &CHRFunctions, Function &F,
                         ProfileSummaryInfo &PSI) {
   if (Opts.disable_chr)
     return false;
@@ -2006,7 +2009,7 @@ void CHR::transformScopes(SmallVectorImpl<CHRScope *> &CHRScopes) {
 }
 
 bool CHR::run() {
-  if (!shouldApply(Opts, F, PSI))
+  if (!shouldApply(Opts, CHRModules, CHRFunctions, F, PSI))
     return false;
 
   CHR_DEBUG(dumpIR(F, "before", nullptr));
@@ -2082,10 +2085,6 @@ bool CHR::run() {
   return Changed;
 }
 
-ControlHeightReductionPass::ControlHeightReductionPass() {
-  parseCHRFilterFiles();
-}
-
 PreservedAnalyses ControlHeightReductionPass::run(
     Function &F,
     FunctionAnalysisManager &FAM) {
@@ -2099,8 +2098,17 @@ PreservedAnalyses ControlHeightReductionPass::run(
   auto &DT = FAM.getResult<DominatorTreeAnalysis>(F);
   auto &RI = FAM.getResult<RegionInfoAnalysis>(F);
   auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
+  const InstrumentationOptions &Opts =
+      F.getContext().getLibraryOptions().get<InstrumentationOptions>();
+  if (&Opts != ParsedOpts &&
+      (!Opts.chr_module_list.empty() || !Opts.chr_function_list.empty())) {
+    CHRModules.clear();
+    CHRFunctions.clear();
+    parseCHRFilterFiles(Opts, CHRModules, CHRFunctions);
+    ParsedOpts = &Opts;
+  }
   bool Changed =
-      CHR(InstrumentationOptions::Global, F, BFI, DT, PSI, RI, ORE).run();
+      CHR(Opts, CHRModules, CHRFunctions, F, BFI, DT, PSI, RI, ORE).run();
   if (!Changed)
     return PreservedAnalyses::all();
   return PreservedAnalyses::none();
diff --git a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
index e16431a3168865..72ebfa0f3a8ce0 100644
--- a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
@@ -3428,8 +3428,9 @@ PreservedAnalyses DataFlowSanitizerPass::run(Module &M,
         AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
     return FAM.getResult<TargetLibraryAnalysis>(F);
   };
-  if (!DataFlowSanitizer(InstrumentationOptions::Global, ABIListFiles, FS)
-           .runImpl(M, GetTLI))
+  const InstrumentationOptions &Opts =
+      M.getContext().getLibraryOptions().get<InstrumentationOptions>();
+  if (!DataFlowSanitizer(Opts, ABIListFiles, FS).runImpl(M, GetTLI))
     return PreservedAnalyses::all();
 
   PreservedAnalyses PA = PreservedAnalyses::none();
diff --git a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
index e3c1602fe7419b..44990595c6e9a4 100644
--- a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
+++ b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp
@@ -66,12 +66,11 @@ static unsigned wordsOfString(StringRef s) {
   return (s.size() / 4) + 2;
 }
 
-GCOVOptions GCOVOptions::getDefault() {
+static GCOVOptions getDefaultOptions(const InstrumentationOptions &Opts) {
   GCOVOptions Options;
   Options.EmitNotes = true;
   Options.EmitData = true;
   Options.NoRedZone = false;
-  const InstrumentationOptions &Opts = InstrumentationOptions::Global;
   Options.Atomic = Opts.gcov_atomic_counter;
 
   if (Opts.default_gcov_version.size() != 4) {
@@ -87,8 +86,6 @@ class GCOVFunction;
 
 class GCOVProfiler {
 public:
-  GCOVProfiler()
-      : GCOVProfiler(GCOVOptions::getDefault(), *vfs::getRealFileSystem()) {}
   GCOVProfiler(const GCOVOptions &Opts, vfs::FileSystem &VFS)
       : Options(Opts), VFS(VFS) {}
   bool
@@ -554,7 +551,9 @@ bool GCOVProfiler::runOnModule(
 PreservedAnalyses GCOVProfilerPass::run(Module &M,
                                         ModuleAnalysisManager &AM) {
 
-  GCOVProfiler Profiler(GCOVOpts, *VFS);
+  const InstrumentationOptions &Opts =
+      M.getContext().getLibraryOptions().get<InstrumentationOptions>();
+  GCOVProfiler Profiler(GCOVOpts ? *GCOVOpts : getDefaultOptions(Opts), *VFS);
   FunctionAnalysisManager &FAM =
       AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
 
diff --git a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
index ea31e08a4661a0..0097f333c2ef63 100644
--- a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
@@ -351,7 +351,8 @@ PreservedAnalyses HWAddressSanitizerPass::run(Module &M,
     return PreservedAnalyses::all();
   const StackSafetyGlobalInfo *SSI = nullptr;
   const Triple &TargetTriple = M.getTargetTriple();
-  const InstrumentationOptions &Opts = InstrumentationOptions::Global;
+  const InstrumentationOptions &Opts =
+      M.getContext().getLibraryOptions().get<InstrumentationOptions>();
   if (shouldUseStackSafetyAnalysis(Opts, TargetTriple,
                                    Options.DisableOptimization))
     SSI = &MAM.getResult<StackSafetyGlobalAnalysis>(M);
diff --git a/llvm/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp b/llvm/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp
index 365bac5a0a7f26..8a547b8647c929 100644
--- a/llvm/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp
+++ b/llvm/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp
@@ -1017,7 +1017,8 @@ PreservedAnalyses PGOIndirectCallPromotion::run(Module &M,
                                                 ModuleAnalysisManager &MAM) {
   ProfileSummaryInfo *PSI = &MAM.getResult<ProfileSummaryAnalysis>(M);
 
-  const InstrumentationOptions &Opts = InstrumentationOptions::Global;
+  const InstrumentationOptions &Opts =
+      M.getContext().getLibraryOptions().get<InstrumentationOptions>();
   if (!promoteIndirectCalls(Opts, M, PSI, InLTO | Opts.icp_lto,
                             SamplePGO | Opts.icp_samplepgo, MAM))
     return PreservedAnalyses::all();
diff --git a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
index 6a7bda565ef212..828e8e987662f1 100644
--- a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
+++ b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp
@@ -76,8 +76,10 @@ namespace llvm {
 extern cl::opt<bool> EnableVTableValueProfiling;
 } // namespace llvm
 
-bool llvm::isProfileCorrelationEnabled() {
-  return InstrumentationOptions::Global.profile_correlate.has_value();
+bool llvm::isProfileCorrelationEnabled(
+    const cl::LibraryOptionsContext &LibraryOptions) {
+  return LibraryOptions.get<InstrumentationOptions>()
+      .profile_correlate.has_value();
 }
 
 namespace {
@@ -639,8 +641,9 @@ PreservedAnalyses InstrProfilingLoweringPass::run(Module &M,
   auto GetTLI = [&FAM](Function &F) -> TargetLibraryInfo & {
     return FAM.getResult<TargetLibraryAnalysis>(F);
   };
-  InstrLowerer Lowerer(InstrumentationOptions::Global, M, Options, GetTLI,
-                       IsCS);
+  const InstrumentationOptions &Opts =
+      M.getContext().getLibraryOptions().get<InstrumentationOptions>();
+  InstrLowerer Lowerer(Opts, M, Options, GetTLI, IsCS);
   if (!Lowerer.lower())
     return PreservedAnalyses::all();
 
@@ -2441,8 +2444,9 @@ void createProfileSamplingVar(Module &M) {
   const StringRef VarName(INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_SAMPLING_VAR));
   IntegerType *SamplingVarTy;
   Constant *ValueZero;
-  if (getSampledInstrumentationConfig(InstrumentationOptions::Global)
-          .UseShort) {
+  const InstrumentationOptions &Opts =
+      M.getContext().getLibraryOptions().get<InstrumentationOptions>();
+  if (getSampledInstrumentationConfig(Opts).UseShort) {
     SamplingVarTy = Type::getInt16Ty(M.getContext());
     ValueZero = Constant::getIntegerValue(SamplingVarTy, APInt(16, 0));
   } else {
diff --git a/llvm/lib/Transforms/Instrumentation/InstrumentationOptions.td b/llvm/lib/Transforms/Instrumentation/InstrumentationOptions.td
index a430c79f325758..44a2c46ed3ec43 100644
--- a/llvm/lib/Transforms/Instrumentation/InstrumentationOptions.td
+++ b/llvm/lib/Transforms/Instrumentation/InstrumentationOptions.td
@@ -8,7 +8,7 @@
 
 include "llvm/Option/LibraryOptions.td"
 
-def InstrumentationOptions : OptionsStruct<perContext = false>;
+def InstrumentationOptions : OptionsStruct;
 
 // AddressSanitizer.cpp
 defm : BoolField<"asan-always-slow-path", "false",
diff --git a/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp b/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp
index d1b6451c3376df..fd969cf4968131 100644
--- a/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp
+++ b/llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp
@@ -67,7 +67,8 @@ static void emitRemark(IntrinsicInst *II, OptimizationRemarkEmitter &ORE,
 
 static bool lowerAllowChecks(Function &F, FunctionAnalysisManager &AM,
                              const LowerAllowCheckPass::Options &Opts) {
-  const InstrumentationOptions &CLOpts = InstrumentationOptions::Global;
+  const InstrumentationOptions &CLOpts =
+      F.getContext().getLibraryOptions().get<InstrumentationOptions>();
   // Lazy analysis getters.
   auto GetBFI = [&AM, &F, BFI = (BlockFrequencyInfo *)nullptr]() mutable
       -> const BlockFrequencyInfo & {
@@ -194,8 +195,10 @@ PreservedAnalyses LowerAllowCheckPass::run(Function &F,
              : PreservedAnalyses::all();
 }
 
-bool LowerAllowCheckPass::IsRequested() {
-  const InstrumentationOptions &CLOpts = InstrumentationOptions::Global;
+bool LowerAllowCheckPass::isRequested(
+    const cl::LibraryOptionsContext &LibraryOptions) {
+  const InstrumentationOptions &CLOpts =
+      LibraryOptions.get<InstrumentationOptions>();
   return CLOpts.lower_allow_check_random_rate ||
          CLOpts.lower_allow_check_percentile_cutoff_hot;
 }
diff --git a/llvm/lib/Transforms/Instrumentation/MemProfInstrumentation.cpp b/llvm/lib/Transforms/Instrumentation/MemProfInstrumentation.cpp
index 96e3a97bbe1ac2..cfd8f8cc93adab 100644
--- a/llvm/lib/Transforms/Instrumentation/MemProfInstrumentation.cpp
+++ b/llvm/lib/Transforms/Instrumentation/MemProfInstrumentation.cpp
@@ -172,7 +172,8 @@ MemProfilerPass::MemProfilerPass() = default;
 
 PreservedAnalyses MemProfilerPass::run(Function &F,
                                        AnalysisManager<Function> &AM) {
-  const InstrumentationOptions &Opts = InstrumentationOptions::Global;
+  const InstrumentationOptions &Opts =
+      F.getContext().getLibraryOptions().get<InstrumentationOptions>();
   assert((!Opts.memprof_histogram ||
           Opts.memprof_mapping_granularity == DefaultMemGranularity) &&
          "Memprof with histogram only supports default mapping granularity");
@@ -188,7 +189,9 @@ ModuleMemProfilerPass::ModuleMemProfilerPass() = default;
 PreservedAnalyses ModuleMemProfilerPass::run(Module &M,
                                              AnalysisManager<Module> &AM) {
 
-  ModuleMemProfiler Profiler(InstrumentationOptions::Global, M);
+  const InstrumentationOptions &Opts =
+      M.getContext().getLibraryOptions().get<InstrumentationOptions>();
+  ModuleMemProfiler Profiler(Opts, M);
   if (Profiler.instrumentModule(M))
     return PreservedAnalyses::none();
   return PreservedAnalyses::all();
diff --git a/llvm/lib/Transforms/Instrumentation/MemProfUse.cpp b/llvm/lib/Transforms/Instrumentation/MemProfUse.cpp
index bbab620269eba1..382222904bb367 100644
--- a/llvm/lib/Transforms/Instrumentation/MemProfUse.cpp
+++ b/llvm/lib/Transforms/Instrumentation/MemProfUse.cpp
@@ -242,6 +242,8 @@ struct AllocMatchInfo {
 DenseMap<uint64_t, SmallVector<CallEdgeTy, 0>>
 memprof::extractCallsFromIR(Module &M, const TargetLibraryInfo &TLI,
                             function_ref<bool(uint64_t)> IsPresentInProfile) {
+  const InstrumentationOptions &Opts =
+      M.getContext().getLibraryOptions().get<InstrumentationOptions>();
   DenseMap<uint64_t, SmallVector<CallEdgeTy, 0>> Calls;
 
   for (Function &F : M) {
@@ -262,8 +264,8 @@ memprof::extractCallsFromIR(Module &M, const TargetLibraryInfo &TLI,
         StringRef CalleeName = CalledFunction->getName();
         // True if we are calling a heap allocation function that supports
         // hot/cold variants.
-        bool IsAlloc = isAllocationWithHotColdVariant(
-            InstrumentationOptions::Global, CalledFunction, TLI);
+        bool IsAlloc =
+            isAllocationWithHotColdVariant(Opts, CalledFunction, TLI);
         // True for the first iteration below, indicating that we are looking at
         // a leaf node.
         bool IsLeaf = true;
@@ -836,7 +838,8 @@ MemProfUsePass::MemProfUsePass(std::string MemoryProfileFile,
 }
 
 PreservedAnalyses MemProfUsePass::run(Module &M, ModuleAnalysisManager &AM) {
-  const InstrumentationOptions &Opts = InstrumentationOptions::Global;
+  const InstrumentationOptions &Opts =
+      M.getContext().getLibraryOptions().get<InstrumentationOptions>();
   // Return immediately if the module doesn't contain any function or global
   // variables.
   if (M.empty() && M.globals().empty())
diff --git a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
index 2e31d692599cf1..a6d4086fb924e7 100644
--- a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
@@ -592,13 +592,33 @@ void insertModuleCtor(const InstrumentationOptions &Opts, Module &M) {
 
 } // end anonymous namespace
 
-MemorySanitizerOptions::MemorySanitizerOptions(int TO, bool R, bool K,
-                                               bool EC) {
-  const InstrumentationOptions &Opts = InstrumentationOptions::Global;
-  Kernel = valueOr(Opts.msan_kernel, K);
-  TrackOrigins = Opts.msan_track_origins.value_or(Kernel ? 2 : TO);
-  Recover = valueOr(Opts.msan_keep_going, Kernel || R);
-  EagerChecks = valueOr(Opts.msan_eager_checks, EC);
+MemorySanitizerOptions::MemorySanitizerOptions(int TO, bool R, bool K, bool EC)
+    : Kernel(K), TrackOrigins(TO), Recover(R), EagerChecks(EC) {}
+
+static MemorySanitizerOptions applyParams(MemorySanitizerOptions O) {
+  O.Kernel = O.KernelParam.value_or(O.Kernel);
+  O.TrackOrigins = O.TrackOriginsParam.value_or(O.TrackOrigins);
+  O.Recover = O.RecoverParam.value_or(O.Recover);
+  O.EagerChecks = O.EagerChecksParam.value_or(O.EagerChecks);
+  return O;
+}
+
+static MemorySanitizerOptions applyKernelDefaults(MemorySanitizerOptions O) {
+  if (O.Kernel) {
+    O.TrackOrigins = 2;
+    O.Recover = true;
+  }
+  return O;
+}
+
+static MemorySanitizerOptions resolveOptions(const InstrumentationOptions &Opts,
+                                             MemorySanitizerOptions O) {
+  O.Kernel = valueOr(Opts.msan_kernel, O.Kernel);
+  O = applyKernelDefaults(O);
+  O.TrackOrigins = Opts.msan_track_origins.value_or(O.TrackOrigins);
+  O.Recover = valueOr(Opts.msan_keep_going, O.Recover);
+  O.EagerChecks = valueOr(Opts.msan_eager_checks, O.EagerChecks);
+  return applyParams(O);
 }
 
 PreservedAnalyses MemorySanitizerPass::run(Module &M,
@@ -606,9 +626,11 @@ PreservedAnalyses MemorySanitizerPass::run(Module &M,
   // Return early if nosanitize_memory module flag is present for the module.
   if (checkIfAlreadyInstrumented(M, "nosanitize_memory"))
     return PreservedAnalyses::all();
-  const InstrumentationOptions &Opts = InstrumentationOptions::Global;
+  const InstrumentationOptions &Opts =
+      M.getContext().getLibraryOptions().get<InstrumentationOptions>();
+  MemorySanitizerOptions MSanOpts = resolveOptions(Opts, Options);
   bool Modified = false;
-  if (!Options.Kernel) {
+  if (!MSanOpts.Kernel) {
     insertModuleCtor(Opts, M);
     Modified = true;
   }
@@ -617,7 +639,7 @@ PreservedAnalyses MemorySanitizerPass::run(Module &M,
   for (Function &F : M) {
     if (F.empty())
       continue;
-    MemorySanitizer Msan(Opts, *F.getParent(), Options);
+    MemorySanitizer Msan(Opts, *F.getParent(), MSanOpts);
     Modified |=
         Msan.sanitizeFunction(F, FAM.getResult<TargetLibraryAnalysis>(F));
   }
@@ -638,13 +660,14 @@ void MemorySanitizerPass::printPipeline(
   static_cast<PassInfoMixin<MemorySanitizerPass> *>(this)->printPipeline(
       OS, MapClassName2PassName);
   OS << '<';
-  if (Options.Recover)
+  MemorySanitizerOptions O = applyParams(applyKernelDefaults(Options));
+  if (O.Recover)
     OS << "recover;";
-  if (Options.Kernel)
+  if (O.Kernel)
     OS << "kernel;";
-  if (Options.EagerChecks)
+  if (O.EagerChecks)
     OS << "eager-checks;";
-  OS << "track-origins=" << Options.TrackOrigins;
+  OS << "track-origins=" << O.TrackOrigins;
   OS << '>';
 }
 
diff --git a/llvm/lib/Transforms/Instrumentation/NumericalStabilitySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/NumericalStabilitySanitizer.cpp
index 61bdaf1f3e3d95..7af39681306e9d 100644
--- a/llvm/lib/Transforms/Instrumentation/NumericalStabilitySanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/NumericalStabilitySanitizer.cpp
@@ -569,7 +569,9 @@ NumericalStabilitySanitizerPass::run(Module &M, ModuleAnalysisManager &MAM) {
       // time. Hook them into the global ctors list in that case:
       [&](Function *Ctor, FunctionCallee) { appendToGlobalCtors(M, Ctor, 0); });
 
-  NumericalStabilitySanitizer Nsan(InstrumentationOptions::Global, M);
+  const InstrumentationOptions &Opts =
+      M.getContext().getLibraryOptions().get<InstrumentationOptions>();
+  NumericalStabilitySanitizer Nsan(Opts, M);
   auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
   for (Function &F : M)
     Nsan.sanitizeFunction(F, FAM.getResult<TargetLibraryAnalysis>(F));
diff --git a/llvm/lib/Transforms/Instrumentation/PGOCtxProfLowering.cpp b/llvm/lib/Transforms/Instrumentation/PGOCtxProfLowering.cpp
index bc75f34e3d8351..5a35c34bc3b29d 100644
--- a/llvm/lib/Transforms/Instrumentation/PGOCtxProfLowering.cpp
+++ b/llvm/lib/Transforms/Instrumentation/PGOCtxProfLowering.cpp
@@ -30,8 +30,10 @@ using namespace llvm;
 
 #define DEBUG_TYPE "ctx-instr-lower"
 
-bool PGOCtxProfLoweringPass::isCtxIRPGOInstrEnabled() {
-  return !InstrumentationOptions::Global.profile_context_root.empty();
+bool PGOCtxProfLoweringPass::isCtxIRPGOInstrEnabled(
+    const cl::LibraryOptionsContext *LibraryOptions) {
+  return !cl::LibraryOptionsContext::get<InstrumentationOptions>(LibraryOptions)
+              .profile_context_root.empty();
 }
 
 // the names of symbols we expect in compiler-rt. Using a namespace for
@@ -153,9 +155,11 @@ CtxInstrumentationLowerer::CtxInstrumentationLowerer(Module &M,
                                                       I32Ty, /*NumCallsites*/
                                                   });
 
+  const InstrumentationOptions &Opts =
+      M.getContext().getLibraryOptions().get<InstrumentationOptions>();
   // Define a global for each entrypoint. We'll reuse the entrypoint's name
   // as prefix. We assume the entrypoint names to be unique.
-  for (StringRef Fname : InstrumentationOptions::Global.profile_context_root) {
+  for (StringRef Fname : Opts.profile_context_root) {
     if (const auto *F = M.getFunction(Fname)) {
       if (F->isDeclaration())
         continue;
diff --git a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
index a3c0c1687ffdc6..2406dfa58b2d14 100644
--- a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
+++ b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
@@ -184,8 +184,10 @@ extern cl::opt<bool> EnableVTableValueProfiling;
 extern cl::opt<bool> EnableVTableProfileUse;
 } // namespace llvm
 
-bool llvm::isPGOInstrumentColdFunctionOnly() {
-  return InstrumentationOptions::Global.pgo_instrument_cold_function_only;
+bool llvm::isPGOInstrumentColdFunctionOnly(
+    const cl::LibraryOptionsContext *LibraryOptions) {
+  return cl::LibraryOptionsContext::get<InstrumentationOptions>(LibraryOptions)
+      .pgo_instrument_cold_function_only;
 }
 
 namespace {
@@ -1890,11 +1892,12 @@ static bool instrumentAllFunctions(
 PreservedAnalyses
 PGOInstrumentationGenCreateVar::run(Module &M, ModuleAnalysisManager &MAM) {
   createProfileFileNameVar(M, CSInstrName);
+  const InstrumentationOptions &Opts =
+      M.getContext().getLibraryOptions().get<InstrumentationOptions>();
   // The variable in a comdat may be discarded by LTO. Ensure the declaration
   // will be retained.
   appendToCompilerUsed(
-      M, createIRLevelProfileFlagVar(InstrumentationOptions::Global, M,
-                                     PGOInstrumentationType::CSFDO));
+      M, createIRLevelProfileFlagVar(Opts, M, PGOInstrumentationType::CSFDO));
   if (ProfileSampling)
     createProfileSamplingVar(M);
   PreservedAnalyses PA;
@@ -1919,9 +1922,10 @@ PreservedAnalyses PGOInstrumentationGen::run(Module &M,
     return &FAM.getResult<LoopAnalysis>(F);
   };
 
-  if (!instrumentAllFunctions(InstrumentationOptions::Global, M, LookupTLI,
-                              LookupBPI, LookupBFI, LookupLI,
-                              InstrumentationType))
+  const InstrumentationOptions &Opts =
+      M.getContext().getLibraryOptions().get<InstrumentationOptions>();
+  if (!instrumentAllFunctions(Opts, M, LookupTLI, LookupBPI, LookupBFI,
+                              LookupLI, InstrumentationType))
     return PreservedAnalyses::all();
 
   return PreservedAnalyses::none();
@@ -2255,11 +2259,6 @@ PGOInstrumentationUse::PGOInstrumentationUse(
     : ProfileFileName(std::move(Filename)),
       ProfileRemappingFileName(std::move(RemappingFilename)), IsCS(IsCS),
       FS(std::move(VFS)) {
-  const InstrumentationOptions &Opts = InstrumentationOptions::Global;
-  if (!Opts.pgo_test_profile_file.empty())
-    ProfileFileName = Opts.pgo_test_profile_file;
-  if (!Opts.pgo_test_profile_remapping_file.empty())
-    ProfileRemappingFileName = Opts.pgo_test_profile_remapping_file;
   if (!FS)
     FS = vfs::getRealFileSystem();
 }
@@ -2282,9 +2281,16 @@ PreservedAnalyses PGOInstrumentationUse::run(Module &M,
   };
 
   auto *PSI = &MAM.getResult<ProfileSummaryAnalysis>(M);
-  if (!annotateAllFunctions(InstrumentationOptions::Global, M, ProfileFileName,
-                            ProfileRemappingFileName, *FS, LookupTLI, LookupBPI,
-                            LookupBFI, LookupLI, PSI, IsCS))
+  const InstrumentationOptions &Opts =
+      M.getContext().getLibraryOptions().get<InstrumentationOptions>();
+  StringRef ProfileFile = ProfileFileName;
+  if (!Opts.pgo_test_profile_file.empty())
+    ProfileFile = Opts.pgo_test_profile_file;
+  StringRef RemappingFile = ProfileRemappingFileName;
+  if (!Opts.pgo_test_profile_remapping_file.empty())
+    RemappingFile = Opts.pgo_test_profile_remapping_file;
+  if (!annotateAllFunctions(Opts, M, ProfileFile, RemappingFile, *FS, LookupTLI,
+                            LookupBPI, LookupBFI, LookupLI, PSI, IsCS))
     return PreservedAnalyses::all();
 
   return PreservedAnalyses::none();
@@ -2312,7 +2318,9 @@ void llvm::setProfMetadata(Instruction *TI, ArrayRef<uint64_t> EdgeCounts,
 
   setBranchWeights(*TI, Weights, /*IsExpected=*/false);
 
-  if (InstrumentationOptions::Global.pgo_emit_branch_prob) {
+  const InstrumentationOptions &Opts =
+      TI->getContext().getLibraryOptions().get<InstrumentationOptions>();
+  if (Opts.pgo_emit_branch_prob) {
     std::string BrCondStr = getBranchCondString(TI);
     if (BrCondStr.empty())
       return;
@@ -2391,7 +2399,9 @@ template <> struct DOTGraphTraits<PGOUseFunc *> : DefaultDOTGraphTraits {
     else
       OS << "Unknown\\l";
 
-    if (!InstrumentationOptions::Global.pgo_instr_select)
+    const InstrumentationOptions &Opts =
+        Node->getContext().getLibraryOptions().get<InstrumentationOptions>();
+    if (!Opts.pgo_instr_select)
       return Result;
 
     for (const Instruction &I : *Node) {
diff --git a/llvm/lib/Transforms/Instrumentation/PGOMemOPSizeOpt.cpp b/llvm/lib/Transforms/Instrumentation/PGOMemOPSizeOpt.cpp
index 290aa53e51204d..d53541595818bf 100644
--- a/llvm/lib/Transforms/Instrumentation/PGOMemOPSizeOpt.cpp
+++ b/llvm/lib/Transforms/Instrumentation/PGOMemOPSizeOpt.cpp
@@ -422,8 +422,9 @@ PreservedAnalyses PGOMemOPSizeOpt::run(Function &F,
   auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
   auto *DT = FAM.getCachedResult<DominatorTreeAnalysis>(F);
   auto &TLI = FAM.getResult<TargetLibraryAnalysis>(F);
-  bool Changed =
-      pgoMemOPSizeOptImpl(InstrumentationOptions::Global, F, BFI, ORE, DT, TLI);
+  const InstrumentationOptions &Opts =
+      F.getContext().getLibraryOptions().get<InstrumentationOptions>();
+  bool Changed = pgoMemOPSizeOptImpl(Opts, F, BFI, ORE, DT, TLI);
   if (!Changed)
     return PreservedAnalyses::all();
   auto PA = PreservedAnalyses();
diff --git a/llvm/lib/Transforms/Instrumentation/SanitizerBinaryMetadata.cpp b/llvm/lib/Transforms/Instrumentation/SanitizerBinaryMetadata.cpp
index 3f788df6ea7bba..9cbb3264ad4a8c 100644
--- a/llvm/lib/Transforms/Instrumentation/SanitizerBinaryMetadata.cpp
+++ b/llvm/lib/Transforms/Instrumentation/SanitizerBinaryMetadata.cpp
@@ -481,8 +481,9 @@ SanitizerBinaryMetadataPass::run(Module &M, AnalysisManager<Module> &AM) {
       return PreservedAnalyses::all();
   }
 
-  SanitizerBinaryMetadata Pass(InstrumentationOptions::Global, M, Options,
-                               std::move(Ignorelist));
+  const InstrumentationOptions &CLOpts =
+      M.getContext().getLibraryOptions().get<InstrumentationOptions>();
+  SanitizerBinaryMetadata Pass(CLOpts, M, Options, std::move(Ignorelist));
   if (Pass.run())
     return PreservedAnalyses::none();
   return PreservedAnalyses::all();
diff --git a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
index f3436f5c9b0fe3..bace11901dcf0d 100644
--- a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
+++ b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp
@@ -265,7 +265,8 @@ PreservedAnalyses SanitizerCoveragePass::run(Module &M,
   auto PDTCallback = [&FAM](Function &F) -> const PostDominatorTree & {
     return FAM.getResult<PostDominatorTreeAnalysis>(F);
   };
-  const InstrumentationOptions &Opts = InstrumentationOptions::Global;
+  const InstrumentationOptions &Opts =
+      M.getContext().getLibraryOptions().get<InstrumentationOptions>();
   ModuleSanitizerCoverage ModuleSancov(Opts, M, DTCallback, PDTCallback,
                                        overrideFromCL(Opts, Options),
                                        Allowlist.get(), Blocklist.get());
diff --git a/llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp
index 216fb3b5eb9fe7..59e03878428e3d 100644
--- a/llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp
@@ -153,7 +153,8 @@ void insertModuleCtor(Module &M) {
 
 PreservedAnalyses ThreadSanitizerPass::run(Function &F,
                                            FunctionAnalysisManager &FAM) {
-  ThreadSanitizer TSan(InstrumentationOptions::Global);
+  ThreadSanitizer TSan(
+      F.getContext().getLibraryOptions().get<InstrumentationOptions>());
   if (TSan.sanitizeFunction(F, FAM.getResult<TargetLibraryAnalysis>(F)))
     return PreservedAnalyses::none();
   return PreservedAnalyses::all();
diff --git a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
index e2d9cc4450ff66..1ef88566dd260d 100644
--- a/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/TypeSanitizer.cpp
@@ -964,7 +964,8 @@ PreservedAnalyses TypeSanitizerPass::run(Module &M,
                                           kTysanInitName, /*InitArgTypes=*/{},
                                           /*InitArgs=*/{});
 
-  const InstrumentationOptions &Opts = InstrumentationOptions::Global;
+  const InstrumentationOptions &Opts =
+      M.getContext().getLibraryOptions().get<InstrumentationOptions>();
   TypeSanitizer TySan(Opts, M);
   TySan.instrumentGlobals(M);
   appendToGlobalCtors(M, TysanCtorFunction, 0);
diff --git a/llvm/lib/Transforms/Instrumentation/ValueProfilePlugins.inc b/llvm/lib/Transforms/Instrumentation/ValueProfilePlugins.inc
index 24fe43e67910ff..c052ee69912f34 100644
--- a/llvm/lib/Transforms/Instrumentation/ValueProfilePlugins.inc
+++ b/llvm/lib/Transforms/Instrumentation/ValueProfilePlugins.inc
@@ -24,6 +24,7 @@ using CandidateInfo = ValueProfileCollector::CandidateInfo;
 
 ///--------------------------- MemIntrinsicPlugin ------------------------------
 class MemIntrinsicPlugin : public InstVisitor<MemIntrinsicPlugin> {
+  const InstrumentationOptions &Opts;
   Function &F;
   TargetLibraryInfo &TLI;
   std::vector<CandidateInfo> *Candidates;
@@ -32,7 +33,8 @@ public:
   static constexpr InstrProfValueKind Kind = IPVK_MemOPSize;
 
   MemIntrinsicPlugin(Function &Fn, TargetLibraryInfo &TLI)
-      : F(Fn), TLI(TLI), Candidates(nullptr) {}
+      : Opts(Fn.getContext().getLibraryOptions().get<InstrumentationOptions>()),
+        F(Fn), TLI(TLI), Candidates(nullptr) {}
 
   void run(std::vector<CandidateInfo> &Cs) {
     Candidates = &Cs;
@@ -50,7 +52,7 @@ public:
     Candidates->emplace_back(CandidateInfo{Length, InsertPt, AnnotatedInst});
   }
   void visitCallInst(CallInst &CI) {
-    if (!InstrumentationOptions::Global.pgo_memop_optimize_memcmp_bcmp)
+    if (!Opts.pgo_memop_optimize_memcmp_bcmp)
       return;
     auto *F = CI.getCalledFunction();
     if (!F)
diff --git a/llvm/lib/Transforms/Scalar/ADCE.cpp b/llvm/lib/Transforms/Scalar/ADCE.cpp
index 2e71d080687826..ca55c0cdb8576f 100644
--- a/llvm/lib/Transforms/Scalar/ADCE.cpp
+++ b/llvm/lib/Transforms/Scalar/ADCE.cpp
@@ -163,9 +163,9 @@ class AggressiveDeadCodeElimination {
   void makeUnconditional(BasicBlock *BB, BasicBlock *Target);
 
 public:
-  AggressiveDeadCodeElimination(Function &F, DominatorTree *DT,
-                                PostDominatorTree &PDT)
-      : Opts(ScalarOptions::Global), F(F), DT(DT), PDT(PDT) {}
+  AggressiveDeadCodeElimination(const ScalarOptions &Opts, Function &F,
+                                DominatorTree *DT, PostDominatorTree &PDT)
+      : Opts(Opts), F(F), DT(DT), PDT(PDT) {}
 
   ADCEChanged performDeadCodeElimination();
 };
@@ -588,8 +588,10 @@ PreservedAnalyses ADCEPass::run(Function &F, FunctionAnalysisManager &FAM) {
   // to update analysis if it is already available.
   auto *DT = FAM.getCachedResult<DominatorTreeAnalysis>(F);
   auto &PDT = FAM.getResult<PostDominatorTreeAnalysis>(F);
-  ADCEChanged Changed =
-      AggressiveDeadCodeElimination(F, DT, PDT).performDeadCodeElimination();
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
+  ADCEChanged Changed = AggressiveDeadCodeElimination(Opts, F, DT, PDT)
+                            .performDeadCodeElimination();
   if (!Changed.ChangedAnything)
     return PreservedAnalyses::all();
 
diff --git a/llvm/lib/Transforms/Scalar/CallSiteSplitting.cpp b/llvm/lib/Transforms/Scalar/CallSiteSplitting.cpp
index d7c201c5753b35..ab4d0a079cab33 100644
--- a/llvm/lib/Transforms/Scalar/CallSiteSplitting.cpp
+++ b/llvm/lib/Transforms/Scalar/CallSiteSplitting.cpp
@@ -172,7 +172,8 @@ static SmallVector<BasicBlock *, 2> getTwoPredecessors(BasicBlock *BB) {
   return Preds;
 }
 
-static bool canSplitCallSite(CallBase &CB, TargetTransformInfo &TTI) {
+static bool canSplitCallSite(const ScalarOptions &Opts, CallBase &CB,
+                             TargetTransformInfo &TTI) {
   if (CB.isConvergent() || CB.cannotDuplicate())
     return false;
 
@@ -202,7 +203,7 @@ static bool canSplitCallSite(CallBase &CB, TargetTransformInfo &TTI) {
        llvm::make_range(CallSiteBB->begin(), CB.getIterator())) {
     Cost += TTI.getInstructionCost(&InstBeforeCall,
                                    TargetTransformInfo::TCK_CodeSize);
-    if (Cost >= ScalarOptions::Global.callsite_splitting_duplication_threshold)
+    if (Cost >= Opts.callsite_splitting_duplication_threshold)
       return false;
   }
 
@@ -475,10 +476,10 @@ static PredsWithCondsTy shouldSplitOnPredicatedArgument(CallBase &CB,
   return PredsCS;
 }
 
-static bool tryToSplitCallSite(CallBase &CB, TargetTransformInfo &TTI,
-                               DomTreeUpdater &DTU) {
+static bool tryToSplitCallSite(const ScalarOptions &Opts, CallBase &CB,
+                               TargetTransformInfo &TTI, DomTreeUpdater &DTU) {
   // Check if we can split the call site.
-  if (!CB.arg_size() || !canSplitCallSite(CB, TTI))
+  if (!CB.arg_size() || !canSplitCallSite(Opts, CB, TTI))
     return false;
 
   auto PredsWithConds = shouldSplitOnPredicatedArgument(CB, DTU);
@@ -494,6 +495,8 @@ static bool tryToSplitCallSite(CallBase &CB, TargetTransformInfo &TTI,
 static bool doCallSiteSplitting(Function &F, TargetLibraryInfo &TLI,
                                 TargetTransformInfo &TTI, DominatorTree &DT) {
 
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
   DomTreeUpdater DTU(&DT, DomTreeUpdater::UpdateStrategy::Lazy);
   bool Changed = false;
   for (BasicBlock &BB : llvm::make_early_inc_range(F)) {
@@ -516,7 +519,7 @@ static bool doCallSiteSplitting(Function &F, TargetLibraryInfo &TLI,
       // Check if such path is possible before attempting the splitting.
       bool IsMustTail = CB->isMustTailCall();
 
-      Changed |= tryToSplitCallSite(*CB, TTI, DTU);
+      Changed |= tryToSplitCallSite(Opts, *CB, TTI, DTU);
 
       // There're no interesting instructions after this. The call site
       // itself might have been erased on splitting.
diff --git a/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp b/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp
index 03a79ac734f719..723a301215937a 100644
--- a/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp
@@ -92,8 +92,7 @@ class ConstantHoistingLegacyPass : public FunctionPass {
 
   void getAnalysisUsage(AnalysisUsage &AU) const override {
     AU.setPreservesCFG();
-    if (ScalarOptions::Global.consthoist_with_block_frequency)
-      AU.addRequired<BlockFrequencyInfoWrapperPass>();
+    AU.addRequired<BlockFrequencyInfoWrapperPass>();
     AU.addRequired<DominatorTreeWrapperPass>();
     AU.addRequired<ProfileSummaryInfoWrapperPass>();
     AU.addRequired<TargetTransformInfoWrapperPass>();
@@ -128,10 +127,12 @@ bool ConstantHoistingLegacyPass::runOnFunction(Function &Fn) {
   LLVM_DEBUG(dbgs() << "********** Begin Constant Hoisting **********\n");
   LLVM_DEBUG(dbgs() << "********** Function: " << Fn.getName() << '\n');
 
+  const ScalarOptions &Opts =
+      Fn.getContext().getLibraryOptions().get<ScalarOptions>();
   bool MadeChange =
       Impl.runImpl(Fn, getAnalysis<TargetTransformInfoWrapperPass>().getTTI(Fn),
                    getAnalysis<DominatorTreeWrapperPass>().getDomTree(),
-                   ScalarOptions::Global.consthoist_with_block_frequency
+                   Opts.consthoist_with_block_frequency
                        ? &getAnalysis<BlockFrequencyInfoWrapperPass>().getBFI()
                        : nullptr,
                    Fn.getEntryBlock(),
@@ -463,7 +464,7 @@ void ConstantHoistingPass::collectConstantCandidates(
   // Visit constant expressions that have constant integers.
   if (auto ConstExpr = dyn_cast<ConstantExpr>(Opnd)) {
     // Handle constant gep expressions.
-    if (ScalarOptions::Global.consthoist_gep && isa<GEPOperator>(ConstExpr))
+    if (Opts->consthoist_gep && isa<GEPOperator>(ConstExpr))
       collectConstantCandidates(ConstCandMap, Inst, Idx, ConstExpr);
 
     // Only visit constant cast expressions.
@@ -846,8 +847,7 @@ bool ConstantHoistingPass::emitBaseConstants(GlobalVariable *BaseGV) {
 
       // If only few constants depend on this IP of base, skip rebasing,
       // assuming the base and the rebased have the same materialization cost.
-      if (ToBeRebased.size() <
-          ScalarOptions::Global.consthoist_min_num_to_rebase) {
+      if (ToBeRebased.size() < Opts->consthoist_min_num_to_rebase) {
         NotRebasedNum += ToBeRebased.size();
         continue;
       }
@@ -912,6 +912,7 @@ void ConstantHoistingPass::deleteDeadCastInst() const {
 bool ConstantHoistingPass::runImpl(Function &Fn, TargetTransformInfo &TTI,
                                    DominatorTree &DT, BlockFrequencyInfo *BFI,
                                    BasicBlock &Entry, ProfileSummaryInfo *PSI) {
+  this->Opts = &Fn.getContext().getLibraryOptions().get<ScalarOptions>();
   this->TTI = &TTI;
   this->DT = &DT;
   this->BFI = BFI;
@@ -955,7 +956,9 @@ PreservedAnalyses ConstantHoistingPass::run(Function &F,
                                             FunctionAnalysisManager &AM) {
   auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
   auto &TTI = AM.getResult<TargetIRAnalysis>(F);
-  auto BFI = ScalarOptions::Global.consthoist_with_block_frequency
+  const ScalarOptions &CLOpts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
+  auto BFI = CLOpts.consthoist_with_block_frequency
                  ? &AM.getResult<BlockFrequencyAnalysis>(F)
                  : nullptr;
   auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 51c118e995096f..be051f7a404643 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -2393,7 +2393,8 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
                                  ScalarEvolution *SE,
                                  OptimizationRemarkEmitter &ORE,
                                  TargetLibraryInfo &TLI) {
-  const ScalarOptions &Opts = ScalarOptions::Global;
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
   bool Changed = false;
   DT.updateDFSNumbers();
   SmallVector<Value *> FunctionArgs(llvm::make_pointer_range(F.args()));
diff --git a/llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp b/llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp
index ac8dfc8f3867ca..cc2f92520223d5 100644
--- a/llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp
@@ -108,10 +108,10 @@ class SelectInstToUnfold {
 
 class DFAJumpThreading {
 public:
-  DFAJumpThreading(AssumptionCache *AC, DomTreeUpdater *DTU, LoopInfo *LI,
-                   TargetTransformInfo *TTI, OptimizationRemarkEmitter *ORE)
-      : Opts(ScalarOptions::Global), AC(AC), DTU(DTU), LI(LI), TTI(TTI),
-        ORE(ORE) {}
+  DFAJumpThreading(const ScalarOptions &Opts, AssumptionCache *AC,
+                   DomTreeUpdater *DTU, LoopInfo *LI, TargetTransformInfo *TTI,
+                   OptimizationRemarkEmitter *ORE)
+      : Opts(Opts), AC(AC), DTU(DTU), LI(LI), TTI(TTI), ORE(ORE) {}
 
   bool run(Function &F);
   bool LoopInfoBroken;
@@ -1530,7 +1530,9 @@ PreservedAnalyses DFAJumpThreadingPass::run(Function &F,
   OptimizationRemarkEmitter ORE(&F);
 
   DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
-  DFAJumpThreading ThreadImpl(&AC, &DTU, &LI, &TTI, &ORE);
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
+  DFAJumpThreading ThreadImpl(Opts, &AC, &DTU, &LI, &TTI, &ORE);
   if (!ThreadImpl.run(F))
     return PreservedAnalyses::all();
 
diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
index 1266fd0708bfe4..4e74bb5a5f9c01 100644
--- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
@@ -2719,7 +2719,8 @@ static bool eliminateDeadStores(Function &F, AliasAnalysis &AA, MemorySSA &MSSA,
                                 DominatorTree &DT, PostDominatorTree &PDT,
                                 const TargetLibraryInfo &TLI,
                                 const CycleInfo &CI) {
-  const ScalarOptions &Opts = ScalarOptions::Global;
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
   bool MadeChange = false;
   DSEState State(Opts, F, AA, MSSA, DT, PDT, TLI, CI);
   // For each store:
diff --git a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
index ccd923cf7cc792..e085316cb4d439 100644
--- a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
+++ b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
@@ -269,13 +269,18 @@ static unsigned getHashValueImpl(SimpleValue Val) {
                       hash_combine_range(Inst->operand_values()));
 }
 
+#ifndef NDEBUG
+// -earlycse-debug-hash of the function being processed, bound once per run.
+static LLVM_THREAD_LOCAL bool DebugHash;
+#endif
+
 unsigned DenseMapInfo<SimpleValue>::getHashValue(SimpleValue Val) {
 #ifndef NDEBUG
   // If -earlycse-debug-hash was specified, return a constant -- this
   // will force all hashing to collide, so we'll exhaustively search
   // the table for a match, and the assertion in isEqual will fire if
   // there's a bug causing equal keys to hash differently.
-  if (ScalarOptions::Global.earlycse_debug_hash)
+  if (DebugHash)
     return 0;
 #endif
   return getHashValueImpl(Val);
@@ -499,6 +504,7 @@ namespace {
 /// expected that a later pass of GVN will catch the interesting/hard cases.
 class EarlyCSE {
 public:
+  const ScalarOptions &Opts;
   const TargetLibraryInfo &TLI;
   const TargetTransformInfo &TTI;
   DominatorTree &DT;
@@ -589,11 +595,11 @@ class EarlyCSE {
   unsigned CurrentGeneration = 0;
 
   /// Set up the EarlyCSE runner for a particular function.
-  EarlyCSE(const DataLayout &DL, const TargetLibraryInfo &TLI,
-           const TargetTransformInfo &TTI, DominatorTree &DT,
-           AssumptionCache &AC, MemorySSA *MSSA)
-      : TLI(TLI), TTI(TTI), DT(DT), AC(AC), SQ(DL, &TLI, &DT, &AC), MSSA(MSSA),
-        MSSAUpdater(std::make_unique<MemorySSAUpdater>(MSSA)) {}
+  EarlyCSE(const ScalarOptions &Opts, const DataLayout &DL,
+           const TargetLibraryInfo &TLI, const TargetTransformInfo &TTI,
+           DominatorTree &DT, AssumptionCache &AC, MemorySSA *MSSA)
+      : Opts(Opts), TLI(TLI), TTI(TTI), DT(DT), AC(AC), SQ(DL, &TLI, &DT, &AC),
+        MSSA(MSSA), MSSAUpdater(std::make_unique<MemorySSAUpdater>(MSSA)) {}
 
   bool run();
 
@@ -1019,7 +1025,7 @@ bool EarlyCSE::isSameMemGeneration(unsigned EarlierGeneration,
   // EarlierInst and LaterInst and neither can any other write that potentially
   // clobbers LaterInst.
   MemoryAccess *LaterDef;
-  if (ClobberCounter < ScalarOptions::Global.earlycse_mssa_optimization_cap) {
+  if (ClobberCounter < Opts.earlycse_mssa_optimization_cap) {
     LaterDef = MSSA->getWalker()->getClobberingMemoryAccess(LaterInst);
     ClobberCounter++;
   } else
@@ -1682,6 +1688,9 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
 }
 
 bool EarlyCSE::run() {
+#ifndef NDEBUG
+  DebugHash = Opts.earlycse_debug_hash;
+#endif
   // Note, deque is being used here because there is significant performance
   // gains over vector when the container becomes very large due to the
   // specific access patterns. For more information see the mailing list
@@ -1741,7 +1750,8 @@ PreservedAnalyses EarlyCSEPass::run(Function &F,
   auto *MSSA =
       UseMemorySSA ? &AM.getResult<MemorySSAAnalysis>(F).getMSSA() : nullptr;
 
-  EarlyCSE CSE(F.getDataLayout(), TLI, TTI, DT, AC, MSSA);
+  EarlyCSE CSE(F.getContext().getLibraryOptions().get<ScalarOptions>(),
+               F.getDataLayout(), TLI, TTI, DT, AC, MSSA);
 
   if (!CSE.run())
     return PreservedAnalyses::all();
@@ -1795,7 +1805,8 @@ class EarlyCSELegacyCommonPass : public FunctionPass {
     auto *MSSA =
         UseMemorySSA ? &getAnalysis<MemorySSAWrapperPass>().getMSSA() : nullptr;
 
-    EarlyCSE CSE(F.getDataLayout(), TLI, TTI, DT, AC, MSSA);
+    EarlyCSE CSE(F.getContext().getLibraryOptions().get<ScalarOptions>(),
+                 F.getDataLayout(), TLI, TTI, DT, AC, MSSA);
 
     return CSE.run();
   }
diff --git a/llvm/lib/Transforms/Scalar/ExpandMemCmp.cpp b/llvm/lib/Transforms/Scalar/ExpandMemCmp.cpp
index a22a2e5e62f089..bd111ebc09c847 100644
--- a/llvm/lib/Transforms/Scalar/ExpandMemCmp.cpp
+++ b/llvm/lib/Transforms/Scalar/ExpandMemCmp.cpp
@@ -961,11 +961,10 @@ Value *MemCmpExpansion::getMemCmpExpansion() {
 /// %loadbb3
 ///  %phi.res = phi i32 [ %48, %loadbb3 ], [ %11, %res_block ]
 ///  ret i32 %phi.res
-static bool expandMemCmp(CallInst *CI, const TargetTransformInfo *TTI,
-                         const DataLayout *DL, ProfileSummaryInfo *PSI,
-                         BlockFrequencyInfo *BFI, DomTreeUpdater *DTU,
-                         const bool IsBCmp) {
-  const ScalarOptions &Opts = ScalarOptions::Global;
+static bool expandMemCmp(const ScalarOptions &Opts, CallInst *CI,
+                         const TargetTransformInfo *TTI, const DataLayout *DL,
+                         ProfileSummaryInfo *PSI, BlockFrequencyInfo *BFI,
+                         DomTreeUpdater *DTU, const bool IsBCmp) {
   NumMemCmpCalls++;
 
   // Early exit from expansion if -Oz.
@@ -1064,9 +1063,11 @@ static PreservedAnalyses runImpl(Function &F, const TargetLibraryInfo *TLI,
     }
   }
 
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
   bool MadeChanges = false;
   for (const auto &[CI, Func] : MemCmpCalls) {
-    if (expandMemCmp(CI, TTI, &DL, PSI, BFI, DTU ? &*DTU : nullptr,
+    if (expandMemCmp(Opts, CI, TTI, &DL, PSI, BFI, DTU ? &*DTU : nullptr,
                      Func == LibFunc_bcmp))
       MadeChanges = true;
   }
diff --git a/llvm/lib/Transforms/Scalar/Float2Int.cpp b/llvm/lib/Transforms/Scalar/Float2Int.cpp
index b8509db5934c62..acb828c0030a7d 100644
--- a/llvm/lib/Transforms/Scalar/Float2Int.cpp
+++ b/llvm/lib/Transforms/Scalar/Float2Int.cpp
@@ -484,8 +484,9 @@ bool Float2IntPass::runImpl(Function &F, const DominatorTree &DT) {
   ConvertedInsts.clear();
   Roots.clear();
 
-  MaxIntegerBW = ScalarOptions::Global.float2int_max_integer_bw;
   Ctx = &F.getParent()->getContext();
+  MaxIntegerBW =
+      Ctx->getLibraryOptions().get<ScalarOptions>().float2int_max_integer_bw;
 
   findRoots(F, DT);
 
diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index 113b3abf484cde..4b63a50713baa8 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -240,15 +240,14 @@ class GVNLegacyPass;
 /// FIXME: We should have a good summary of the GVN algorithm implemented by
 /// this particular pass here.
 class llvm::GVNPassImpl {
-  const ScalarOptions &Opts;
+  const ScalarOptions *Opts = nullptr;
   llvm::GVNOptions Options;
 
 public:
   struct AvailableValue;
   struct AvailableValueInBlock;
 
-  GVNPassImpl(llvm::GVNOptions Options = {})
-      : Opts(ScalarOptions::Global), Options(Options) {}
+  GVNPassImpl(llvm::GVNOptions Options = {}) : Options(Options) {}
 
   /// This removes the specified instruction from
   /// our various maps and marks it for deletion.
@@ -1127,20 +1126,20 @@ void GVNLeaderMap::erase(uint32_t N, Instruction *I, const BasicBlock *BB) {
 //===----------------------------------------------------------------------===//
 
 bool GVNPassImpl::isScalarPREEnabled() const {
-  return Options.AllowScalarPRE.value_or(Opts.enable_scalar_pre);
+  return Options.AllowScalarPRE.value_or(Opts->enable_scalar_pre);
 }
 
 bool GVNPassImpl::isLoadPREEnabled() const {
-  return Options.AllowLoadPRE.value_or(Opts.enable_load_pre);
+  return Options.AllowLoadPRE.value_or(Opts->enable_load_pre);
 }
 
 bool GVNPassImpl::isLoadInLoopPREEnabled() const {
-  return Options.AllowLoadInLoopPRE.value_or(Opts.enable_load_in_loop_pre);
+  return Options.AllowLoadInLoopPRE.value_or(Opts->enable_load_in_loop_pre);
 }
 
 bool GVNPassImpl::isLoadPRESplitBackedgeEnabled() const {
   return Options.AllowLoadPRESplitBackedge.value_or(
-      Opts.enable_split_backedge_in_load_pre);
+      Opts->enable_split_backedge_in_load_pre);
 }
 
 bool GVNPassImpl::isMemDepEnabled() const {
@@ -1149,11 +1148,11 @@ bool GVNPassImpl::isMemDepEnabled() const {
   // overrides default independently, so honor MemorySSA winning here too.
   if (isMemorySSAEnabled())
     return Options.AllowMemDep.value_or(false);
-  return Options.AllowMemDep.value_or(valueOr(Opts.enable_gvn_memdep, true));
+  return Options.AllowMemDep.value_or(valueOr(Opts->enable_gvn_memdep, true));
 }
 
 bool GVNPassImpl::isMemorySSAEnabled() const {
-  return Options.AllowMemorySSA.value_or(Opts.enable_gvn_memoryssa);
+  return Options.AllowMemorySSA.value_or(Opts->enable_gvn_memoryssa);
 }
 
 GVNPass::GVNPass(GVNOptions Options)
@@ -1170,6 +1169,7 @@ PreservedAnalyses GVNPass::run(Function &F, FunctionAnalysisManager &AM) {
   // significant! Re-ordering these variables will cause GVN when run alone to
   // be less effective! We should fix memdep and basic-aa to not exhibit this
   // behavior, but until then don't change the order here.
+  Impl->Opts = &F.getContext().getLibraryOptions().get<ScalarOptions>();
   auto &AC = AM.getResult<AssumptionAnalysis>(F);
   auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
   auto &TLI = AM.getResult<TargetLibraryAnalysis>(F);
@@ -1627,11 +1627,11 @@ GVNPassImpl::analyzeSelectAvailability(LoadInst *Load, SelectInst *Sel,
   // loaded values only if both sides have a dominating, non-clobbered value of
   // the right type in the extended basic block ending at From.
   auto Loc = MemoryLocation::get(Load);
-  Value *V1 = findDominatingValue(Opts, Loc.getWithNewPtr(TrueAddr),
+  Value *V1 = findDominatingValue(*Opts, Loc.getWithNewPtr(TrueAddr),
                                   Load->getType(), From, getAliasAnalysis());
   if (!V1)
     return std::nullopt;
-  Value *V2 = findDominatingValue(Opts, Loc.getWithNewPtr(FalseAddr),
+  Value *V2 = findDominatingValue(*Opts, Loc.getWithNewPtr(FalseAddr),
                                   Load->getType(), From, getAliasAnalysis());
   if (!V2)
     return std::nullopt;
@@ -1869,7 +1869,7 @@ LoadInst *GVNPassImpl::findLoadToHoistIntoPred(BasicBlock *Pred,
   if (!SuccBB->getSinglePredecessor())
     return nullptr;
 
-  unsigned int NumInsts = Opts.gvn_max_num_insns;
+  unsigned int NumInsts = Opts->gvn_max_num_insns;
   for (Instruction &Inst : *SuccBB) {
     if (isa<PseudoProbeInst>(Inst))
       continue;
@@ -2080,7 +2080,7 @@ bool GVNPassImpl::performLoadPRE(LoadInst *Load,
       return false;
     }
 
-    if (isValueFullyAvailableInBlock(Opts, Pred, FullyAvailableBlocks)) {
+    if (isValueFullyAvailableInBlock(*Opts, Pred, FullyAvailableBlocks)) {
       continue;
     }
 
@@ -2361,7 +2361,7 @@ bool GVNPassImpl::processNonLocalLoad(LoadInst *Load) {
   // dependencies, this load isn't worth worrying about.  Optimizing
   // it will be too expensive.
   unsigned NumDeps = Deps.size();
-  if (NumDeps > Opts.gvn_max_num_deps)
+  if (NumDeps > Opts->gvn_max_num_deps)
     return false;
 
   SmallVector<ReachingMemVal, 64> MemVals;
@@ -2653,7 +2653,7 @@ std::optional<GVNPassImpl::ReachingMemVal> GVNPassImpl::scanMemoryAccessesUsers(
   for (MemoryAccess *MA : ClobbersList) {
     unsigned Scanned = 0;
     for (User *U : MA->users()) {
-      if (++Scanned >= Opts.gvn_scan_users_limit)
+      if (++Scanned >= Opts->gvn_scan_users_limit)
         return ReachingMemVal::getUnknown(BB, Loc.Ptr);
 
       auto *UseOrDef = dyn_cast<MemoryUseOrDef>(U);
@@ -2745,7 +2745,7 @@ std::optional<GVNPassImpl::ReachingMemVal> GVNPassImpl::accessMayModifyLocation(
     // the latter unchanged.
     if (auto *SI = dyn_cast<StoreInst>(ClobberI))
       if (isStorePreservingMemoryLocation(SI, Loc, LoadAlign, AA,
-                                          Opts.gvn_max_num_insns))
+                                          Opts->gvn_max_num_insns))
         return std::nullopt;
 
     if (AR == AliasResult::MayAlias ||
@@ -2979,7 +2979,7 @@ bool GVNPassImpl::findReachingValuesForLoad(
   auto Worklist = InitialWorklist;
   while (!Worklist.empty()) {
     // Match MemDep's cutoff for expensive non-local queries.
-    if (Blocks.size() > Opts.gvn_max_num_reaching_blocks)
+    if (Blocks.size() > Opts->gvn_max_num_reaching_blocks)
       return false;
     auto *BB = Worklist.pop_back_val();
     DependencyBlockInfo &Info = Blocks.find(BB)->second;
@@ -3832,8 +3832,8 @@ bool GVNPassImpl::run(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT,
   // lets MemorySSA win for the common single-flag case, but an explicit
   // request for both via -enable-gvn-{memdep,memoryssa} is a contradiction we
   // reject rather than resolve arbitrarily.
-  if (Opts.enable_gvn_memdep == BoolOrDefault::True &&
-      Opts.enable_gvn_memoryssa)
+  if (Opts->enable_gvn_memdep == BoolOrDefault::True &&
+      Opts->enable_gvn_memoryssa)
     report_fatal_error("GVN: -enable-gvn-memdep and -enable-gvn-memoryssa are "
                        "mutually exclusive",
                        /*gen_crash_diag=*/false);
@@ -4377,15 +4377,8 @@ class GVNLegacyPass : public FunctionPass {
 public:
   static char ID; // Pass identification, replacement for typeid.
 
-  explicit GVNLegacyPass(
-      bool MemDepAnalysis = valueOr(ScalarOptions::Global.enable_gvn_memdep,
-                                    true),
-      bool MemSSAAnalysis = ScalarOptions::Global.enable_gvn_memoryssa,
-      bool ScalarPRE = true)
-      : FunctionPass(ID), Impl(GVNOptions()
-                                   .setMemDep(MemDepAnalysis)
-                                   .setMemorySSA(MemSSAAnalysis)
-                                   .setScalarPRE(ScalarPRE)) {
+  explicit GVNLegacyPass(bool ScalarPRE = true)
+      : FunctionPass(ID), Impl(GVNOptions().setScalarPRE(ScalarPRE)) {
     initializeGVNLegacyPassPass(*PassRegistry::getPassRegistry());
   }
 
@@ -4393,21 +4386,27 @@ class GVNLegacyPass : public FunctionPass {
     if (skipFunction(F))
       return false;
 
-    auto *MSSAWP = getAnalysisIfAvailable<MemorySSAWrapperPass>();
-    if (Impl.isMemorySSAEnabled() && !MSSAWP)
-      MSSAWP = &getAnalysis<MemorySSAWrapperPass>();
+    Impl.Opts = &F.getContext().getLibraryOptions().get<ScalarOptions>();
+    auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
+    auto &AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
+    MemorySSA *MSSA = nullptr;
+    std::unique_ptr<MemorySSA> LocalMSSA;
+    if (auto *MSSAWP = getAnalysisIfAvailable<MemorySSAWrapperPass>()) {
+      MSSA = &MSSAWP->getMSSA();
+    } else if (Impl.isMemorySSAEnabled()) {
+      // getAnalysisUsage cannot read the context's -enable-gvn-memoryssa.
+      LocalMSSA = std::make_unique<MemorySSA>(F, &AA, &DT);
+      MSSA = LocalMSSA.get();
+    }
 
     return Impl.run(
-        F, getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F),
-        getAnalysis<DominatorTreeWrapperPass>().getDomTree(),
-        getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F),
-        getAnalysis<AAResultsWrapperPass>().getAAResults(),
+        F, getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F), DT,
+        getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F), AA,
         Impl.isMemDepEnabled()
             ? &getAnalysis<MemoryDependenceWrapperPass>().getMemDep()
             : nullptr,
         getAnalysis<LoopInfoWrapperPass>().getLoopInfo(),
-        &getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE(),
-        MSSAWP ? &MSSAWP->getMSSA() : nullptr);
+        &getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE(), MSSA);
   }
 
   void getAnalysisUsage(AnalysisUsage &AU) const override {
@@ -4415,8 +4414,7 @@ class GVNLegacyPass : public FunctionPass {
     AU.addRequired<DominatorTreeWrapperPass>();
     AU.addRequired<TargetLibraryInfoWrapperPass>();
     AU.addRequired<LoopInfoWrapperPass>();
-    if (Impl.isMemDepEnabled())
-      AU.addRequired<MemoryDependenceWrapperPass>();
+    AU.addRequired<MemoryDependenceWrapperPass>();
     AU.addRequired<AAResultsWrapperPass>();
     AU.addPreserved<DominatorTreeWrapperPass>();
     AU.addPreserved<GlobalsAAWrapperPass>();
@@ -4424,8 +4422,6 @@ class GVNLegacyPass : public FunctionPass {
     AU.addPreserved<LoopInfoWrapperPass>();
     AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
     AU.addPreserved<MemorySSAWrapperPass>();
-    if (Impl.isMemorySSAEnabled())
-      AU.addRequired<MemorySSAWrapperPass>();
   }
 
 private:
@@ -4448,7 +4444,5 @@ INITIALIZE_PASS_END(GVNLegacyPass, "gvn", "Global Value Numbering", false, false
 // The public interface to this file...
 FunctionPass *llvm::createGVNPass() { return new GVNLegacyPass(); }
 FunctionPass *llvm::createGVNPass(bool ScalarPRE) {
-  const ScalarOptions &Opts = ScalarOptions::Global;
-  return new GVNLegacyPass(valueOr(Opts.enable_gvn_memdep, true),
-                           Opts.enable_gvn_memoryssa, ScalarPRE);
+  return new GVNLegacyPass(ScalarPRE);
 }
diff --git a/llvm/lib/Transforms/Scalar/GVNHoist.cpp b/llvm/lib/Transforms/Scalar/GVNHoist.cpp
index 86fe5177a0fba9..200ef27cf8af04 100644
--- a/llvm/lib/Transforms/Scalar/GVNHoist.cpp
+++ b/llvm/lib/Transforms/Scalar/GVNHoist.cpp
@@ -222,9 +222,9 @@ class CallInfo {
 // cases reduce critical path (by exposing more ILP).
 class GVNHoist {
 public:
-  GVNHoist(DominatorTree *DT, PostDominatorTree *PDT, AliasAnalysis *AA,
-           MemorySSA *MSSA)
-      : Opts(ScalarOptions::Global), DT(DT), PDT(PDT), AA(AA), MSSA(MSSA),
+  GVNHoist(const ScalarOptions &Opts, DominatorTree *DT, PostDominatorTree *PDT,
+           AliasAnalysis *AA, MemorySSA *MSSA)
+      : Opts(Opts), DT(DT), PDT(PDT), AA(AA), MSSA(MSSA),
         MSSAUpdater(std::make_unique<MemorySSAUpdater>(MSSA)) {
     MSSA->ensureOptimizedUses();
   }
@@ -1187,7 +1187,9 @@ PreservedAnalyses GVNHoistPass::run(Function &F, FunctionAnalysisManager &AM) {
   PostDominatorTree &PDT = AM.getResult<PostDominatorTreeAnalysis>(F);
   AliasAnalysis &AA = AM.getResult<AAManager>(F);
   MemorySSA &MSSA = AM.getResult<MemorySSAAnalysis>(F).getMSSA();
-  GVNHoist G(&DT, &PDT, &AA, &MSSA);
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
+  GVNHoist G(Opts, &DT, &PDT, &AA, &MSSA);
   if (!G.run(F))
     return PreservedAnalyses::all();
 
diff --git a/llvm/lib/Transforms/Scalar/GuardWidening.cpp b/llvm/lib/Transforms/Scalar/GuardWidening.cpp
index 3675f3d24d5313..0b236424e7580a 100644
--- a/llvm/lib/Transforms/Scalar/GuardWidening.cpp
+++ b/llvm/lib/Transforms/Scalar/GuardWidening.cpp
@@ -125,6 +125,7 @@ findInsertionPointForWideCondition(Instruction *WCOrGuard) {
 namespace {
 
 class GuardWideningImpl {
+  const ScalarOptions &Opts;
   DominatorTree &DT;
   PostDominatorTree *PDT;
   LoopInfo &LI;
@@ -312,11 +313,12 @@ class GuardWideningImpl {
   }
 
 public:
-  explicit GuardWideningImpl(DominatorTree &DT, PostDominatorTree *PDT,
-                             LoopInfo &LI, AssumptionCache &AC,
-                             MemorySSAUpdater *MSSAU, DomTreeNode *Root,
+  explicit GuardWideningImpl(const ScalarOptions &Opts, DominatorTree &DT,
+                             PostDominatorTree *PDT, LoopInfo &LI,
+                             AssumptionCache &AC, MemorySSAUpdater *MSSAU,
+                             DomTreeNode *Root,
                              std::function<bool(BasicBlock *)> BlockFilter)
-      : DT(DT), PDT(PDT), LI(LI), AC(AC), MSSAU(MSSAU), Root(Root),
+      : Opts(Opts), DT(DT), PDT(PDT), LI(LI), AC(AC), MSSAU(MSSAU), Root(Root),
         BlockFilter(BlockFilter) {}
 
   /// The entry point for this pass.
@@ -324,11 +326,11 @@ class GuardWideningImpl {
 };
 } // namespace
 
-static bool isSupportedGuardInstruction(const Instruction *Insn) {
+static bool isSupportedGuardInstruction(const ScalarOptions &Opts,
+                                        const Instruction *Insn) {
   if (isGuard(Insn))
     return true;
-  if (ScalarOptions::Global.guard_widening_widen_branch_guards &&
-      isGuardAsWidenableBranch(Insn))
+  if (Opts.guard_widening_widen_branch_guards && isGuardAsWidenableBranch(Insn))
     return true;
   return false;
 }
@@ -345,7 +347,7 @@ bool GuardWideningImpl::run() {
     auto &CurrentList = GuardsInBlock[BB];
 
     for (auto &I : *BB)
-      if (isSupportedGuardInstruction(&I))
+      if (isSupportedGuardInstruction(Opts, &I))
         CurrentList.push_back(cast<Instruction>(&I));
 
     for (auto *II : CurrentList)
@@ -356,7 +358,7 @@ bool GuardWideningImpl::run() {
   for (auto *I : EliminatedGuardsAndBranches)
     if (!WidenedGuards.count(I)) {
       assert(isa<ConstantInt>(getCondition(I)) && "Should be!");
-      if (isSupportedGuardInstruction(I))
+      if (isSupportedGuardInstruction(Opts, I))
         eliminateGuard(I, MSSAU);
       else {
         assert(isa<CondBrInst>(I) &&
@@ -990,7 +992,9 @@ PreservedAnalyses GuardWideningPass::run(Function &F,
   std::unique_ptr<MemorySSAUpdater> MSSAU;
   if (MSSAA)
     MSSAU = std::make_unique<MemorySSAUpdater>(&MSSAA->getMSSA());
-  if (!GuardWideningImpl(DT, &PDT, LI, AC, MSSAU ? MSSAU.get() : nullptr,
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
+  if (!GuardWideningImpl(Opts, DT, &PDT, LI, AC, MSSAU ? MSSAU.get() : nullptr,
                          DT.getRootNode(), [](BasicBlock *) { return true; })
            .run())
     return PreservedAnalyses::all();
@@ -1013,7 +1017,9 @@ PreservedAnalyses GuardWideningPass::run(Loop &L, LoopAnalysisManager &AM,
   std::unique_ptr<MemorySSAUpdater> MSSAU;
   if (AR.MSSA)
     MSSAU = std::make_unique<MemorySSAUpdater>(AR.MSSA);
-  if (!GuardWideningImpl(AR.DT, nullptr, AR.LI, AR.AC,
+  const ScalarOptions &Opts =
+      L.getHeader()->getContext().getLibraryOptions().get<ScalarOptions>();
+  if (!GuardWideningImpl(Opts, AR.DT, nullptr, AR.LI, AR.AC,
                          MSSAU ? MSSAU.get() : nullptr, AR.DT.getNode(RootBB),
                          BlockFilter)
            .run())
diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
index 267eabedce27f0..55045ada06c10e 100644
--- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
+++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
@@ -2183,7 +2183,8 @@ PreservedAnalyses IndVarSimplifyPass::run(Loop &L, LoopAnalysisManager &AM,
                                           LPMUpdater &) {
   Function *F = L.getHeader()->getParent();
   const DataLayout &DL = F->getDataLayout();
-  const ScalarOptions &Opts = ScalarOptions::Global;
+  const ScalarOptions &Opts =
+      F->getContext().getLibraryOptions().get<ScalarOptions>();
 
   IndVarSimplify IVS(Opts, &AR.LI, &AR.SE, &AR.DT, DL, &AR.TLI, &AR.TTI,
                      AR.MSSA, WidenIndVars && Opts.indvars_widen_indvars);
diff --git a/llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp b/llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp
index 2e75ed6c9e2334..b700a73c60b521 100644
--- a/llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp
@@ -861,7 +861,8 @@ IntersectUnsignedRange(ScalarEvolution &SE,
 }
 
 PreservedAnalyses IRCEPass::run(Function &F, FunctionAnalysisManager &AM) {
-  const ScalarOptions &Opts = ScalarOptions::Global;
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
   auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
   LoopInfo &LI = AM.getResult<LoopAnalysis>(F);
   // There are no loops in the function. Return before computing other expensive
diff --git a/llvm/lib/Transforms/Scalar/JumpTableToSwitch.cpp b/llvm/lib/Transforms/Scalar/JumpTableToSwitch.cpp
index 1b659df769b58b..f10bdb8381ae19 100644
--- a/llvm/lib/Transforms/Scalar/JumpTableToSwitch.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpTableToSwitch.cpp
@@ -38,10 +38,10 @@ struct JumpTableTy {
 };
 } // anonymous namespace
 
-static std::optional<JumpTableTy> parseJumpTable(GetElementPtrInst *GEP,
+static std::optional<JumpTableTy> parseJumpTable(const ScalarOptions &Opts,
+                                                 GetElementPtrInst *GEP,
                                                  PointerType *PtrTy,
                                                  FunctionType *CallFTy) {
-  const ScalarOptions &Opts = ScalarOptions::Global;
   Constant *Ptr = dyn_cast<Constant>(GEP->getPointerOperand());
   if (!Ptr)
     return std::nullopt;
@@ -194,6 +194,8 @@ PreservedAnalyses JumpTableToSwitchPass::run(Function &F,
   DominatorTree *DT = AM.getCachedResult<DominatorTreeAnalysis>(F);
   PostDominatorTree *PDT = AM.getCachedResult<PostDominatorTreeAnalysis>(F);
   DomTreeUpdater DTU(DT, PDT, DomTreeUpdater::UpdateStrategy::Lazy);
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
   bool Changed = false;
   auto FuncToGuid = [&](const Function &Fct) {
     if (const auto MaybeGUID = Fct.getGUIDIfAssigned(); MaybeGUID)
@@ -221,7 +223,7 @@ PreservedAnalyses JumpTableToSwitchPass::run(Function &F,
         auto *PtrTy = dyn_cast<PointerType>(L->getType());
         assert(PtrTy && "call operand must be a pointer");
         std::optional<JumpTableTy> JumpTable =
-            parseJumpTable(GEP, PtrTy, Call->getFunctionType());
+            parseJumpTable(Opts, GEP, PtrTy, Call->getFunctionType());
         if (!JumpTable)
           continue;
         SplittedOutTail =
diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
index ee12796d988842..21e9ddf33f5206 100644
--- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
@@ -268,7 +268,7 @@ bool JumpThreadingPass::runImpl(Function &F_, FunctionAnalysisManager *FAM_,
                                 BlockFrequencyInfo *BFI_,
                                 BranchProbabilityInfo *BPI_) {
   LLVM_DEBUG(dbgs() << "Jump threading on function '" << F_.getName() << "'\n");
-  Opts = &ScalarOptions::Global;
+  Opts = &F_.getContext().getLibraryOptions().get<ScalarOptions>();
   F = &F_;
   FAM = FAM_;
   TLI = TLI_;
diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp
index a72aabfc3e1e0e..04c048a94bf9bb 100644
--- a/llvm/lib/Transforms/Scalar/LICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LICM.cpp
@@ -116,12 +116,16 @@ STATISTIC(NumIntAssociationsHoisted,
 STATISTIC(NumBOAssociationsHoisted, "Number of invariant BinaryOp expressions "
                                     "reassociated and hoisted out of the loop");
 
-unsigned llvm::getLicmMssaOptCap() {
-  return ScalarOptions::Global.licm_mssa_optimization_cap;
+unsigned
+llvm::getLicmMssaOptCap(const cl::LibraryOptionsContext *LibraryOptions) {
+  return cl::LibraryOptionsContext::get<ScalarOptions>(LibraryOptions)
+      .licm_mssa_optimization_cap;
 }
 
-unsigned llvm::getLicmMssaNoAccForPromotionCap() {
-  return ScalarOptions::Global.licm_mssa_max_acc_promotion;
+unsigned llvm::getLicmMssaNoAccForPromotionCap(
+    const cl::LibraryOptionsContext *LibraryOptions) {
+  return cl::LibraryOptionsContext::get<ScalarOptions>(LibraryOptions)
+      .licm_mssa_max_acc_promotion;
 }
 
 static bool inSubLoop(BasicBlock *BB, Loop *CurLoop, LoopInfo *LI);
@@ -151,7 +155,7 @@ static bool pointerInvalidatedByLoop(MemorySSA *MSSA, MemoryUse *MU,
 static bool pointerInvalidatedByBlock(BasicBlock &BB, MemorySSA &MSSA,
                                       MemoryUse &MU);
 /// Aggregates various functions for hoisting computations out of loop.
-static bool hoistArithmetics(Instruction &I, Loop &L,
+static bool hoistArithmetics(const ScalarOptions &Opts, Instruction &I, Loop &L,
                              ICFLoopSafetyInfo &SafetyInfo,
                              MemorySSAUpdater &MSSAU, AssumptionCache *AC,
                              DominatorTree *DT);
@@ -180,6 +184,10 @@ static SmallVector<PointersAndHasReadsOutsideSet, 0> collectPromotionCandidates(
     ICFLoopSafetyInfo *SafetyInfo,
     const SmallPtrSetImpl<const MDNode *> &LoopLocalAliasScopes, Loop *L);
 
+static const ScalarOptions &getScalarOptions(const Loop &L) {
+  return L.getHeader()->getContext().getLibraryOptions().get<ScalarOptions>();
+}
+
 namespace {
 struct LoopInvariantCodeMotion {
   bool runOnLoop(Loop *L, AAResults *AA, LoopInfo *LI, DominatorTree *DT,
@@ -187,14 +195,15 @@ struct LoopInvariantCodeMotion {
                  TargetTransformInfo *TTI, ScalarEvolution *SE, MemorySSA *MSSA,
                  OptimizationRemarkEmitter *ORE, bool LoopNestMode = false);
 
-  LoopInvariantCodeMotion(unsigned LicmMssaOptCap,
-                          unsigned LicmMssaNoAccForPromotionCap,
-                          bool LicmAllowSpeculation)
-      : LicmMssaOptCap(LicmMssaOptCap),
-        LicmMssaNoAccForPromotionCap(LicmMssaNoAccForPromotionCap),
-        LicmAllowSpeculation(LicmAllowSpeculation) {}
+  LoopInvariantCodeMotion(const ScalarOptions &Opts, const LICMOptions &LO)
+      : Opts(Opts),
+        LicmMssaOptCap(LO.MssaOptCap.value_or(Opts.licm_mssa_optimization_cap)),
+        LicmMssaNoAccForPromotionCap(LO.MssaNoAccForPromotionCap.value_or(
+            Opts.licm_mssa_max_acc_promotion)),
+        LicmAllowSpeculation(LO.AllowSpeculation) {}
 
 private:
+  const ScalarOptions &Opts;
   unsigned LicmMssaOptCap;
   unsigned LicmMssaNoAccForPromotionCap;
   bool LicmAllowSpeculation;
@@ -202,13 +211,7 @@ struct LoopInvariantCodeMotion {
 
 struct LegacyLICMPass : public LoopPass {
   static char ID; // Pass identification, replacement for typeid
-  LegacyLICMPass(unsigned LicmMssaOptCap =
-                     ScalarOptions::Global.licm_mssa_optimization_cap,
-                 unsigned LicmMssaNoAccForPromotionCap =
-                     ScalarOptions::Global.licm_mssa_max_acc_promotion,
-                 bool LicmAllowSpeculation = true)
-      : LoopPass(ID), LICM(LicmMssaOptCap, LicmMssaNoAccForPromotionCap,
-                           LicmAllowSpeculation) {
+  LegacyLICMPass() : LoopPass(ID) {
     initializeLegacyLICMPassPass(*PassRegistry::getPassRegistry());
   }
 
@@ -227,6 +230,9 @@ struct LegacyLICMPass : public LoopPass {
     // pass. Function analyses need to be preserved across loop transformations
     // but ORE cannot be preserved (see comment before the pass definition).
     OptimizationRemarkEmitter ORE(L->getHeader()->getParent());
+    const ScalarOptions &Opts =
+        F->getContext().getLibraryOptions().get<ScalarOptions>();
+    LoopInvariantCodeMotion LICM(Opts, LICMOptions());
     return LICM.runOnLoop(
         L, &getAnalysis<AAResultsWrapperPass>().getAAResults(),
         &getAnalysis<LoopInfoWrapperPass>().getLoopInfo(),
@@ -253,9 +259,6 @@ struct LegacyLICMPass : public LoopPass {
     AU.addPreserved<LazyBlockFrequencyInfoPass>();
     AU.addPreserved<LazyBranchProbabilityInfoPass>();
   }
-
-private:
-  LoopInvariantCodeMotion LICM;
 };
 } // namespace
 
@@ -269,8 +272,7 @@ PreservedAnalyses LICMPass::run(Loop &L, LoopAnalysisManager &AM,
   // but ORE cannot be preserved (see comment before the pass definition).
   OptimizationRemarkEmitter ORE(L.getHeader()->getParent());
 
-  LoopInvariantCodeMotion LICM(Opts.MssaOptCap, Opts.MssaNoAccForPromotionCap,
-                               Opts.AllowSpeculation);
+  LoopInvariantCodeMotion LICM(getScalarOptions(L), Opts);
   if (!LICM.runOnLoop(&L, &AR.AA, &AR.LI, &AR.DT, &AR.AC, &AR.TLI, &AR.TTI,
                       &AR.SE, AR.MSSA, &ORE))
     return PreservedAnalyses::all();
@@ -302,10 +304,9 @@ PreservedAnalyses LNICMPass::run(LoopNest &LN, LoopAnalysisManager &AM,
   // but ORE cannot be preserved (see comment before the pass definition).
   OptimizationRemarkEmitter ORE(LN.getParent());
 
-  LoopInvariantCodeMotion LICM(Opts.MssaOptCap, Opts.MssaNoAccForPromotionCap,
-                               Opts.AllowSpeculation);
-
   Loop &OutermostLoop = LN.getOutermostLoop();
+  LoopInvariantCodeMotion LICM(getScalarOptions(OutermostLoop), Opts);
+
   bool Changed = LICM.runOnLoop(&OutermostLoop, &AR.AA, &AR.LI, &AR.DT, &AR.AC,
                                 &AR.TLI, &AR.TTI, &AR.SE, AR.MSSA, &ORE, true);
 
@@ -346,8 +347,8 @@ Pass *llvm::createLICMPass() { return new LegacyLICMPass(); }
 
 llvm::SinkAndHoistLICMFlags::SinkAndHoistLICMFlags(bool IsSink, Loop &L,
                                                    MemorySSA &MSSA)
-    : SinkAndHoistLICMFlags(ScalarOptions::Global.licm_mssa_optimization_cap,
-                            ScalarOptions::Global.licm_mssa_max_acc_promotion,
+    : SinkAndHoistLICMFlags(getScalarOptions(L).licm_mssa_optimization_cap,
+                            getScalarOptions(L).licm_mssa_max_acc_promotion,
                             IsSink, L, MSSA) {}
 
 llvm::SinkAndHoistLICMFlags::SinkAndHoistLICMFlags(
@@ -454,9 +455,8 @@ bool LoopInvariantCodeMotion::runOnLoop(Loop *L, AAResults *AA, LoopInfo *LI,
   // make sure we catch that. An additional load may be generated in the
   // preheader for SSA updater, so also avoid sinking when no preheader
   // is available.
-  if (!ScalarOptions::Global.disable_licm_promotion && Preheader &&
-      L->hasDedicatedExits() && !Flags.tooManyMemoryAccesses() &&
-      !HasCoroSuspendInst) {
+  if (!Opts.disable_licm_promotion && Preheader && L->hasDedicatedExits() &&
+      !Flags.tooManyMemoryAccesses() && !HasCoroSuspendInst) {
     // Figure out the loop exits and their insertion points
     SmallVector<BasicBlock *, 8> ExitBlocks;
     L->getUniqueExitBlocks(ExitBlocks);
@@ -639,6 +639,7 @@ bool llvm::hoistRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI,
          CurLoop != nullptr && SafetyInfo != nullptr &&
          "Unexpected input to hoistRegion.");
 
+  const ScalarOptions &Opts = getScalarOptions(*CurLoop);
   LoopBlocksRPO Worklist(CurLoop);
   Worklist.perform(LI);
   bool Changed = false;
@@ -716,7 +717,7 @@ bool llvm::hoistRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI,
 
       // Try to reassociate instructions so that part of computations can be
       // done out of loop.
-      if (hoistArithmetics(I, *CurLoop, *SafetyInfo, MSSAU, AC, DT)) {
+      if (hoistArithmetics(Opts, I, *CurLoop, *SafetyInfo, MSSAU, AC, DT)) {
         Changed = true;
         continue;
       }
@@ -837,12 +838,14 @@ static bool isLoadInvariantInLoop(LoadInst *LI, DominatorTree *DT,
   if (isa<Constant>(Addr))
     return false;
 
+  const ScalarOptions &Opts =
+      LI->getContext().getLibraryOptions().get<ScalarOptions>();
   unsigned UsesVisited = 0;
   // Traverse all uses of the load operand value, to see if invariant.start is
   // one of the uses, and whether it dominates the load instruction.
   for (auto *U : Addr->users()) {
     // Avoid traversing for Load operand with high number of users.
-    if (++UsesVisited > ScalarOptions::Global.licm_max_num_uses_traversed)
+    if (++UsesVisited > Opts.licm_max_num_uses_traversed)
       return false;
     IntrinsicInst *II = dyn_cast<IntrinsicInst>(U);
     // If there are escaping uses of invariant.start instruction, the load maybe
@@ -2584,11 +2587,10 @@ static bool isReassociableOp(Instruction *I, unsigned IntOpcode,
 /// ((A1 * C * B1) + (A2 * C * B2) + ...) and hoist the (A1 * C), (A2 * C), ...
 /// invariant expressions. This functions returns true only if any hoisting has
 /// actually occurred.
-static bool hoistMulAddAssociation(Instruction &I, Loop &L,
-                                   ICFLoopSafetyInfo &SafetyInfo,
+static bool hoistMulAddAssociation(const ScalarOptions &Opts, Instruction &I,
+                                   Loop &L, ICFLoopSafetyInfo &SafetyInfo,
                                    MemorySSAUpdater &MSSAU, AssumptionCache *AC,
                                    DominatorTree *DT) {
-  const ScalarOptions &Opts = ScalarOptions::Global;
   if (!isReassociableOp(&I, Instruction::Mul, Instruction::FMul))
     return false;
   Value *VariantOp = I.getOperand(0);
@@ -2854,7 +2856,7 @@ static bool hoistSubAddAssociation(Instruction &I, Loop &L,
   return true;
 }
 
-static bool hoistArithmetics(Instruction &I, Loop &L,
+static bool hoistArithmetics(const ScalarOptions &Opts, Instruction &I, Loop &L,
                              ICFLoopSafetyInfo &SafetyInfo,
                              MemorySSAUpdater &MSSAU, AssumptionCache *AC,
                              DominatorTree *DT) {
@@ -2882,7 +2884,7 @@ static bool hoistArithmetics(Instruction &I, Loop &L,
   }
 
   bool IsInt = I.getType()->isIntOrIntVectorTy();
-  if (hoistMulAddAssociation(I, L, SafetyInfo, MSSAU, AC, DT)) {
+  if (hoistMulAddAssociation(Opts, I, L, SafetyInfo, MSSAU, AC, DT)) {
     ++NumHoisted;
     if (IsInt)
       ++NumIntAssociationsHoisted;
diff --git a/llvm/lib/Transforms/Scalar/LoopDataPrefetch.cpp b/llvm/lib/Transforms/Scalar/LoopDataPrefetch.cpp
index ed0ab6be395a47..490190b2fa71dc 100644
--- a/llvm/lib/Transforms/Scalar/LoopDataPrefetch.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopDataPrefetch.cpp
@@ -41,11 +41,11 @@ namespace {
 /// Loop prefetch implementation class.
 class LoopDataPrefetch {
 public:
-  LoopDataPrefetch(AssumptionCache *AC, DominatorTree *DT, LoopInfo *LI,
-                   ScalarEvolution *SE, const TargetTransformInfo *TTI,
+  LoopDataPrefetch(const ScalarOptions &Opts, AssumptionCache *AC,
+                   DominatorTree *DT, LoopInfo *LI, ScalarEvolution *SE,
+                   const TargetTransformInfo *TTI,
                    OptimizationRemarkEmitter *ORE)
-      : Opts(ScalarOptions::Global), AC(AC), DT(DT), LI(LI), SE(SE), TTI(TTI),
-        ORE(ORE) {}
+      : Opts(Opts), AC(AC), DT(DT), LI(LI), SE(SE), TTI(TTI), ORE(ORE) {}
 
   bool run();
 
@@ -159,7 +159,9 @@ PreservedAnalyses LoopDataPrefetchPass::run(Function &F,
       &AM.getResult<OptimizationRemarkEmitterAnalysis>(F);
   const TargetTransformInfo *TTI = &AM.getResult<TargetIRAnalysis>(F);
 
-  LoopDataPrefetch LDP(AC, DT, LI, SE, TTI, ORE);
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
+  LoopDataPrefetch LDP(Opts, AC, DT, LI, SE, TTI, ORE);
   bool Changed = LDP.run();
 
   if (Changed) {
@@ -186,7 +188,9 @@ bool LoopDataPrefetchLegacyPass::runOnFunction(Function &F) {
   const TargetTransformInfo *TTI =
       &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
 
-  LoopDataPrefetch LDP(AC, DT, LI, SE, TTI, ORE);
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
+  LoopDataPrefetch LDP(Opts, AC, DT, LI, SE, TTI, ORE);
   return LDP.run();
 }
 
diff --git a/llvm/lib/Transforms/Scalar/LoopDeletion.cpp b/llvm/lib/Transforms/Scalar/LoopDeletion.cpp
index 2dc696edc5accd..ce121bd6ef708b 100644
--- a/llvm/lib/Transforms/Scalar/LoopDeletion.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopDeletion.cpp
@@ -212,7 +212,11 @@ getValueOnFirstIteration(Value *V, DenseMap<Value *, Value *> &FirstIterValue,
 static bool canProveExitOnFirstIteration(Loop *L, DominatorTree &DT,
                                          LoopInfo &LI) {
   // Disabled by option.
-  if (!ScalarOptions::Global.loop_deletion_enable_symbolic_execution)
+  if (!L->getHeader()
+           ->getContext()
+           .getLibraryOptions()
+           .get<ScalarOptions>()
+           .loop_deletion_enable_symbolic_execution)
     return false;
 
   BasicBlock *Predecessor = L->getLoopPredecessor();
diff --git a/llvm/lib/Transforms/Scalar/LoopDistribute.cpp b/llvm/lib/Transforms/Scalar/LoopDistribute.cpp
index 0044174efcb664..317d70f7a0a6dc 100644
--- a/llvm/lib/Transforms/Scalar/LoopDistribute.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopDistribute.cpp
@@ -958,7 +958,8 @@ static bool runImpl(Function &F, LoopInfo *LI, DominatorTree *DT,
         Worklist.push_back(L);
 
   // Now walk the identified inner loops.
-  const ScalarOptions &Opts = ScalarOptions::Global;
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
   bool Changed = false;
   for (Loop *L : Worklist) {
     LoopDistributeForLoop LDL(Opts, L, &F, LI, DT, SE, LAIs, ORE);
diff --git a/llvm/lib/Transforms/Scalar/LoopFlatten.cpp b/llvm/lib/Transforms/Scalar/LoopFlatten.cpp
index f1fe6f5d4d87f8..89ceabbbf06603 100644
--- a/llvm/lib/Transforms/Scalar/LoopFlatten.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopFlatten.cpp
@@ -131,8 +131,8 @@ struct FlattenInfo {
 
   Value *NewTripCount = nullptr; // The tripcount of the flattened loop.
 
-  FlattenInfo(Loop *OL, Loop *IL)
-      : Opts(ScalarOptions::Global), OuterLoop(OL), InnerLoop(IL) {}
+  FlattenInfo(const ScalarOptions &Opts, Loop *OL, Loop *IL)
+      : Opts(Opts), OuterLoop(OL), InnerLoop(IL) {}
 
   bool isNarrowInductionPhi(PHINode *Phi) {
     // This can't be the narrow phi if we haven't widened the IV first.
@@ -994,11 +994,13 @@ PreservedAnalyses LoopFlattenPass::run(LoopNest &LN, LoopAnalysisManager &LAM,
   // regardless of whether anything ends up being flattened.
   LoopAccessInfoManager LAIM(AR.SE, AR.AA, AR.DT, AR.LI, &AR.TTI, nullptr,
                              &AR.AC);
+  const ScalarOptions &Opts =
+      LN.getParent()->getContext().getLibraryOptions().get<ScalarOptions>();
   for (Loop *InnerLoop : LN.getLoops()) {
     auto *OuterLoop = InnerLoop->getParentLoop();
     if (!OuterLoop)
       continue;
-    FlattenInfo FI(OuterLoop, InnerLoop);
+    FlattenInfo FI(Opts, OuterLoop, InnerLoop);
     Changed |=
         FlattenLoopPair(FI, &AR.DT, &AR.LI, &AR.SE, &AR.AC, &AR.TTI, &U,
                         MSSAU ? &*MSSAU : nullptr, LAIM.getInfo(*OuterLoop));
diff --git a/llvm/lib/Transforms/Scalar/LoopFuse.cpp b/llvm/lib/Transforms/Scalar/LoopFuse.cpp
index b9e65fb0ed5209..464a8e933f4311 100644
--- a/llvm/lib/Transforms/Scalar/LoopFuse.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopFuse.cpp
@@ -2053,7 +2053,9 @@ PreservedAnalyses LoopFusePass::run(Function &F, FunctionAnalysisManager &AM) {
   if (Changed)
     PDT.recalculate(F);
 
-  LoopFuser LF(ScalarOptions::Global, LI, DT, DI, AA, SE, PDT, ORE, AC, TTI);
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
+  LoopFuser LF(Opts, LI, DT, DI, AA, SE, PDT, ORE, AC, TTI);
   Changed |= LF.fuseLoops(F);
   if (!Changed)
     return PreservedAnalyses::all();
diff --git a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
index a188c33528e5e9..f3ad76afabd1aa 100644
--- a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
@@ -176,14 +176,14 @@ class LoopIdiomRecognize {
   std::unique_ptr<MemorySSAUpdater> MSSAU;
 
 public:
-  explicit LoopIdiomRecognize(AliasAnalysis *AA, DominatorTree *DT,
-                              LoopInfo *LI, ScalarEvolution *SE,
-                              TargetLibraryInfo *TLI,
+  explicit LoopIdiomRecognize(const ScalarOptions &Opts, AliasAnalysis *AA,
+                              DominatorTree *DT, LoopInfo *LI,
+                              ScalarEvolution *SE, TargetLibraryInfo *TLI,
                               const TargetTransformInfo *TTI, MemorySSA *MSSA,
                               const DataLayout *DL,
                               OptimizationRemarkEmitter &ORE)
-      : Opts(ScalarOptions::Global), AA(AA), DT(DT), LI(LI), SE(SE), TLI(TLI),
-        TTI(TTI), DL(DL), ORE(ORE) {
+      : Opts(Opts), AA(AA), DT(DT), LI(LI), SE(SE), TLI(TLI), TTI(TTI), DL(DL),
+        ORE(ORE) {
     if (MSSA)
       MSSAU = std::make_unique<MemorySSAUpdater>(MSSA);
   }
@@ -297,7 +297,9 @@ PreservedAnalyses LoopIdiomRecognizePass::run(Loop &L, LoopAnalysisManager &AM,
   // but ORE cannot be preserved (see comment before the pass definition).
   OptimizationRemarkEmitter ORE(L.getHeader()->getParent());
 
-  LoopIdiomRecognize LIR(&AR.AA, &AR.DT, &AR.LI, &AR.SE, &AR.TLI, &AR.TTI,
+  const ScalarOptions &Opts =
+      L.getHeader()->getContext().getLibraryOptions().get<ScalarOptions>();
+  LoopIdiomRecognize LIR(Opts, &AR.AA, &AR.DT, &AR.LI, &AR.SE, &AR.TLI, &AR.TTI,
                          AR.MSSA, DL, ORE);
   if (!LIR.runOnLoop(&L))
     return PreservedAnalyses::all();
diff --git a/llvm/lib/Transforms/Scalar/LoopInterchange.cpp b/llvm/lib/Transforms/Scalar/LoopInterchange.cpp
index 53196b5b579e17..1d384f40607f62 100644
--- a/llvm/lib/Transforms/Scalar/LoopInterchange.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopInterchange.cpp
@@ -635,11 +635,11 @@ struct LoopInterchange {
   /// Interface to emit optimization remarks.
   OptimizationRemarkEmitter *ORE;
 
-  LoopInterchange(ScalarEvolution *SE, LoopInfo *LI, DependenceInfo *DI,
-                  DominatorTree *DT, LoopStandardAnalysisResults *AR,
+  LoopInterchange(const ScalarOptions &Opts, ScalarEvolution *SE, LoopInfo *LI,
+                  DependenceInfo *DI, DominatorTree *DT,
+                  LoopStandardAnalysisResults *AR,
                   OptimizationRemarkEmitter *ORE)
-      : Opts(ScalarOptions::Global), SE(SE), LI(LI), DI(DI), DT(DT), AR(AR),
-        ORE(ORE) {}
+      : Opts(Opts), SE(SE), LI(LI), DI(DI), DT(DT), AR(AR), ORE(ORE) {}
 
   bool run(Loop *L) {
     if (L->getParentLoop())
@@ -2711,7 +2711,9 @@ PreservedAnalyses LoopInterchangePass::run(LoopNest &LN,
   });
 
   DependenceInfo DI(&F, &AR.AA, &AR.SE, &AR.LI);
-  if (!LoopInterchange(&AR.SE, &AR.LI, &DI, &AR.DT, &AR, &ORE).run(LN))
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
+  if (!LoopInterchange(Opts, &AR.SE, &AR.LI, &DI, &AR.DT, &AR, &ORE).run(LN))
     return PreservedAnalyses::all();
   U.markLoopNestChanged(true);
   return getLoopPassPreservedAnalyses();
diff --git a/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp b/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp
index 9925b59f26950d..04d924e0e4c013 100644
--- a/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp
@@ -482,7 +482,8 @@ class LoadEliminationForLoop {
   /// Top-level driver for each loop: find store->load forwarding
   /// candidates, add run-time checks and perform transformation.
   bool processLoop() {
-    const ScalarOptions &Opts = ScalarOptions::Global;
+    const ScalarOptions &Opts =
+        L->getHeader()->getContext().getLibraryOptions().get<ScalarOptions>();
     LLVM_DEBUG(dbgs() << "\nIn \"" << L->getHeader()->getParent()->getName()
                       << "\" checking " << *L << "\n");
 
diff --git a/llvm/lib/Transforms/Scalar/LoopPredication.cpp b/llvm/lib/Transforms/Scalar/LoopPredication.cpp
index 467592ac88d0fe..7250a1d22cd827 100644
--- a/llvm/lib/Transforms/Scalar/LoopPredication.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopPredication.cpp
@@ -290,10 +290,10 @@ class LoopPredication {
   bool predicateLoopExits(Loop *L, SCEVExpander &Rewriter);
 
 public:
-  LoopPredication(AliasAnalysis *AA, DominatorTree *DT, ScalarEvolution *SE,
-                  LoopInfo *LI, MemorySSAUpdater *MSSAU)
-      : Opts(ScalarOptions::Global), AA(AA), DT(DT), SE(SE), LI(LI),
-        MSSAU(MSSAU) {};
+  LoopPredication(const ScalarOptions &Opts, AliasAnalysis *AA,
+                  DominatorTree *DT, ScalarEvolution *SE, LoopInfo *LI,
+                  MemorySSAUpdater *MSSAU)
+      : Opts(Opts), AA(AA), DT(DT), SE(SE), LI(LI), MSSAU(MSSAU) {};
   bool runOnLoop(Loop *L);
 };
 
@@ -305,7 +305,9 @@ PreservedAnalyses LoopPredicationPass::run(Loop &L, LoopAnalysisManager &AM,
   std::unique_ptr<MemorySSAUpdater> MSSAU;
   if (AR.MSSA)
     MSSAU = std::make_unique<MemorySSAUpdater>(AR.MSSA);
-  LoopPredication LP(&AR.AA, &AR.DT, &AR.SE, &AR.LI,
+  const ScalarOptions &Opts =
+      L.getHeader()->getContext().getLibraryOptions().get<ScalarOptions>();
+  LoopPredication LP(Opts, &AR.AA, &AR.DT, &AR.SE, &AR.LI,
                      MSSAU ? MSSAU.get() : nullptr);
   if (!LP.runOnLoop(&L))
     return PreservedAnalyses::all();
diff --git a/llvm/lib/Transforms/Scalar/LoopRotation.cpp b/llvm/lib/Transforms/Scalar/LoopRotation.cpp
index 1255a2d3349494..bd8b01d5205500 100644
--- a/llvm/lib/Transforms/Scalar/LoopRotation.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopRotation.cpp
@@ -56,7 +56,8 @@ void LoopRotatePass::printPipeline(
 PreservedAnalyses LoopRotatePass::run(Loop &L, LoopAnalysisManager &AM,
                                       LoopStandardAnalysisResults &AR,
                                       LPMUpdater &) {
-  const ScalarOptions &Opts = ScalarOptions::Global;
+  const ScalarOptions &Opts =
+      L.getHeader()->getContext().getLibraryOptions().get<ScalarOptions>();
   // Vectorization requires loop-rotation. Use default threshold for loops the
   // user explicitly marked for vectorization, even when header duplication is
   // disabled.
diff --git a/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp b/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp
index a2ff998864456c..b04a3d6c628540 100644
--- a/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp
@@ -664,11 +664,12 @@ class ConstantTerminatorFoldingImpl {
 
 /// Turn branches and switches with known constant conditions into unconditional
 /// branches.
-static bool constantFoldTerminators(Loop &L, DominatorTree &DT, LoopInfo &LI,
+static bool constantFoldTerminators(const ScalarOptions &Opts, Loop &L,
+                                    DominatorTree &DT, LoopInfo &LI,
                                     ScalarEvolution &SE,
                                     MemorySSAUpdater *MSSAU,
                                     bool &IsLoopDeleted) {
-  if (!ScalarOptions::Global.enable_loop_simplifycfg_term_folding)
+  if (!Opts.enable_loop_simplifycfg_term_folding)
     return false;
 
   // To keep things simple, only process loops with single latch. We
@@ -720,10 +721,12 @@ static bool mergeBlocksIntoPredecessors(Loop &L, DominatorTree &DT,
 static bool simplifyLoopCFG(Loop &L, DominatorTree &DT, LoopInfo &LI,
                             ScalarEvolution &SE, MemorySSAUpdater *MSSAU,
                             bool &IsLoopDeleted) {
+  const ScalarOptions &Opts =
+      L.getHeader()->getContext().getLibraryOptions().get<ScalarOptions>();
   bool Changed = false;
 
   // Constant-fold terminators with known constant conditions.
-  Changed |= constantFoldTerminators(L, DT, LI, SE, MSSAU, IsLoopDeleted);
+  Changed |= constantFoldTerminators(Opts, L, DT, LI, SE, MSSAU, IsLoopDeleted);
 
   if (IsLoopDeleted)
     return true;
diff --git a/llvm/lib/Transforms/Scalar/LoopSink.cpp b/llvm/lib/Transforms/Scalar/LoopSink.cpp
index add4f804b3abb9..68c0d87f88e084 100644
--- a/llvm/lib/Transforms/Scalar/LoopSink.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopSink.cpp
@@ -295,7 +295,8 @@ static bool sinkLoopInvariantInstructions(Loop &L, AAResults &AA, LoopInfo &LI,
                                           BlockFrequencyInfo &BFI,
                                           MemorySSA &MSSA,
                                           ScalarEvolution *SE) {
-  const ScalarOptions &Opts = ScalarOptions::Global;
+  const ScalarOptions &Opts =
+      L.getHeader()->getContext().getLibraryOptions().get<ScalarOptions>();
   BasicBlock *Preheader = L.getLoopPreheader();
   assert(Preheader && "Expected loop to have preheader");
 
diff --git a/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp b/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
index 6073a177babafd..912fb890491bb2 100644
--- a/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
@@ -7131,7 +7131,8 @@ static bool ReduceLoopStrength(Loop *L, IVUsers &IU, ScalarEvolution &SE,
                                const TargetTransformInfo &TTI,
                                AssumptionCache &AC, TargetLibraryInfo &TLI,
                                MemorySSA *MSSA, bool PreserveLCSSA) {
-  const ScalarOptions &Opts = ScalarOptions::Global;
+  const ScalarOptions &Opts =
+      L->getHeader()->getContext().getLibraryOptions().get<ScalarOptions>();
 
   // Debug preservation - before we start removing anything identify which DVI
   // meet the salvageable criteria and store their DIExpression and SCEVs.
diff --git a/llvm/lib/Transforms/Scalar/LoopUnrollAndJamPass.cpp b/llvm/lib/Transforms/Scalar/LoopUnrollAndJamPass.cpp
index 87b038f55c7d84..2fa73c1b45a2a8 100644
--- a/llvm/lib/Transforms/Scalar/LoopUnrollAndJamPass.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopUnrollAndJamPass.cpp
@@ -248,7 +248,8 @@ tryToUnrollAndJamLoop(Loop *L, DominatorTree &DT, LoopInfo *LI,
                       ScalarEvolution &SE, const TargetTransformInfo &TTI,
                       AssumptionCache &AC, DependenceInfo &DI,
                       OptimizationRemarkEmitter &ORE, int OptLevel) {
-  const ScalarOptions &Opts = ScalarOptions::Global;
+  const ScalarOptions &Opts =
+      L->getHeader()->getContext().getLibraryOptions().get<ScalarOptions>();
   TargetTransformInfo::UnrollingPreferences UP = gatherUnrollingPreferences(
       L, SE, TTI, nullptr, nullptr, ORE, OptLevel, std::nullopt, std::nullopt,
       std::nullopt, std::nullopt, std::nullopt);
diff --git a/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp b/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp
index be62b15186b145..983befea300a86 100644
--- a/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp
@@ -74,8 +74,10 @@ using namespace llvm;
 
 #define DEBUG_TYPE "loop-unroll"
 
-bool llvm::getForgetSCEVInLoopUnroll() {
-  return ScalarOptions::Global.forget_scev_loop_unroll;
+bool llvm::getForgetSCEVInLoopUnroll(
+    const cl::LibraryOptionsContext *LibraryOptions) {
+  return cl::LibraryOptionsContext::get<ScalarOptions>(LibraryOptions)
+      .forget_scev_loop_unroll;
 }
 
 /// A magic value for use with the Threshold parameter to indicate
@@ -92,7 +94,8 @@ TargetTransformInfo::UnrollingPreferences llvm::gatherUnrollingPreferences(
     std::optional<unsigned> UserThreshold, std::optional<bool> UserAllowPartial,
     std::optional<bool> UserRuntime, std::optional<bool> UserUpperBound,
     std::optional<unsigned> UserFullUnrollMaxCount) {
-  const ScalarOptions &Opts = ScalarOptions::Global;
+  const ScalarOptions &Opts =
+      L->getHeader()->getContext().getLibraryOptions().get<ScalarOptions>();
   TargetTransformInfo::UnrollingPreferences UP;
 
   // Set up the defaults
@@ -684,7 +687,11 @@ static unsigned unrollCountPragmaValue(const Loop *L) {
 }
 
 UnrollPragmaInfo::UnrollPragmaInfo(const Loop *L)
-    : UserUnrollCount(ScalarOptions::Global.unroll_count.has_value()),
+    : UserUnrollCount(L->getHeader()
+                          ->getContext()
+                          .getLibraryOptions()
+                          .get<ScalarOptions>()
+                          .unroll_count.has_value()),
       PragmaFullUnroll(hasUnrollFullPragma(L)),
       PragmaCount(unrollCountPragmaValue(L)),
       PragmaEnableUnroll(hasUnrollEnablePragma(L)),
@@ -920,7 +927,8 @@ unsigned llvm::computeUnrollCount(
     const unsigned TripMultiple, const UnrollCostEstimator &UCE,
     TargetTransformInfo::UnrollingPreferences &UP,
     TargetTransformInfo::PeelingPreferences &PP) {
-  const ScalarOptions &Opts = ScalarOptions::Global;
+  const ScalarOptions &Opts =
+      L->getHeader()->getContext().getLibraryOptions().get<ScalarOptions>();
 
   unsigned LoopSize = UCE.getRolledLoopSize();
 
@@ -1544,6 +1552,8 @@ PreservedAnalyses LoopFullUnrollPass::run(Loop &L, LoopAnalysisManager &AM,
   // pass. Function analyses need to be preserved across loop transformations
   // but ORE cannot be preserved (see comment before the pass definition).
   OptimizationRemarkEmitter ORE(L.getHeader()->getParent());
+  const ScalarOptions &Opts =
+      L.getHeader()->getContext().getLibraryOptions().get<ScalarOptions>();
 
   // Keep track of the previous loop structure so we can identify new loops
   // created by unrolling.
@@ -1613,7 +1623,7 @@ PreservedAnalyses LoopFullUnrollPass::run(Loop &L, LoopAnalysisManager &AM,
     Updater.markLoopAsDeleted(L, LoopName);
   } else {
     // We can only walk child loops if the current loop remained valid.
-    if (ScalarOptions::Global.unroll_revisit_child_loops) {
+    if (Opts.unroll_revisit_child_loops) {
       // Walk *all* of the child loops.
       SmallVector<Loop *, 4> ChildLoops(L.begin(), L.end());
       Updater.addChildLoops(ChildLoops);
diff --git a/llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp b/llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp
index 04d174b80e2605..7dee72e8a581a3 100644
--- a/llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp
@@ -545,8 +545,9 @@ PreservedAnalyses LoopVersioningLICMPass::run(Loop &L, LoopAnalysisManager &AM,
   OptimizationRemarkEmitter ORE(F);
 
   LoopAccessInfoManager LAIs(*SE, *AA, *DT, LAR.LI, nullptr, nullptr, &LAR.AC);
-  if (!LoopVersioningLICM(ScalarOptions::Global, AA, SE, &ORE, LAIs, LAR.LI, &L)
-           .run(DT))
+  const ScalarOptions &Opts =
+      F->getContext().getLibraryOptions().get<ScalarOptions>();
+  if (!LoopVersioningLICM(Opts, AA, SE, &ORE, LAIs, LAR.LI, &L).run(DT))
     return PreservedAnalyses::all();
   return getLoopPassPreservedAnalyses();
 }
diff --git a/llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp b/llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp
index d81404dda3b2c5..8470e4ea15fb63 100644
--- a/llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp
+++ b/llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp
@@ -41,9 +41,10 @@ STATISTIC(ExpectIntrinsicsHandled,
 // programmers may be using __builtin_expect() / llvm.expect to annotate that a
 // branch is likely or unlikely to be taken.
 
-static std::tuple<uint32_t, uint32_t>
-getBranchWeight(Intrinsic::ID IntrinsicID, CallInst *CI, int BranchCount) {
-  const ScalarOptions &Opts = ScalarOptions::Global;
+static std::tuple<uint32_t, uint32_t> getBranchWeight(const ScalarOptions &Opts,
+                                                      Intrinsic::ID IntrinsicID,
+                                                      CallInst *CI,
+                                                      int BranchCount) {
   if (IntrinsicID == Intrinsic::expect) {
     // __builtin_expect
     return std::make_tuple(Opts.likely_branch_weight,
@@ -63,7 +64,7 @@ getBranchWeight(Intrinsic::ID IntrinsicID, CallInst *CI, int BranchCount) {
   }
 }
 
-static bool handleSwitchExpect(SwitchInst &SI) {
+static bool handleSwitchExpect(const ScalarOptions &Opts, SwitchInst &SI) {
   CallInst *CI = dyn_cast<CallInst>(SI.getCondition());
   if (!CI)
     return false;
@@ -82,7 +83,7 @@ static bool handleSwitchExpect(SwitchInst &SI) {
   unsigned n = SI.getNumCases(); // +1 for default case.
   uint32_t LikelyBranchWeightVal, UnlikelyBranchWeightVal;
   std::tie(LikelyBranchWeightVal, UnlikelyBranchWeightVal) =
-      getBranchWeight(Fn->getIntrinsicID(), CI, n + 1);
+      getBranchWeight(Opts, Fn->getIntrinsicID(), CI, n + 1);
 
   SmallVector<uint32_t, 16> Weights(n + 1, UnlikelyBranchWeightVal);
 
@@ -103,7 +104,7 @@ static bool handleSwitchExpect(SwitchInst &SI) {
 /// with the expected value of phi def, then the corresponding incoming
 /// edge of the phi is unlikely to be taken. Using that information,
 /// the branch probability info for the originating branch can be inferred.
-static void handlePhiDef(CallInst *Expect) {
+static void handlePhiDef(const ScalarOptions &Opts, CallInst *Expect) {
   Value &Arg = *Expect->getArgOperand(0);
   ConstantInt *ExpectedValue = dyn_cast<ConstantInt>(Expect->getArgOperand(1));
   if (!ExpectedValue)
@@ -241,7 +242,7 @@ static void handlePhiDef(CallInst *Expect) {
     };
     uint32_t LikelyBranchWeightVal, UnlikelyBranchWeightVal;
     std::tie(LikelyBranchWeightVal, UnlikelyBranchWeightVal) = getBranchWeight(
-        Expect->getCalledFunction()->getIntrinsicID(), Expect, 2);
+        Opts, Expect->getCalledFunction()->getIntrinsicID(), Expect, 2);
     if (!ExpectedValueIsLikely)
       std::swap(LikelyBranchWeightVal, UnlikelyBranchWeightVal);
 
@@ -259,7 +260,8 @@ static void handlePhiDef(CallInst *Expect) {
 }
 
 // Handle both CondBrInst and SelectInst.
-template <class BrSelInst> static bool handleBrSelExpect(BrSelInst &BSI) {
+template <class BrSelInst>
+static bool handleBrSelExpect(const ScalarOptions &Opts, BrSelInst &BSI) {
 
   // Handle non-optimized IR code like:
   //   %expval = call i64 @llvm.expect.i64(i64 %conv1, i64 1)
@@ -314,7 +316,7 @@ template <class BrSelInst> static bool handleBrSelExpect(BrSelInst &BSI) {
 
   uint32_t LikelyBranchWeightVal, UnlikelyBranchWeightVal;
   std::tie(LikelyBranchWeightVal, UnlikelyBranchWeightVal) =
-      getBranchWeight(Fn->getIntrinsicID(), CI, 2);
+      getBranchWeight(Opts, Fn->getIntrinsicID(), CI, 2);
 
   SmallVector<uint32_t, 4> ExpectedWeights;
   if ((ExpectedValue->getZExtValue() == ValueComparedTo) ==
@@ -341,15 +343,17 @@ template <class BrSelInst> static bool handleBrSelExpect(BrSelInst &BSI) {
 }
 
 static bool lowerExpectIntrinsic(Function &F) {
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
   bool Changed = false;
 
   for (BasicBlock &BB : F) {
     // Create "block_weights" metadata.
     if (CondBrInst *BI = dyn_cast<CondBrInst>(BB.getTerminator())) {
-      if (handleBrSelExpect<CondBrInst>(*BI))
+      if (handleBrSelExpect<CondBrInst>(Opts, *BI))
         ExpectIntrinsicsHandled++;
     } else if (SwitchInst *SI = dyn_cast<SwitchInst>(BB.getTerminator())) {
-      if (handleSwitchExpect(*SI))
+      if (handleSwitchExpect(Opts, *SI))
         ExpectIntrinsicsHandled++;
     }
 
@@ -360,7 +364,7 @@ static bool lowerExpectIntrinsic(Function &F) {
       CallInst *CI = dyn_cast<CallInst>(&Inst);
       if (!CI) {
         if (SelectInst *SI = dyn_cast<SelectInst>(&Inst)) {
-          if (handleBrSelExpect(*SI))
+          if (handleBrSelExpect(Opts, *SI))
             ExpectIntrinsicsHandled++;
         }
         continue;
@@ -372,7 +376,7 @@ static bool lowerExpectIntrinsic(Function &F) {
         // Before erasing the llvm.expect, walk backward to find
         // phi that define llvm.expect's first arg, and
         // infer branch probability:
-        handlePhiDef(CI);
+        handlePhiDef(Opts, CI);
         Value *Exp = CI->getArgOperand(0);
         CI->replaceAllUsesWith(Exp);
         CI->eraseFromParent();
diff --git a/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp b/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp
index 44af9c7dbc9761..485eae8e5273a6 100644
--- a/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp
+++ b/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp
@@ -160,12 +160,8 @@ struct ShapeInfo {
   unsigned NumRows;
   unsigned NumColumns;
 
-  bool IsColumnMajor;
-
   ShapeInfo(unsigned NumRows = 0, unsigned NumColumns = 0)
-      : NumRows(NumRows), NumColumns(NumColumns),
-        IsColumnMajor(ScalarOptions::Global.matrix_default_layout ==
-                      MatrixLayoutTy::ColumnMajor) {}
+      : NumRows(NumRows), NumColumns(NumColumns) {}
 
   ShapeInfo(Value *NumRows, Value *NumColumns)
       : ShapeInfo(cast<ConstantInt>(NumRows)->getZExtValue(),
@@ -183,18 +179,6 @@ struct ShapeInfo {
     return NumRows != 0;
   }
 
-  unsigned getStride() const {
-    if (IsColumnMajor)
-      return NumRows;
-    return NumColumns;
-  }
-
-  unsigned getNumVectors() const {
-    if (IsColumnMajor)
-      return NumColumns;
-    return NumRows;
-  }
-
   /// Returns the transposed shape.
   ShapeInfo t() const { return ShapeInfo(NumColumns, NumRows); }
 
@@ -384,13 +368,16 @@ class LowerMatrixIntrinsics {
 
     OpInfoTy OpInfo;
 
-    bool IsColumnMajor = ScalarOptions::Global.matrix_default_layout ==
-                         MatrixLayoutTy::ColumnMajor;
+    bool IsColumnMajor = true;
 
   public:
     MatrixTy() = default;
-    MatrixTy(ArrayRef<Value *> Vectors) : Vectors(Vectors) {}
-    MatrixTy(unsigned NumRows, unsigned NumColumns, Type *EltTy) {
+    explicit MatrixTy(bool IsColumnMajor) : IsColumnMajor(IsColumnMajor) {}
+    MatrixTy(bool IsColumnMajor, ArrayRef<Value *> Vectors)
+        : Vectors(Vectors), IsColumnMajor(IsColumnMajor) {}
+    MatrixTy(bool IsColumnMajor, unsigned NumRows, unsigned NumColumns,
+             Type *EltTy)
+        : IsColumnMajor(IsColumnMajor) {
 
       unsigned D = isColumnMajor() ? NumColumns : NumRows;
       for (unsigned J = 0; J < D; ++J)
@@ -550,11 +537,22 @@ class LowerMatrixIntrinsics {
     return FMF;
   }
 
+  bool isColumnMajor() const {
+    return Opts.matrix_default_layout == MatrixLayoutTy::ColumnMajor;
+  }
+
+  unsigned getStride(const ShapeInfo &SI) const {
+    return isColumnMajor() ? SI.NumRows : SI.NumColumns;
+  }
+
+  unsigned getNumVectors(const ShapeInfo &SI) const {
+    return isColumnMajor() ? SI.NumColumns : SI.NumRows;
+  }
+
 public:
-  LowerMatrixIntrinsics(Function &F, TargetTransformInfo &TTI,
-                        FunctionAnalysisManager *AM)
-      : Opts(ScalarOptions::Global), Func(F), DL(F.getDataLayout()), TTI(TTI),
-        AM(AM) {}
+  LowerMatrixIntrinsics(const ScalarOptions &Opts, Function &F,
+                        TargetTransformInfo &TTI, FunctionAnalysisManager *AM)
+      : Opts(Opts), Func(F), DL(F.getDataLayout()), TTI(TTI), AM(AM) {}
 
   unsigned getNumOps(Type *VT) {
     assert(isa<FixedVectorType>(VT) && "Expected vector type");
@@ -623,9 +621,9 @@ class LowerMatrixIntrinsics {
     // Otherwise split MatrixVal.
     SmallVector<Value *, 16> SplitVecs;
     for (unsigned MaskStart = 0; MaskStart < VType->getNumElements();
-         MaskStart += SI.getStride()) {
+         MaskStart += getStride(SI)) {
       Value *V = Builder.CreateShuffleVector(
-          MatrixVal, createSequentialMask(MaskStart, SI.getStride(), 0),
+          MatrixVal, createSequentialMask(MaskStart, getStride(SI), 0),
           "split");
       SplitVecs.push_back(V);
     }
@@ -655,7 +653,7 @@ class LowerMatrixIntrinsics {
       }
     }
 
-    return {SplitVecs};
+    return {isColumnMajor(), SplitVecs};
   }
 
   /// If \p V already has a known shape return false.  Otherwise set the shape
@@ -1150,7 +1148,7 @@ class LowerMatrixIntrinsics {
 
       const ShapeInfo &SI = ShapeMap.at(Inst);
       auto *EltTy = cast<FixedVectorType>(PHI->getType())->getElementType();
-      MatrixTy PhiM(SI.NumRows, SI.NumColumns, EltTy);
+      MatrixTy PhiM(isColumnMajor(), SI.NumRows, SI.NumColumns, EltTy);
 
       IRBuilder<> Builder(Inst);
       for (unsigned VI = 0, VE = PhiM.getNumVectors(); VI != VE; ++VI)
@@ -1247,7 +1245,7 @@ class LowerMatrixIntrinsics {
       return LowerColumnMajorStore(Inst, Builder);
     case Intrinsic::abs:
     case Intrinsic::fabs: {
-      MatrixTy Result;
+      MatrixTy Result(isColumnMajor());
       MatrixTy M = getMatrix(Inst->getOperand(0), SI, Builder);
       Builder.setFastMathFlags(getFastMathFlags(Inst));
 
@@ -1320,14 +1318,14 @@ class LowerMatrixIntrinsics {
                       bool IsVolatile, ShapeInfo Shape, IRBuilder<> &Builder) {
     auto *VType = cast<FixedVectorType>(Ty);
     Type *EltTy = VType->getElementType();
-    Type *VecTy = FixedVectorType::get(EltTy, Shape.getStride());
+    Type *VecTy = FixedVectorType::get(EltTy, getStride(Shape));
     Value *EltPtr = Ptr;
-    MatrixTy Result;
+    MatrixTy Result(isColumnMajor());
     Stride = castToIndexType(Ptr, Stride, Builder);
-    for (unsigned I = 0, E = Shape.getNumVectors(); I < E; ++I) {
+    for (unsigned I = 0, E = getNumVectors(Shape); I < E; ++I) {
       Value *GEP = computeVectorAddr(
           EltPtr, Builder.getIntN(Stride->getType()->getScalarSizeInBits(), I),
-          Stride, Shape.getStride(), EltTy, Builder);
+          Stride, getStride(Shape), EltTy, Builder);
       Value *Vector = Builder.CreateAlignedLoad(
           VecTy, GEP, getAlignForIndex(I, Stride, EltTy, MAlign),
           IsVolatile, "col.load");
@@ -1345,14 +1343,14 @@ class LowerMatrixIntrinsics {
                       ShapeInfo ResultShape, Type *EltTy,
                       IRBuilder<> &Builder) {
     Value *Offset = Builder.CreateAdd(
-        Builder.CreateMul(J, getIndex(MatrixPtr, MatrixShape.getStride())), I);
+        Builder.CreateMul(J, getIndex(MatrixPtr, getStride(MatrixShape))), I);
 
     Value *TileStart = Builder.CreateInBoundsGEP(EltTy, MatrixPtr, Offset);
     auto *TileTy = FixedVectorType::get(EltTy, ResultShape.NumRows *
                                                    ResultShape.NumColumns);
 
     return loadMatrix(TileTy, TileStart, Align,
-                      getIndex(MatrixPtr, MatrixShape.getStride()), IsVolatile,
+                      getIndex(MatrixPtr, getStride(MatrixShape)), IsVolatile,
                       ResultShape, Builder);
   }
 
@@ -1383,14 +1381,14 @@ class LowerMatrixIntrinsics {
                    MaybeAlign MAlign, bool IsVolatile, ShapeInfo MatrixShape,
                    Value *I, Value *J, Type *EltTy, IRBuilder<> &Builder) {
     Value *Offset = Builder.CreateAdd(
-        Builder.CreateMul(J, getIndex(MatrixPtr, MatrixShape.getStride())), I);
+        Builder.CreateMul(J, getIndex(MatrixPtr, getStride(MatrixShape))), I);
 
     Value *TileStart = Builder.CreateInBoundsGEP(EltTy, MatrixPtr, Offset);
     auto *TileTy = FixedVectorType::get(EltTy, StoreVal.getNumRows() *
                                                    StoreVal.getNumColumns());
 
     storeMatrix(TileTy, StoreVal, TileStart, MAlign,
-                getIndex(MatrixPtr, MatrixShape.getStride()), IsVolatile,
+                getIndex(MatrixPtr, getStride(MatrixShape)), IsVolatile,
                 Builder);
   }
 
@@ -1414,8 +1412,9 @@ class LowerMatrixIntrinsics {
                                                   MAlign),
                                  IsVolatile);
     }
-    return MatrixTy().addNumStores(getNumOps(StoreVal.getVectorTy()) *
-                                   StoreVal.getNumVectors());
+    return MatrixTy(isColumnMajor())
+        .addNumStores(getNumOps(StoreVal.getVectorTy()) *
+                      StoreVal.getNumVectors());
   }
 
   /// Lower a store instruction with shape information.
@@ -1990,7 +1989,7 @@ class LowerMatrixIntrinsics {
   }
 
   MatrixTy getZeroMatrix(Type *EltType, unsigned R, unsigned C) {
-    MatrixTy Res;
+    MatrixTy Res(isColumnMajor());
     auto *ColumType = FixedVectorType::get(EltType, R);
     for (unsigned I = 0; I < C; ++I)
       Res.addVector(ConstantAggregateZero::get(ColumType));
@@ -2014,7 +2013,7 @@ class LowerMatrixIntrinsics {
 
     Type *TileVecTy = FixedVectorType::get(MatMul->getType()->getScalarType(),
                                            Opts.fuse_matrix_tile_size);
-    MatrixTy TileResult;
+    MatrixTy TileResult(isColumnMajor());
     // Insert in the inner loop header.
     Builder.SetInsertPoint(TI.KLoop.Header->getTerminator());
     // Create PHI nodes for the result columns to accumulate across iterations.
@@ -2183,7 +2182,7 @@ class LowerMatrixIntrinsics {
       }
 
       // Initialize the output
-      MatrixTy Result(R, C, EltType);
+      MatrixTy Result(isColumnMajor(), R, C, EltType);
 
       emitMatrixMultiply(Result, MA, MB, Builder, false, true,
                          getFastMathFlags(MatMul));
@@ -2194,7 +2193,7 @@ class LowerMatrixIntrinsics {
         ToRemove.push_back(cast<Instruction>(Transpose));
         // TODO: add a fake entry for the folded instruction so that this is
         // included in the expression in the remark.
-        Inst2ColumnMatrix[Transpose] = MatrixTy(M, C, EltType);
+        Inst2ColumnMatrix[Transpose] = MatrixTy(isColumnMajor(), M, C, EltType);
       }
       finalizeLowering(MatMul, Result, Builder);
       return;
@@ -2306,7 +2305,7 @@ class LowerMatrixIntrinsics {
     assert(LShape.NumColumns == RShape.NumRows);
 
     // Initialize the output
-    MatrixTy Result(R, C, EltType);
+    MatrixTy Result(isColumnMajor(), R, C, EltType);
     assert(Lhs.getElementType() == Result.getElementType() &&
            "Matrix multiply result element type does not match arguments.");
 
@@ -2317,7 +2316,7 @@ class LowerMatrixIntrinsics {
 
   /// Lowers llvm.matrix.transpose.
   MatrixTy LowerTranspose(CallInst *Inst, IRBuilder<> &Builder) {
-    MatrixTy Result;
+    MatrixTy Result(isColumnMajor());
     Value *InputVal = Inst->getArgOperand(0);
     FixedVectorType *VectorTy = cast<FixedVectorType>(InputVal->getType());
     ShapeInfo ArgShape(Inst->getArgOperand(1), Inst->getArgOperand(2));
@@ -2352,14 +2351,14 @@ class LowerMatrixIntrinsics {
   /// Lower load instructions.
   MatrixTy VisitLoad(LoadInst *Inst, const ShapeInfo &SI, Value *Ptr,
                      IRBuilder<> &Builder) {
-    return LowerLoad(Inst, Ptr, Inst->getAlign(), getIndex(Ptr, SI.getStride()),
+    return LowerLoad(Inst, Ptr, Inst->getAlign(), getIndex(Ptr, getStride(SI)),
                      Inst->isVolatile(), SI, Builder);
   }
 
   MatrixTy VisitStore(StoreInst *Inst, const ShapeInfo &SI, Value *StoredVal,
                       Value *Ptr, IRBuilder<> &Builder) {
     return LowerStore(Inst, StoredVal, Ptr, Inst->getAlign(),
-                      getIndex(Ptr, SI.getStride()), Inst->isVolatile(), SI,
+                      getIndex(Ptr, getStride(SI)), Inst->isVolatile(), SI,
                       Builder);
   }
 
@@ -2404,7 +2403,7 @@ class LowerMatrixIntrinsics {
     Value *Lhs = Inst->getOperand(0);
     Value *Rhs = Inst->getOperand(1);
 
-    MatrixTy Result;
+    MatrixTy Result(isColumnMajor());
     MatrixTy A = getMatrix(Lhs, SI, Builder);
     MatrixTy B = getMatrix(Rhs, SI, Builder);
     assert(A.isColumnMajor() == B.isColumnMajor() &&
@@ -2425,7 +2424,7 @@ class LowerMatrixIntrinsics {
                               IRBuilder<> &Builder) {
     Value *Op = Inst->getOperand(0);
 
-    MatrixTy Result;
+    MatrixTy Result(isColumnMajor());
     MatrixTy M = getMatrix(Op, SI, Builder);
 
     Builder.setFastMathFlags(getFastMathFlags(Inst));
@@ -2452,7 +2451,7 @@ class LowerMatrixIntrinsics {
                                 IRBuilder<> &Builder) {
     Value *Op = Inst->getOperand(0);
 
-    MatrixTy Result;
+    MatrixTy Result(isColumnMajor());
     MatrixTy M = getMatrix(Op, Shape, Builder);
 
     Builder.setFastMathFlags(getFastMathFlags(Inst));
@@ -2475,7 +2474,7 @@ class LowerMatrixIntrinsics {
     Value *OpA = Inst->getOperand(1);
     Value *OpB = Inst->getOperand(2);
 
-    MatrixTy Result;
+    MatrixTy Result(isColumnMajor());
     MatrixTy A = getMatrix(OpA, Shape, Builder);
     MatrixTy B = getMatrix(OpB, Shape, Builder);
 
@@ -2937,7 +2936,9 @@ PreservedAnalyses LowerMatrixIntrinsicsPass::run(Function &F,
                                                  FunctionAnalysisManager &AM) {
   auto &TTI = AM.getResult<TargetIRAnalysis>(F);
 
-  LowerMatrixIntrinsics LMT(F, TTI, Minimal ? nullptr : &AM);
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
+  LowerMatrixIntrinsics LMT(Opts, F, TTI, Minimal ? nullptr : &AM);
   if (LMT.Visit()) {
     PreservedAnalyses PA;
     if (!Minimal) {
diff --git a/llvm/lib/Transforms/Scalar/NewGVN.cpp b/llvm/lib/Transforms/Scalar/NewGVN.cpp
index c69ae80f494225..8d082b90996d03 100644
--- a/llvm/lib/Transforms/Scalar/NewGVN.cpp
+++ b/llvm/lib/Transforms/Scalar/NewGVN.cpp
@@ -633,11 +633,10 @@ class NewGVN {
   SmallPtrSet<Instruction *, 8> InstructionsToErase;
 
 public:
-  NewGVN(Function &F, DominatorTree *DT, AssumptionCache *AC,
-         TargetLibraryInfo *TLI, AliasAnalysis *AA, MemorySSA *MSSA,
-         const DataLayout &DL)
-      : Opts(ScalarOptions::Global), F(F), DT(DT), TLI(TLI), AA(AA), MSSA(MSSA),
-        AC(AC), DL(DL),
+  NewGVN(const ScalarOptions &Opts, Function &F, DominatorTree *DT,
+         AssumptionCache *AC, TargetLibraryInfo *TLI, AliasAnalysis *AA,
+         MemorySSA *MSSA, const DataLayout &DL)
+      : Opts(Opts), F(F), DT(DT), TLI(TLI), AA(AA), MSSA(MSSA), AC(AC), DL(DL),
         // Reuse ExpressionAllocator for PredicateInfo as well.
         PredInfo(
             std::make_unique<PredicateInfo>(F, *DT, *AC, ExpressionAllocator)),
@@ -4227,9 +4226,10 @@ PreservedAnalyses NewGVNPass::run(Function &F, AnalysisManager<Function> &AM) {
   auto &TLI = AM.getResult<TargetLibraryAnalysis>(F);
   auto &AA = AM.getResult<AAManager>(F);
   auto &MSSA = AM.getResult<MemorySSAAnalysis>(F).getMSSA();
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
   bool Changed =
-      NewGVN(F, &DT, &AC, &TLI, &AA, &MSSA, F.getDataLayout())
-          .runGVN();
+      NewGVN(Opts, F, &DT, &AC, &TLI, &AA, &MSSA, F.getDataLayout()).runGVN();
   if (!Changed)
     return PreservedAnalyses::all();
   PreservedAnalyses PA;
diff --git a/llvm/lib/Transforms/Scalar/PlaceSafepoints.cpp b/llvm/lib/Transforms/Scalar/PlaceSafepoints.cpp
index eafb4cc0469259..ab55a0a27e2cd4 100644
--- a/llvm/lib/Transforms/Scalar/PlaceSafepoints.cpp
+++ b/llvm/lib/Transforms/Scalar/PlaceSafepoints.cpp
@@ -97,8 +97,7 @@ class PlaceBackedgeSafepointsLegacyPass : public FunctionPass {
   bool CallSafepointsEnabled;
 
   PlaceBackedgeSafepointsLegacyPass(bool CallSafepoints = false)
-      : FunctionPass(ID), CallSafepointsEnabled(CallSafepoints),
-        Opts(ScalarOptions::Global) {
+      : FunctionPass(ID), CallSafepointsEnabled(CallSafepoints) {
     initializePlaceBackedgeSafepointsLegacyPassPass(
         *PassRegistry::getPassRegistry());
   }
@@ -113,6 +112,7 @@ class PlaceBackedgeSafepointsLegacyPass : public FunctionPass {
   }
 
   bool runOnFunction(Function &F) override {
+    Opts = &F.getContext().getLibraryOptions().get<ScalarOptions>();
     SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
     DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
     LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
@@ -134,7 +134,7 @@ class PlaceBackedgeSafepointsLegacyPass : public FunctionPass {
   }
 
 private:
-  const ScalarOptions &Opts;
+  const ScalarOptions *Opts = nullptr;
   ScalarEvolution *SE = nullptr;
   DominatorTree *DT = nullptr;
   LoopInfo *LI = nullptr;
@@ -191,8 +191,8 @@ bool PlaceBackedgeSafepointsLegacyPass::runOnLoop(Loop *L) {
     // Make a policy decision about whether this loop needs a safepoint or
     // not.  Note that this is about unburdening the optimizer in loops, not
     // avoiding the runtime cost of the actual safepoint.
-    if (!Opts.spp_all_backedges) {
-      if (mustBeFiniteCountedLoop(Opts, L, SE, Pred)) {
+    if (!Opts->spp_all_backedges) {
+      if (mustBeFiniteCountedLoop(*Opts, L, SE, Pred)) {
         LLVM_DEBUG(dbgs() << "skipping safepoint placement in finite loop\n");
         FiniteExecution++;
         continue;
@@ -245,7 +245,8 @@ bool PlaceSafepointsPass::runImpl(Function &F, const TargetLibraryInfo &TLI) {
   if (!shouldRewriteFunction(F))
     return false;
 
-  const ScalarOptions &Opts = ScalarOptions::Global;
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
   bool Modified = false;
 
   // In various bits below, we rely on the fact that uses are reachable from
diff --git a/llvm/lib/Transforms/Scalar/Reassociate.cpp b/llvm/lib/Transforms/Scalar/Reassociate.cpp
index 8ce7d7061b403b..0d2f7c5684e905 100644
--- a/llvm/lib/Transforms/Scalar/Reassociate.cpp
+++ b/llvm/lib/Transforms/Scalar/Reassociate.cpp
@@ -2554,7 +2554,7 @@ void ReassociatePass::ReassociateExpression(BinaryOperator *I) {
     // reordering on the values that live in the first seen basic block.
     // The main idea is that we want to avoid forming expressions that would
     // become loop dependent.
-    if (ScalarOptions::Global.reassociate_use_cse_local) {
+    if (UseCSELocal) {
       const BasicBlock *FirstSeenBB = nullptr;
       int StartIdx = Ops.size() - 1;
       // Skip the first value of the expression since we need at least two
@@ -2731,6 +2731,10 @@ PreservedAnalyses ReassociatePass::run(Function &F,
 
 PreservedAnalyses ReassociatePass::runImpl(Function &F, UniformityInfo &UI) {
   UA = &UI;
+  UseCSELocal = F.getContext()
+                    .getLibraryOptions()
+                    .get<ScalarOptions>()
+                    .reassociate_use_cse_local;
 
   // Get the functions basic blocks in Reverse Post Order. This order is used by
   // BuildRankMap to pre calculate ranks correctly. It also excludes dead basic
diff --git a/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp b/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
index 93493e7f2877cd..35d86bafb5c532 100644
--- a/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
+++ b/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
@@ -3012,7 +3012,8 @@ bool RewriteStatepointsForGC::runOnFunction(Function &F, DominatorTree &DT,
   assert(!F.isDeclaration() && !F.empty() &&
          "need function body to rewrite statepoints in");
   assert(shouldRewriteStatepointsIn(F) && "mismatch in rewrite decision");
-  const ScalarOptions &Opts = ScalarOptions::Global;
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
 
   auto NeedsRewrite = [&](Instruction &I) {
     if (const auto *Call = dyn_cast<CallBase>(&I)) {
diff --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp
index e6407049899ec4..90c0bb016711f1 100644
--- a/llvm/lib/Transforms/Scalar/SROA.cpp
+++ b/llvm/lib/Transforms/Scalar/SROA.cpp
@@ -6469,7 +6469,7 @@ bool SROA::promoteAllocas() {
   if (PromotableAllocas.empty())
     return false;
 
-  if (ScalarOptions::Global.sroa_skip_mem2reg) {
+  if (C->getLibraryOptions().get<ScalarOptions>().sroa_skip_mem2reg) {
     LLVM_DEBUG(dbgs() << "Not promoting allocas with mem2reg!\n");
   } else {
     LLVM_DEBUG(dbgs() << "Promoting allocas with mem2reg...\n");
diff --git a/llvm/lib/Transforms/Scalar/ScalarOptions.td b/llvm/lib/Transforms/Scalar/ScalarOptions.td
index 8ca44f7009eaff..0f7cba53e38509 100644
--- a/llvm/lib/Transforms/Scalar/ScalarOptions.td
+++ b/llvm/lib/Transforms/Scalar/ScalarOptions.td
@@ -8,7 +8,7 @@
 
 include "llvm/Option/LibraryOptions.td"
 
-def ScalarOptions : OptionsStruct<perContext = false>;
+def ScalarOptions : OptionsStruct;
 
 // ADCE.cpp
 // This is a temporary option until we change the interface to this pass based
diff --git a/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp b/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp
index 3c5c6359729027..574a9b78594940 100644
--- a/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp
+++ b/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp
@@ -1331,7 +1331,8 @@ bool SeparateConstOffsetFromGEPLegacyPass::runOnFunction(Function &F) {
 }
 
 bool SeparateConstOffsetFromGEP::run(Function &F) {
-  const ScalarOptions &Opts = ScalarOptions::Global;
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
   if (Opts.disable_separate_const_offset_from_gep)
     return false;
 
diff --git a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
index 0d8b04c409d5bd..727b4b8505c433 100644
--- a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
+++ b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
@@ -3385,7 +3385,8 @@ static bool unswitchLoop(Loop &L, DominatorTree &DT, LoopInfo &LI,
                          TargetTransformInfo &TTI, bool Trivial,
                          bool NonTrivial, ScalarEvolution *SE,
                          MemorySSAUpdater *MSSAU, LPMUpdater &LoopUpdater) {
-  const ScalarOptions &Opts = ScalarOptions::Global;
+  const ScalarOptions &Opts =
+      L.getHeader()->getContext().getLibraryOptions().get<ScalarOptions>();
   assert(L.isRecursivelyLCSSAForm(DT, LI) &&
          "Loops must be in LCSSA form before unswitching.");
 
diff --git a/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp b/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp
index c3d9c3644e8a60..7d33458784d4ac 100644
--- a/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp
+++ b/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp
@@ -264,9 +264,13 @@ static bool simplifyFunctionCFGImpl(Function &F, const TargetTransformInfo &TTI,
   return true;
 }
 
+static void applyCommandLineOverridesToOptions(const ScalarOptions &Opts,
+                                               SimplifyCFGOptions &Options);
+
 static bool simplifyFunctionCFG(Function &F, const TargetTransformInfo &TTI,
-                                DominatorTree *DT,
-                                const SimplifyCFGOptions &Options) {
+                                DominatorTree *DT, SimplifyCFGOptions Options) {
+  applyCommandLineOverridesToOptions(
+      F.getContext().getLibraryOptions().get<ScalarOptions>(), Options);
   assert((!RequireAndPreserveDomTree ||
           (DT && DT->verify(DominatorTree::VerificationLevel::Full))) &&
          "Original domtree is invalid?");
@@ -281,8 +285,8 @@ static bool simplifyFunctionCFG(Function &F, const TargetTransformInfo &TTI,
 }
 
 // Command-line settings override compile-time settings.
-static void applyCommandLineOverridesToOptions(SimplifyCFGOptions &Options) {
-  const ScalarOptions &Opts = ScalarOptions::Global;
+static void applyCommandLineOverridesToOptions(const ScalarOptions &Opts,
+                                               SimplifyCFGOptions &Options) {
   if (Opts.bonus_inst_threshold)
     Options.BonusInstThreshold = *Opts.bonus_inst_threshold;
   Options.ForwardSwitchCondToPhi =
@@ -304,14 +308,10 @@ static void applyCommandLineOverridesToOptions(SimplifyCFGOptions &Options) {
       valueOr(Opts.speculate_unpredictables, Options.SpeculateUnpredictables);
 }
 
-SimplifyCFGPass::SimplifyCFGPass() {
-  applyCommandLineOverridesToOptions(Options);
-}
+SimplifyCFGPass::SimplifyCFGPass() = default;
 
 SimplifyCFGPass::SimplifyCFGPass(const SimplifyCFGOptions &Opts)
-    : Options(Opts) {
-  applyCommandLineOverridesToOptions(Options);
-}
+    : Options(Opts) {}
 
 void SimplifyCFGPass::printPipeline(
     raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) {
@@ -368,9 +368,6 @@ struct CFGSimplifyPass : public FunctionPass {
       : FunctionPass(ID), Options(Options_), PredicateFtor(std::move(Ftor)) {
 
     initializeCFGSimplifyPassPass(*PassRegistry::getPassRegistry());
-
-    // Check for command-line overrides of options for debug/customization.
-    applyCommandLineOverridesToOptions(Options);
   }
 
   bool runOnFunction(Function &F) override {
diff --git a/llvm/lib/Transforms/Scalar/SpeculativeExecution.cpp b/llvm/lib/Transforms/Scalar/SpeculativeExecution.cpp
index cdafa383fd0035..d2f643ad17f268 100644
--- a/llvm/lib/Transforms/Scalar/SpeculativeExecution.cpp
+++ b/llvm/lib/Transforms/Scalar/SpeculativeExecution.cpp
@@ -82,10 +82,7 @@ class SpeculativeExecutionLegacyPass : public FunctionPass {
 public:
   static char ID;
   explicit SpeculativeExecutionLegacyPass(bool OnlyIfDivergentTarget = false)
-      : FunctionPass(ID),
-        OnlyIfDivergentTarget(
-            OnlyIfDivergentTarget ||
-            ScalarOptions::Global.spec_exec_only_if_divergent_target),
+      : FunctionPass(ID), OnlyIfDivergentTarget(OnlyIfDivergentTarget),
         Impl(OnlyIfDivergentTarget) {}
 
   void getAnalysisUsage(AnalysisUsage &AU) const override;
@@ -128,7 +125,9 @@ bool SpeculativeExecutionLegacyPass::runOnFunction(Function &F) {
 }
 
 bool SpeculativeExecutionPass::runImpl(Function &F, TargetTransformInfo *TTI) {
-  if (OnlyIfDivergentTarget && !TTI->hasBranchDivergence(&F)) {
+  Opts = &F.getContext().getLibraryOptions().get<ScalarOptions>();
+  if ((OnlyIfDivergentTarget || Opts->spec_exec_only_if_divergent_target) &&
+      !TTI->hasBranchDivergence(&F)) {
     LLVM_DEBUG(dbgs() << "Not running SpeculativeExecution because "
                          "TTI->hasBranchDivergence() is false.\n");
     return false;
@@ -259,7 +258,6 @@ static InstructionCost ComputeSpeculationCost(const Instruction *I,
 
 bool SpeculativeExecutionPass::considerHoistingFromTo(
     BasicBlock &FromBlock, BasicBlock &ToBlock) {
-  const ScalarOptions &Opts = ScalarOptions::Global;
   SmallPtrSet<const Instruction *, 8> NotHoisted;
   auto HasNoUnhoistedInstr = [&NotHoisted](auto Values) {
     for (const Value *V : Values) {
@@ -281,11 +279,11 @@ bool SpeculativeExecutionPass::considerHoistingFromTo(
     if (Cost.isValid() && isSafeToSpeculativelyExecute(&I) &&
         AllPrecedingUsesFromBlockHoisted(&I)) {
       TotalSpeculationCost += Cost;
-      if (TotalSpeculationCost > Opts.spec_exec_max_speculation_cost)
+      if (TotalSpeculationCost > Opts->spec_exec_max_speculation_cost)
         return false;  // too much to hoist
     } else {
       NotHoistedInstCount++;
-      if (NotHoistedInstCount > Opts.spec_exec_max_not_hoisted)
+      if (NotHoistedInstCount > Opts->spec_exec_max_not_hoisted)
         return false; // too much left behind
       NotHoisted.insert(&I);
     }
@@ -313,9 +311,7 @@ FunctionPass *llvm::createSpeculativeExecutionIfHasBranchDivergencePass() {
 }
 
 SpeculativeExecutionPass::SpeculativeExecutionPass(bool OnlyIfDivergentTarget)
-    : OnlyIfDivergentTarget(
-          OnlyIfDivergentTarget ||
-          ScalarOptions::Global.spec_exec_only_if_divergent_target) {}
+    : OnlyIfDivergentTarget(OnlyIfDivergentTarget) {}
 
 PreservedAnalyses SpeculativeExecutionPass::run(Function &F,
                                                 FunctionAnalysisManager &AM) {
diff --git a/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp b/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp
index 242bf1ac9ae42e..664d32c4ad39a0 100644
--- a/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp
+++ b/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp
@@ -152,9 +152,10 @@ class StraightLineStrengthReduceLegacyPass : public FunctionPass {
 
 class StraightLineStrengthReduce {
 public:
-  StraightLineStrengthReduce(const DataLayout *DL, DominatorTree *DT,
-                             ScalarEvolution *SE, TargetTransformInfo *TTI)
-      : DL(DL), DT(DT), SE(SE), TTI(TTI) {}
+  StraightLineStrengthReduce(const ScalarOptions &Opts, const DataLayout *DL,
+                             DominatorTree *DT, ScalarEvolution *SE,
+                             TargetTransformInfo *TTI)
+      : Opts(Opts), DL(DL), DT(DT), SE(SE), TTI(TTI) {}
 
   // SLSR candidate. Such a candidate must be in one of the forms described in
   // the header comments.
@@ -407,6 +408,7 @@ class StraightLineStrengthReduce {
   static Value *emitBump(const Candidate &Basis, const Candidate &C,
                          IRBuilder<> &Builder, const DataLayout *DL);
 
+  const ScalarOptions &Opts;
   const DataLayout *DL = nullptr;
   DominatorTree *DT = nullptr;
   ScalarEvolution *SE;
@@ -1094,7 +1096,7 @@ void StraightLineStrengthReduce::allocateCandidatesAndFindBasis(
   // doing this early we avoid calling canReuseInstruction repeatedly for the
   // same instruction. The DropList is stored on the Candidate so the flags can
   // be dropped only if this candidate is used by an executed rewrite.
-  if (!ScalarOptions::Global.enable_poison_reuse_guard ||
+  if (!Opts.enable_poison_reuse_guard ||
       SE->canReuseInstruction(SE->getSCEV(I), I, Candidates.back().DropList)) {
     CandidateDict.add(Candidates.back());
   }
@@ -1404,7 +1406,9 @@ bool StraightLineStrengthReduceLegacyPass::runOnFunction(Function &F) {
   auto *TTI = &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
   auto *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
   auto *SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
-  return StraightLineStrengthReduce(DL, DT, SE, TTI).runOnFunction(F);
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
+  return StraightLineStrengthReduce(Opts, DL, DT, SE, TTI).runOnFunction(F);
 }
 
 bool StraightLineStrengthReduce::runOnFunction(Function &F) {
@@ -1454,7 +1458,9 @@ StraightLineStrengthReducePass::run(Function &F, FunctionAnalysisManager &AM) {
   auto *SE = &AM.getResult<ScalarEvolutionAnalysis>(F);
   auto *TTI = &AM.getResult<TargetIRAnalysis>(F);
 
-  if (!StraightLineStrengthReduce(DL, DT, SE, TTI).runOnFunction(F))
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
+  if (!StraightLineStrengthReduce(Opts, DL, DT, SE, TTI).runOnFunction(F))
     return PreservedAnalyses::all();
 
   PreservedAnalyses PA;
diff --git a/llvm/lib/Transforms/Scalar/StructurizeCFG.cpp b/llvm/lib/Transforms/Scalar/StructurizeCFG.cpp
index 5b1063f37ff224..5a021e6384f1d3 100644
--- a/llvm/lib/Transforms/Scalar/StructurizeCFG.cpp
+++ b/llvm/lib/Transforms/Scalar/StructurizeCFG.cpp
@@ -357,7 +357,8 @@ class StructurizeCFG {
 public:
   void init(Region *R);
   bool run(Region *R, DominatorTree *DT, const TargetTransformInfo *TTI);
-  bool makeUniformRegion(Region *R, UniformityInfo &UA);
+  bool makeUniformRegion(const ScalarOptions &Opts, Region *R,
+                         UniformityInfo &UA);
 };
 
 class StructurizeCFGLegacyPass : public RegionPass {
@@ -368,19 +369,18 @@ class StructurizeCFGLegacyPass : public RegionPass {
 
   explicit StructurizeCFGLegacyPass(bool SkipUniformRegions_ = false)
       : RegionPass(ID), SkipUniformRegions(SkipUniformRegions_) {
-    SkipUniformRegions =
-        valueOr(ScalarOptions::Global.structurizecfg_skip_uniform_regions,
-                SkipUniformRegions);
     initializeStructurizeCFGLegacyPassPass(*PassRegistry::getPassRegistry());
   }
 
   bool runOnRegion(Region *R, RGPassManager &RGM) override {
     StructurizeCFG SCFG;
     SCFG.init(R);
-    if (SkipUniformRegions) {
+    const ScalarOptions &Opts =
+        R->getEntry()->getContext().getLibraryOptions().get<ScalarOptions>();
+    if (valueOr(Opts.structurizecfg_skip_uniform_regions, SkipUniformRegions)) {
       UniformityInfo &UA =
           getAnalysis<UniformityInfoWrapperPass>().getUniformityInfo();
-      if (SCFG.makeUniformRegion(R, UA))
+      if (SCFG.makeUniformRegion(Opts, R, UA))
         return false;
     }
     Function *F = R->getEntry()->getParent();
@@ -393,8 +393,7 @@ class StructurizeCFGLegacyPass : public RegionPass {
   StringRef getPassName() const override { return "Structurize control flow"; }
 
   void getAnalysisUsage(AnalysisUsage &AU) const override {
-    if (SkipUniformRegions)
-      AU.addRequired<UniformityInfoWrapperPass>();
+    AU.addRequired<UniformityInfoWrapperPass>();
     AU.addRequired<DominatorTreeWrapperPass>();
     AU.addRequired<TargetTransformInfoWrapperPass>();
 
@@ -1278,7 +1277,8 @@ void StructurizeCFG::rebuildSSA() {
     }
 }
 
-static bool hasOnlyUniformBranches(Region *R, unsigned UniformMDKindID,
+static bool hasOnlyUniformBranches(const ScalarOptions &Opts, Region *R,
+                                   unsigned UniformMDKindID,
                                    const UniformityInfo &UA) {
   // Bool for if all sub-regions are uniform.
   bool SubRegionsAreUniform = true;
@@ -1316,7 +1316,7 @@ static bool hasOnlyUniformBranches(Region *R, unsigned UniformMDKindID,
 
         if (!Br->getMetadata(UniformMDKindID)) {
           // Early exit if we cannot have relaxed uniform regions.
-          if (!ScalarOptions::Global.structurizecfg_relaxed_uniform_regions)
+          if (!Opts.structurizecfg_relaxed_uniform_regions)
             return false;
 
           SubRegionsAreUniform = false;
@@ -1346,7 +1346,8 @@ void StructurizeCFG::init(Region *R) {
   this->UA = nullptr;
 }
 
-bool StructurizeCFG::makeUniformRegion(Region *R, UniformityInfo &UA) {
+bool StructurizeCFG::makeUniformRegion(const ScalarOptions &Opts, Region *R,
+                                       UniformityInfo &UA) {
   if (R->isTopLevelRegion())
     return false;
 
@@ -1359,7 +1360,7 @@ bool StructurizeCFG::makeUniformRegion(Region *R, UniformityInfo &UA) {
   unsigned UniformMDKindID =
       R->getEntry()->getContext().getMDKindID("structurizecfg.uniform");
 
-  if (hasOnlyUniformBranches(R, UniformMDKindID, UA)) {
+  if (hasOnlyUniformBranches(Opts, R, UniformMDKindID, UA)) {
     LLVM_DEBUG(dbgs() << "Skipping region with uniform control flow: " << *R
                       << '\n');
 
@@ -1439,11 +1440,7 @@ static void addRegionIntoQueue(Region &R, std::vector<Region *> &Regions) {
 }
 
 StructurizeCFGPass::StructurizeCFGPass(bool SkipUniformRegions_)
-    : SkipUniformRegions(SkipUniformRegions_) {
-  SkipUniformRegions =
-      valueOr(ScalarOptions::Global.structurizecfg_skip_uniform_regions,
-              SkipUniformRegions);
-}
+    : SkipUniformRegions(SkipUniformRegions_) {}
 
 void StructurizeCFGPass::printPipeline(
     raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) {
@@ -1460,8 +1457,12 @@ PreservedAnalyses StructurizeCFGPass::run(Function &F,
   DominatorTree *DT = &AM.getResult<DominatorTreeAnalysis>(F);
   auto &RI = AM.getResult<RegionInfoAnalysis>(F);
   TargetTransformInfo *TTI = &AM.getResult<TargetIRAnalysis>(F);
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
+  bool SkipUniform =
+      valueOr(Opts.structurizecfg_skip_uniform_regions, SkipUniformRegions);
   UniformityInfo *UI = nullptr;
-  if (SkipUniformRegions)
+  if (SkipUniform)
     UI = &AM.getResult<UniformityInfoAnalysis>(F);
 
   std::vector<Region *> Regions;
@@ -1473,7 +1474,7 @@ PreservedAnalyses StructurizeCFGPass::run(Function &F,
     StructurizeCFG SCFG;
     SCFG.init(R);
 
-    if (SkipUniformRegions && SCFG.makeUniformRegion(R, *UI)) {
+    if (SkipUniform && SCFG.makeUniformRegion(Opts, R, *UI)) {
       Changed = true; // May have added metadata.
       continue;
     }
diff --git a/llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp b/llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp
index f891bf693b560f..9b48f582821595 100644
--- a/llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp
@@ -1148,7 +1148,8 @@ bool TailRecursionEliminator::eliminate(
   if (F.getFnAttribute("disable-tail-calls").getValueAsBool())
     return false;
 
-  const ScalarOptions &Opts = ScalarOptions::Global;
+  const ScalarOptions &Opts =
+      F.getContext().getLibraryOptions().get<ScalarOptions>();
   bool MadeChange = false;
   MadeChange |= markTails(Opts, F, ORE, PSI, BFI);
 
diff --git a/llvm/tools/llvm-cgdata/llvm-cgdata.cpp b/llvm/tools/llvm-cgdata/llvm-cgdata.cpp
index 9cb7b1657aa0ea..3a551b4c1dbcd2 100644
--- a/llvm/tools/llvm-cgdata/llvm-cgdata.cpp
+++ b/llvm/tools/llvm-cgdata/llvm-cgdata.cpp
@@ -22,6 +22,7 @@
 #include "llvm/Option/Option.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Driver.h"
+#include "llvm/Support/LibraryOptionsContext.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/VirtualFileSystem.h"
 #include "llvm/Support/WithColor.h"
@@ -108,7 +109,8 @@ static int convert_main(int argc, const char *argv[]) {
     exitWithErrorCode(EC, OutputFilename);
 
   auto FS = vfs::getRealFileSystem();
-  auto ReaderOrErr = CodeGenDataReader::create(Filename, *FS, LazyLoading);
+  auto ReaderOrErr = CodeGenDataReader::create(cl::LibraryOptionsContext(),
+                                               Filename, *FS, LazyLoading);
   if (Error E = ReaderOrErr.takeError())
     exitWithError(std::move(E), Filename);
 
@@ -206,7 +208,7 @@ static int merge_main(int argc, const char *argv[]) {
   if (!Result)
     exitWithError("failed to merge codegen data files.");
 
-  GlobalFunctionMapRecord.finalize(SkipTrim);
+  GlobalFunctionMapRecord.finalize(cl::LibraryOptionsContext(), SkipTrim);
 
   CodeGenDataWriter Writer;
   if (!GlobalOutlineRecord.empty())
@@ -240,7 +242,8 @@ static int show_main(int argc, const char *argv[]) {
     exitWithErrorCode(EC, OutputFilename);
 
   auto FS = vfs::getRealFileSystem();
-  auto ReaderOrErr = CodeGenDataReader::create(Filename, *FS, LazyLoading);
+  auto ReaderOrErr = CodeGenDataReader::create(cl::LibraryOptionsContext(),
+                                               Filename, *FS, LazyLoading);
   if (Error E = ReaderOrErr.takeError())
     exitWithError(std::move(E), Filename);
 
diff --git a/llvm/tools/opt/NewPMDriver.cpp b/llvm/tools/opt/NewPMDriver.cpp
index 2dd062f8d2c9c0..fb56822589a11b 100644
--- a/llvm/tools/opt/NewPMDriver.cpp
+++ b/llvm/tools/opt/NewPMDriver.cpp
@@ -473,7 +473,7 @@ bool llvm::runPassPipeline(
     Debugify.registerCallbacks(PIC, MAM);
   }
 
-  PipelineTuningOptions PTO;
+  PipelineTuningOptions PTO(&M.getContext().getLibraryOptions());
   // LoopUnrolling defaults on to true and DisableLoopUnrolling is initialized
   // to false above so we shouldn't necessarily need to check whether or not the
   // option has been enabled.
diff --git a/llvm/unittests/CGData/StableFunctionMapTest.cpp b/llvm/unittests/CGData/StableFunctionMapTest.cpp
index 5cf62ae0b39435..4727960be3e7c5 100644
--- a/llvm/unittests/CGData/StableFunctionMapTest.cpp
+++ b/llvm/unittests/CGData/StableFunctionMapTest.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/CGData/StableFunctionMap.h"
+#include "llvm/Support/LibraryOptionsContext.h"
 #include "gmock/gmock-matchers.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
@@ -90,7 +91,7 @@ TEST(StableFunctionMap, Finalize1) {
   Map.insert(Func2);
 
   // Instruction count is mis-matched, so they're not mergeable.
-  Map.finalize();
+  Map.finalize(cl::LibraryOptionsContext());
   EXPECT_THAT(Map, IsEmpty());
 }
 
@@ -102,7 +103,7 @@ TEST(StableFunctionMap, Finalize2) {
   Map.insert(Func2);
 
   // Operand map size is mis-matched, so they're not mergeable.
-  Map.finalize();
+  Map.finalize(cl::LibraryOptionsContext());
   EXPECT_THAT(Map, IsEmpty());
 }
 
@@ -114,7 +115,7 @@ TEST(StableFunctionMap, Finalize3) {
   Map.insert(Func2);
 
   // The same operand entry is removed, which is redundant.
-  Map.finalize();
+  Map.finalize(cl::LibraryOptionsContext());
   auto &M = Map.getFunctionMap();
   EXPECT_THAT(M, SizeIs(1));
   auto &FuncEntries = M.begin()->second.Entries;
diff --git a/polly/lib/Support/RegisterPasses.cpp b/polly/lib/Support/RegisterPasses.cpp
index bd3264fb2e4b59..63c73b85231430 100644
--- a/polly/lib/Support/RegisterPasses.cpp
+++ b/polly/lib/Support/RegisterPasses.cpp
@@ -458,13 +458,13 @@ parsePollyCustomOptions(StringRef Params) {
 /// @param EnableForOpt Whether to add Polly IR transformations. If False, only
 ///                     the analysis passes are added, skipping Polly itself.
 ///                     The IR may still be modified.
-static void buildCommonPollyPipeline(FunctionPassManager &PM,
-                                     OptimizationLevel Level,
-                                     IntrusiveRefCntPtr<vfs::FileSystem> FS,
-                                     bool EnableForOpt) {
+static void
+buildCommonPollyPipeline(const cl::LibraryOptionsContext *LibraryOptions,
+                         FunctionPassManager &PM, OptimizationLevel Level,
+                         IntrusiveRefCntPtr<vfs::FileSystem> FS,
+                         bool EnableForOpt) {
   PassBuilder PB(
-      /*TM=*/nullptr,
-      /*PipelineTuningOptions=*/{},
+      /*TM=*/nullptr, PipelineTuningOptions(LibraryOptions),
       /*PGOOpt=*/{},
       /*PIC=*/nullptr, std::move(FS));
 
@@ -480,9 +480,11 @@ static void buildCommonPollyPipeline(FunctionPassManager &PM,
     PM.addPass(llvm::CFGPrinterPass());
 }
 
-static void buildEarlyPollyPipeline(llvm::ModulePassManager &MPM,
-                                    llvm::OptimizationLevel Level,
-                                    IntrusiveRefCntPtr<vfs::FileSystem> FS) {
+static void
+buildEarlyPollyPipeline(const cl::LibraryOptionsContext *LibraryOptions,
+                        llvm::ModulePassManager &MPM,
+                        llvm::OptimizationLevel Level,
+                        IntrusiveRefCntPtr<vfs::FileSystem> FS) {
   bool EnableForOpt =
       shouldEnablePollyForOptimization() && Level != OptimizationLevel::O0;
   if (!shouldEnablePollyForDiagnostic() && !EnableForOpt)
@@ -501,7 +503,8 @@ static void buildEarlyPollyPipeline(llvm::ModulePassManager &MPM,
     FPM = FunctionPassManager();
   }
 
-  buildCommonPollyPipeline(FPM, Level, std::move(FS), EnableForOpt);
+  buildCommonPollyPipeline(LibraryOptions, FPM, Level, std::move(FS),
+                           EnableForOpt);
   MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
 
   if (DumpAfter)
@@ -510,9 +513,10 @@ static void buildEarlyPollyPipeline(llvm::ModulePassManager &MPM,
     MPM.addPass(DumpModulePass(Filename, false));
 }
 
-static void buildLatePollyPipeline(FunctionPassManager &PM,
-                                   llvm::OptimizationLevel Level,
-                                   IntrusiveRefCntPtr<vfs::FileSystem> FS) {
+static void
+buildLatePollyPipeline(const cl::LibraryOptionsContext *LibraryOptions,
+                       FunctionPassManager &PM, llvm::OptimizationLevel Level,
+                       IntrusiveRefCntPtr<vfs::FileSystem> FS) {
   bool EnableForOpt =
       shouldEnablePollyForOptimization() && Level != OptimizationLevel::O0;
   if (!shouldEnablePollyForDiagnostic() && !EnableForOpt)
@@ -526,7 +530,8 @@ static void buildLatePollyPipeline(FunctionPassManager &PM,
         "not supported with NPM",
         false);
 
-  buildCommonPollyPipeline(PM, Level, std::move(FS), EnableForOpt);
+  buildCommonPollyPipeline(LibraryOptions, PM, Level, std::move(FS),
+                           EnableForOpt);
 
   if (DumpAfter)
     PM.addPass(DumpFunctionPass("-after"));
@@ -634,6 +639,7 @@ parseModulePipeline(StringRef Name, llvm::ModulePassManager &MPM,
 void registerPollyPasses(PassBuilder &PB) {
   PassInstrumentationCallbacks *PIC = PB.getPassInstrumentationCallbacks();
   IntrusiveRefCntPtr<vfs::FileSystem> FS = PB.getVirtualFileSystemPtr();
+  const cl::LibraryOptionsContext *LibraryOptions = PB.getLibraryOptions();
 
 #define MODULE_PASS(NAME, CREATE_PASS, PARSER)                                 \
   {                                                                            \
@@ -677,14 +683,15 @@ void registerPollyPasses(PassBuilder &PB) {
   switch (PassPosition) {
   case POSITION_EARLY:
     PB.registerPipelineStartEPCallback(
-        [FS](ModulePassManager &MPM, OptimizationLevel Level) {
-          buildEarlyPollyPipeline(MPM, Level, FS);
+        [FS, LibraryOptions](ModulePassManager &MPM, OptimizationLevel Level) {
+          buildEarlyPollyPipeline(LibraryOptions, MPM, Level, FS);
         });
     break;
   case POSITION_BEFORE_VECTORIZER:
     PB.registerVectorizerStartEPCallback(
-        [FS](FunctionPassManager &FPM, OptimizationLevel Level) {
-          buildLatePollyPipeline(FPM, Level, FS);
+        [FS, LibraryOptions](FunctionPassManager &FPM,
+                             OptimizationLevel Level) {
+          buildLatePollyPipeline(LibraryOptions, FPM, Level, FS);
         });
     break;
   }
diff --git a/polly/lib/Transform/ScopInliner.cpp b/polly/lib/Transform/ScopInliner.cpp
index 50082abf55a0d6..222f4914dd456c 100644
--- a/polly/lib/Transform/ScopInliner.cpp
+++ b/polly/lib/Transform/ScopInliner.cpp
@@ -54,7 +54,7 @@ bool runScopInlinerImpl(Function *F, SCC_t &SCC,
 
   PassBuilder PB(
       /*TM=*/nullptr,
-      /*PipelineTuningOptions=*/{},
+      PipelineTuningOptions(&F->getContext().getLibraryOptions()),
       /*PGOOpt=*/{},
       /*PIC=*/nullptr, std::move(FS));
   // Populate analysis managers and register Polly-specific analyses.



More information about the flang-commits mailing list